diff options
Diffstat (limited to 'drivers/gpu/drm/rockchip')
| -rw-r--r-- | drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 42 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/cdn-dp-core.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/cdn-dp-reg.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 21 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 195 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/inno_hdmi.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/rk3066_hdmi.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 13 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 142 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_lvds.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_rgb.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 49 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 1 |
15 files changed, 302 insertions, 179 deletions
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index d30f0983a53a..fdab71d51e2a 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -28,6 +28,7 @@ #include <drm/bridge/analogix_dp.h> #include <drm/drm_of.h> #include <drm/drm_panel.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> @@ -330,38 +331,29 @@ static int rockchip_dp_of_probe(struct rockchip_dp_device *dp) struct device_node *np = dev->of_node; dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); - if (IS_ERR(dp->grf)) { - DRM_DEV_ERROR(dev, "failed to get rockchip,grf property\n"); - return PTR_ERR(dp->grf); - } + if (IS_ERR(dp->grf)) + return dev_err_probe(dev, PTR_ERR(dp->grf), + "failed to get rockchip,grf property\n"); - dp->grfclk = devm_clk_get(dev, "grf"); - if (PTR_ERR(dp->grfclk) == -ENOENT) { - dp->grfclk = NULL; - } else if (PTR_ERR(dp->grfclk) == -EPROBE_DEFER) { - return -EPROBE_DEFER; - } else if (IS_ERR(dp->grfclk)) { - DRM_DEV_ERROR(dev, "failed to get grf clock\n"); - return PTR_ERR(dp->grfclk); - } + dp->grfclk = devm_clk_get_optional(dev, "grf"); + if (IS_ERR(dp->grfclk)) + return dev_err_probe(dev, PTR_ERR(dp->grfclk), + "failed to get grf clock\n"); dp->pclk = devm_clk_get(dev, "pclk"); - if (IS_ERR(dp->pclk)) { - DRM_DEV_ERROR(dev, "failed to get pclk property\n"); - return PTR_ERR(dp->pclk); - } + if (IS_ERR(dp->pclk)) + return dev_err_probe(dev, PTR_ERR(dp->pclk), + "failed to get pclk property\n"); dp->rst = devm_reset_control_get(dev, "dp"); - if (IS_ERR(dp->rst)) { - DRM_DEV_ERROR(dev, "failed to get dp reset control\n"); - return PTR_ERR(dp->rst); - } + if (IS_ERR(dp->rst)) + return dev_err_probe(dev, PTR_ERR(dp->rst), + "failed to get dp reset control\n"); dp->apbrst = devm_reset_control_get_optional(dev, "apb"); - if (IS_ERR(dp->apbrst)) { - DRM_DEV_ERROR(dev, "failed to get apb reset control\n"); - return PTR_ERR(dp->apbrst); - } + if (IS_ERR(dp->apbrst)) + return dev_err_probe(dev, PTR_ERR(dp->apbrst), + "failed to get apb reset control\n"); return 0; } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index b7e3f5dcf8d5..177e30445ee8 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -21,6 +21,7 @@ #include <drm/drm_bridge_connector.h> #include <drm/drm_edid.h> #include <drm/drm_of.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index 924fb1d3ece2..0dc3804051a9 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -11,6 +11,8 @@ #include <linux/iopoll.h> #include <linux/reset.h> +#include <drm/drm_print.h> + #include "cdn-dp-core.h" #include "cdn-dp-reg.h" diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index 5523911b990d..2dad6b7b61b2 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -24,6 +24,7 @@ #include <drm/bridge/dw_mipi_dsi.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_of.h> +#include <drm/drm_print.h> #include <drm/drm_simple_kms_helper.h> #include "rockchip_drm_drv.h" @@ -163,6 +164,11 @@ #define RK3288_DSI0_LCDC_SEL BIT(6) #define RK3288_DSI1_LCDC_SEL BIT(9) +#define RK3368_GRF_SOC_CON7 0x41c +#define RK3368_DSI_FORCETXSTOPMODE (0xf << 7) +#define RK3368_DSI_FORCERXMODE BIT(6) +#define RK3368_DSI_TURNDISABLE BIT(5) + #define RK3399_GRF_SOC_CON20 0x6250 #define RK3399_DSI0_LCDC_SEL BIT(0) #define RK3399_DSI1_LCDC_SEL BIT(4) @@ -1528,6 +1534,18 @@ static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = { { /* sentinel */ } }; +static const struct rockchip_dw_dsi_chip_data rk3368_chip_data[] = { + { + .reg = 0xff960000, + .lanecfg1_grf_reg = RK3368_GRF_SOC_CON7, + .lanecfg1 = FIELD_PREP_WM16_CONST((RK3368_DSI_TURNDISABLE | + RK3368_DSI_FORCETXSTOPMODE | + RK3368_DSI_FORCERXMODE), 0), + .max_data_lanes = 4, + }, + { /* sentinel */ } +}; + static int rk3399_dphy_tx1rx1_init(struct phy *phy) { struct dw_mipi_dsi_rockchip *dsi = phy_get_drvdata(phy); @@ -1688,6 +1706,9 @@ static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = { .compatible = "rockchip,rk3288-mipi-dsi", .data = &rk3288_chip_data, }, { + .compatible = "rockchip,rk3368-mipi-dsi", + .data = &rk3368_chip_data, + }, { .compatible = "rockchip,rk3399-mipi-dsi", .data = &rk3399_chip_data, }, { diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c index ed6e8f036f4b..c9fe6aa3e3e3 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/phy/phy.h> +#include <linux/phy/phy-hdmi.h> #include <linux/regmap.h> #include <linux/workqueue.h> @@ -38,21 +39,16 @@ #define RK3576_HDMI_HDCP14_MEM_EN BIT(15) #define RK3576_VO0_GRF_SOC_CON8 0x0020 -#define RK3576_COLOR_FORMAT_MASK (0xf << 4) -#define RK3576_COLOR_DEPTH_MASK (0xf << 8) -#define RK3576_RGB (0 << 4) -#define RK3576_YUV422 (0x1 << 4) -#define RK3576_YUV444 (0x2 << 4) -#define RK3576_YUV420 (0x3 << 4) -#define RK3576_8BPC (0x0 << 8) -#define RK3576_10BPC (0x6 << 8) +#define RK3576_COLOR_DEPTH_MASK GENMASK(11, 8) +#define RK3576_8BPC 0x0 +#define RK3576_10BPC 0x6 +#define RK3576_COLOR_FORMAT_MASK GENMASK(7, 4) +#define RK3576_RGB 0x9 +#define RK3576_YUV422 0x1 +#define RK3576_YUV444 0x2 +#define RK3576_YUV420 0x3 #define RK3576_CECIN_MASK BIT(3) -#define RK3576_VO0_GRF_SOC_CON12 0x0030 -#define RK3576_GRF_OSDA_DLYN (0xf << 12) -#define RK3576_GRF_OSDA_DIV (0x7f << 1) -#define RK3576_GRF_OSDA_DLY_EN BIT(0) - #define RK3576_VO0_GRF_SOC_CON14 0x0038 #define RK3576_I2S_SEL_MASK BIT(0) #define RK3576_SPDIF_SEL_MASK BIT(1) @@ -74,6 +70,12 @@ #define RK3588_HDMI1_LEVEL_INT BIT(24) #define RK3588_GRF_VO1_CON3 0x000c #define RK3588_GRF_VO1_CON6 0x0018 +#define RK3588_COLOR_DEPTH_MASK GENMASK(7, 4) +#define RK3588_8BPC 0x0 +#define RK3588_10BPC 0x6 +#define RK3588_COLOR_FORMAT_MASK GENMASK(3, 0) +#define RK3588_RGB 0x0 +#define RK3588_YUV420 0x3 #define RK3588_SCLIN_MASK BIT(9) #define RK3588_SDAIN_MASK BIT(10) #define RK3588_MODE_MASK BIT(11) @@ -92,14 +94,16 @@ struct rockchip_hdmi_qp { struct rockchip_encoder encoder; struct dw_hdmi_qp *hdmi; struct phy *phy; - struct gpio_desc *enable_gpio; + struct gpio_desc *frl_enable_gpio; struct delayed_work hpd_work; int port_id; const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops; + unsigned long long tmds_char_rate; }; struct rockchip_hdmi_qp_ctrl_ops { void (*io_init)(struct rockchip_hdmi_qp *hdmi); + void (*enc_init)(struct rockchip_hdmi_qp *hdmi, struct rockchip_crtc_state *state); irqreturn_t (*irq_callback)(int irq, void *dev_id); irqreturn_t (*hardirq_callback)(int irq, void *dev_id); }; @@ -115,23 +119,15 @@ static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder) { struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder); struct drm_crtc *crtc = encoder->crtc; - unsigned long long rate; /* Unconditionally switch to TMDS as FRL is not yet supported */ - gpiod_set_value(hdmi->enable_gpio, 1); - - if (crtc && crtc->state) { - rate = drm_hdmi_compute_mode_clock(&crtc->state->adjusted_mode, - 8, HDMI_COLORSPACE_RGB); - /* - * FIXME: Temporary workaround to pass pixel clock rate - * to the PHY driver until phy_configure_opts_hdmi - * becomes available in the PHY API. See also the related - * comment in rk_hdptx_phy_power_on() from - * drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c - */ - phy_set_bus_width(hdmi->phy, div_u64(rate, 100)); - } + gpiod_set_value(hdmi->frl_enable_gpio, 0); + + if (!crtc || !crtc->state) + return; + + if (hdmi->ctrl_ops->enc_init) + hdmi->ctrl_ops->enc_init(hdmi, to_rockchip_crtc_state(crtc->state)); } static int @@ -139,12 +135,29 @@ dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { + struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder); struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + union phy_configure_opts phy_cfg = {}; + int ret; + + if (hdmi->tmds_char_rate == conn_state->hdmi.tmds_char_rate && + s->output_bpc == conn_state->hdmi.output_bpc) + return 0; + + phy_cfg.hdmi.tmds_char_rate = conn_state->hdmi.tmds_char_rate; + phy_cfg.hdmi.bpc = conn_state->hdmi.output_bpc; + + ret = phy_configure(hdmi->phy, &phy_cfg); + if (!ret) { + hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate; + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + s->output_type = DRM_MODE_CONNECTOR_HDMIA; + s->output_bpc = conn_state->hdmi.output_bpc; + } else { + dev_err(hdmi->dev, "Failed to configure phy: %d\n", ret); + } - s->output_mode = ROCKCHIP_OUT_MODE_AAAA; - s->output_type = DRM_MODE_CONNECTOR_HDMIA; - - return 0; + return ret; } static const struct @@ -375,15 +388,45 @@ static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi) regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); } +static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi, + struct rockchip_crtc_state *state) +{ + u32 val; + + if (state->output_bpc == 10) + val = FIELD_PREP_WM16(RK3576_COLOR_DEPTH_MASK, RK3576_10BPC); + else + val = FIELD_PREP_WM16(RK3576_COLOR_DEPTH_MASK, RK3576_8BPC); + + regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON8, val); +} + +static void dw_hdmi_qp_rk3588_enc_init(struct rockchip_hdmi_qp *hdmi, + struct rockchip_crtc_state *state) +{ + u32 val; + + if (state->output_bpc == 10) + val = FIELD_PREP_WM16(RK3588_COLOR_DEPTH_MASK, RK3588_10BPC); + else + val = FIELD_PREP_WM16(RK3588_COLOR_DEPTH_MASK, RK3588_8BPC); + + regmap_write(hdmi->vo_regmap, + hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3, + val); +} + static const struct rockchip_hdmi_qp_ctrl_ops rk3576_hdmi_ctrl_ops = { .io_init = dw_hdmi_qp_rk3576_io_init, - .irq_callback = dw_hdmi_qp_rk3576_irq, + .enc_init = dw_hdmi_qp_rk3576_enc_init, + .irq_callback = dw_hdmi_qp_rk3576_irq, .hardirq_callback = dw_hdmi_qp_rk3576_hardirq, }; static const struct rockchip_hdmi_qp_ctrl_ops rk3588_hdmi_ctrl_ops = { .io_init = dw_hdmi_qp_rk3588_io_init, - .irq_callback = dw_hdmi_qp_rk3588_irq, + .enc_init = dw_hdmi_qp_rk3588_enc_init, + .irq_callback = dw_hdmi_qp_rk3588_irq, .hardirq_callback = dw_hdmi_qp_rk3588_hardirq, }; @@ -429,14 +472,15 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); + struct dw_hdmi_qp_plat_data plat_data = {}; const struct rockchip_hdmi_qp_cfg *cfg; - struct dw_hdmi_qp_plat_data plat_data; struct drm_device *drm = data; struct drm_connector *connector; struct drm_encoder *encoder; struct rockchip_hdmi_qp *hdmi; struct resource *res; struct clk_bulk_data *clks; + struct clk *ref_clk; int ret, irq, i; if (!pdev->dev.of_node) @@ -455,10 +499,8 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, return -ENODEV; if (!cfg->ctrl_ops || !cfg->ctrl_ops->io_init || - !cfg->ctrl_ops->irq_callback || !cfg->ctrl_ops->hardirq_callback) { - dev_err(dev, "Missing platform ctrl ops\n"); - return -ENODEV; - } + !cfg->ctrl_ops->irq_callback || !cfg->ctrl_ops->hardirq_callback) + return dev_err_probe(dev, -ENODEV, "Missing platform ctrl ops\n"); hdmi->ctrl_ops = cfg->ctrl_ops; hdmi->dev = &pdev->dev; @@ -471,13 +513,13 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, break; } } - if (hdmi->port_id < 0) { - dev_err(hdmi->dev, "Failed to match HDMI port ID\n"); - return hdmi->port_id; - } + if (hdmi->port_id < 0) + return dev_err_probe(hdmi->dev, hdmi->port_id, + "Failed to match HDMI port ID\n"); plat_data.phy_ops = cfg->phy_ops; plat_data.phy_data = hdmi; + plat_data.max_bpc = 10; encoder = &hdmi->encoder.encoder; encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); @@ -495,39 +537,38 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); - if (IS_ERR(hdmi->regmap)) { - dev_err(hdmi->dev, "Unable to get rockchip,grf\n"); - return PTR_ERR(hdmi->regmap); - } + if (IS_ERR(hdmi->regmap)) + return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->regmap), + "Unable to get rockchip,grf\n"); hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vo-grf"); - if (IS_ERR(hdmi->vo_regmap)) { - dev_err(hdmi->dev, "Unable to get rockchip,vo-grf\n"); - return PTR_ERR(hdmi->vo_regmap); - } + if (IS_ERR(hdmi->vo_regmap)) + return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->vo_regmap), + "Unable to get rockchip,vo-grf\n"); ret = devm_clk_bulk_get_all_enabled(hdmi->dev, &clks); - if (ret < 0) { - dev_err(hdmi->dev, "Failed to get clocks: %d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(hdmi->dev, ret, "Failed to get clocks\n"); - hdmi->enable_gpio = devm_gpiod_get_optional(hdmi->dev, "enable", - GPIOD_OUT_HIGH); - if (IS_ERR(hdmi->enable_gpio)) { - ret = PTR_ERR(hdmi->enable_gpio); - dev_err(hdmi->dev, "Failed to request enable GPIO: %d\n", ret); - return ret; - } + ref_clk = clk_get(hdmi->dev, "ref"); + if (IS_ERR(ref_clk)) + return dev_err_probe(hdmi->dev, PTR_ERR(ref_clk), + "Failed to get ref clock\n"); + + plat_data.ref_clk_rate = clk_get_rate(ref_clk); + clk_put(ref_clk); + + hdmi->frl_enable_gpio = devm_gpiod_get_optional(hdmi->dev, "frl-enable", + GPIOD_OUT_LOW); + if (IS_ERR(hdmi->frl_enable_gpio)) + return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->frl_enable_gpio), + "Failed to request FRL enable GPIO\n"); hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0); - if (IS_ERR(hdmi->phy)) { - ret = PTR_ERR(hdmi->phy); - if (ret != -EPROBE_DEFER) - dev_err(hdmi->dev, "failed to get phy: %d\n", ret); - return ret; - } + if (IS_ERR(hdmi->phy)) + return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->phy), + "Failed to get phy\n"); cfg->ctrl_ops->io_init(hdmi); @@ -537,6 +578,10 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, if (plat_data.main_irq < 0) return plat_data.main_irq; + plat_data.cec_irq = platform_get_irq_byname(pdev, "cec"); + if (plat_data.cec_irq < 0) + return plat_data.cec_irq; + irq = platform_get_irq_byname(pdev, "hpd"); if (irq < 0) return irq; @@ -556,17 +601,15 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data); if (IS_ERR(hdmi->hdmi)) { - ret = PTR_ERR(hdmi->hdmi); drm_encoder_cleanup(encoder); - return ret; + return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi), + "Failed to bind dw-hdmi-qp"); } connector = drm_bridge_connector_init(drm, encoder); - if (IS_ERR(connector)) { - ret = PTR_ERR(connector); - dev_err(hdmi->dev, "failed to init bridge connector: %d\n", ret); - return ret; - } + if (IS_ERR(connector)) + return dev_err_probe(hdmi->dev, PTR_ERR(connector), + "Failed to init bridge connector\n"); return drm_connector_attach_encoder(connector, encoder); } diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f24827dc1421..9f7a8cf0ab44 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -22,6 +22,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_edid.h> #include <drm/drm_of.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index ae4a5ac2299a..997429115068 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -10,6 +10,7 @@ #include <drm/display/drm_hdmi_state_helper.h> #include <drm/drm_edid.h> #include <drm/drm_of.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index eb77bde9f628..3099408e9d05 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -22,6 +22,7 @@ #include <drm/drm_fbdev_dma.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_of.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> @@ -96,6 +97,9 @@ void rockchip_drm_dma_init_device(struct drm_device *drm_dev, private->iommu_dev = ERR_PTR(-ENODEV); else if (!private->iommu_dev) private->iommu_dev = dev; + + if (!IS_ERR(private->iommu_dev)) + drm_dev_set_dma_dev(drm_dev, private->iommu_dev); } static int rockchip_drm_init_iommu(struct drm_device *drm_dev) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 6330b883efc3..df9a8bff2e22 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -9,10 +9,12 @@ #include <linux/vmalloc.h> #include <drm/drm.h> +#include <drm/drm_dumb_buffers.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_prime.h> +#include <drm/drm_print.h> #include <drm/drm_vma_manager.h> #include "rockchip_drm_drv.h" @@ -403,13 +405,12 @@ int rockchip_gem_dumb_create(struct drm_file *file_priv, struct drm_mode_create_dumb *args) { struct rockchip_gem_object *rk_obj; - int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); + int ret; - /* - * align to 64 bytes since Mali requires it. - */ - args->pitch = ALIGN(min_pitch, 64); - args->size = args->pitch * args->height; + /* 64-byte alignment required by Mali */ + ret = drm_mode_size_dumb(dev, args, SZ_64, 0); + if (ret) + return ret; rk_obj = rockchip_gem_create_with_handle(file_priv, dev, args->size, &args->handle); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index ba6b0528d1e5..ad4ab894391a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -27,6 +27,7 @@ #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_self_refresh_helper.h> #include <drm/drm_vblank.h> @@ -826,8 +827,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane, if (!crtc || WARN_ON(!fb)) return 0; - crtc_state = drm_atomic_get_existing_crtc_state(state, - crtc); + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); if (WARN_ON(!crtc_state)) return -EINVAL; @@ -1092,7 +1092,8 @@ static int vop_plane_atomic_async_check(struct drm_plane *plane, if (!plane->state->fb) return -EINVAL; - crtc_state = drm_atomic_get_existing_crtc_state(state, new_plane_state->crtc); + crtc_state = drm_atomic_get_new_crtc_state(state, + new_plane_state->crtc); /* Special case for asynchronous cursor updates. */ if (!crtc_state) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 7ec7bea5e38e..498df0ce4680 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -29,6 +29,7 @@ #include <drm/drm_flip_work.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> @@ -101,7 +102,7 @@ enum vop2_afbc_format { VOP2_AFBC_FMT_INVALID = -1, }; -#define VOP2_MAX_DCLK_RATE 600000000 +#define VOP2_MAX_DCLK_RATE 600000000UL /* * bus-format types. @@ -1003,6 +1004,8 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_rect *src = &pstate->src; int min_scale = FRAC_16_16(1, 8); int max_scale = FRAC_16_16(8, 1); + int src_x, src_w, src_h; + int dest_w, dest_h; int format; int ret; @@ -1013,7 +1016,7 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, vop2 = vp->vop2; vop2_data = vop2->data; - cstate = drm_atomic_get_existing_crtc_state(pstate->state, crtc); + cstate = drm_atomic_get_new_crtc_state(pstate->state, crtc); if (WARN_ON(!cstate)) return -EINVAL; @@ -1030,22 +1033,25 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, if (format < 0) return format; - if (drm_rect_width(src) >> 16 < 4 || drm_rect_height(src) >> 16 < 4 || - drm_rect_width(dest) < 4 || drm_rect_height(dest) < 4) { - drm_err(vop2->drm, "Invalid size: %dx%d->%dx%d, min size is 4x4\n", - drm_rect_width(src) >> 16, drm_rect_height(src) >> 16, - drm_rect_width(dest), drm_rect_height(dest)); - pstate->visible = false; - return 0; + /* Co-ordinates have now been clipped */ + src_x = src->x1 >> 16; + src_w = drm_rect_width(src) >> 16; + src_h = drm_rect_height(src) >> 16; + dest_w = drm_rect_width(dest); + dest_h = drm_rect_height(dest); + + if (src_w < 4 || src_h < 4 || dest_w < 4 || dest_h < 4) { + drm_dbg_kms(vop2->drm, "Invalid size: %dx%d->%dx%d, min size is 4x4\n", + src_w, src_h, dest_w, dest_h); + return -EINVAL; } - if (drm_rect_width(src) >> 16 > vop2_data->max_input.width || - drm_rect_height(src) >> 16 > vop2_data->max_input.height) { - drm_err(vop2->drm, "Invalid source: %dx%d. max input: %dx%d\n", - drm_rect_width(src) >> 16, - drm_rect_height(src) >> 16, - vop2_data->max_input.width, - vop2_data->max_input.height); + if (src_w > vop2_data->max_input.width || + src_h > vop2_data->max_input.height) { + drm_dbg_kms(vop2->drm, "Invalid source: %dx%d. max input: %dx%d\n", + src_w, src_h, + vop2_data->max_input.width, + vop2_data->max_input.height); return -EINVAL; } @@ -1053,8 +1059,8 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, * Src.x1 can be odd when do clip, but yuv plane start point * need align with 2 pixel. */ - if (fb->format->is_yuv && ((pstate->src.x1 >> 16) % 2)) { - drm_err(vop2->drm, "Invalid Source: Yuv format not support odd xpos\n"); + if (fb->format->is_yuv && src_x % 2) { + drm_dbg_kms(vop2->drm, "Invalid Source: Yuv format not support odd xpos\n"); return -EINVAL; } @@ -1140,7 +1146,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, struct vop2 *vop2 = win->vop2; struct drm_framebuffer *fb = pstate->fb; u32 bpp = vop2_get_bpp(fb->format); - u32 actual_w, actual_h, dsp_w, dsp_h; + u32 src_w, src_h, dsp_w, dsp_h; u32 act_info, dsp_info; u32 format; u32 afbc_format; @@ -1204,8 +1210,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, uv_mst = rk_obj->dma_addr + offset + fb->offsets[1]; } - actual_w = drm_rect_width(src) >> 16; - actual_h = drm_rect_height(src) >> 16; + src_w = drm_rect_width(src) >> 16; + src_h = drm_rect_height(src) >> 16; dsp_w = drm_rect_width(dest); if (dest->x1 + dsp_w > adjusted_mode->hdisplay) { @@ -1215,7 +1221,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, dsp_w = adjusted_mode->hdisplay - dest->x1; if (dsp_w < 4) dsp_w = 4; - actual_w = dsp_w * actual_w / drm_rect_width(dest); + src_w = dsp_w * src_w / drm_rect_width(dest); } dsp_h = drm_rect_height(dest); @@ -1227,35 +1233,35 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, dsp_h = adjusted_mode->vdisplay - dest->y1; if (dsp_h < 4) dsp_h = 4; - actual_h = dsp_h * actual_h / drm_rect_height(dest); + src_h = dsp_h * src_h / drm_rect_height(dest); } /* * This is workaround solution for IC design: - * esmart can't support scale down when actual_w % 16 == 1. + * esmart can't support scale down when src_w % 16 == 1. */ if (!(win->data->feature & WIN_FEATURE_AFBDC)) { - if (actual_w > dsp_w && (actual_w & 0xf) == 1) { + if (src_w > dsp_w && (src_w & 0xf) == 1) { drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n", - vp->id, win->data->name, actual_w); - actual_w -= 1; + vp->id, win->data->name, src_w); + src_w -= 1; } } - if (afbc_en && actual_w % 4) { - drm_dbg_kms(vop2->drm, "vp%d %s actual_w[%d] not 4 pixel aligned\n", - vp->id, win->data->name, actual_w); - actual_w = ALIGN_DOWN(actual_w, 4); + if (afbc_en && src_w % 4) { + drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n", + vp->id, win->data->name, src_w); + src_w = ALIGN_DOWN(src_w, 4); } - act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff); + act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff); dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff); format = vop2_convert_format(fb->format->format); half_block_en = vop2_half_block_enable(pstate); drm_dbg(vop2->drm, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%p4cc_%s] addr[%pad]\n", - vp->id, win->data->name, actual_w, actual_h, dsp_w, dsp_h, + vp->id, win->data->name, src_w, src_h, dsp_w, dsp_h, dest->x1, dest->y1, &fb->format->format, afbc_en ? "AFBC" : "", &yrgb_mst); @@ -1284,7 +1290,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, if (fb->modifier & AFBC_FORMAT_MOD_YTR) afbc_format |= (1 << 4); - afbc_tile_num = ALIGN(actual_w, block_w) / block_w; + afbc_tile_num = ALIGN(src_w, block_w) / block_w; /* * AFBC pic_vir_width is count by pixel, this is different @@ -1362,8 +1368,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, if (rotate_90 || rotate_270) { act_info = swahw32(act_info); - actual_w = drm_rect_height(src) >> 16; - actual_h = drm_rect_width(src) >> 16; + src_w = drm_rect_height(src) >> 16; + src_h = drm_rect_width(src) >> 16; } vop2_win_write(win, VOP2_WIN_FORMAT, format); @@ -1379,7 +1385,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, vop2_win_write(win, VOP2_WIN_UV_MST, uv_mst); } - vop2_setup_scale(vop2, win, actual_w, actual_h, dsp_w, dsp_h, fb->format->format); + vop2_setup_scale(vop2, win, src_w, src_h, dsp_w, dsp_h, fb->format->format); if (!vop2_cluster_window(win)) vop2_plane_setup_color_key(plane, 0); vop2_win_write(win, VOP2_WIN_ACT_INFO, act_info); @@ -1737,36 +1743,42 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, * Switch to HDMI PHY PLL as DCLK source for display modes up * to 4K@60Hz, if available, otherwise keep using the system CRU. */ - if ((vop2->pll_hdmiphy0 || vop2->pll_hdmiphy1) && clock <= VOP2_MAX_DCLK_RATE) { - drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { - struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); - - if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) { - if (!vop2->pll_hdmiphy0) + if (vop2->pll_hdmiphy0 || vop2->pll_hdmiphy1) { + unsigned long max_dclk = DIV_ROUND_CLOSEST_ULL(VOP2_MAX_DCLK_RATE * 8, + vcstate->output_bpc); + if (clock <= max_dclk) { + drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); + + if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) { + if (!vop2->pll_hdmiphy0) + break; + + if (!vp->dclk_src) + vp->dclk_src = clk_get_parent(vp->dclk); + + ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy0); + if (ret < 0) + drm_warn(vop2->drm, + "Could not switch to HDMI0 PHY PLL: %d\n", + ret); break; + } - if (!vp->dclk_src) - vp->dclk_src = clk_get_parent(vp->dclk); + if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI1) { + if (!vop2->pll_hdmiphy1) + break; - ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy0); - if (ret < 0) - drm_warn(vop2->drm, - "Could not switch to HDMI0 PHY PLL: %d\n", ret); - break; - } + if (!vp->dclk_src) + vp->dclk_src = clk_get_parent(vp->dclk); - if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI1) { - if (!vop2->pll_hdmiphy1) + ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy1); + if (ret < 0) + drm_warn(vop2->drm, + "Could not switch to HDMI1 PHY PLL: %d\n", + ret); break; - - if (!vp->dclk_src) - vp->dclk_src = clk_get_parent(vp->dclk); - - ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy1); - if (ret < 0) - drm_warn(vop2->drm, - "Could not switch to HDMI1 PHY PLL: %d\n", ret); - break; + } } } } @@ -2647,6 +2659,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) if (IS_ERR(vop2->map)) return PTR_ERR(vop2->map); + /* Set the bounds for framebuffer creation */ + drm->mode_config.min_width = 4; + drm->mode_config.min_height = 4; + drm->mode_config.max_width = vop2_data->max_input.width; + drm->mode_config.max_height = vop2_data->max_input.height; + ret = vop2_win_init(vop2); if (ret) return ret; diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 2411260db51d..75f898a10cbc 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -22,6 +22,7 @@ #include <drm/drm_bridge_connector.h> #include <drm/drm_of.h> #include <drm/drm_panel.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c index 811020665120..5c0c6e2cc28d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_rgb.c +++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c @@ -15,6 +15,7 @@ #include <drm/drm_bridge_connector.h> #include <drm/drm_of.h> #include <drm/drm_panel.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 38c49030c7ab..cd8380f0eddc 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -1369,6 +1369,25 @@ static const struct vop2_regs_dump rk3588_regs_dump[] = { }, }; +/* + * phys_id is used to identify a main window(Cluster Win/Smart Win, not + * include the sub win of a cluster or the multi area) that can do overlay + * in main overlay stage. + */ +static struct vop2_win *vop2_find_win_by_phys_id(struct vop2 *vop2, uint8_t phys_id) +{ + struct vop2_win *win; + int i; + + for (i = 0; i < vop2->data->win_size; i++) { + win = &vop2->win[i]; + if (win->data->phys_id == phys_id) + return win; + } + + return NULL; +} + static unsigned long rk3568_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags) { struct vop2 *vop2 = vp->vop2; @@ -1842,15 +1861,31 @@ static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config, alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE; } -static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id) +static int vop2_find_start_mixer_id_for_vp(struct vop2_video_port *vp) { - struct vop2_video_port *vp; - int used_layer = 0; + struct vop2 *vop2 = vp->vop2; + struct vop2_win *win; + u32 layer_sel = vop2->old_layer_sel; + u32 used_layer = 0; + unsigned long win_mask = vp->win_mask; + unsigned long phys_id; + bool match; int i; - for (i = 0; i < port_id; i++) { - vp = &vop2->vps[i]; - used_layer += hweight32(vp->win_mask); + for (i = 0; i < 31; i += 4) { + match = false; + for_each_set_bit(phys_id, &win_mask, ROCKCHIP_VOP2_ESMART3) { + win = vop2_find_win_by_phys_id(vop2, phys_id); + if (win->data->layer_sel_id[vp->id] == ((layer_sel >> i) & 0xf)) { + match = true; + break; + } + } + + if (!match) + used_layer += 1; + else + break; } return used_layer; @@ -1935,7 +1970,7 @@ static void vop2_setup_alpha(struct vop2_video_port *vp) u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE; if (vop2->version <= VOP_VERSION_RK3588) - mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id); + mixer_id = vop2_find_start_mixer_id_for_vp(vp); else mixer_id = 0; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index d1f788763318..219f8c2fa88e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -880,6 +880,7 @@ static const struct vop_data rk3368_vop = { .win = rk3368_vop_win_data, .win_size = ARRAY_SIZE(rk3368_vop_win_data), .max_output = { 4096, 2160 }, + .lut_size = 1024, }; static const struct vop_intr rk3366_vop_intr = { |
