From 988a47311952db42b3bf84be0dd515ca7d86aaa3 Mon Sep 17 00:00:00 2001 From: Hyungwon Hwang Date: Wed, 1 Jul 2015 19:09:24 +0900 Subject: [PATCH 01/53] drm/exynos: gsc: fix wrong bitwise operation for swap detection The bits for rotation are not used as exclusively. So GSC_IN_ROT_270 can not be used for swap detection. The definition of it is same with GSC_IN_ROT_MASK. It is enough to check GSC_IN_ROT_90 bit is set or not to check whether width / height size swapping is needed. Signed-off-by: Hyungwon Hwang Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 8040ed2a831f..f1c6b76c127f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -593,8 +593,7 @@ static int gsc_src_set_transf(struct device *dev, gsc_write(cfg, GSC_IN_CON); - ctx->rotation = cfg & - (GSC_IN_ROT_90 | GSC_IN_ROT_270) ? 1 : 0; + ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0; *swap = ctx->rotation; return 0; @@ -857,8 +856,7 @@ static int gsc_dst_set_transf(struct device *dev, gsc_write(cfg, GSC_IN_CON); - ctx->rotation = cfg & - (GSC_IN_ROT_90 | GSC_IN_ROT_270) ? 1 : 0; + ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0; *swap = ctx->rotation; return 0; From 64ebd8904fab29ee0b76f923aac77da5caa0437d Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 08:25:38 +0200 Subject: [PATCH 02/53] drm/exynos/hdmi: fix edid memory leak edid returned by drm_get_edid should be freed. The patch fixes it. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 99e286489031..4a00990e4ae4 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1064,6 +1064,7 @@ static int hdmi_get_modes(struct drm_connector *connector) { struct hdmi_context *hdata = ctx_from_connector(connector); struct edid *edid; + int ret; if (!hdata->ddc_adpt) return -ENODEV; @@ -1079,7 +1080,11 @@ static int hdmi_get_modes(struct drm_connector *connector) drm_mode_connector_update_edid_property(connector, edid); - return drm_add_edid_modes(connector, edid); + ret = drm_add_edid_modes(connector, edid); + + kfree(edid); + + return ret; } static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) From 81a464df5c5cdb47c2c5e271f7440e011d694018 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 10:07:53 +0200 Subject: [PATCH 03/53] drm/exynos/mixer: fix interrupt clearing The driver used incorrect flags to clear interrupt status. The patch fixes it. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index cae98db33062..25f0aac01a89 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -718,6 +718,10 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) /* handling VSYNC */ if (val & MXR_INT_STATUS_VSYNC) { + /* vsync interrupt use different bit for read and clear */ + val |= MXR_INT_CLEAR_VSYNC; + val &= ~MXR_INT_STATUS_VSYNC; + /* interlace scan need to check shadow register */ if (ctx->interlace) { base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0)); @@ -743,11 +747,6 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) out: /* clear interrupts */ - if (~val & MXR_INT_EN_VSYNC) { - /* vsync interrupt use different bit for read and clear */ - val &= ~MXR_INT_EN_VSYNC; - val |= MXR_INT_CLEAR_VSYNC; - } mixer_reg_write(res, MXR_INT_STATUS, val); spin_unlock(&res->reg_slock); From fc073248ceb56af8cedebff36bf1cdc5da3c6847 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 08:25:40 +0200 Subject: [PATCH 04/53] drm/exynos/mixer: correct vsync configuration sequence Specification advises to clear vsync indicator before configuring vsync. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 25f0aac01a89..923aa75143bf 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -906,8 +906,8 @@ static int mixer_enable_vblank(struct exynos_drm_crtc *crtc) } /* enable vsync interrupt */ - mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC, - MXR_INT_EN_VSYNC); + mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); + mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC); return 0; } @@ -918,6 +918,7 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc) struct mixer_resources *res = &mixer_ctx->mixer_res; /* disable vsync interrupt */ + mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); } @@ -1046,6 +1047,8 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET); + if (ctx->int_en & MXR_INT_EN_VSYNC) + mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); mixer_reg_write(res, MXR_INT_EN, ctx->int_en); mixer_win_reset(ctx); } From 947710c6702a4916a7a01b3af4decb66ae7fc34f Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 08:25:41 +0200 Subject: [PATCH 05/53] drm/exynos/mixer: always update INT_EN cache INT_EN cache field was updated only by mixer_enable_vblank. The patch adds update also by mixer_disable_vblank function. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 923aa75143bf..4706b56902b4 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -917,6 +917,11 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc) struct mixer_context *mixer_ctx = crtc->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; + if (!mixer_ctx->powered) { + mixer_ctx->int_en &= MXR_INT_EN_VSYNC; + return; + } + /* disable vsync interrupt */ mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); From e920efe6fe06b3d4a181a00c54ae00ee83545992 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 9 Apr 2015 10:46:00 +0200 Subject: [PATCH 06/53] drm/exynos/fimc: fix runtime pm support Once pm_runtime_set_active() gets called, the kernel assumes that given device has already enabled runtime pm and will call pm_runtime_suspend() without matching pm_runtime_resume(). In case of DRM FIMC IPP driver, this will result in calling clk_disable() without respective call to clk_enable(). This patch removes call to pm_runtime_set_active() to ensure that pm_runtime_suspend/resume calls will match. Signed-off-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index 842d6b8dc3c4..2a652359af64 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -1745,7 +1745,6 @@ static int fimc_probe(struct platform_device *pdev) spin_lock_init(&ctx->lock); platform_set_drvdata(pdev, ctx); - pm_runtime_set_active(dev); pm_runtime_enable(dev); ret = exynos_drm_ippdrv_register(ippdrv); From d36b3004ca2c99f39e9691ad8a10c02803ad28fc Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 16:28:06 +0200 Subject: [PATCH 07/53] drm/exynos/hdmi: remove old platform data code s5p_hdmi_platform_data were used before device tree introduction. As HDMI driver is DT only we can drop this struct completely. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 36 ++++------------------------ 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 4a00990e4ae4..3cf09bb995a3 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -48,7 +48,6 @@ #include "exynos_mixer.h" #include -#include #define ctx_from_connector(c) container_of(c, struct hdmi_context, connector) @@ -2259,30 +2258,6 @@ static int hdmi_resources_init(struct hdmi_context *hdata) return ret; } -static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata - (struct device *dev) -{ - struct device_node *np = dev->of_node; - struct s5p_hdmi_platform_data *pd; - u32 value; - - pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); - if (!pd) - goto err_data; - - if (!of_find_property(np, "hpd-gpio", &value)) { - DRM_ERROR("no hpd gpio property found\n"); - goto err_data; - } - - pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0); - - return pd; - -err_data: - return NULL; -} - static struct of_device_id hdmi_match_types[] = { { .compatible = "samsung,exynos5-hdmi", @@ -2343,7 +2318,6 @@ static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev) static int hdmi_probe(struct platform_device *pdev) { struct device_node *ddc_node, *phy_node; - struct s5p_hdmi_platform_data *pdata; struct hdmi_driver_data *drv_data; const struct of_device_id *match; struct device *dev = &pdev->dev; @@ -2354,10 +2328,6 @@ static int hdmi_probe(struct platform_device *pdev) if (!dev->of_node) return -ENODEV; - pdata = drm_hdmi_dt_parse_pdata(dev); - if (!pdata) - return -EINVAL; - hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL); if (!hdata) return -ENOMEM; @@ -2378,8 +2348,12 @@ static int hdmi_probe(struct platform_device *pdev) hdata->phy_confs = drv_data->phy_confs; hdata->phy_conf_count = drv_data->phy_conf_count; - hdata->hpd_gpio = pdata->hpd_gpio; hdata->dev = dev; + hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0); + if (hdata->hpd_gpio < 0) { + DRM_ERROR("cannot get hpd gpio property\n"); + return hdata->hpd_gpio; + } ret = hdmi_resources_init(hdata); if (ret) { From ef6ce28bc7c529d4d0b8c699d26fb568208bc305 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 16:28:07 +0200 Subject: [PATCH 08/53] drm/exynos/hdmi: Simplify HPD gpio handling GPIO is tested only in hdmi_detect, so there is no reason to set it in other places and to preserve its value in context. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 3cf09bb995a3..1d07bdf78776 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -186,7 +186,6 @@ struct hdmi_context { struct drm_device *drm_dev; struct drm_connector connector; struct drm_encoder *encoder; - bool hpd; bool powered; bool dvi_mode; struct mutex hdmi_mutex; @@ -1037,10 +1036,10 @@ static enum drm_connector_status hdmi_detect(struct drm_connector *connector, { struct hdmi_context *hdata = ctx_from_connector(connector); - hdata->hpd = gpio_get_value(hdata->hpd_gpio); + if (gpio_get_value(hdata->hpd_gpio)) + return connector_status_connected; - return hdata->hpd ? connector_status_connected : - connector_status_disconnected; + return connector_status_disconnected; } static void hdmi_connector_destroy(struct drm_connector *connector) @@ -2156,10 +2155,6 @@ static void hdmi_hotplug_work_func(struct work_struct *work) hdata = container_of(work, struct hdmi_context, hotplug_work.work); - mutex_lock(&hdata->hdmi_mutex); - hdata->hpd = gpio_get_value(hdata->hpd_gpio); - mutex_unlock(&hdata->hdmi_mutex); - if (hdata->drm_dev) drm_helper_hpd_irq_event(hdata->drm_dev); } @@ -2428,8 +2423,6 @@ static int hdmi_probe(struct platform_device *pdev) goto err_hdmiphy; } - hdata->hpd = gpio_get_value(hdata->hpd_gpio); - INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func); ret = devm_request_threaded_irq(dev, hdata->irq, NULL, From 882a0644fd3427a17d80ad14d1ca3a6228a3860f Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 16:28:08 +0200 Subject: [PATCH 09/53] drm/exynos/hdmi: remove private lock code Most of the code is called by drm core framework, so it is already synchronized. The only async function is irq routine which only calls drm framework so it does not need to be synchronized. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 1d07bdf78776..f2e909de68fe 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -22,7 +22,6 @@ #include "regs-hdmi.h" #include -#include #include #include #include @@ -188,7 +187,6 @@ struct hdmi_context { struct drm_encoder *encoder; bool powered; bool dvi_mode; - struct mutex hdmi_mutex; void __iomem *regs; int irq; @@ -1774,10 +1772,8 @@ static void hdmi_conf_apply(struct hdmi_context *hdata) hdmiphy_conf_reset(hdata); hdmiphy_conf_apply(hdata); - mutex_lock(&hdata->hdmi_mutex); hdmi_start(hdata, false); hdmi_conf_init(hdata); - mutex_unlock(&hdata->hdmi_mutex); hdmi_audio_init(hdata); @@ -2029,12 +2025,8 @@ static void hdmi_commit(struct exynos_drm_display *display) { struct hdmi_context *hdata = display_to_hdmi(display); - mutex_lock(&hdata->hdmi_mutex); - if (!hdata->powered) { - mutex_unlock(&hdata->hdmi_mutex); + if (!hdata->powered) return; - } - mutex_unlock(&hdata->hdmi_mutex); hdmi_conf_apply(hdata); } @@ -2043,16 +2035,11 @@ static void hdmi_poweron(struct hdmi_context *hdata) { struct hdmi_resources *res = &hdata->res; - mutex_lock(&hdata->hdmi_mutex); - if (hdata->powered) { - mutex_unlock(&hdata->hdmi_mutex); + if (hdata->powered) return; - } hdata->powered = true; - mutex_unlock(&hdata->hdmi_mutex); - pm_runtime_get_sync(hdata->dev); if (regulator_bulk_enable(res->regul_count, res->regul_bulk)) @@ -2073,10 +2060,8 @@ static void hdmi_poweroff(struct hdmi_context *hdata) { struct hdmi_resources *res = &hdata->res; - mutex_lock(&hdata->hdmi_mutex); if (!hdata->powered) - goto out; - mutex_unlock(&hdata->hdmi_mutex); + return; /* HDMI System Disable */ hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN); @@ -2096,11 +2081,7 @@ static void hdmi_poweroff(struct hdmi_context *hdata) pm_runtime_put_sync(hdata->dev); - mutex_lock(&hdata->hdmi_mutex); hdata->powered = false; - -out: - mutex_unlock(&hdata->hdmi_mutex); } static void hdmi_dpms(struct exynos_drm_display *display, int mode) @@ -2330,8 +2311,6 @@ static int hdmi_probe(struct platform_device *pdev) hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI; hdata->display.ops = &hdmi_display_ops; - mutex_init(&hdata->hdmi_mutex); - platform_set_drvdata(pdev, hdata); match = of_match_node(hdmi_match_types, dev->of_node); From cd240cde91fa637449b564c08b31030073769ad7 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 16:28:09 +0200 Subject: [PATCH 10/53] drm/exynos/hdmi: add driver data pointer to private context The patch replaces duplicated driver data fields in private context with pointer to driver data. It also simplifies driver data lookup code. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 49 ++++++++++++---------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index f2e909de68fe..f9c4de16d91a 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -32,8 +32,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -200,14 +200,12 @@ struct hdmi_context { struct hdmi_conf_regs mode_conf; struct hdmi_resources res; + const struct hdmi_driver_data *drv_data; int hpd_gpio; void __iomem *regs_hdmiphy; - const struct hdmiphy_config *phy_confs; - unsigned int phy_conf_count; struct regmap *pmureg; - enum hdmi_type type; }; static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d) @@ -926,7 +924,7 @@ static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix) static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix) { - if (hdata->type == HDMI_TYPE13) + if (hdata->drv_data->type == HDMI_TYPE13) hdmi_v13_regs_dump(hdata, prefix); else hdmi_v14_regs_dump(hdata, prefix); @@ -1087,8 +1085,8 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) { int i; - for (i = 0; i < hdata->phy_conf_count; i++) - if (hdata->phy_confs[i].pixel_clock == pixel_clock) + for (i = 0; i < hdata->drv_data->phy_conf_count; i++) + if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock) return i; DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock); @@ -1253,7 +1251,7 @@ static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr) hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]); hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]); - if (hdata->type == HDMI_TYPE13) + if (hdata->drv_data->type == HDMI_TYPE13) hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4); else hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4); @@ -1387,7 +1385,7 @@ static void hdmi_conf_init(struct hdmi_context *hdata) HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS); } - if (hdata->type == HDMI_TYPE13) { + if (hdata->drv_data->type == HDMI_TYPE13) { /* choose bluescreen (fecal) color */ hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12); hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34); @@ -1666,7 +1664,7 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) static void hdmi_mode_apply(struct hdmi_context *hdata) { - if (hdata->type == HDMI_TYPE13) + if (hdata->drv_data->type == HDMI_TYPE13) hdmi_v13_mode_apply(hdata); else hdmi_v14_mode_apply(hdata); @@ -1684,7 +1682,7 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata) hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, HDMI_PHY_ENABLE_MODE_SET); - if (hdata->type == HDMI_TYPE13) + if (hdata->drv_data->type == HDMI_TYPE13) reg = HDMI_V13_PHY_RSTOUT; else reg = HDMI_PHY_RSTOUT; @@ -1698,7 +1696,7 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata) static void hdmiphy_poweron(struct hdmi_context *hdata) { - if (hdata->type != HDMI_TYPE14) + if (hdata->drv_data->type != HDMI_TYPE14) return; DRM_DEBUG_KMS("\n"); @@ -1718,7 +1716,7 @@ static void hdmiphy_poweron(struct hdmi_context *hdata) static void hdmiphy_poweroff(struct hdmi_context *hdata) { - if (hdata->type != HDMI_TYPE14) + if (hdata->drv_data->type != HDMI_TYPE14) return; DRM_DEBUG_KMS("\n"); @@ -1750,7 +1748,8 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) return; } - ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32); + ret = hdmiphy_reg_write_buf(hdata, 0, + hdata->drv_data->phy_confs[i].conf, 32); if (ret) { DRM_ERROR("failed to configure hdmiphy\n"); return; @@ -2015,7 +2014,7 @@ static void hdmi_mode_set(struct exynos_drm_display *display, /* preserve mode information for later use. */ drm_mode_copy(&hdata->current_mode, mode); - if (hdata->type == HDMI_TYPE13) + if (hdata->drv_data->type == HDMI_TYPE13) hdmi_v13_mode_set(hdata, mode); else hdmi_v14_mode_set(hdata, mode); @@ -2294,34 +2293,26 @@ static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev) static int hdmi_probe(struct platform_device *pdev) { struct device_node *ddc_node, *phy_node; - struct hdmi_driver_data *drv_data; const struct of_device_id *match; struct device *dev = &pdev->dev; struct hdmi_context *hdata; struct resource *res; int ret; - if (!dev->of_node) - return -ENODEV; - hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL); if (!hdata) return -ENOMEM; + match = of_match_device(hdmi_match_types, dev); + if (!match) + return -ENODEV; + + hdata->drv_data = match->data; hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI; hdata->display.ops = &hdmi_display_ops; platform_set_drvdata(pdev, hdata); - match = of_match_node(hdmi_match_types, dev->of_node); - if (!match) - return -ENODEV; - - drv_data = (struct hdmi_driver_data *)match->data; - hdata->type = drv_data->type; - hdata->phy_confs = drv_data->phy_confs; - hdata->phy_conf_count = drv_data->phy_conf_count; - hdata->dev = dev; hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0); if (hdata->hpd_gpio < 0) { @@ -2379,7 +2370,7 @@ static int hdmi_probe(struct platform_device *pdev) } out_get_phy_port: - if (drv_data->is_apb_phy) { + if (hdata->drv_data->is_apb_phy) { hdata->regs_hdmiphy = of_iomap(phy_node, 0); if (!hdata->regs_hdmiphy) { DRM_ERROR("failed to ioremap hdmi phy\n"); From c93aaebfd1945fd0c3efacad001906dd6bcbb3df Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 16:28:10 +0200 Subject: [PATCH 11/53] drm/exynos/hdmi: remove redundant configuration fields The patch removes redundant fields from hdmi_conf_regs. Their values can be calculated from current_mode. This patch is the first step to remove whole hdmi_conf_regs structure. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 68 ++++++++++------------------ 1 file changed, 24 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index f9c4de16d91a..a3fe2f06b80c 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -169,14 +169,9 @@ struct hdmi_v14_conf { struct hdmi_tg_regs tg; }; -struct hdmi_conf_regs { - int pixel_clock; - int cea_video_id; - enum hdmi_picture_aspect aspect_ratio; - union { - struct hdmi_v13_conf v13_conf; - struct hdmi_v14_conf v14_conf; - } conf; +union hdmi_conf_regs { + struct hdmi_v13_conf v13_conf; + struct hdmi_v14_conf v14_conf; }; struct hdmi_context { @@ -197,7 +192,8 @@ struct hdmi_context { /* current hdmiphy conf regs */ struct drm_display_mode current_mode; - struct hdmi_conf_regs mode_conf; + u8 cea_video_id; + union hdmi_conf_regs mode_conf; struct hdmi_resources res; const struct hdmi_driver_data *drv_data; @@ -951,7 +947,7 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, u32 hdr_sum; u8 chksum; u32 mod; - u32 vic; + u8 ar; mod = hdmi_reg_read(hdata, HDMI_MODE_SEL); if (hdata->dvi_mode) { @@ -982,27 +978,22 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, * Set the aspect ratio as per the mode, mentioned in * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard */ - switch (hdata->mode_conf.aspect_ratio) { + ar = hdata->current_mode.picture_aspect_ratio; + switch (ar) { case HDMI_PICTURE_ASPECT_4_3: - hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), - hdata->mode_conf.aspect_ratio | - AVI_4_3_CENTER_RATIO); + ar |= AVI_4_3_CENTER_RATIO; break; case HDMI_PICTURE_ASPECT_16_9: - hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), - hdata->mode_conf.aspect_ratio | - AVI_16_9_CENTER_RATIO); + ar |= AVI_16_9_CENTER_RATIO; break; case HDMI_PICTURE_ASPECT_NONE: default: - hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), - hdata->mode_conf.aspect_ratio | - AVI_SAME_AS_PIC_ASPECT_RATIO); + ar |= AVI_SAME_AS_PIC_ASPECT_RATIO; break; } + hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar); - vic = hdata->mode_conf.cea_video_id; - hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic); + hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id); chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1), infoframe->any.length, hdr_sum); @@ -1418,9 +1409,8 @@ static void hdmi_conf_init(struct hdmi_context *hdata) static void hdmi_v13_mode_apply(struct hdmi_context *hdata) { - const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg; - const struct hdmi_v13_core_regs *core = - &hdata->mode_conf.conf.v13_conf.core; + const struct hdmi_tg_regs *tg = &hdata->mode_conf.v13_conf.tg; + const struct hdmi_v13_core_regs *core = &hdata->mode_conf.v13_conf.core; int tries; /* setting core registers */ @@ -1502,9 +1492,8 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) static void hdmi_v14_mode_apply(struct hdmi_context *hdata) { - const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg; - const struct hdmi_v14_core_regs *core = - &hdata->mode_conf.conf.v14_conf.core; + const struct hdmi_tg_regs *tg = &hdata->mode_conf.v14_conf.tg; + const struct hdmi_v14_core_regs *core = &hdata->mode_conf.v14_conf.core; int tries; /* setting core registers */ @@ -1742,7 +1731,7 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) int i; /* pixel clock */ - i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock); + i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000); if (i < 0) { DRM_ERROR("failed to find hdmiphy conf\n"); return; @@ -1794,15 +1783,10 @@ static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value) static void hdmi_v13_mode_set(struct hdmi_context *hdata, struct drm_display_mode *m) { - struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core; - struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg; + struct hdmi_v13_core_regs *core = &hdata->mode_conf.v13_conf.core; + struct hdmi_tg_regs *tg = &hdata->mode_conf.v13_conf.tg; unsigned int val; - hdata->mode_conf.cea_video_id = - drm_match_cea_mode((struct drm_display_mode *)m); - hdata->mode_conf.pixel_clock = m->clock * 1000; - hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio; - hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay); hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal); @@ -1891,14 +1875,8 @@ static void hdmi_v13_mode_set(struct hdmi_context *hdata, static void hdmi_v14_mode_set(struct hdmi_context *hdata, struct drm_display_mode *m) { - struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg; - struct hdmi_v14_core_regs *core = - &hdata->mode_conf.conf.v14_conf.core; - - hdata->mode_conf.cea_video_id = - drm_match_cea_mode((struct drm_display_mode *)m); - hdata->mode_conf.pixel_clock = m->clock * 1000; - hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio; + struct hdmi_tg_regs *tg = &hdata->mode_conf.v14_conf.tg; + struct hdmi_v14_core_regs *core = &hdata->mode_conf.v14_conf.core; hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay); hdmi_set_reg(core->v_line, 2, m->vtotal); @@ -2014,6 +1992,8 @@ static void hdmi_mode_set(struct exynos_drm_display *display, /* preserve mode information for later use. */ drm_mode_copy(&hdata->current_mode, mode); + hdata->cea_video_id = drm_match_cea_mode(mode); + if (hdata->drv_data->type == HDMI_TYPE13) hdmi_v13_mode_set(hdata, mode); else From edb6e41201c626439a8f3687a0cc81c0d1f13c84 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 16:28:11 +0200 Subject: [PATCH 12/53] drm/exynos/hdmi: remove hdmi_v13_conf struct The patch removes intermediate struct for HDMIv13 register configuration, instead registry values are calculated on the fly. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 280 ++++++++++----------------- 1 file changed, 101 insertions(+), 179 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index a3fe2f06b80c..60663ad9891f 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -107,19 +107,6 @@ struct hdmi_tg_regs { u8 tg_3d[1]; }; -struct hdmi_v13_core_regs { - u8 h_blank[2]; - u8 v_blank[3]; - u8 h_v_line[3]; - u8 vsync_pol[1]; - u8 int_pro_mode[1]; - u8 v_blank_f[3]; - u8 h_sync_gen[3]; - u8 v_sync_gen1[3]; - u8 v_sync_gen2[3]; - u8 v_sync_gen3[3]; -}; - struct hdmi_v14_core_regs { u8 h_blank[2]; u8 v2_blank[2]; @@ -159,21 +146,11 @@ struct hdmi_v14_core_regs { u8 vact_space_6[2]; }; -struct hdmi_v13_conf { - struct hdmi_v13_core_regs core; - struct hdmi_tg_regs tg; -}; - struct hdmi_v14_conf { struct hdmi_v14_core_regs core; struct hdmi_tg_regs tg; }; -union hdmi_conf_regs { - struct hdmi_v13_conf v13_conf; - struct hdmi_v14_conf v14_conf; -}; - struct hdmi_context { struct exynos_drm_display display; struct device *dev; @@ -193,7 +170,7 @@ struct hdmi_context { /* current hdmiphy conf regs */ struct drm_display_mode current_mode; u8 cea_video_id; - union hdmi_conf_regs mode_conf; + struct hdmi_v14_conf mode_conf; struct hdmi_resources res; const struct hdmi_driver_data *drv_data; @@ -614,6 +591,16 @@ static inline void hdmi_reg_writeb(struct hdmi_context *hdata, writeb(value, hdata->regs + reg_id); } +static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id, + int bytes, u32 val) +{ + while (--bytes >= 0) { + writeb(val & 0xff, hdata->regs + reg_id); + val >>= 8; + reg_id += 4; + } +} + static inline void hdmi_reg_writemask(struct hdmi_context *hdata, u32 reg_id, u32 value, u32 mask) { @@ -1409,65 +1396,94 @@ static void hdmi_conf_init(struct hdmi_context *hdata) static void hdmi_v13_mode_apply(struct hdmi_context *hdata) { - const struct hdmi_tg_regs *tg = &hdata->mode_conf.v13_conf.tg; - const struct hdmi_v13_core_regs *core = &hdata->mode_conf.v13_conf.core; + struct drm_display_mode *m = &hdata->current_mode; + unsigned int val; int tries; - /* setting core registers */ - hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]); - hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]); - hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]); - hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]); - hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]); - hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]); - hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]); - hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]); - hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]); - hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]); - hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]); - hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]); - hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]); - hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]); - hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]); - hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]); - hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]); - hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]); - hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]); - hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]); - hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]); - hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]); - hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]); - hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]); - hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]); + hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay); + hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3, + (m->htotal << 12) | m->vtotal); + + val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0; + hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val); + + val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0; + hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val); + + val = (m->hsync_start - m->hdisplay - 2); + val |= ((m->hsync_end - m->hdisplay - 2) << 10); + val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20; + hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val); + + /* + * Quirk requirement for exynos HDMI IP design, + * 2 pixels less than the actual calculation for hsync_start + * and end. + */ + + /* Following values & calculations differ for different type of modes */ + if (m->flags & DRM_MODE_FLAG_INTERLACE) { + /* Interlaced Mode */ + val = ((m->vsync_end - m->vdisplay) / 2); + val |= ((m->vsync_start - m->vdisplay) / 2) << 12; + hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val); + + val = m->vtotal / 2; + val |= ((m->vtotal - m->vdisplay) / 2) << 11; + hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val); + + val = (m->vtotal + + ((m->vsync_end - m->vsync_start) * 4) + 5) / 2; + val |= m->vtotal << 11; + hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val); + + val = ((m->vtotal / 2) + 7); + val |= ((m->vtotal / 2) + 2) << 12; + hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val); + + val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay)); + val |= ((m->htotal / 2) + + (m->hsync_start - m->hdisplay)) << 12; + hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val); + + hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, + (m->vtotal - m->vdisplay) / 2); + hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2); + + hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249); + } else { + /* Progressive Mode */ + + val = m->vtotal; + val |= (m->vtotal - m->vdisplay) << 11; + hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val); + + hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0); + + val = (m->vsync_end - m->vdisplay); + val |= ((m->vsync_start - m->vdisplay) << 12); + hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val); + + hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001); + hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001); + hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, + m->vtotal - m->vdisplay); + hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay); + hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248); + } + /* Timing generator registers */ - hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]); - hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]); - hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]); - hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]); - hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]); - hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]); - hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]); - hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]); + hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal); + hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay); + hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay); + hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal); + hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1); + hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233); + hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233); + hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1); + hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233); + hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1); + hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233); /* waiting for HDMIPHY's PLL to get to steady state */ for (tries = 100; tries; --tries) { @@ -1492,8 +1508,8 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) static void hdmi_v14_mode_apply(struct hdmi_context *hdata) { - const struct hdmi_tg_regs *tg = &hdata->mode_conf.v14_conf.tg; - const struct hdmi_v14_core_regs *core = &hdata->mode_conf.v14_conf.core; + const struct hdmi_tg_regs *tg = &hdata->mode_conf.tg; + const struct hdmi_v14_core_regs *core = &hdata->mode_conf.core; int tries; /* setting core registers */ @@ -1780,103 +1796,11 @@ static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value) reg_pair[i] = (value >> (8 * i)) & 0xff; } -static void hdmi_v13_mode_set(struct hdmi_context *hdata, - struct drm_display_mode *m) -{ - struct hdmi_v13_core_regs *core = &hdata->mode_conf.v13_conf.core; - struct hdmi_tg_regs *tg = &hdata->mode_conf.v13_conf.tg; - unsigned int val; - - hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay); - hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal); - - val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0; - hdmi_set_reg(core->vsync_pol, 1, val); - - val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0; - hdmi_set_reg(core->int_pro_mode, 1, val); - - val = (m->hsync_start - m->hdisplay - 2); - val |= ((m->hsync_end - m->hdisplay - 2) << 10); - val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20; - hdmi_set_reg(core->h_sync_gen, 3, val); - - /* - * Quirk requirement for exynos HDMI IP design, - * 2 pixels less than the actual calculation for hsync_start - * and end. - */ - - /* Following values & calculations differ for different type of modes */ - if (m->flags & DRM_MODE_FLAG_INTERLACE) { - /* Interlaced Mode */ - val = ((m->vsync_end - m->vdisplay) / 2); - val |= ((m->vsync_start - m->vdisplay) / 2) << 12; - hdmi_set_reg(core->v_sync_gen1, 3, val); - - val = m->vtotal / 2; - val |= ((m->vtotal - m->vdisplay) / 2) << 11; - hdmi_set_reg(core->v_blank, 3, val); - - val = (m->vtotal + - ((m->vsync_end - m->vsync_start) * 4) + 5) / 2; - val |= m->vtotal << 11; - hdmi_set_reg(core->v_blank_f, 3, val); - - val = ((m->vtotal / 2) + 7); - val |= ((m->vtotal / 2) + 2) << 12; - hdmi_set_reg(core->v_sync_gen2, 3, val); - - val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay)); - val |= ((m->htotal / 2) + - (m->hsync_start - m->hdisplay)) << 12; - hdmi_set_reg(core->v_sync_gen3, 3, val); - - hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2); - hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2); - - hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/ - } else { - /* Progressive Mode */ - - val = m->vtotal; - val |= (m->vtotal - m->vdisplay) << 11; - hdmi_set_reg(core->v_blank, 3, val); - - hdmi_set_reg(core->v_blank_f, 3, 0); - - val = (m->vsync_end - m->vdisplay); - val |= ((m->vsync_start - m->vdisplay) << 12); - hdmi_set_reg(core->v_sync_gen1, 3, val); - - hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */ - hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */ - hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay); - hdmi_set_reg(tg->vact_sz, 2, m->vdisplay); - hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */ - } - - /* Timing generator registers */ - hdmi_set_reg(tg->cmd, 1, 0x0); - hdmi_set_reg(tg->h_fsz, 2, m->htotal); - hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay); - hdmi_set_reg(tg->hact_sz, 2, m->hdisplay); - hdmi_set_reg(tg->v_fsz, 2, m->vtotal); - hdmi_set_reg(tg->vsync, 2, 0x1); - hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */ - hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */ - hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */ - hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */ - hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */ - hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */ - hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */ -} - static void hdmi_v14_mode_set(struct hdmi_context *hdata, struct drm_display_mode *m) { - struct hdmi_tg_regs *tg = &hdata->mode_conf.v14_conf.tg; - struct hdmi_v14_core_regs *core = &hdata->mode_conf.v14_conf.core; + struct hdmi_tg_regs *tg = &hdata->mode_conf.tg; + struct hdmi_v14_core_regs *core = &hdata->mode_conf.core; hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay); hdmi_set_reg(core->v_line, 2, m->vtotal); @@ -1994,9 +1918,7 @@ static void hdmi_mode_set(struct exynos_drm_display *display, hdata->cea_video_id = drm_match_cea_mode(mode); - if (hdata->drv_data->type == HDMI_TYPE13) - hdmi_v13_mode_set(hdata, mode); - else + if (hdata->drv_data->type == HDMI_TYPE14) hdmi_v14_mode_set(hdata, mode); } From 7b5102da0a9f008a5d59fa4e3cd9e6006848f3bd Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 16:28:12 +0200 Subject: [PATCH 13/53] drm/exynos/hdmi: remove hdmi_v14_conf struct The patch removes intermediate struct for HDMIv14 register configuration, instead registry values are calculated on the fly. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 427 +++++++-------------------- 1 file changed, 109 insertions(+), 318 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 60663ad9891f..448f53449b99 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -86,71 +86,6 @@ struct hdmi_resources { int regul_count; }; -struct hdmi_tg_regs { - u8 cmd[1]; - u8 h_fsz[2]; - u8 hact_st[2]; - u8 hact_sz[2]; - u8 v_fsz[2]; - u8 vsync[2]; - u8 vsync2[2]; - u8 vact_st[2]; - u8 vact_sz[2]; - u8 field_chg[2]; - u8 vact_st2[2]; - u8 vact_st3[2]; - u8 vact_st4[2]; - u8 vsync_top_hdmi[2]; - u8 vsync_bot_hdmi[2]; - u8 field_top_hdmi[2]; - u8 field_bot_hdmi[2]; - u8 tg_3d[1]; -}; - -struct hdmi_v14_core_regs { - u8 h_blank[2]; - u8 v2_blank[2]; - u8 v1_blank[2]; - u8 v_line[2]; - u8 h_line[2]; - u8 hsync_pol[1]; - u8 vsync_pol[1]; - u8 int_pro_mode[1]; - u8 v_blank_f0[2]; - u8 v_blank_f1[2]; - u8 h_sync_start[2]; - u8 h_sync_end[2]; - u8 v_sync_line_bef_2[2]; - u8 v_sync_line_bef_1[2]; - u8 v_sync_line_aft_2[2]; - u8 v_sync_line_aft_1[2]; - u8 v_sync_line_aft_pxl_2[2]; - u8 v_sync_line_aft_pxl_1[2]; - u8 v_blank_f2[2]; /* for 3D mode */ - u8 v_blank_f3[2]; /* for 3D mode */ - u8 v_blank_f4[2]; /* for 3D mode */ - u8 v_blank_f5[2]; /* for 3D mode */ - u8 v_sync_line_aft_3[2]; - u8 v_sync_line_aft_4[2]; - u8 v_sync_line_aft_5[2]; - u8 v_sync_line_aft_6[2]; - u8 v_sync_line_aft_pxl_3[2]; - u8 v_sync_line_aft_pxl_4[2]; - u8 v_sync_line_aft_pxl_5[2]; - u8 v_sync_line_aft_pxl_6[2]; - u8 vact_space_1[2]; - u8 vact_space_2[2]; - u8 vact_space_3[2]; - u8 vact_space_4[2]; - u8 vact_space_5[2]; - u8 vact_space_6[2]; -}; - -struct hdmi_v14_conf { - struct hdmi_v14_core_regs core; - struct hdmi_tg_regs tg; -}; - struct hdmi_context { struct exynos_drm_display display; struct device *dev; @@ -170,7 +105,6 @@ struct hdmi_context { /* current hdmiphy conf regs */ struct drm_display_mode current_mode; u8 cea_video_id; - struct hdmi_v14_conf mode_conf; struct hdmi_resources res; const struct hdmi_driver_data *drv_data; @@ -1508,143 +1442,119 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) static void hdmi_v14_mode_apply(struct hdmi_context *hdata) { - const struct hdmi_tg_regs *tg = &hdata->mode_conf.tg; - const struct hdmi_v14_core_regs *core = &hdata->mode_conf.core; + struct drm_display_mode *m = &hdata->current_mode; int tries; - /* setting core registers */ - hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]); - hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]); - hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]); - hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]); - hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]); - hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]); - hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]); - hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]); - hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]); - hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]); - hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]); - hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]); - hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]); - hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]); - hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]); - hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]); - hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]); - hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]); - hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]); - hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]); - hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0, - core->v_sync_line_bef_2[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1, - core->v_sync_line_bef_2[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0, - core->v_sync_line_bef_1[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1, - core->v_sync_line_bef_1[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0, - core->v_sync_line_aft_2[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1, - core->v_sync_line_aft_2[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0, - core->v_sync_line_aft_1[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1, - core->v_sync_line_aft_1[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, - core->v_sync_line_aft_pxl_2[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1, - core->v_sync_line_aft_pxl_2[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, - core->v_sync_line_aft_pxl_1[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1, - core->v_sync_line_aft_pxl_1[1]); - hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]); - hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]); - hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]); - hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]); - hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]); - hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]); - hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]); - hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0, - core->v_sync_line_aft_3[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1, - core->v_sync_line_aft_3[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0, - core->v_sync_line_aft_4[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1, - core->v_sync_line_aft_4[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0, - core->v_sync_line_aft_5[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1, - core->v_sync_line_aft_5[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0, - core->v_sync_line_aft_6[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1, - core->v_sync_line_aft_6[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, - core->v_sync_line_aft_pxl_3[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1, - core->v_sync_line_aft_pxl_3[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, - core->v_sync_line_aft_pxl_4[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1, - core->v_sync_line_aft_pxl_4[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, - core->v_sync_line_aft_pxl_5[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1, - core->v_sync_line_aft_pxl_5[1]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, - core->v_sync_line_aft_pxl_6[0]); - hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1, - core->v_sync_line_aft_pxl_6[1]); - hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]); - hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]); - hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]); - hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]); - hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]); - hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]); - hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]); - hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]); - hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]); - hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]); - hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]); - hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]); + hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay); + hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal); + hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal); + hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1, + (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0); + hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, + (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0); + hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, + (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0); + + /* + * Quirk requirement for exynos 5 HDMI IP design, + * 2 pixels less than the actual calculation for hsync_start + * and end. + */ + + /* Following values & calculations differ for different type of modes */ + if (m->flags & DRM_MODE_FLAG_INTERLACE) { + /* Interlaced Mode */ + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2, + (m->vsync_end - m->vdisplay) / 2); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2, + (m->vsync_start - m->vdisplay) / 2); + hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2); + hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2, + (m->vtotal - m->vdisplay) / 2); + hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, + m->vtotal - m->vdisplay / 2); + hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, + (m->vtotal / 2) + 7); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, + (m->vtotal / 2) + 2); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, + (m->htotal / 2) + (m->hsync_start - m->hdisplay)); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, + (m->htotal / 2) + (m->hsync_start - m->hdisplay)); + hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, + (m->vtotal - m->vdisplay) / 2); + hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2); + hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, + m->vtotal - m->vdisplay / 2); + hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, + (m->vtotal / 2) + 1); + hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, + (m->vtotal / 2) + 1); + hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, + (m->vtotal / 2) + 1); + hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0); + hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0); + } else { + /* Progressive Mode */ + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2, + m->vsync_end - m->vdisplay); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2, + m->vsync_start - m->vdisplay); + hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal); + hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2, + m->vtotal - m->vdisplay); + hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, + m->vtotal - m->vdisplay); + hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay); + hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248); + hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b); + hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae); + hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233); + hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233); + hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233); + } + + /* Following values & calculations are same irrespective of mode type */ + hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2, + m->hsync_start - m->hdisplay - 2); + hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2, + m->hsync_end - m->hdisplay - 2); + hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff); + hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff); /* Timing generator registers */ - hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]); - hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]); - hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]); - hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]); - hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]); - hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]); - hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]); - hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]); - hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]); + hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal); + hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay); + hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay); + hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal); + hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1); + hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233); + hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1); + hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1); + hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0); /* waiting for HDMIPHY's PLL to get to steady state */ for (tries = 100; tries; --tries) { @@ -1788,120 +1698,6 @@ static void hdmi_conf_apply(struct hdmi_context *hdata) hdmi_regs_dump(hdata, "start"); } -static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value) -{ - int i; - BUG_ON(num_bytes > 4); - for (i = 0; i < num_bytes; i++) - reg_pair[i] = (value >> (8 * i)) & 0xff; -} - -static void hdmi_v14_mode_set(struct hdmi_context *hdata, - struct drm_display_mode *m) -{ - struct hdmi_tg_regs *tg = &hdata->mode_conf.tg; - struct hdmi_v14_core_regs *core = &hdata->mode_conf.core; - - hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay); - hdmi_set_reg(core->v_line, 2, m->vtotal); - hdmi_set_reg(core->h_line, 2, m->htotal); - hdmi_set_reg(core->hsync_pol, 1, - (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0); - hdmi_set_reg(core->vsync_pol, 1, - (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0); - hdmi_set_reg(core->int_pro_mode, 1, - (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0); - - /* - * Quirk requirement for exynos 5 HDMI IP design, - * 2 pixels less than the actual calculation for hsync_start - * and end. - */ - - /* Following values & calculations differ for different type of modes */ - if (m->flags & DRM_MODE_FLAG_INTERLACE) { - /* Interlaced Mode */ - hdmi_set_reg(core->v_sync_line_bef_2, 2, - (m->vsync_end - m->vdisplay) / 2); - hdmi_set_reg(core->v_sync_line_bef_1, 2, - (m->vsync_start - m->vdisplay) / 2); - hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2); - hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2); - hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2); - hdmi_set_reg(core->v_blank_f1, 2, m->vtotal); - hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7); - hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2); - hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, - (m->htotal / 2) + (m->hsync_start - m->hdisplay)); - hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, - (m->htotal / 2) + (m->hsync_start - m->hdisplay)); - hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2); - hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2); - hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2); - hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1); - hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1); - hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1); - hdmi_set_reg(tg->vact_st3, 2, 0x0); - hdmi_set_reg(tg->vact_st4, 2, 0x0); - } else { - /* Progressive Mode */ - hdmi_set_reg(core->v_sync_line_bef_2, 2, - m->vsync_end - m->vdisplay); - hdmi_set_reg(core->v_sync_line_bef_1, 2, - m->vsync_start - m->vdisplay); - hdmi_set_reg(core->v2_blank, 2, m->vtotal); - hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay); - hdmi_set_reg(core->v_blank_f0, 2, 0xffff); - hdmi_set_reg(core->v_blank_f1, 2, 0xffff); - hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff); - hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff); - hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff); - hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff); - hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay); - hdmi_set_reg(tg->vact_sz, 2, m->vdisplay); - hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */ - hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */ - hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */ - hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */ - hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */ - hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */ - } - - /* Following values & calculations are same irrespective of mode type */ - hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2); - hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2); - hdmi_set_reg(core->vact_space_1, 2, 0xffff); - hdmi_set_reg(core->vact_space_2, 2, 0xffff); - hdmi_set_reg(core->vact_space_3, 2, 0xffff); - hdmi_set_reg(core->vact_space_4, 2, 0xffff); - hdmi_set_reg(core->vact_space_5, 2, 0xffff); - hdmi_set_reg(core->vact_space_6, 2, 0xffff); - hdmi_set_reg(core->v_blank_f2, 2, 0xffff); - hdmi_set_reg(core->v_blank_f3, 2, 0xffff); - hdmi_set_reg(core->v_blank_f4, 2, 0xffff); - hdmi_set_reg(core->v_blank_f5, 2, 0xffff); - hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff); - hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff); - hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff); - hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff); - hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff); - hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff); - hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff); - hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff); - - /* Timing generator registers */ - hdmi_set_reg(tg->cmd, 1, 0x0); - hdmi_set_reg(tg->h_fsz, 2, m->htotal); - hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay); - hdmi_set_reg(tg->hact_sz, 2, m->hdisplay); - hdmi_set_reg(tg->v_fsz, 2, m->vtotal); - hdmi_set_reg(tg->vsync, 2, 0x1); - hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */ - hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */ - hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */ - hdmi_set_reg(tg->tg_3d, 1, 0x0); -} - static void hdmi_mode_set(struct exynos_drm_display *display, struct drm_display_mode *mode) { @@ -1913,13 +1709,8 @@ static void hdmi_mode_set(struct exynos_drm_display *display, m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ? "INTERLACED" : "PROGRESSIVE"); - /* preserve mode information for later use. */ drm_mode_copy(&hdata->current_mode, mode); - hdata->cea_video_id = drm_match_cea_mode(mode); - - if (hdata->drv_data->type == HDMI_TYPE14) - hdmi_v14_mode_set(hdata, mode); } static void hdmi_commit(struct exynos_drm_display *display) From 5149705dacfb24406634d2060880cd5605772540 Mon Sep 17 00:00:00 2001 From: Hyungwon Hwang Date: Wed, 1 Jul 2015 19:09:25 +0900 Subject: [PATCH 14/53] drm/exynos: gsc: Handles the combination of rotation and flip The unique results of all the combination of rotation and flip can be represented by just 8 states. This patch handles all the combination correctly. Signed-off-by: Hyungwon Hwang Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index f1c6b76c127f..808a0a013780 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -582,9 +582,17 @@ static int gsc_src_set_transf(struct device *dev, break; case EXYNOS_DRM_DEGREE_180: cfg |= GSC_IN_ROT_180; + if (flip & EXYNOS_DRM_FLIP_VERTICAL) + cfg &= ~GSC_IN_ROT_XFLIP; + if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) + cfg &= ~GSC_IN_ROT_YFLIP; break; case EXYNOS_DRM_DEGREE_270: cfg |= GSC_IN_ROT_270; + if (flip & EXYNOS_DRM_FLIP_VERTICAL) + cfg &= ~GSC_IN_ROT_XFLIP; + if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) + cfg &= ~GSC_IN_ROT_YFLIP; break; default: dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); @@ -845,9 +853,17 @@ static int gsc_dst_set_transf(struct device *dev, break; case EXYNOS_DRM_DEGREE_180: cfg |= GSC_IN_ROT_180; + if (flip & EXYNOS_DRM_FLIP_VERTICAL) + cfg &= ~GSC_IN_ROT_XFLIP; + if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) + cfg &= ~GSC_IN_ROT_YFLIP; break; case EXYNOS_DRM_DEGREE_270: cfg |= GSC_IN_ROT_270; + if (flip & EXYNOS_DRM_FLIP_VERTICAL) + cfg &= ~GSC_IN_ROT_XFLIP; + if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) + cfg &= ~GSC_IN_ROT_YFLIP; break; default: dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); From b24919575ea26937013a4380a604c4e8c0a71c81 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 2 Jul 2015 21:49:37 +0900 Subject: [PATCH 15/53] drm/exynos: remove to use ifdef CONFIG_ARM_DMA_USE_IOMMU If CONFIG_ARM_DMA_USE_IOMMU is disable, CONFIG_DRM_EXYNOS_IOMMU also is disable. When CONFIG_DRM_EXYNOS_IOMMU is disable, is_drm_iommu_supported() returns always false, so we can remove to use ifdef CONFIG_ARM_DMA_USE_IOMMU in is_drm_iommu_supported(). Signed-off-by: Joonyoung Shim Tested-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_iommu.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h index 8341c7a475b4..a90357fc163d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.h +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.h @@ -29,13 +29,9 @@ void drm_iommu_detach_device(struct drm_device *dev_dev, static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) { -#ifdef CONFIG_ARM_DMA_USE_IOMMU struct device *dev = drm_dev->dev; return dev->archdata.mapping ? true : false; -#else - return false; -#endif } int drm_iommu_attach_device_if_possible( From bf56608a73444037d6960204d81662ccbdebe282 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 2 Jul 2015 21:49:38 +0900 Subject: [PATCH 16/53] drm/exynos: remove unnecessary checking to support iommu Already drm_iommu_attach_device and drm_iommu_detach_device check whether support iommu internally, so we don't have to call is_drm_iommu_supported before call them. Signed-off-by: Joonyoung Shim Tested-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 3 +-- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 3 +-- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 9 +-------- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 6 ------ drivers/gpu/drm/exynos/exynos_drm_iommu.c | 11 +++-------- drivers/gpu/drm/exynos/exynos_drm_ipp.c | 16 ++++++---------- drivers/gpu/drm/exynos/exynos_mixer.c | 3 +-- 7 files changed, 13 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 8b1225f245fc..ba43437014ce 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -514,8 +514,7 @@ static void decon_unbind(struct device *dev, struct device *master, void *data) decon_disable(ctx->crtc); /* detach this sub driver from iommu mapping if supported. */ - if (is_drm_iommu_supported(ctx->drm_dev)) - drm_iommu_detach_device(ctx->drm_dev, ctx->dev); + drm_iommu_detach_device(ctx->drm_dev, ctx->dev); } static const struct component_ops decon_component_ops = { diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 362532afd1a5..2c296353c9c3 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -136,8 +136,7 @@ static int decon_ctx_initialize(struct decon_context *ctx, static void decon_ctx_remove(struct decon_context *ctx) { /* detach this sub driver from iommu mapping if supported. */ - if (is_drm_iommu_supported(ctx->drm_dev)) - drm_iommu_detach_device(ctx->drm_dev, ctx->dev); + drm_iommu_detach_device(ctx->drm_dev, ctx->dev); } static u32 decon_calc_clkdiv(struct decon_context *ctx, diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 794e56c8798e..300730c7af63 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -348,13 +348,6 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc) pm_runtime_put(ctx->dev); } -static void fimd_iommu_detach_devices(struct fimd_context *ctx) -{ - /* detach this sub driver from iommu mapping if supported. */ - if (is_drm_iommu_supported(ctx->drm_dev)) - drm_iommu_detach_device(ctx->drm_dev, ctx->dev); -} - static u32 fimd_calc_clkdiv(struct fimd_context *ctx, const struct drm_display_mode *mode) { @@ -978,7 +971,7 @@ static void fimd_unbind(struct device *dev, struct device *master, fimd_disable(ctx->crtc); - fimd_iommu_detach_devices(ctx); + drm_iommu_detach_device(ctx->drm_dev, ctx->dev); if (ctx->display) exynos_dpi_remove(ctx->display); diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 81a250830808..ba008391a2fc 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -1319,9 +1319,6 @@ static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev) return ret; } - if (!is_drm_iommu_supported(drm_dev)) - return 0; - ret = drm_iommu_attach_device(drm_dev, dev); if (ret < 0) { dev_err(dev, "failed to enable iommu.\n"); @@ -1334,9 +1331,6 @@ static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev) static void g2d_subdrv_remove(struct drm_device *drm_dev, struct device *dev) { - if (!is_drm_iommu_supported(drm_dev)) - return; - drm_iommu_detach_device(drm_dev, dev); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c index d4ec7465e9cc..4c2ec1bef252 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c @@ -87,10 +87,8 @@ int drm_iommu_attach_device(struct drm_device *drm_dev, struct device *dev = drm_dev->dev; int ret; - if (!dev->archdata.mapping) { - DRM_ERROR("iommu_mapping is null.\n"); - return -EFAULT; - } + if (!dev->archdata.mapping) + return 0; subdrv_dev->dma_parms = devm_kzalloc(subdrv_dev, sizeof(*subdrv_dev->dma_parms), @@ -148,13 +146,10 @@ void drm_iommu_detach_device(struct drm_device *drm_dev, int drm_iommu_attach_device_if_possible(struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev, struct device *subdrv_dev) { - int ret = 0; - if (is_drm_iommu_supported(drm_dev)) { if (exynos_crtc->ops->clear_channels) exynos_crtc->ops->clear_channels(exynos_crtc); - return drm_iommu_attach_device(drm_dev, subdrv_dev); } - return ret; + return drm_iommu_attach_device(drm_dev, subdrv_dev); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 67e5451e066f..67d24236e745 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -1622,12 +1622,10 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) INIT_LIST_HEAD(&ippdrv->cmd_list); mutex_init(&ippdrv->cmd_lock); - if (is_drm_iommu_supported(drm_dev)) { - ret = drm_iommu_attach_device(drm_dev, ippdrv->dev); - if (ret) { - DRM_ERROR("failed to activate iommu\n"); - goto err; - } + ret = drm_iommu_attach_device(drm_dev, ippdrv->dev); + if (ret) { + DRM_ERROR("failed to activate iommu\n"); + goto err; } } @@ -1637,8 +1635,7 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) /* get ipp driver entry */ list_for_each_entry_continue_reverse(ippdrv, &exynos_drm_ippdrv_list, drv_list) { - if (is_drm_iommu_supported(drm_dev)) - drm_iommu_detach_device(drm_dev, ippdrv->dev); + drm_iommu_detach_device(drm_dev, ippdrv->dev); ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv->prop_list.ipp_id); @@ -1654,8 +1651,7 @@ static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev) /* get ipp driver entry */ list_for_each_entry_safe(ippdrv, t, &exynos_drm_ippdrv_list, drv_list) { - if (is_drm_iommu_supported(drm_dev)) - drm_iommu_detach_device(drm_dev, ippdrv->dev); + drm_iommu_detach_device(drm_dev, ippdrv->dev); ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv->prop_list.ipp_id); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 4706b56902b4..b7e438fc7fdd 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -891,8 +891,7 @@ static int mixer_initialize(struct mixer_context *mixer_ctx, static void mixer_ctx_remove(struct mixer_context *mixer_ctx) { - if (is_drm_iommu_supported(mixer_ctx->drm_dev)) - drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev); + drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev); } static int mixer_enable_vblank(struct exynos_drm_crtc *crtc) From a44652e845739b88214adf9f40478f1ed037348d Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 08:25:42 +0200 Subject: [PATCH 17/53] drm/exynos/mixer: simplify poweron flag The driver uses bool protected by mutex to track power state. The patch replaces this combo with single bit and atomic bitops. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 52 ++++++++------------------- 1 file changed, 14 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index b7e438fc7fdd..e275e36af0ae 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -69,6 +69,10 @@ enum mixer_version_id { MXR_VER_128_0_0_184, }; +enum mixer_flag_bits { + MXR_BIT_POWERED, +}; + struct mixer_context { struct platform_device *pdev; struct device *dev; @@ -76,13 +80,12 @@ struct mixer_context { struct exynos_drm_crtc *crtc; struct exynos_drm_plane planes[MIXER_WIN_NR]; int pipe; + unsigned long flags; bool interlace; - bool powered; bool vp_enabled; bool has_sclk; u32 int_en; - struct mutex mixer_mutex; struct mixer_resources mixer_res; enum mixer_version_id mxr_ver; wait_queue_head_t wait_vsync_queue; @@ -899,7 +902,7 @@ static int mixer_enable_vblank(struct exynos_drm_crtc *crtc) struct mixer_context *mixer_ctx = crtc->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; - if (!mixer_ctx->powered) { + if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) { mixer_ctx->int_en |= MXR_INT_EN_VSYNC; return 0; } @@ -916,7 +919,7 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc) struct mixer_context *mixer_ctx = crtc->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; - if (!mixer_ctx->powered) { + if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) { mixer_ctx->int_en &= MXR_INT_EN_VSYNC; return; } @@ -932,12 +935,8 @@ static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) DRM_DEBUG_KMS("win: %d\n", win); - mutex_lock(&mixer_ctx->mixer_mutex); - if (!mixer_ctx->powered) { - mutex_unlock(&mixer_ctx->mixer_mutex); + if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) return; - } - mutex_unlock(&mixer_ctx->mixer_mutex); if (win > 1 && mixer_ctx->vp_enabled) vp_video_buffer(mixer_ctx, win); @@ -953,12 +952,8 @@ static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) DRM_DEBUG_KMS("win: %d\n", win); - mutex_lock(&mixer_ctx->mixer_mutex); - if (!mixer_ctx->powered) { - mutex_unlock(&mixer_ctx->mixer_mutex); + if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) return; - } - mutex_unlock(&mixer_ctx->mixer_mutex); spin_lock_irqsave(&res->reg_slock, flags); mixer_vsync_set_update(mixer_ctx, false); @@ -974,12 +969,8 @@ static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc) struct mixer_context *mixer_ctx = crtc->ctx; int err; - mutex_lock(&mixer_ctx->mixer_mutex); - if (!mixer_ctx->powered) { - mutex_unlock(&mixer_ctx->mixer_mutex); + if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) return; - } - mutex_unlock(&mixer_ctx->mixer_mutex); err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe); if (err < 0) { @@ -1007,13 +998,8 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) struct mixer_resources *res = &ctx->mixer_res; int ret; - mutex_lock(&ctx->mixer_mutex); - if (ctx->powered) { - mutex_unlock(&ctx->mixer_mutex); + if (test_bit(MXR_BIT_POWERED, &ctx->flags)) return; - } - - mutex_unlock(&ctx->mixer_mutex); pm_runtime_get_sync(ctx->dev); @@ -1045,9 +1031,7 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) } } - mutex_lock(&ctx->mixer_mutex); - ctx->powered = true; - mutex_unlock(&ctx->mixer_mutex); + set_bit(MXR_BIT_POWERED, &ctx->flags); mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET); @@ -1063,12 +1047,8 @@ static void mixer_disable(struct exynos_drm_crtc *crtc) struct mixer_resources *res = &ctx->mixer_res; int i; - mutex_lock(&ctx->mixer_mutex); - if (!ctx->powered) { - mutex_unlock(&ctx->mixer_mutex); + if (!test_bit(MXR_BIT_POWERED, &ctx->flags)) return; - } - mutex_unlock(&ctx->mixer_mutex); mixer_stop(ctx); mixer_regs_dump(ctx); @@ -1078,9 +1058,7 @@ static void mixer_disable(struct exynos_drm_crtc *crtc) ctx->int_en = mixer_reg_read(res, MXR_INT_EN); - mutex_lock(&ctx->mixer_mutex); - ctx->powered = false; - mutex_unlock(&ctx->mixer_mutex); + clear_bit(MXR_BIT_POWERED, &ctx->flags); clk_disable_unprepare(res->hdmi); clk_disable_unprepare(res->mixer); @@ -1242,8 +1220,6 @@ static int mixer_probe(struct platform_device *pdev) return -ENOMEM; } - mutex_init(&ctx->mixer_mutex); - if (dev->of_node) { const struct of_device_id *match; From 0df5e4acf584ad1b1b5689d283e1e81655eefab1 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 08:25:43 +0200 Subject: [PATCH 18/53] drm/exynos/mixer: replace MXR_INT_EN register cache with flag Driver uses only VSYNC interrupts, so we need to cache VSYNC bit state only. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index e275e36af0ae..c6384feaf2a2 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -71,6 +71,7 @@ enum mixer_version_id { enum mixer_flag_bits { MXR_BIT_POWERED, + MXR_BIT_VSYNC, }; struct mixer_context { @@ -84,7 +85,6 @@ struct mixer_context { bool interlace; bool vp_enabled; bool has_sclk; - u32 int_en; struct mixer_resources mixer_res; enum mixer_version_id mxr_ver; @@ -902,10 +902,9 @@ static int mixer_enable_vblank(struct exynos_drm_crtc *crtc) struct mixer_context *mixer_ctx = crtc->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; - if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) { - mixer_ctx->int_en |= MXR_INT_EN_VSYNC; + __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags); + if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) return 0; - } /* enable vsync interrupt */ mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); @@ -919,10 +918,10 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc) struct mixer_context *mixer_ctx = crtc->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; - if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) { - mixer_ctx->int_en &= MXR_INT_EN_VSYNC; + __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags); + + if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) return; - } /* disable vsync interrupt */ mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); @@ -1035,9 +1034,10 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET); - if (ctx->int_en & MXR_INT_EN_VSYNC) + if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) { mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); - mixer_reg_write(res, MXR_INT_EN, ctx->int_en); + mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC); + } mixer_win_reset(ctx); } @@ -1056,8 +1056,6 @@ static void mixer_disable(struct exynos_drm_crtc *crtc) for (i = 0; i < MIXER_WIN_NR; i++) mixer_win_disable(crtc, i); - ctx->int_en = mixer_reg_read(res, MXR_INT_EN); - clear_bit(MXR_BIT_POWERED, &ctx->flags); clk_disable_unprepare(res->hdmi); From 735c21c3c802e9e89ce302ab40ea92f5d1151e02 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Wed, 15 Jul 2015 12:04:39 +0900 Subject: [PATCH 19/53] drm/exynos: move order to register vidi kms driver The vidi is virtual kms driver and now it is registered earlier than actual hw kms drivers, so it will occupy crtc index 0. Some users assume the condition yet that actual hw kms driver has crtc index 0. It may or may not be matter but let's arrange register order. Signed-off-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 63a68c60a353..f1d69667b4e8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -345,9 +345,6 @@ static struct platform_driver exynos_drm_platform_driver; * because connector requires pipe number of its crtc during initialization. */ static struct platform_driver *const exynos_drm_kms_drivers[] = { -#ifdef CONFIG_DRM_EXYNOS_VIDI - &vidi_driver, -#endif #ifdef CONFIG_DRM_EXYNOS_FIMD &fimd_driver, #endif @@ -370,6 +367,9 @@ static struct platform_driver *const exynos_drm_kms_drivers[] = { &mixer_driver, &hdmi_driver, #endif +#ifdef CONFIG_DRM_EXYNOS_VIDI + &vidi_driver, +#endif }; static struct platform_driver *const exynos_drm_non_kms_drivers[] = { From eb7a3fc74c58be9c01cdbe23947ae9eb032e8365 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 2 Jul 2015 21:49:39 +0900 Subject: [PATCH 20/53] drm/exynos: remove drm_iommu_attach_device_if_possible Already drm_iommu_attach_device checks whether support iommu internally. It should clear channels always regardless iommu support. We didn't know because we can detect the problem when iommu is enabled, so we don't have to use drm_iommu_attach_device_if_possible and then we can remove drm_iommu_attach_device_if_possible and clear_channels function pointer. Signed-off-by: Joonyoung Shim Tested-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 5 +++-- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 5 +++-- drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 - drivers/gpu/drm/exynos/exynos_drm_fimd.c | 5 +++-- drivers/gpu/drm/exynos/exynos_drm_iommu.c | 11 ----------- drivers/gpu/drm/exynos/exynos_drm_iommu.h | 11 ----------- drivers/gpu/drm/exynos/exynos_mixer.c | 3 +-- 7 files changed, 10 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index ba43437014ce..b2794f815b3c 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -463,7 +463,6 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = { .win_commit = decon_win_commit, .win_disable = decon_win_disable, .te_handler = decon_te_irq_handler, - .clear_channels = decon_clear_channels, }; static int decon_bind(struct device *dev, struct device *master, void *data) @@ -497,7 +496,9 @@ static int decon_bind(struct device *dev, struct device *master, void *data) goto err; } - ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, dev); + decon_clear_channels(ctx->crtc); + + ret = drm_iommu_attach_device(drm_dev, dev); if (ret) goto err; diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 2c296353c9c3..a80b9184c866 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -126,7 +126,9 @@ static int decon_ctx_initialize(struct decon_context *ctx, ctx->drm_dev = drm_dev; ctx->pipe = priv->pipe++; - ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, ctx->dev); + decon_clear_channels(ctx->crtc); + + ret = drm_iommu_attach_device(drm_dev, ctx->dev); if (ret) priv->pipe--; @@ -622,7 +624,6 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = { .wait_for_vblank = decon_wait_for_vblank, .win_commit = decon_win_commit, .win_disable = decon_win_disable, - .clear_channels = decon_clear_channels, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index dd00f160c1e5..7da593fd081f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -177,7 +177,6 @@ struct exynos_drm_crtc_ops { void (*win_disable)(struct exynos_drm_crtc *crtc, unsigned int zpos); void (*te_handler)(struct exynos_drm_crtc *crtc); void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); - void (*clear_channels)(struct exynos_drm_crtc *crtc); }; /* diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 300730c7af63..8d362b9365d3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -887,7 +887,6 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = { .win_disable = fimd_win_disable, .te_handler = fimd_te_handler, .clock_enable = fimd_dp_clock_enable, - .clear_channels = fimd_clear_channels, }; static irqreturn_t fimd_irq_handler(int irq, void *dev_id) @@ -957,7 +956,9 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) if (ctx->display) exynos_drm_create_enc_conn(drm_dev, ctx->display); - ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, dev); + fimd_clear_channels(ctx->crtc); + + ret = drm_iommu_attach_device(drm_dev, dev); if (ret) priv->pipe--; diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c index 4c2ec1bef252..055e8ec2ef21 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c @@ -142,14 +142,3 @@ void drm_iommu_detach_device(struct drm_device *drm_dev, iommu_detach_device(mapping->domain, subdrv_dev); drm_release_iommu_mapping(drm_dev); } - -int drm_iommu_attach_device_if_possible(struct exynos_drm_crtc *exynos_crtc, - struct drm_device *drm_dev, struct device *subdrv_dev) -{ - if (is_drm_iommu_supported(drm_dev)) { - if (exynos_crtc->ops->clear_channels) - exynos_crtc->ops->clear_channels(exynos_crtc); - } - - return drm_iommu_attach_device(drm_dev, subdrv_dev); -} diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h index a90357fc163d..dc1b5441f491 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.h +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.h @@ -34,10 +34,6 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) return dev->archdata.mapping ? true : false; } -int drm_iommu_attach_device_if_possible( - struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev, - struct device *subdrv_dev); - #else static inline int drm_create_iommu_mapping(struct drm_device *drm_dev) @@ -65,12 +61,5 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) return false; } -static inline int drm_iommu_attach_device_if_possible( - struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev, - struct device *subdrv_dev) -{ - return 0; -} - #endif #endif diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index c6384feaf2a2..370e0a306ad0 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -884,8 +884,7 @@ static int mixer_initialize(struct mixer_context *mixer_ctx, } } - ret = drm_iommu_attach_device_if_possible(mixer_ctx->crtc, drm_dev, - mixer_ctx->dev); + ret = drm_iommu_attach_device(drm_dev, mixer_ctx->dev); if (ret) priv->pipe--; From 43a3b866a9e73e9bd215ec3f36c71e42469e70c6 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 28 Jul 2015 17:51:02 +0900 Subject: [PATCH 21/53] drm/exynos: clear channels only when iommu is enabled This is simplest solution about reported problem[1]. It's no problem to clear channel only when iommu is enabled, if we consider that we cannot recognize iommu errors when iommu is disabled and it have been valid until now. But this cannot be nice solution. [1] https://lkml.org/lkml/2015/7/21/404 Reported-by: Krzysztof Kozlowski Signed-off-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 8d362b9365d3..337af025a594 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -956,7 +956,8 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) if (ctx->display) exynos_drm_create_enc_conn(drm_dev, ctx->display); - fimd_clear_channels(ctx->crtc); + if (is_drm_iommu_supported(drm_dev)) + fimd_clear_channels(ctx->crtc); ret = drm_iommu_attach_device(drm_dev, dev); if (ret) From 451a8c0c59b3feebb5bf6a1ce1335e9f3e428355 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 16 Jul 2015 12:23:31 -0300 Subject: [PATCH 22/53] drm/exynos: pass the correct pipe number Instead of giving -1 to as arg to drm_send_vblank_event() pass the correct pipe number to it. Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 1610757230a5..f6017262ac02 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -205,7 +205,7 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe) spin_lock_irqsave(&dev->event_lock, flags); if (exynos_crtc->event) { - drm_send_vblank_event(dev, -1, exynos_crtc->event); + drm_send_vblank_event(dev, pipe, exynos_crtc->event); drm_vblank_put(dev, pipe); wake_up(&exynos_crtc->pending_flip_queue); From eafd540aeaae6f1c4d04fdf3959419716d23cdc5 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 16 Jul 2015 12:23:32 -0300 Subject: [PATCH 23/53] drm/exynos: use KMS version of DRM vblanks functions Get rid of legacy DRM vblank function that are less clear to use. The new ones basically requires only the crtc as parameters. It also clean ups exynos_drm_crtc_finish_pageflip() parameters as a consequence. Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 6 +++--- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 14 ++++++-------- drivers/gpu/drm/exynos/exynos_drm_crtc.h | 2 +- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 8 ++++---- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 4 ++-- drivers/gpu/drm/exynos/exynos_mixer.c | 4 ++-- 7 files changed, 20 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index b2794f815b3c..b00800b72950 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -407,7 +407,7 @@ void decon_te_irq_handler(struct exynos_drm_crtc *crtc) writel(val, ctx->addr + DECON_TRIGCON); } - drm_handle_vblank(ctx->drm_dev, ctx->pipe); + drm_crtc_handle_vblank(&ctx->crtc->base); } static void decon_clear_channels(struct exynos_drm_crtc *crtc) @@ -533,7 +533,7 @@ static irqreturn_t decon_vsync_irq_handler(int irq, void *dev_id) val = readl(ctx->addr + DECON_VIDINTCON1); if (val & VIDINTCON1_INTFRMPEND) { - drm_handle_vblank(ctx->drm_dev, ctx->pipe); + drm_crtc_handle_vblank(&ctx->crtc->base); /* clear */ writel(VIDINTCON1_INTFRMPEND, ctx->addr + DECON_VIDINTCON1); @@ -553,7 +553,7 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id) val = readl(ctx->addr + DECON_VIDINTCON1); if (val & VIDINTCON1_INTFRMDONEPEND) { - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + exynos_drm_crtc_finish_pageflip(ctx->crtc); /* clear */ writel(VIDINTCON1_INTFRMDONEPEND, diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index a80b9184c866..1cd78b6a1635 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -643,8 +643,8 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id) goto out; if (!ctx->i80_if) { - drm_handle_vblank(ctx->drm_dev, ctx->pipe); - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + drm_crtc_handle_vblank(&ctx->crtc->base); + exynos_drm_crtc_finish_pageflip(ctx->crtc); /* set wait vsync event to zero and wake up queue. */ if (atomic_read(&ctx->wait_vsync_event)) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index f6017262ac02..fb213502082d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -195,24 +195,22 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) exynos_crtc->ops->disable_vblank(exynos_crtc); } -void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe) +void exynos_drm_crtc_finish_pageflip(struct exynos_drm_crtc *exynos_crtc) { - struct exynos_drm_private *dev_priv = dev->dev_private; - struct drm_crtc *drm_crtc = dev_priv->crtc[pipe]; - struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc); + struct drm_crtc *crtc = &exynos_crtc->base; unsigned long flags; - spin_lock_irqsave(&dev->event_lock, flags); + spin_lock_irqsave(&crtc->dev->event_lock, flags); if (exynos_crtc->event) { - drm_send_vblank_event(dev, pipe, exynos_crtc->event); - drm_vblank_put(dev, pipe); + drm_crtc_send_vblank_event(crtc, exynos_crtc->event); + drm_crtc_vblank_put(crtc); wake_up(&exynos_crtc->pending_flip_queue); } exynos_crtc->event = NULL; - spin_unlock_irqrestore(&dev->event_lock, flags); + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); } void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index 0f3aa70818e3..d01d49a69298 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -25,7 +25,7 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, void *context); int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe); void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe); -void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe); +void exynos_drm_crtc_finish_pageflip(struct exynos_drm_crtc *exynos_crtc); void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb); /* This function gets pipe value to crtc device matched with out_type. */ diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 337af025a594..b79f472d3a74 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -855,7 +855,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc) } if (test_bit(0, &ctx->irq_flags)) - drm_handle_vblank(ctx->drm_dev, ctx->pipe); + drm_crtc_handle_vblank(&ctx->crtc->base); } static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable) @@ -905,13 +905,13 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) goto out; if (ctx->i80_if) { - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + exynos_drm_crtc_finish_pageflip(ctx->crtc); /* Exits triggering mode */ atomic_set(&ctx->triggering, 0); } else { - drm_handle_vblank(ctx->drm_dev, ctx->pipe); - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + drm_crtc_handle_vblank(&ctx->crtc->base); + exynos_drm_crtc_finish_pageflip(ctx->crtc); /* set wait vsync event to zero and wake up queue. */ if (atomic_read(&ctx->wait_vsync_event)) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 3413393d8a16..9b97105ddc54 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -196,7 +196,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work) mutex_lock(&ctx->lock); if (ctx->direct_vblank) { - drm_handle_vblank(ctx->drm_dev, ctx->pipe); + drm_crtc_handle_vblank(&ctx->crtc->base); ctx->direct_vblank = false; mutex_unlock(&ctx->lock); return; @@ -204,7 +204,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work) mutex_unlock(&ctx->lock); - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + exynos_drm_crtc_finish_pageflip(ctx->crtc); } static int vidi_show_connection(struct device *dev, diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 370e0a306ad0..ca12540e384b 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -738,8 +738,8 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) goto out; } - drm_handle_vblank(ctx->drm_dev, ctx->pipe); - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + drm_crtc_handle_vblank(&ctx->crtc->base); + exynos_drm_crtc_finish_pageflip(ctx->crtc); /* set wait vsync event to zero and wake up queue. */ if (atomic_read(&ctx->wait_vsync_event)) { From f59a89d05f1290d0cdaa588d29871e05cdec159b Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 16 Jul 2015 12:23:33 -0300 Subject: [PATCH 24/53] drm/exynos: remove duplicated check for suspend The same check is placed twice in fimd/decon_update_plane(), remove one of them. Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 3 --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 1cd78b6a1635..fe31e413324f 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -401,9 +401,6 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) plane = &ctx->planes[win]; - if (ctx->suspended) - return; - /* * SHADOWCON/PRTCON register is used for enabling timing. * diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index b79f472d3a74..785101210d22 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -623,9 +623,6 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) plane = &ctx->planes[win]; - if (ctx->suspended) - return; - /* * SHADOWCON/PRTCON register is used for enabling timing. * From 9cc7610a2375a94ec967f771ce74b51db0d43d1c Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 3 Aug 2015 14:38:05 +0900 Subject: [PATCH 25/53] drm/exynos: rename win_commit/disable to atomic-like names Rename win_commit() helper to update_plane() and win_disable() to disable_plane(). Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 10 +++++----- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 10 +++++----- drivers/gpu/drm/exynos/exynos_drm_drv.h | 8 ++++---- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 10 +++++----- drivers/gpu/drm/exynos/exynos_drm_plane.c | 10 +++++----- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 6 +++--- drivers/gpu/drm/exynos/exynos_mixer.c | 10 +++++----- 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index b00800b72950..83fbf387f4d8 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -219,7 +219,7 @@ static void decon_shadow_protect_win(struct decon_context *ctx, int win, writel(val, ctx->addr + DECON_SHADOWCON); } -static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) +static void decon_update_plane(struct exynos_drm_crtc *crtc, unsigned int win) { struct decon_context *ctx = crtc->ctx; struct exynos_drm_plane *plane; @@ -277,7 +277,7 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) atomic_set(&ctx->win_updated, 1); } -static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) +static void decon_disable_plane(struct exynos_drm_crtc *crtc, unsigned int win) { struct decon_context *ctx = crtc->ctx; struct exynos_drm_plane *plane; @@ -378,7 +378,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc) * a destroyed buffer later. */ for (i = 0; i < WINDOWS_NR; i++) - decon_win_disable(crtc, i); + decon_disable_plane(crtc, i); decon_swreset(ctx); @@ -460,8 +460,8 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = { .enable_vblank = decon_enable_vblank, .disable_vblank = decon_disable_vblank, .commit = decon_commit, - .win_commit = decon_win_commit, - .win_disable = decon_win_disable, + .update_plane = decon_update_plane, + .disable_plane = decon_disable_plane, .te_handler = decon_te_irq_handler, }; diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index fe31e413324f..31210bef3ece 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -383,7 +383,7 @@ static void decon_shadow_protect_win(struct decon_context *ctx, writel(val, ctx->regs + SHADOWCON); } -static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) +static void decon_update_plane(struct exynos_drm_crtc *crtc, unsigned int win) { struct decon_context *ctx = crtc->ctx; struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; @@ -493,7 +493,7 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) writel(val, ctx->regs + DECON_UPDATE); } -static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) +static void decon_disable_plane(struct exynos_drm_crtc *crtc, unsigned int win) { struct decon_context *ctx = crtc->ctx; struct exynos_drm_plane *plane; @@ -599,7 +599,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc) * a destroyed buffer later. */ for (i = 0; i < WINDOWS_NR; i++) - decon_win_disable(crtc, i); + decon_disable_plane(crtc, i); clk_disable_unprepare(ctx->vclk); clk_disable_unprepare(ctx->eclk); @@ -619,8 +619,8 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = { .enable_vblank = decon_enable_vblank, .disable_vblank = decon_disable_vblank, .wait_for_vblank = decon_wait_for_vblank, - .win_commit = decon_win_commit, - .win_disable = decon_win_disable, + .update_plane = decon_update_plane, + .disable_plane = decon_disable_plane, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 7da593fd081f..ac7eb317cc88 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -153,8 +153,8 @@ struct exynos_drm_display { * @disable_vblank: specific driver callback for disabling vblank interrupt. * @wait_for_vblank: wait for vblank interrupt to make sure that * hardware overlay is updated. - * @win_commit: apply hardware specific overlay data to registers. - * @win_disable: disable hardware specific overlay. + * @update_plane: apply hardware specific overlay data to registers. + * @disable_plane: disable hardware specific overlay. * @te_handler: trigger to transfer video image at the tearing effect * synchronization signal if there is a page flip request. * @clock_enable: optional function enabling/disabling display domain clock, @@ -173,8 +173,8 @@ struct exynos_drm_crtc_ops { int (*enable_vblank)(struct exynos_drm_crtc *crtc); void (*disable_vblank)(struct exynos_drm_crtc *crtc); void (*wait_for_vblank)(struct exynos_drm_crtc *crtc); - void (*win_commit)(struct exynos_drm_crtc *crtc, unsigned int zpos); - void (*win_disable)(struct exynos_drm_crtc *crtc, unsigned int zpos); + void (*update_plane)(struct exynos_drm_crtc *crtc, unsigned int zpos); + void (*disable_plane)(struct exynos_drm_crtc *crtc, unsigned int zpos); void (*te_handler)(struct exynos_drm_crtc *crtc); void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 785101210d22..81bc34253510 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -607,7 +607,7 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx, writel(val, ctx->regs + reg); } -static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) +static void fimd_update_plane(struct exynos_drm_crtc *crtc, unsigned int win) { struct fimd_context *ctx = crtc->ctx; struct exynos_drm_plane *plane; @@ -715,7 +715,7 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) atomic_set(&ctx->win_updated, 1); } -static void fimd_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) +static void fimd_disable_plane(struct exynos_drm_crtc *crtc, unsigned int win) { struct fimd_context *ctx = crtc->ctx; struct exynos_drm_plane *plane; @@ -785,7 +785,7 @@ static void fimd_disable(struct exynos_drm_crtc *crtc) * a destroyed buffer later. */ for (i = 0; i < WINDOWS_NR; i++) - fimd_win_disable(crtc, i); + fimd_disable_plane(crtc, i); fimd_enable_vblank(crtc); fimd_wait_for_vblank(crtc); @@ -880,8 +880,8 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = { .enable_vblank = fimd_enable_vblank, .disable_vblank = fimd_disable_vblank, .wait_for_vblank = fimd_wait_for_vblank, - .win_commit = fimd_win_commit, - .win_disable = fimd_win_disable, + .update_plane = fimd_update_plane, + .disable_plane = fimd_disable_plane, .te_handler = fimd_te_handler, .clock_enable = fimd_dp_clock_enable, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index a729980d3c2f..eb9eec944326 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -179,8 +179,8 @@ static void exynos_plane_atomic_update(struct drm_plane *plane, state->src_x >> 16, state->src_y >> 16, state->src_w >> 16, state->src_h >> 16); - if (exynos_crtc->ops->win_commit) - exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos); + if (exynos_crtc->ops->update_plane) + exynos_crtc->ops->update_plane(exynos_crtc, exynos_plane->zpos); } static void exynos_plane_atomic_disable(struct drm_plane *plane, @@ -192,9 +192,9 @@ static void exynos_plane_atomic_disable(struct drm_plane *plane, if (!old_state->crtc) return; - if (exynos_crtc->ops->win_disable) - exynos_crtc->ops->win_disable(exynos_crtc, - exynos_plane->zpos); + if (exynos_crtc->ops->disable_plane) + exynos_crtc->ops->disable_plane(exynos_crtc, + exynos_plane->zpos); } static const struct drm_plane_helper_funcs plane_helper_funcs = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 9b97105ddc54..59d85ef04650 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -100,7 +100,7 @@ static int vidi_enable_vblank(struct exynos_drm_crtc *crtc) /* * in case of page flip request, vidi_finish_pageflip function * will not be called because direct_vblank is true and then - * that function will be called by crtc_ops->win_commit callback + * that function will be called by crtc_ops->update_plane callback */ schedule_work(&ctx->work); @@ -118,7 +118,7 @@ static void vidi_disable_vblank(struct exynos_drm_crtc *crtc) ctx->vblank_on = false; } -static void vidi_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) +static void vidi_update_plane(struct exynos_drm_crtc *crtc, unsigned int win) { struct vidi_context *ctx = crtc->ctx; struct exynos_drm_plane *plane; @@ -179,7 +179,7 @@ static const struct exynos_drm_crtc_ops vidi_crtc_ops = { .disable = vidi_disable, .enable_vblank = vidi_enable_vblank, .disable_vblank = vidi_disable_vblank, - .win_commit = vidi_win_commit, + .update_plane = vidi_update_plane, }; static void vidi_fake_vblank_handler(struct work_struct *work) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index ca12540e384b..72bdded845f4 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -927,7 +927,7 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc) mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); } -static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) +static void mixer_update_plane(struct exynos_drm_crtc *crtc, unsigned int win) { struct mixer_context *mixer_ctx = crtc->ctx; @@ -942,7 +942,7 @@ static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) mixer_graph_buffer(mixer_ctx, win); } -static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) +static void mixer_disable_plane(struct exynos_drm_crtc *crtc, unsigned int win) { struct mixer_context *mixer_ctx = crtc->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; @@ -1053,7 +1053,7 @@ static void mixer_disable(struct exynos_drm_crtc *crtc) mixer_regs_dump(ctx); for (i = 0; i < MIXER_WIN_NR; i++) - mixer_win_disable(crtc, i); + mixer_disable_plane(crtc, i); clear_bit(MXR_BIT_POWERED, &ctx->flags); @@ -1094,8 +1094,8 @@ static const struct exynos_drm_crtc_ops mixer_crtc_ops = { .enable_vblank = mixer_enable_vblank, .disable_vblank = mixer_disable_vblank, .wait_for_vblank = mixer_wait_for_vblank, - .win_commit = mixer_win_commit, - .win_disable = mixer_win_disable, + .update_plane = mixer_update_plane, + .disable_plane = mixer_disable_plane, }; static struct mixer_drv_data exynos5420_mxr_drv_data = { From 1e1d13932283419ddfdb60c73319cc0e753ded5b Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 3 Aug 2015 14:39:36 +0900 Subject: [PATCH 26/53] drm/exynos: pass struct exynos_drm_plane in update/enable We already have the plane pointer in before calling .update_plane() or disable_plane() so pass it directly to those calls avoiding a new conversion from zpos to struct exynos_drm_plane. v2: don't remove check for suspended in FIMD (comment by Joonyoung) Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 22 ++++++------------- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 22 ++++++------------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 6 +++-- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 22 ++++++------------- drivers/gpu/drm/exynos/exynos_drm_plane.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 9 ++------ drivers/gpu/drm/exynos/exynos_mixer.c | 20 +++++++++-------- 7 files changed, 40 insertions(+), 65 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 83fbf387f4d8..a4ea09665b83 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -219,17 +219,13 @@ static void decon_shadow_protect_win(struct decon_context *ctx, int win, writel(val, ctx->addr + DECON_SHADOWCON); } -static void decon_update_plane(struct exynos_drm_crtc *crtc, unsigned int win) +static void decon_update_plane(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) { struct decon_context *ctx = crtc->ctx; - struct exynos_drm_plane *plane; + unsigned int win = plane->zpos; u32 val; - if (win < 0 || win >= WINDOWS_NR) - return; - - plane = &ctx->planes[win]; - if (ctx->suspended) return; @@ -277,17 +273,13 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, unsigned int win) atomic_set(&ctx->win_updated, 1); } -static void decon_disable_plane(struct exynos_drm_crtc *crtc, unsigned int win) +static void decon_disable_plane(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) { struct decon_context *ctx = crtc->ctx; - struct exynos_drm_plane *plane; + unsigned int win = plane->zpos; u32 val; - if (win < 0 || win >= WINDOWS_NR) - return; - - plane = &ctx->planes[win]; - if (ctx->suspended) return; @@ -378,7 +370,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc) * a destroyed buffer later. */ for (i = 0; i < WINDOWS_NR; i++) - decon_disable_plane(crtc, i); + decon_disable_plane(crtc, &ctx->planes[i]); decon_swreset(ctx); diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 31210bef3ece..0bb393867da4 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -383,24 +383,20 @@ static void decon_shadow_protect_win(struct decon_context *ctx, writel(val, ctx->regs + SHADOWCON); } -static void decon_update_plane(struct exynos_drm_crtc *crtc, unsigned int win) +static void decon_update_plane(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) { struct decon_context *ctx = crtc->ctx; struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; - struct exynos_drm_plane *plane; int padding; unsigned long val, alpha; unsigned int last_x; unsigned int last_y; + unsigned int win = plane->zpos; if (ctx->suspended) return; - if (win < 0 || win >= WINDOWS_NR) - return; - - plane = &ctx->planes[win]; - /* * SHADOWCON/PRTCON register is used for enabling timing. * @@ -493,17 +489,13 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, unsigned int win) writel(val, ctx->regs + DECON_UPDATE); } -static void decon_disable_plane(struct exynos_drm_crtc *crtc, unsigned int win) +static void decon_disable_plane(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) { struct decon_context *ctx = crtc->ctx; - struct exynos_drm_plane *plane; + unsigned int win = plane->zpos; u32 val; - if (win < 0 || win >= WINDOWS_NR) - return; - - plane = &ctx->planes[win]; - if (ctx->suspended) return; @@ -599,7 +591,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc) * a destroyed buffer later. */ for (i = 0; i < WINDOWS_NR; i++) - decon_disable_plane(crtc, i); + decon_disable_plane(crtc, &ctx->planes[i]); clk_disable_unprepare(ctx->vclk); clk_disable_unprepare(ctx->eclk); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index ac7eb317cc88..18d04d0e7364 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -173,8 +173,10 @@ struct exynos_drm_crtc_ops { int (*enable_vblank)(struct exynos_drm_crtc *crtc); void (*disable_vblank)(struct exynos_drm_crtc *crtc); void (*wait_for_vblank)(struct exynos_drm_crtc *crtc); - void (*update_plane)(struct exynos_drm_crtc *crtc, unsigned int zpos); - void (*disable_plane)(struct exynos_drm_crtc *crtc, unsigned int zpos); + void (*update_plane)(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane); + void (*disable_plane)(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane); void (*te_handler)(struct exynos_drm_crtc *crtc); void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 81bc34253510..2527997c4f24 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -607,22 +607,18 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx, writel(val, ctx->regs + reg); } -static void fimd_update_plane(struct exynos_drm_crtc *crtc, unsigned int win) +static void fimd_update_plane(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) { struct fimd_context *ctx = crtc->ctx; - struct exynos_drm_plane *plane; dma_addr_t dma_addr; unsigned long val, size, offset; unsigned int last_x, last_y, buf_offsize, line_size; + unsigned int win = plane->zpos; if (ctx->suspended) return; - if (win < 0 || win >= WINDOWS_NR) - return; - - plane = &ctx->planes[win]; - /* * SHADOWCON/PRTCON register is used for enabling timing. * @@ -715,15 +711,11 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, unsigned int win) atomic_set(&ctx->win_updated, 1); } -static void fimd_disable_plane(struct exynos_drm_crtc *crtc, unsigned int win) +static void fimd_disable_plane(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) { struct fimd_context *ctx = crtc->ctx; - struct exynos_drm_plane *plane; - - if (win < 0 || win >= WINDOWS_NR) - return; - - plane = &ctx->planes[win]; + unsigned int win = plane->zpos; if (ctx->suspended) return; @@ -785,7 +777,7 @@ static void fimd_disable(struct exynos_drm_crtc *crtc) * a destroyed buffer later. */ for (i = 0; i < WINDOWS_NR; i++) - fimd_disable_plane(crtc, i); + fimd_disable_plane(crtc, &ctx->planes[i]); fimd_enable_vblank(crtc); fimd_wait_for_vblank(crtc); diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index eb9eec944326..b5aa5b75d82b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -180,7 +180,7 @@ static void exynos_plane_atomic_update(struct drm_plane *plane, state->src_w >> 16, state->src_h >> 16); if (exynos_crtc->ops->update_plane) - exynos_crtc->ops->update_plane(exynos_crtc, exynos_plane->zpos); + exynos_crtc->ops->update_plane(exynos_crtc, exynos_plane); } static void exynos_plane_atomic_disable(struct drm_plane *plane, @@ -194,7 +194,7 @@ static void exynos_plane_atomic_disable(struct drm_plane *plane, if (exynos_crtc->ops->disable_plane) exynos_crtc->ops->disable_plane(exynos_crtc, - exynos_plane->zpos); + exynos_plane); } static const struct drm_plane_helper_funcs plane_helper_funcs = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 59d85ef04650..ade59eeb8554 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -118,19 +118,14 @@ static void vidi_disable_vblank(struct exynos_drm_crtc *crtc) ctx->vblank_on = false; } -static void vidi_update_plane(struct exynos_drm_crtc *crtc, unsigned int win) +static void vidi_update_plane(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) { struct vidi_context *ctx = crtc->ctx; - struct exynos_drm_plane *plane; if (ctx->suspended) return; - if (win < 0 || win >= WINDOWS_NR) - return; - - plane = &ctx->planes[win]; - DRM_DEBUG_KMS("dma_addr = %pad\n", plane->dma_addr); if (ctx->vblank_on) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 72bdded845f4..9275d3af385f 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -927,28 +927,30 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc) mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); } -static void mixer_update_plane(struct exynos_drm_crtc *crtc, unsigned int win) +static void mixer_update_plane(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) { struct mixer_context *mixer_ctx = crtc->ctx; - DRM_DEBUG_KMS("win: %d\n", win); + DRM_DEBUG_KMS("win: %d\n", plane->zpos); if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) return; - if (win > 1 && mixer_ctx->vp_enabled) - vp_video_buffer(mixer_ctx, win); + if (plane->zpos > 1 && mixer_ctx->vp_enabled) + vp_video_buffer(mixer_ctx, plane->zpos); else - mixer_graph_buffer(mixer_ctx, win); + mixer_graph_buffer(mixer_ctx, plane->zpos); } -static void mixer_disable_plane(struct exynos_drm_crtc *crtc, unsigned int win) +static void mixer_disable_plane(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) { struct mixer_context *mixer_ctx = crtc->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; unsigned long flags; - DRM_DEBUG_KMS("win: %d\n", win); + DRM_DEBUG_KMS("win: %d\n", plane->zpos); if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) return; @@ -956,7 +958,7 @@ static void mixer_disable_plane(struct exynos_drm_crtc *crtc, unsigned int win) spin_lock_irqsave(&res->reg_slock, flags); mixer_vsync_set_update(mixer_ctx, false); - mixer_cfg_layer(mixer_ctx, win, false); + mixer_cfg_layer(mixer_ctx, plane->zpos, false); mixer_vsync_set_update(mixer_ctx, true); spin_unlock_irqrestore(&res->reg_slock, flags); @@ -1053,7 +1055,7 @@ static void mixer_disable(struct exynos_drm_crtc *crtc) mixer_regs_dump(ctx); for (i = 0; i < MIXER_WIN_NR; i++) - mixer_disable_plane(crtc, i); + mixer_disable_plane(crtc, &ctx->planes[i]); clear_bit(MXR_BIT_POWERED, &ctx->flags); From 2eeb2e5e6634dbb97bdda81f65f70e4b037028d5 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 3 Aug 2015 14:40:44 +0900 Subject: [PATCH 27/53] drm/exynos: use drm atomic state directly For some fields the use of struct exynos_drm_plane filled with data from the plane state just creates a source of duplicated information and overhead. Here we change the crtc drivers to access the plane state directly simplifying the code by not relying on a exynos internal struct. Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 21 +++--- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 23 ++++--- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 29 +++++---- drivers/gpu/drm/exynos/exynos_drm_plane.c | 12 ---- drivers/gpu/drm/exynos/exynos_mixer.c | 65 ++++++++++--------- 5 files changed, 75 insertions(+), 75 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index a4ea09665b83..2489e7a0a3d2 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -152,15 +152,15 @@ static void decon_commit(struct exynos_drm_crtc *crtc) #define OFFSIZE(x) (((x) & 0x3fff) << 14) #define PAGEWIDTH(x) ((x) & 0x3fff) -static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) +static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, + struct drm_framebuffer *fb) { - struct exynos_drm_plane *plane = &ctx->planes[win]; unsigned long val; val = readl(ctx->addr + DECON_WINCONx(win)); val &= ~WINCONx_BPPMODE_MASK; - switch (plane->pixel_format) { + switch (fb->pixel_format) { case DRM_FORMAT_XRGB1555: val |= WINCONx_BPPMODE_16BPP_I1555; val |= WINCONx_HAWSWP_F; @@ -186,7 +186,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) return; } - DRM_DEBUG_KMS("bpp = %u\n", plane->bpp); + DRM_DEBUG_KMS("bpp = %u\n", fb->bits_per_pixel); /* * In case of exynos, setting dma-burst to 16Word causes permanent @@ -196,7 +196,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) * movement causes unstable DMA which results into iommu crash/tear. */ - if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) { + if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) { val &= ~WINCONx_BURSTLEN_MASK; val |= WINCONx_BURSTLEN_8WORD; } @@ -223,7 +223,10 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { struct decon_context *ctx = crtc->ctx; + struct drm_plane_state *state = plane->base.state; unsigned int win = plane->zpos; + unsigned int bpp = state->fb->bits_per_pixel >> 3; + unsigned int pitch = state->fb->pitches[0]; u32 val; if (ctx->suspended) @@ -248,14 +251,14 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win)); - val = plane->dma_addr[0] + plane->pitch * plane->crtc_height; + val = plane->dma_addr[0] + pitch * plane->crtc_height; writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); - val = OFFSIZE(plane->pitch - plane->crtc_width * (plane->bpp >> 3)) - | PAGEWIDTH(plane->crtc_width * (plane->bpp >> 3)); + val = OFFSIZE(pitch - plane->crtc_width * bpp) + | PAGEWIDTH(plane->crtc_width * bpp); writel(val, ctx->addr + DECON_VIDW0xADD2(win)); - decon_win_set_pixfmt(ctx, win); + decon_win_set_pixfmt(ctx, win, state->fb); /* window enable */ val = readl(ctx->addr + DECON_WINCONx(win)); diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 0bb393867da4..9c56d116311d 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -272,16 +272,16 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc) } } -static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) +static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, + struct drm_framebuffer *fb) { - struct exynos_drm_plane *plane = &ctx->planes[win]; unsigned long val; int padding; val = readl(ctx->regs + WINCON(win)); val &= ~WINCONx_BPPMODE_MASK; - switch (plane->pixel_format) { + switch (fb->pixel_format) { case DRM_FORMAT_RGB565: val |= WINCONx_BPPMODE_16BPP_565; val |= WINCONx_BURSTLEN_16WORD; @@ -330,7 +330,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) break; } - DRM_DEBUG_KMS("bpp = %d\n", plane->bpp); + DRM_DEBUG_KMS("bpp = %d\n", fb->bits_per_pixel); /* * In case of exynos, setting dma-burst to 16Word causes permanent @@ -340,8 +340,8 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) * movement causes unstable DMA which results into iommu crash/tear. */ - padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width; - if (plane->fb_width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) { + padding = (fb->pitches[0] / (fb->bits_per_pixel >> 3)) - fb->width; + if (fb->width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) { val &= ~WINCONx_BURSTLEN_MASK; val |= WINCONx_BURSTLEN_8WORD; } @@ -388,11 +388,14 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, { struct decon_context *ctx = crtc->ctx; struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; + struct drm_plane_state *state = plane->base.state; int padding; unsigned long val, alpha; unsigned int last_x; unsigned int last_y; unsigned int win = plane->zpos; + unsigned int bpp = state->fb->bits_per_pixel >> 3; + unsigned int pitch = state->fb->pitches[0]; if (ctx->suspended) return; @@ -414,11 +417,11 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, val = (unsigned long)plane->dma_addr[0]; writel(val, ctx->regs + VIDW_BUF_START(win)); - padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width; + padding = (pitch / bpp) - state->fb->width; /* buffer size */ - writel(plane->fb_width + padding, ctx->regs + VIDW_WHOLE_X(win)); - writel(plane->fb_height, ctx->regs + VIDW_WHOLE_Y(win)); + writel(state->fb->width + padding, ctx->regs + VIDW_WHOLE_X(win)); + writel(state->fb->height, ctx->regs + VIDW_WHOLE_Y(win)); /* offset from the start of the buffer to read */ writel(plane->src_x, ctx->regs + VIDW_OFFSET_X(win)); @@ -469,7 +472,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, writel(alpha, ctx->regs + VIDOSD_D(win)); - decon_win_set_pixfmt(ctx, win); + decon_win_set_pixfmt(ctx, win, state->fb); /* hardware window 0 doesn't support color key. */ if (win != 0) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 2527997c4f24..5491715ec558 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -479,9 +479,9 @@ static void fimd_commit(struct exynos_drm_crtc *crtc) } -static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) +static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win, + struct drm_framebuffer *fb) { - struct exynos_drm_plane *plane = &ctx->planes[win]; unsigned long val; val = WINCONx_ENWIN; @@ -491,11 +491,11 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) * So the request format is ARGB8888 then change it to XRGB8888. */ if (ctx->driver_data->has_limited_fmt && !win) { - if (plane->pixel_format == DRM_FORMAT_ARGB8888) - plane->pixel_format = DRM_FORMAT_XRGB8888; + if (fb->pixel_format == DRM_FORMAT_ARGB8888) + fb->pixel_format = DRM_FORMAT_XRGB8888; } - switch (plane->pixel_format) { + switch (fb->pixel_format) { case DRM_FORMAT_C8: val |= WINCON0_BPPMODE_8BPP_PALETTE; val |= WINCONx_BURSTLEN_8WORD; @@ -531,7 +531,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) break; } - DRM_DEBUG_KMS("bpp = %d\n", plane->bpp); + DRM_DEBUG_KMS("bpp = %d\n", fb->bits_per_pixel); /* * In case of exynos, setting dma-burst to 16Word causes permanent @@ -541,7 +541,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) * movement causes unstable DMA which results into iommu crash/tear. */ - if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) { + if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) { val &= ~WINCONx_BURSTLEN_MASK; val |= WINCONx_BURSTLEN_4WORD; } @@ -611,10 +611,13 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { struct fimd_context *ctx = crtc->ctx; + struct drm_plane_state *state = plane->base.state; dma_addr_t dma_addr; unsigned long val, size, offset; unsigned int last_x, last_y, buf_offsize, line_size; unsigned int win = plane->zpos; + unsigned int bpp = state->fb->bits_per_pixel >> 3; + unsigned int pitch = state->fb->pitches[0]; if (ctx->suspended) return; @@ -633,8 +636,8 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, fimd_shadow_protect_win(ctx, win, true); - offset = plane->src_x * (plane->bpp >> 3); - offset += plane->src_y * plane->pitch; + offset = plane->src_x * bpp; + offset += plane->src_y * pitch; /* buffer start address */ dma_addr = plane->dma_addr[0] + offset; @@ -642,7 +645,7 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, writel(val, ctx->regs + VIDWx_BUF_START(win, 0)); /* buffer end address */ - size = plane->pitch * plane->crtc_height; + size = pitch * plane->crtc_height; val = (unsigned long)(dma_addr + size); writel(val, ctx->regs + VIDWx_BUF_END(win, 0)); @@ -652,8 +655,8 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, plane->crtc_width, plane->crtc_height); /* buffer size */ - buf_offsize = plane->pitch - (plane->crtc_width * (plane->bpp >> 3)); - line_size = plane->crtc_width * (plane->bpp >> 3); + buf_offsize = pitch - (plane->crtc_width * bpp); + line_size = plane->crtc_width * bpp; val = VIDW_BUF_SIZE_OFFSET(buf_offsize) | VIDW_BUF_SIZE_PAGEWIDTH(line_size) | VIDW_BUF_SIZE_OFFSET_E(buf_offsize) | @@ -693,7 +696,7 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val); } - fimd_win_set_pixfmt(ctx, win); + fimd_win_set_pixfmt(ctx, win, state->fb); /* hardware window 0 doesn't support color key. */ if (win != 0) diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index b5aa5b75d82b..960279777b05 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -99,24 +99,12 @@ static void exynos_plane_mode_set(struct drm_plane *plane, exynos_plane->src_y = src_y; exynos_plane->src_width = (actual_w * exynos_plane->h_ratio) >> 16; exynos_plane->src_height = (actual_h * exynos_plane->v_ratio) >> 16; - exynos_plane->fb_width = fb->width; - exynos_plane->fb_height = fb->height; - exynos_plane->bpp = fb->bits_per_pixel; - exynos_plane->pitch = fb->pitches[0]; - exynos_plane->pixel_format = fb->pixel_format; /* set plane range to be displayed. */ exynos_plane->crtc_x = crtc_x; exynos_plane->crtc_y = crtc_y; exynos_plane->crtc_width = actual_w; exynos_plane->crtc_height = actual_h; - - /* set drm mode data. */ - exynos_plane->mode_width = mode->hdisplay; - exynos_plane->mode_height = mode->vdisplay; - exynos_plane->refresh = mode->vrefresh; - exynos_plane->scan_flag = mode->flags; - DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)", exynos_plane->crtc_x, exynos_plane->crtc_y, exynos_plane->crtc_width, exynos_plane->crtc_height); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 9275d3af385f..076a97eebad9 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -383,19 +383,20 @@ static void mixer_stop(struct mixer_context *ctx) usleep_range(10000, 12000); } -static void vp_video_buffer(struct mixer_context *ctx, unsigned int win) +static void vp_video_buffer(struct mixer_context *ctx, + struct exynos_drm_plane *plane) { struct mixer_resources *res = &ctx->mixer_res; + struct drm_plane_state *state = plane->base.state; + struct drm_framebuffer *fb = state->fb; + struct drm_display_mode *mode = &state->crtc->mode; unsigned long flags; - struct exynos_drm_plane *plane; dma_addr_t luma_addr[2], chroma_addr[2]; bool tiled_mode = false; bool crcb_mode = false; u32 val; - plane = &ctx->planes[win]; - - switch (plane->pixel_format) { + switch (fb->pixel_format) { case DRM_FORMAT_NV12: crcb_mode = false; break; @@ -404,21 +405,21 @@ static void vp_video_buffer(struct mixer_context *ctx, unsigned int win) break; default: DRM_ERROR("pixel format for vp is wrong [%d].\n", - plane->pixel_format); + fb->pixel_format); return; } luma_addr[0] = plane->dma_addr[0]; chroma_addr[0] = plane->dma_addr[1]; - if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) { + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { ctx->interlace = true; if (tiled_mode) { luma_addr[1] = luma_addr[0] + 0x40; chroma_addr[1] = chroma_addr[0] + 0x40; } else { - luma_addr[1] = luma_addr[0] + plane->pitch; - chroma_addr[1] = chroma_addr[0] + plane->pitch; + luma_addr[1] = luma_addr[0] + fb->pitches[0]; + chroma_addr[1] = chroma_addr[0] + fb->pitches[0]; } } else { ctx->interlace = false; @@ -439,11 +440,11 @@ static void vp_video_buffer(struct mixer_context *ctx, unsigned int win) vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK); /* setting size of input image */ - vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(plane->pitch) | - VP_IMG_VSIZE(plane->fb_height)); + vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) | + VP_IMG_VSIZE(fb->height)); /* chroma height has to reduced by 2 to avoid chroma distorions */ - vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(plane->pitch) | - VP_IMG_VSIZE(plane->fb_height / 2)); + vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) | + VP_IMG_VSIZE(fb->height / 2)); vp_reg_write(res, VP_SRC_WIDTH, plane->src_width); vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height); @@ -472,9 +473,9 @@ static void vp_video_buffer(struct mixer_context *ctx, unsigned int win) vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]); vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]); - mixer_cfg_scan(ctx, plane->mode_height); - mixer_cfg_rgb_fmt(ctx, plane->mode_height); - mixer_cfg_layer(ctx, win, true); + mixer_cfg_scan(ctx, mode->vdisplay); + mixer_cfg_rgb_fmt(ctx, mode->vdisplay); + mixer_cfg_layer(ctx, plane->zpos, true); mixer_run(ctx); mixer_vsync_set_update(ctx, true); @@ -515,20 +516,22 @@ static int mixer_setup_scale(const struct exynos_drm_plane *plane, return -ENOTSUPP; } -static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win) +static void mixer_graph_buffer(struct mixer_context *ctx, + struct exynos_drm_plane *plane) { struct mixer_resources *res = &ctx->mixer_res; + struct drm_plane_state *state = plane->base.state; + struct drm_framebuffer *fb = state->fb; + struct drm_display_mode *mode = &state->crtc->mode; unsigned long flags; - struct exynos_drm_plane *plane; + unsigned int win = plane->zpos; unsigned int x_ratio = 0, y_ratio = 0; unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset; dma_addr_t dma_addr; unsigned int fmt; u32 val; - plane = &ctx->planes[win]; - - switch (plane->pixel_format) { + switch (fb->pixel_format) { case DRM_FORMAT_XRGB4444: fmt = MXR_FORMAT_ARGB4444; break; @@ -560,12 +563,12 @@ static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win) /* converting dma address base and source offset */ dma_addr = plane->dma_addr[0] - + (plane->src_x * plane->bpp >> 3) - + (plane->src_y * plane->pitch); + + (plane->src_x * fb->bits_per_pixel >> 3) + + (plane->src_y * fb->pitches[0]); src_x_offset = 0; src_y_offset = 0; - if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) + if (mode->flags & DRM_MODE_FLAG_INTERLACE) ctx->interlace = true; else ctx->interlace = false; @@ -579,13 +582,13 @@ static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win) /* setup geometry */ mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), - plane->pitch / (plane->bpp >> 3)); + fb->pitches[0] / (fb->bits_per_pixel >> 3)); /* setup display size */ if (ctx->mxr_ver == MXR_VER_128_0_0_184 && win == MIXER_DEFAULT_WIN) { - val = MXR_MXR_RES_HEIGHT(plane->mode_height); - val |= MXR_MXR_RES_WIDTH(plane->mode_width); + val = MXR_MXR_RES_HEIGHT(mode->vdisplay); + val |= MXR_MXR_RES_WIDTH(mode->hdisplay); mixer_reg_write(res, MXR_RESOLUTION, val); } @@ -608,8 +611,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win) /* set buffer address to mixer */ mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr); - mixer_cfg_scan(ctx, plane->mode_height); - mixer_cfg_rgb_fmt(ctx, plane->mode_height); + mixer_cfg_scan(ctx, mode->vdisplay); + mixer_cfg_rgb_fmt(ctx, mode->vdisplay); mixer_cfg_layer(ctx, win, true); /* layer update mandatory for mixer 16.0.33.0 */ @@ -938,9 +941,9 @@ static void mixer_update_plane(struct exynos_drm_crtc *crtc, return; if (plane->zpos > 1 && mixer_ctx->vp_enabled) - vp_video_buffer(mixer_ctx, plane->zpos); + vp_video_buffer(mixer_ctx, plane); else - mixer_graph_buffer(mixer_ctx, plane->zpos); + mixer_graph_buffer(mixer_ctx, plane); } static void mixer_disable_plane(struct exynos_drm_crtc *crtc, From a1bcc9da90ab44d29c38fc6e4a8dba633e97f3f3 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 16 Jul 2015 12:23:37 -0300 Subject: [PATCH 28/53] drm/exynos: remove unused fields from struct exynos_drm_plane Now after the move to use drm_plane_state directly struct drm_plane_state has many unused fields, along with others that weren't used before the plane state change. Thus remove them all. Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 18d04d0e7364..26b78483e9ae 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -46,21 +46,12 @@ enum exynos_drm_output_type { * - the unit is screen coordinates. * @src_width: width of a partial image to be displayed from framebuffer. * @src_height: height of a partial image to be displayed from framebuffer. - * @fb_width: width of a framebuffer. - * @fb_height: height of a framebuffer. * @crtc_x: offset x on hardware screen. * @crtc_y: offset y on hardware screen. * @crtc_width: window width to be displayed (hardware screen). * @crtc_height: window height to be displayed (hardware screen). - * @mode_width: width of screen mode. - * @mode_height: height of screen mode. * @h_ratio: horizontal scaling ratio, 16.16 fixed point * @v_ratio: vertical scaling ratio, 16.16 fixed point - * @refresh: refresh rate. - * @scan_flag: interlace or progressive way. - * (it could be DRM_MODE_FLAG_*) - * @bpp: pixel size.(in bit) - * @pixel_format: fourcc pixel format of this overlay * @dma_addr: array of bus(accessed by dma) address to the memory region * allocated for a overlay. * @zpos: order of overlay layer(z position). @@ -75,21 +66,12 @@ struct exynos_drm_plane { unsigned int src_y; unsigned int src_width; unsigned int src_height; - unsigned int fb_width; - unsigned int fb_height; unsigned int crtc_x; unsigned int crtc_y; unsigned int crtc_width; unsigned int crtc_height; - unsigned int mode_width; - unsigned int mode_height; unsigned int h_ratio; unsigned int v_ratio; - unsigned int refresh; - unsigned int scan_flag; - unsigned int bpp; - unsigned int pitch; - uint32_t pixel_format; dma_addr_t dma_addr[MAX_FB_BUFFER]; unsigned int zpos; }; From d88d2463fecb13c67d8eec78c4b61671900deb94 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 16 Jul 2015 12:23:38 -0300 Subject: [PATCH 29/53] drm/exynos: unify exynos_drm_plane names with drm core Rename crtc_{widht,height} to crtc_{w,h} and src_{width,height} to src_{w,h} to make it similar to the atomic state names. Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 10 ++++----- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 14 ++++++------ drivers/gpu/drm/exynos/exynos_drm_drv.h | 16 +++++++------- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 14 ++++++------ drivers/gpu/drm/exynos/exynos_drm_plane.c | 11 +++++----- drivers/gpu/drm/exynos/exynos_mixer.c | 22 +++++++++---------- 6 files changed, 44 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 2489e7a0a3d2..484e312e0a22 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -237,8 +237,8 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y); writel(val, ctx->addr + DECON_VIDOSDxA(win)); - val = COORDINATE_X(plane->crtc_x + plane->crtc_width - 1) | - COORDINATE_Y(plane->crtc_y + plane->crtc_height - 1); + val = COORDINATE_X(plane->crtc_x + plane->crtc_w - 1) | + COORDINATE_Y(plane->crtc_y + plane->crtc_h - 1); writel(val, ctx->addr + DECON_VIDOSDxB(win)); val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | @@ -251,11 +251,11 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win)); - val = plane->dma_addr[0] + pitch * plane->crtc_height; + val = plane->dma_addr[0] + pitch * plane->crtc_h; writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); - val = OFFSIZE(pitch - plane->crtc_width * bpp) - | PAGEWIDTH(plane->crtc_width * bpp); + val = OFFSIZE(pitch - plane->crtc_w * bpp) + | PAGEWIDTH(plane->crtc_w * bpp); writel(val, ctx->addr + DECON_VIDW0xADD2(win)); decon_win_set_pixfmt(ctx, win, state->fb); diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 9c56d116311d..cfd0b5eeb498 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -430,25 +430,25 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, DRM_DEBUG_KMS("start addr = 0x%lx\n", (unsigned long)val); DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", - plane->crtc_width, plane->crtc_height); + plane->crtc_w, plane->crtc_h); /* * OSD position. * In case the window layout goes of LCD layout, DECON fails. */ - if ((plane->crtc_x + plane->crtc_width) > mode->hdisplay) - plane->crtc_x = mode->hdisplay - plane->crtc_width; - if ((plane->crtc_y + plane->crtc_height) > mode->vdisplay) - plane->crtc_y = mode->vdisplay - plane->crtc_height; + if ((plane->crtc_x + plane->crtc_w) > mode->hdisplay) + plane->crtc_x = mode->hdisplay - plane->crtc_w; + if ((plane->crtc_y + plane->crtc_h) > mode->vdisplay) + plane->crtc_y = mode->vdisplay - plane->crtc_h; val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) | VIDOSDxA_TOPLEFT_Y(plane->crtc_y); writel(val, ctx->regs + VIDOSD_A(win)); - last_x = plane->crtc_x + plane->crtc_width; + last_x = plane->crtc_x + plane->crtc_w; if (last_x) last_x--; - last_y = plane->crtc_y + plane->crtc_height; + last_y = plane->crtc_y + plane->crtc_h; if (last_y) last_y--; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 26b78483e9ae..9f23db44fb42 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -44,12 +44,12 @@ enum exynos_drm_output_type { * - the unit is screen coordinates. * @src_y: offset y on a framebuffer to be displayed. * - the unit is screen coordinates. - * @src_width: width of a partial image to be displayed from framebuffer. - * @src_height: height of a partial image to be displayed from framebuffer. + * @src_w: width of a partial image to be displayed from framebuffer. + * @src_h: height of a partial image to be displayed from framebuffer. * @crtc_x: offset x on hardware screen. * @crtc_y: offset y on hardware screen. - * @crtc_width: window width to be displayed (hardware screen). - * @crtc_height: window height to be displayed (hardware screen). + * @crtc_w: window width to be displayed (hardware screen). + * @crtc_h: window height to be displayed (hardware screen). * @h_ratio: horizontal scaling ratio, 16.16 fixed point * @v_ratio: vertical scaling ratio, 16.16 fixed point * @dma_addr: array of bus(accessed by dma) address to the memory region @@ -64,12 +64,12 @@ struct exynos_drm_plane { struct drm_plane base; unsigned int src_x; unsigned int src_y; - unsigned int src_width; - unsigned int src_height; + unsigned int src_w; + unsigned int src_h; unsigned int crtc_x; unsigned int crtc_y; - unsigned int crtc_width; - unsigned int crtc_height; + unsigned int crtc_w; + unsigned int crtc_h; unsigned int h_ratio; unsigned int v_ratio; dma_addr_t dma_addr[MAX_FB_BUFFER]; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 5491715ec558..88dea9d6dacf 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -645,18 +645,18 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, writel(val, ctx->regs + VIDWx_BUF_START(win, 0)); /* buffer end address */ - size = pitch * plane->crtc_height; + size = pitch * plane->crtc_h; val = (unsigned long)(dma_addr + size); writel(val, ctx->regs + VIDWx_BUF_END(win, 0)); DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n", (unsigned long)dma_addr, val, size); DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", - plane->crtc_width, plane->crtc_height); + plane->crtc_w, plane->crtc_h); /* buffer size */ - buf_offsize = pitch - (plane->crtc_width * bpp); - line_size = plane->crtc_width * bpp; + buf_offsize = pitch - (plane->crtc_w * bpp); + line_size = plane->crtc_w * bpp; val = VIDW_BUF_SIZE_OFFSET(buf_offsize) | VIDW_BUF_SIZE_PAGEWIDTH(line_size) | VIDW_BUF_SIZE_OFFSET_E(buf_offsize) | @@ -670,10 +670,10 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, VIDOSDxA_TOPLEFT_Y_E(plane->crtc_y); writel(val, ctx->regs + VIDOSD_A(win)); - last_x = plane->crtc_x + plane->crtc_width; + last_x = plane->crtc_x + plane->crtc_w; if (last_x) last_x--; - last_y = plane->crtc_y + plane->crtc_height; + last_y = plane->crtc_y + plane->crtc_h; if (last_y) last_y--; @@ -690,7 +690,7 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, u32 offset = VIDOSD_D(win); if (win == 0) offset = VIDOSD_C(win); - val = plane->crtc_width * plane->crtc_height; + val = plane->crtc_w * plane->crtc_h; writel(val, ctx->regs + offset); DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val); diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 960279777b05..bebc9572d404 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -97,17 +97,18 @@ static void exynos_plane_mode_set(struct drm_plane *plane, /* set drm framebuffer data. */ exynos_plane->src_x = src_x; exynos_plane->src_y = src_y; - exynos_plane->src_width = (actual_w * exynos_plane->h_ratio) >> 16; - exynos_plane->src_height = (actual_h * exynos_plane->v_ratio) >> 16; + exynos_plane->src_w = (actual_w * exynos_plane->h_ratio) >> 16; + exynos_plane->src_h = (actual_h * exynos_plane->v_ratio) >> 16; /* set plane range to be displayed. */ exynos_plane->crtc_x = crtc_x; exynos_plane->crtc_y = crtc_y; - exynos_plane->crtc_width = actual_w; - exynos_plane->crtc_height = actual_h; + exynos_plane->crtc_w = actual_w; + exynos_plane->crtc_h = actual_h; + DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)", exynos_plane->crtc_x, exynos_plane->crtc_y, - exynos_plane->crtc_width, exynos_plane->crtc_height); + exynos_plane->crtc_w, exynos_plane->crtc_h); plane->crtc = crtc; } diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 076a97eebad9..e68340c77676 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -446,19 +446,19 @@ static void vp_video_buffer(struct mixer_context *ctx, vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) | VP_IMG_VSIZE(fb->height / 2)); - vp_reg_write(res, VP_SRC_WIDTH, plane->src_width); - vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height); + vp_reg_write(res, VP_SRC_WIDTH, plane->src_w); + vp_reg_write(res, VP_SRC_HEIGHT, plane->src_h); vp_reg_write(res, VP_SRC_H_POSITION, VP_SRC_H_POSITION_VAL(plane->src_x)); vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y); - vp_reg_write(res, VP_DST_WIDTH, plane->crtc_width); + vp_reg_write(res, VP_DST_WIDTH, plane->crtc_w); vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x); if (ctx->interlace) { - vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2); + vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_h / 2); vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2); } else { - vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height); + vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_h); vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y); } @@ -495,15 +495,15 @@ static void mixer_layer_update(struct mixer_context *ctx) static int mixer_setup_scale(const struct exynos_drm_plane *plane, unsigned int *x_ratio, unsigned int *y_ratio) { - if (plane->crtc_width != plane->src_width) { - if (plane->crtc_width == 2 * plane->src_width) + if (plane->crtc_w != plane->src_w) { + if (plane->crtc_w == 2 * plane->src_w) *x_ratio = 1; else goto fail; } - if (plane->crtc_height != plane->src_height) { - if (plane->crtc_height == 2 * plane->src_height) + if (plane->crtc_h != plane->src_h) { + if (plane->crtc_h == 2 * plane->src_h) *y_ratio = 1; else goto fail; @@ -592,8 +592,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, mixer_reg_write(res, MXR_RESOLUTION, val); } - val = MXR_GRP_WH_WIDTH(plane->src_width); - val |= MXR_GRP_WH_HEIGHT(plane->src_height); + val = MXR_GRP_WH_WIDTH(plane->src_w); + val |= MXR_GRP_WH_HEIGHT(plane->src_h); val |= MXR_GRP_WH_H_SCALE(x_ratio); val |= MXR_GRP_WH_V_SCALE(y_ratio); mixer_reg_write(res, MXR_GRAPHIC_WH(win), val); From 08dd20099f3ce55a2ded0045b5a087aefea38cd8 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 16 Jul 2015 12:23:39 -0300 Subject: [PATCH 30/53] drm/exynos: return return value of exynos_crtc->enable_vblank Instead of blindly ignore the return value of enable_vblank return it to the upper DRM layer for error handling. Suggested-by: Joonyoung Shim Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index fb213502082d..b13c9492291b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -177,7 +177,7 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) return -EPERM; if (exynos_crtc->ops->enable_vblank) - exynos_crtc->ops->enable_vblank(exynos_crtc); + return exynos_crtc->ops->enable_vblank(exynos_crtc); return 0; } From b6595dc7e1ccc0964862a5bd436a8f004b36c02f Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 10 Aug 2015 21:37:04 -0300 Subject: [PATCH 31/53] drm/exynos: split display's .dpms() into .enable() and .disable() The DRM Core doesn't have a dpms() operation anymore, everything now is enable() or disable(). Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_dp_core.c | 36 ++++-------- drivers/gpu/drm/exynos/exynos_drm_dpi.c | 36 +++--------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 6 +- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 44 +++++--------- drivers/gpu/drm/exynos/exynos_drm_encoder.c | 8 +-- drivers/gpu/drm/exynos/exynos_hdmi.c | 65 ++++++++------------- 6 files changed, 65 insertions(+), 130 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 172b8002a2c8..ef249520e5bb 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1066,8 +1066,9 @@ static void exynos_dp_phy_exit(struct exynos_dp_device *dp) phy_power_off(dp->phy); } -static void exynos_dp_poweron(struct exynos_dp_device *dp) +static void exynos_dp_enable(struct exynos_drm_display *display) { + struct exynos_dp_device *dp = display_to_dp(display); struct exynos_drm_crtc *crtc = dp_to_crtc(dp); if (dp->dpms_mode == DRM_MODE_DPMS_ON) @@ -1088,10 +1089,13 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp) exynos_dp_init_dp(dp); enable_irq(dp->irq); exynos_dp_commit(&dp->display); + + dp->dpms_mode = DRM_MODE_DPMS_ON; } -static void exynos_dp_poweroff(struct exynos_dp_device *dp) +static void exynos_dp_disable(struct exynos_drm_display *display) { + struct exynos_dp_device *dp = display_to_dp(display); struct exynos_drm_crtc *crtc = dp_to_crtc(dp); if (dp->dpms_mode != DRM_MODE_DPMS_ON) @@ -1116,30 +1120,14 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp) if (drm_panel_unprepare(dp->panel)) DRM_ERROR("failed to turnoff the panel\n"); } -} - -static void exynos_dp_dpms(struct exynos_drm_display *display, int mode) -{ - struct exynos_dp_device *dp = display_to_dp(display); - switch (mode) { - case DRM_MODE_DPMS_ON: - exynos_dp_poweron(dp); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - exynos_dp_poweroff(dp); - break; - default: - break; - } - dp->dpms_mode = mode; + dp->dpms_mode = DRM_MODE_DPMS_OFF; } static struct exynos_drm_display_ops exynos_dp_display_ops = { .create_connector = exynos_dp_create_connector, - .dpms = exynos_dp_dpms, + .enable = exynos_dp_enable, + .disable = exynos_dp_disable, .commit = exynos_dp_commit, }; @@ -1319,7 +1307,7 @@ static void exynos_dp_unbind(struct device *dev, struct device *master, { struct exynos_dp_device *dp = dev_get_drvdata(dev); - exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF); + exynos_dp_disable(&dp->display); } static const struct component_ops exynos_dp_ops = { @@ -1377,7 +1365,7 @@ static int exynos_dp_suspend(struct device *dev) { struct exynos_dp_device *dp = dev_get_drvdata(dev); - exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF); + exynos_dp_disable(&dp->display); return 0; } @@ -1385,7 +1373,7 @@ static int exynos_dp_resume(struct device *dev) { struct exynos_dp_device *dp = dev_get_drvdata(dev); - exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_ON); + exynos_dp_enable(&dp->display); return 0; } #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 7cb6595c1894..e0426707c911 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -32,7 +32,6 @@ struct exynos_dpi { struct drm_encoder *encoder; struct videomode *vm; - int dpms_mode; }; #define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector) @@ -133,46 +132,30 @@ static int exynos_dpi_create_connector(struct exynos_drm_display *display, return 0; } -static void exynos_dpi_poweron(struct exynos_dpi *ctx) +static void exynos_dpi_enable(struct exynos_drm_display *display) { + struct exynos_dpi *ctx = display_to_dpi(display); + if (ctx->panel) { drm_panel_prepare(ctx->panel); drm_panel_enable(ctx->panel); } } -static void exynos_dpi_poweroff(struct exynos_dpi *ctx) +static void exynos_dpi_disable(struct exynos_drm_display *display) { + struct exynos_dpi *ctx = display_to_dpi(display); + if (ctx->panel) { drm_panel_disable(ctx->panel); drm_panel_unprepare(ctx->panel); } } -static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode) -{ - struct exynos_dpi *ctx = display_to_dpi(display); - - switch (mode) { - case DRM_MODE_DPMS_ON: - if (ctx->dpms_mode != DRM_MODE_DPMS_ON) - exynos_dpi_poweron(ctx); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - if (ctx->dpms_mode == DRM_MODE_DPMS_ON) - exynos_dpi_poweroff(ctx); - break; - default: - break; - } - ctx->dpms_mode = mode; -} - static struct exynos_drm_display_ops exynos_dpi_display_ops = { .create_connector = exynos_dpi_create_connector, - .dpms = exynos_dpi_dpms + .enable = exynos_dpi_enable, + .disable = exynos_dpi_disable, }; /* of_* functions will be removed after merge of of_graph patches */ @@ -311,7 +294,6 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev) ctx->display.type = EXYNOS_DISPLAY_TYPE_LCD; ctx->display.ops = &exynos_dpi_display_ops; ctx->dev = dev; - ctx->dpms_mode = DRM_MODE_DPMS_OFF; ret = exynos_dpi_parse_dt(ctx); if (ret < 0) { @@ -332,7 +314,7 @@ int exynos_dpi_remove(struct exynos_drm_display *display) { struct exynos_dpi *ctx = display_to_dpi(display); - exynos_dpi_dpms(&ctx->display, DRM_MODE_DPMS_OFF); + exynos_dpi_disable(&ctx->display); if (ctx->panel) drm_panel_detach(ctx->panel); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 9f23db44fb42..5c55606a4095 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -86,7 +86,8 @@ struct exynos_drm_plane { * @mode_set: convert drm_display_mode to hw specific display mode and * would be called by encoder->mode_set(). * @check_mode: check if mode is valid or not. - * @dpms: display device on or off. + * @enable: display device on. + * @disable: display device off. * @commit: apply changes to hw */ struct exynos_drm_display; @@ -102,7 +103,8 @@ struct exynos_drm_display_ops { struct drm_display_mode *mode); int (*check_mode)(struct exynos_drm_display *display, struct drm_display_mode *mode); - void (*dpms)(struct exynos_drm_display *display, int mode); + void (*enable)(struct exynos_drm_display *display); + void (*disable)(struct exynos_drm_display *display); void (*commit)(struct exynos_drm_display *display); }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 0e58b36cb8c2..281b97d3465b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1518,16 +1518,17 @@ static void exynos_dsi_poweroff(struct exynos_dsi *dsi) dev_err(dsi->dev, "cannot disable regulators %d\n", ret); } -static int exynos_dsi_enable(struct exynos_dsi *dsi) +static void exynos_dsi_enable(struct exynos_drm_display *display) { + struct exynos_dsi *dsi = display_to_dsi(display); int ret; if (dsi->state & DSIM_STATE_ENABLED) - return 0; + return; ret = exynos_dsi_poweron(dsi); if (ret < 0) - return ret; + return; dsi->state |= DSIM_STATE_ENABLED; @@ -1535,7 +1536,7 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) if (ret < 0) { dsi->state &= ~DSIM_STATE_ENABLED; exynos_dsi_poweroff(dsi); - return ret; + return; } exynos_dsi_set_display_mode(dsi); @@ -1547,16 +1548,16 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) exynos_dsi_set_display_enable(dsi, false); drm_panel_unprepare(dsi->panel); exynos_dsi_poweroff(dsi); - return ret; + return; } dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; - - return 0; } -static void exynos_dsi_disable(struct exynos_dsi *dsi) +static void exynos_dsi_disable(struct exynos_drm_display *display) { + struct exynos_dsi *dsi = display_to_dsi(display); + if (!(dsi->state & DSIM_STATE_ENABLED)) return; @@ -1571,26 +1572,6 @@ static void exynos_dsi_disable(struct exynos_dsi *dsi) exynos_dsi_poweroff(dsi); } -static void exynos_dsi_dpms(struct exynos_drm_display *display, int mode) -{ - struct exynos_dsi *dsi = display_to_dsi(display); - - if (dsi->panel) { - switch (mode) { - case DRM_MODE_DPMS_ON: - exynos_dsi_enable(dsi); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - exynos_dsi_disable(dsi); - break; - default: - break; - } - } -} - static enum drm_connector_status exynos_dsi_detect(struct drm_connector *connector, bool force) { @@ -1604,7 +1585,7 @@ exynos_dsi_detect(struct drm_connector *connector, bool force) struct exynos_drm_display *display; display = platform_get_drvdata(to_platform_device(dsi->dev)); - exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF); + exynos_dsi_disable(display); drm_panel_detach(dsi->panel); dsi->panel = NULL; } @@ -1698,7 +1679,8 @@ static void exynos_dsi_mode_set(struct exynos_drm_display *display, static struct exynos_drm_display_ops exynos_dsi_display_ops = { .create_connector = exynos_dsi_create_connector, .mode_set = exynos_dsi_mode_set, - .dpms = exynos_dsi_dpms + .enable = exynos_dsi_enable, + .disable = exynos_dsi_disable, }; MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); @@ -1849,7 +1831,7 @@ static void exynos_dsi_unbind(struct device *dev, struct device *master, struct exynos_drm_display *display = dev_get_drvdata(dev); struct exynos_dsi *dsi = display_to_dsi(display); - exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF); + exynos_dsi_disable(display); mipi_dsi_host_unregister(&dsi->dsi_host); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 7b89fd520e45..0aa4a58c912c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -70,8 +70,8 @@ static void exynos_drm_encoder_enable(struct drm_encoder *encoder) struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); struct exynos_drm_display *display = exynos_encoder->display; - if (display->ops->dpms) - display->ops->dpms(display, DRM_MODE_DPMS_ON); + if (display->ops->enable) + display->ops->enable(display); if (display->ops->commit) display->ops->commit(display); @@ -82,8 +82,8 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder) struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); struct exynos_drm_display *display = exynos_encoder->display; - if (display->ops->dpms) - display->ops->dpms(display, DRM_MODE_DPMS_OFF); + if (display->ops->disable) + display->ops->disable(display); } static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 448f53449b99..9b9396a3214d 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1723,8 +1723,9 @@ static void hdmi_commit(struct exynos_drm_display *display) hdmi_conf_apply(hdata); } -static void hdmi_poweron(struct hdmi_context *hdata) +static void hdmi_enable(struct exynos_drm_display *display) { + struct hdmi_context *hdata = display_to_hdmi(display); struct hdmi_resources *res = &hdata->res; if (hdata->powered) @@ -1745,16 +1746,33 @@ static void hdmi_poweron(struct hdmi_context *hdata) clk_prepare_enable(res->sclk_hdmi); hdmiphy_poweron(hdata); - hdmi_commit(&hdata->display); + hdmi_commit(display); } -static void hdmi_poweroff(struct hdmi_context *hdata) +static void hdmi_disable(struct exynos_drm_display *display) { + struct hdmi_context *hdata = display_to_hdmi(display); struct hdmi_resources *res = &hdata->res; + struct drm_crtc *crtc = hdata->encoder->crtc; + const struct drm_crtc_helper_funcs *funcs = NULL; if (!hdata->powered) return; + /* + * The SFRs of VP and Mixer are updated by Vertical Sync of + * Timing generator which is a part of HDMI so the sequence + * to disable TV Subsystem should be as following, + * VP -> Mixer -> HDMI + * + * Below codes will try to disable Mixer and VP(if used) + * prior to disabling HDMI. + */ + if (crtc) + funcs = crtc->helper_private; + if (funcs && funcs->disable) + (*funcs->disable)(crtc); + /* HDMI System Disable */ hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN); @@ -1776,49 +1794,12 @@ static void hdmi_poweroff(struct hdmi_context *hdata) hdata->powered = false; } -static void hdmi_dpms(struct exynos_drm_display *display, int mode) -{ - struct hdmi_context *hdata = display_to_hdmi(display); - struct drm_encoder *encoder = hdata->encoder; - struct drm_crtc *crtc = encoder->crtc; - const struct drm_crtc_helper_funcs *funcs = NULL; - - DRM_DEBUG_KMS("mode %d\n", mode); - - switch (mode) { - case DRM_MODE_DPMS_ON: - hdmi_poweron(hdata); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - /* - * The SFRs of VP and Mixer are updated by Vertical Sync of - * Timing generator which is a part of HDMI so the sequence - * to disable TV Subsystem should be as following, - * VP -> Mixer -> HDMI - * - * Below codes will try to disable Mixer and VP(if used) - * prior to disabling HDMI. - */ - if (crtc) - funcs = crtc->helper_private; - if (funcs && funcs->disable) - (*funcs->disable)(crtc); - - hdmi_poweroff(hdata); - break; - default: - DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); - break; - } -} - static struct exynos_drm_display_ops hdmi_display_ops = { .create_connector = hdmi_create_connector, .mode_fixup = hdmi_mode_fixup, .mode_set = hdmi_mode_set, - .dpms = hdmi_dpms, + .enable = hdmi_enable, + .disable = hdmi_disable, .commit = hdmi_commit, }; From b6f3c36183470bbbee9da1c0a8cc892e69f88c4f Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 5 Aug 2015 20:24:13 -0300 Subject: [PATCH 32/53] drm/exynos: remove wrappers for phy_power_{on,off} phy_power_on() and phy_power_off() already checks for NULL pointer. This patch removes the wrappers exynos_dp_phy_init() and exynos_dp_phy_exit() since the only think they were doing was a check for NULL phy. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_dp_core.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index ef249520e5bb..173f3e05bda9 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1054,18 +1054,6 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display, return ret; } -static void exynos_dp_phy_init(struct exynos_dp_device *dp) -{ - if (dp->phy) - phy_power_on(dp->phy); -} - -static void exynos_dp_phy_exit(struct exynos_dp_device *dp) -{ - if (dp->phy) - phy_power_off(dp->phy); -} - static void exynos_dp_enable(struct exynos_drm_display *display) { struct exynos_dp_device *dp = display_to_dp(display); @@ -1085,7 +1073,7 @@ static void exynos_dp_enable(struct exynos_drm_display *display) crtc->ops->clock_enable(dp_to_crtc(dp), true); clk_prepare_enable(dp->clock); - exynos_dp_phy_init(dp); + phy_power_on(dp->phy); exynos_dp_init_dp(dp); enable_irq(dp->irq); exynos_dp_commit(&dp->display); @@ -1110,7 +1098,7 @@ static void exynos_dp_disable(struct exynos_drm_display *display) disable_irq(dp->irq); flush_work(&dp->hotplug_work); - exynos_dp_phy_exit(dp); + phy_power_off(dp->phy); clk_disable_unprepare(dp->clock); if (crtc->ops->clock_enable) @@ -1285,7 +1273,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug); - exynos_dp_phy_init(dp); + phy_power_on(dp->phy); exynos_dp_init_dp(dp); From a090f45ff0acae51aa0363a72e5c3b47332af9f9 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 5 Aug 2015 20:24:14 -0300 Subject: [PATCH 33/53] drm/exynos: remove unused .remove() and .check_mode() ops from display These two display_ops are not used anywhere, remove them. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 5c55606a4095..47ea400735c6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -81,11 +81,9 @@ struct exynos_drm_plane { * - this structure is common to analog tv, digital tv and lcd panel. * * @create_connector: initialize and register a new connector - * @remove: cleans up the display for removal * @mode_fixup: fix mode data comparing to hw specific display mode. * @mode_set: convert drm_display_mode to hw specific display mode and * would be called by encoder->mode_set(). - * @check_mode: check if mode is valid or not. * @enable: display device on. * @disable: display device off. * @commit: apply changes to hw @@ -94,15 +92,12 @@ struct exynos_drm_display; struct exynos_drm_display_ops { int (*create_connector)(struct exynos_drm_display *display, struct drm_encoder *encoder); - void (*remove)(struct exynos_drm_display *display); void (*mode_fixup)(struct exynos_drm_display *display, struct drm_connector *connector, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); void (*mode_set)(struct exynos_drm_display *display, struct drm_display_mode *mode); - int (*check_mode)(struct exynos_drm_display *display, - struct drm_display_mode *mode); void (*enable)(struct exynos_drm_display *display); void (*disable)(struct exynos_drm_display *display); void (*commit)(struct exynos_drm_display *display); From d1fa72d0a6e70057f6aa0d0f6187e4a49e261fa8 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 5 Aug 2015 20:24:15 -0300 Subject: [PATCH 34/53] drm/exynos: simplify calculation of possible CRTCs All CRTCs can only be LCD, HDMI or VIDI, so basically all CRTCs will be a possible CRTCs. This patch removes an extra function with switch that was only checking if the CRTC type was one of those three above. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_encoder.c | 29 ++++----------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 0aa4a58c912c..7ba3a2d17ed5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -105,36 +105,17 @@ static struct drm_encoder_funcs exynos_encoder_funcs = { .destroy = exynos_drm_encoder_destroy, }; -static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder) +void exynos_drm_encoder_setup(struct drm_device *dev) { - struct drm_encoder *clone; - struct drm_device *dev = encoder->dev; - struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); - struct exynos_drm_display *display = exynos_encoder->display; + struct drm_encoder *encoder; unsigned int clone_mask = 0; int cnt = 0; - list_for_each_entry(clone, &dev->mode_config.encoder_list, head) { - switch (display->type) { - case EXYNOS_DISPLAY_TYPE_LCD: - case EXYNOS_DISPLAY_TYPE_HDMI: - case EXYNOS_DISPLAY_TYPE_VIDI: - clone_mask |= (1 << (cnt++)); - break; - default: - continue; - } - } - - return clone_mask; -} - -void exynos_drm_encoder_setup(struct drm_device *dev) -{ - struct drm_encoder *encoder; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + clone_mask |= (1 << (cnt++)); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) - encoder->possible_clones = exynos_drm_encoder_clones(encoder); + encoder->possible_clones = clone_mask; } struct drm_encoder * From cf67cc9a29ac19c98bc4fa0e6d14b0c1f592d322 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 11 Aug 2015 17:38:06 +0900 Subject: [PATCH 35/53] drm/exynos: remove struct exynos_drm_display This struct was just representing encoder information, it was a member of struct exynos_drm_encoder, so any code trying to access encoder data would have to go through the encoder struct, get the display struct and then get the data it want. During this patchset we also realized that the only data exynos_drm_encoder needs to store is the drm_encoder parent and the exynos_drm_encoder_ops. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 17 ++--- drivers/gpu/drm/exynos/exynos_dp_core.c | 46 ++++++------- drivers/gpu/drm/exynos/exynos_dp_core.h | 3 +- drivers/gpu/drm/exynos/exynos_drm_core.c | 23 +++---- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_crtc.h | 2 +- drivers/gpu/drm/exynos/exynos_drm_dpi.c | 41 ++++++----- drivers/gpu/drm/exynos/exynos_drm_drv.h | 47 ++++++------- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 58 ++++++++-------- drivers/gpu/drm/exynos/exynos_drm_encoder.c | 75 ++++++--------------- drivers/gpu/drm/exynos/exynos_drm_encoder.h | 6 +- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 18 ++--- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 43 ++++-------- drivers/gpu/drm/exynos/exynos_hdmi.c | 48 +++++++------ 14 files changed, 177 insertions(+), 252 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index cfd0b5eeb498..1b89e947bec9 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -61,7 +61,7 @@ struct decon_context { atomic_t wait_vsync_event; struct exynos_drm_panel_info panel; - struct exynos_drm_display *display; + struct exynos_drm_encoder *encoder; }; static const struct of_device_id decon_driver_dt_match[] = { @@ -681,8 +681,9 @@ static int decon_bind(struct device *dev, struct device *master, void *data) return PTR_ERR(ctx->crtc); } - if (ctx->display) - exynos_drm_create_enc_conn(drm_dev, ctx->display); + if (ctx->encoder) + exynos_drm_create_enc_conn(drm_dev, ctx->encoder, + EXYNOS_DISPLAY_TYPE_LCD); return 0; @@ -695,8 +696,8 @@ static void decon_unbind(struct device *dev, struct device *master, decon_disable(ctx->crtc); - if (ctx->display) - exynos_dpi_remove(ctx->display); + if (ctx->encoder) + exynos_dpi_remove(ctx->encoder); decon_ctx_remove(ctx); } @@ -781,9 +782,9 @@ static int decon_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - ctx->display = exynos_dpi_probe(dev); - if (IS_ERR(ctx->display)) { - ret = PTR_ERR(ctx->display); + ctx->encoder = exynos_dpi_probe(dev); + if (IS_ERR(ctx->encoder)) { + ret = PTR_ERR(ctx->encoder); goto err_iounmap; } diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 173f3e05bda9..2118737ab462 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -38,13 +38,13 @@ static inline struct exynos_drm_crtc *dp_to_crtc(struct exynos_dp_device *dp) { - return to_exynos_crtc(dp->encoder->crtc); + return to_exynos_crtc(dp->encoder.base.crtc); } -static inline struct exynos_dp_device * -display_to_dp(struct exynos_drm_display *d) +static inline struct exynos_dp_device *encoder_to_dp( + struct exynos_drm_encoder *e) { - return container_of(d, struct exynos_dp_device, display); + return container_of(e, struct exynos_dp_device, encoder); } struct bridge_init { @@ -891,9 +891,9 @@ static void exynos_dp_hotplug(struct work_struct *work) drm_helper_hpd_irq_event(dp->drm_dev); } -static void exynos_dp_commit(struct exynos_drm_display *display) +static void exynos_dp_commit(struct exynos_drm_encoder *encoder) { - struct exynos_dp_device *dp = display_to_dp(display); + struct exynos_dp_device *dp = encoder_to_dp(encoder); int ret; /* Keep the panel disabled while we configure video */ @@ -994,7 +994,7 @@ static struct drm_encoder *exynos_dp_best_encoder( { struct exynos_dp_device *dp = ctx_from_connector(connector); - return dp->encoder; + return &dp->encoder.base; } static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = { @@ -1019,15 +1019,13 @@ static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp, return 0; } -static int exynos_dp_create_connector(struct exynos_drm_display *display, - struct drm_encoder *encoder) +static int exynos_dp_create_connector(struct exynos_drm_encoder *exynos_encoder) { - struct exynos_dp_device *dp = display_to_dp(display); + struct exynos_dp_device *dp = encoder_to_dp(exynos_encoder); + struct drm_encoder *encoder = &exynos_encoder->base; struct drm_connector *connector = &dp->connector; int ret; - dp->encoder = encoder; - /* Pre-empt DP connector creation if there's a bridge */ if (dp->bridge) { ret = exynos_drm_attach_lcd_bridge(dp, encoder); @@ -1054,9 +1052,9 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display, return ret; } -static void exynos_dp_enable(struct exynos_drm_display *display) +static void exynos_dp_enable(struct exynos_drm_encoder *encoder) { - struct exynos_dp_device *dp = display_to_dp(display); + struct exynos_dp_device *dp = encoder_to_dp(encoder); struct exynos_drm_crtc *crtc = dp_to_crtc(dp); if (dp->dpms_mode == DRM_MODE_DPMS_ON) @@ -1076,14 +1074,14 @@ static void exynos_dp_enable(struct exynos_drm_display *display) phy_power_on(dp->phy); exynos_dp_init_dp(dp); enable_irq(dp->irq); - exynos_dp_commit(&dp->display); + exynos_dp_commit(&dp->encoder); dp->dpms_mode = DRM_MODE_DPMS_ON; } -static void exynos_dp_disable(struct exynos_drm_display *display) +static void exynos_dp_disable(struct exynos_drm_encoder *encoder) { - struct exynos_dp_device *dp = display_to_dp(display); + struct exynos_dp_device *dp = encoder_to_dp(encoder); struct exynos_drm_crtc *crtc = dp_to_crtc(dp); if (dp->dpms_mode != DRM_MODE_DPMS_ON) @@ -1112,7 +1110,7 @@ static void exynos_dp_disable(struct exynos_drm_display *display) dp->dpms_mode = DRM_MODE_DPMS_OFF; } -static struct exynos_drm_display_ops exynos_dp_display_ops = { +static struct exynos_drm_encoder_ops exynos_dp_encoder_ops = { .create_connector = exynos_dp_create_connector, .enable = exynos_dp_enable, .disable = exynos_dp_disable, @@ -1287,7 +1285,8 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) dp->drm_dev = drm_dev; - return exynos_drm_create_enc_conn(drm_dev, &dp->display); + return exynos_drm_create_enc_conn(drm_dev, &dp->encoder, + EXYNOS_DISPLAY_TYPE_LCD); } static void exynos_dp_unbind(struct device *dev, struct device *master, @@ -1295,7 +1294,7 @@ static void exynos_dp_unbind(struct device *dev, struct device *master, { struct exynos_dp_device *dp = dev_get_drvdata(dev); - exynos_dp_disable(&dp->display); + exynos_dp_disable(&dp->encoder); } static const struct component_ops exynos_dp_ops = { @@ -1314,8 +1313,7 @@ static int exynos_dp_probe(struct platform_device *pdev) if (!dp) return -ENOMEM; - dp->display.type = EXYNOS_DISPLAY_TYPE_LCD; - dp->display.ops = &exynos_dp_display_ops; + dp->encoder.ops = &exynos_dp_encoder_ops; platform_set_drvdata(pdev, dp); panel_node = of_parse_phandle(dev->of_node, "panel", 0); @@ -1353,7 +1351,7 @@ static int exynos_dp_suspend(struct device *dev) { struct exynos_dp_device *dp = dev_get_drvdata(dev); - exynos_dp_disable(&dp->display); + exynos_dp_disable(&dp->encoder); return 0; } @@ -1361,7 +1359,7 @@ static int exynos_dp_resume(struct device *dev) { struct exynos_dp_device *dp = dev_get_drvdata(dev); - exynos_dp_enable(&dp->display); + exynos_dp_enable(&dp->encoder); return 0; } #endif diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h index a4e799679669..f8cc20207dbd 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.h +++ b/drivers/gpu/drm/exynos/exynos_dp_core.h @@ -147,11 +147,10 @@ struct link_train { }; struct exynos_dp_device { - struct exynos_drm_display display; + struct exynos_drm_encoder encoder; struct device *dev; struct drm_device *drm_dev; struct drm_connector connector; - struct drm_encoder *encoder; struct drm_panel *panel; struct drm_bridge *bridge; struct clk *clock; diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 4c9f972eaa07..e3864525fd7b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c @@ -21,38 +21,33 @@ static LIST_HEAD(exynos_drm_subdrv_list); int exynos_drm_create_enc_conn(struct drm_device *dev, - struct exynos_drm_display *display) + struct exynos_drm_encoder *exynos_encoder, + enum exynos_drm_output_type type) { - struct drm_encoder *encoder; int ret; unsigned long possible_crtcs = 0; - ret = exynos_drm_crtc_get_pipe_from_type(dev, display->type); + ret = exynos_drm_crtc_get_pipe_from_type(dev, type); if (ret < 0) return ret; possible_crtcs |= 1 << ret; /* create and initialize a encoder for this sub driver. */ - encoder = exynos_drm_encoder_create(dev, display, possible_crtcs); - if (!encoder) { + ret = exynos_drm_encoder_create(dev, exynos_encoder, possible_crtcs); + if (ret) { DRM_ERROR("failed to create encoder\n"); - return -EFAULT; + return ret; } - display->encoder = encoder; - - ret = display->ops->create_connector(display, encoder); + ret = exynos_encoder->ops->create_connector(exynos_encoder); if (ret) { DRM_ERROR("failed to create connector ret = %d\n", ret); - goto err_destroy_encoder; + drm_encoder_cleanup(&exynos_encoder->base); + return ret; } return 0; - -err_destroy_encoder: - encoder->funcs->destroy(encoder); - return ret; } int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index b13c9492291b..21427cca0a49 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -237,7 +237,7 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) } int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, - unsigned int out_type) + enum exynos_drm_output_type out_type) { struct drm_crtc *crtc; diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index d01d49a69298..9e7027d6c2f6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -30,7 +30,7 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb); /* This function gets pipe value to crtc device matched with out_type. */ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, - unsigned int out_type); + enum exynos_drm_output_type out_type); /* * This function calls the crtc device(manager)'s te_handler() callback diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index e0426707c911..60a316183a4c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -23,22 +23,21 @@ #include "exynos_drm_drv.h" struct exynos_dpi { - struct exynos_drm_display display; + struct exynos_drm_encoder encoder; struct device *dev; struct device_node *panel_node; struct drm_panel *panel; struct drm_connector connector; - struct drm_encoder *encoder; struct videomode *vm; }; #define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector) -static inline struct exynos_dpi *display_to_dpi(struct exynos_drm_display *d) +static inline struct exynos_dpi *encoder_to_dpi(struct exynos_drm_encoder *e) { - return container_of(d, struct exynos_dpi, display); + return container_of(e, struct exynos_dpi, encoder); } static enum drm_connector_status @@ -98,7 +97,7 @@ exynos_dpi_best_encoder(struct drm_connector *connector) { struct exynos_dpi *ctx = connector_to_dpi(connector); - return ctx->encoder; + return &ctx->encoder.base; } static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = { @@ -106,15 +105,14 @@ static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = { .best_encoder = exynos_dpi_best_encoder, }; -static int exynos_dpi_create_connector(struct exynos_drm_display *display, - struct drm_encoder *encoder) +static int exynos_dpi_create_connector( + struct exynos_drm_encoder *exynos_encoder) { - struct exynos_dpi *ctx = display_to_dpi(display); + struct exynos_dpi *ctx = encoder_to_dpi(exynos_encoder); + struct drm_encoder *encoder = &exynos_encoder->base; struct drm_connector *connector = &ctx->connector; int ret; - ctx->encoder = encoder; - connector->polled = DRM_CONNECTOR_POLL_HPD; ret = drm_connector_init(encoder->dev, connector, @@ -132,9 +130,9 @@ static int exynos_dpi_create_connector(struct exynos_drm_display *display, return 0; } -static void exynos_dpi_enable(struct exynos_drm_display *display) +static void exynos_dpi_enable(struct exynos_drm_encoder *encoder) { - struct exynos_dpi *ctx = display_to_dpi(display); + struct exynos_dpi *ctx = encoder_to_dpi(encoder); if (ctx->panel) { drm_panel_prepare(ctx->panel); @@ -142,9 +140,9 @@ static void exynos_dpi_enable(struct exynos_drm_display *display) } } -static void exynos_dpi_disable(struct exynos_drm_display *display) +static void exynos_dpi_disable(struct exynos_drm_encoder *encoder) { - struct exynos_dpi *ctx = display_to_dpi(display); + struct exynos_dpi *ctx = encoder_to_dpi(encoder); if (ctx->panel) { drm_panel_disable(ctx->panel); @@ -152,7 +150,7 @@ static void exynos_dpi_disable(struct exynos_drm_display *display) } } -static struct exynos_drm_display_ops exynos_dpi_display_ops = { +static struct exynos_drm_encoder_ops exynos_dpi_encoder_ops = { .create_connector = exynos_dpi_create_connector, .enable = exynos_dpi_enable, .disable = exynos_dpi_disable, @@ -282,7 +280,7 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx) return 0; } -struct exynos_drm_display *exynos_dpi_probe(struct device *dev) +struct exynos_drm_encoder *exynos_dpi_probe(struct device *dev) { struct exynos_dpi *ctx; int ret; @@ -291,8 +289,7 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev) if (!ctx) return ERR_PTR(-ENOMEM); - ctx->display.type = EXYNOS_DISPLAY_TYPE_LCD; - ctx->display.ops = &exynos_dpi_display_ops; + ctx->encoder.ops = &exynos_dpi_encoder_ops; ctx->dev = dev; ret = exynos_dpi_parse_dt(ctx); @@ -307,14 +304,14 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev) return ERR_PTR(-EPROBE_DEFER); } - return &ctx->display; + return &ctx->encoder; } -int exynos_dpi_remove(struct exynos_drm_display *display) +int exynos_dpi_remove(struct exynos_drm_encoder *encoder) { - struct exynos_dpi *ctx = display_to_dpi(display); + struct exynos_dpi *ctx = encoder_to_dpi(encoder); - exynos_dpi_disable(&ctx->display); + exynos_dpi_disable(&ctx->encoder); if (ctx->panel) drm_panel_detach(ctx->panel); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 47ea400735c6..4931193eb4e2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -22,6 +22,7 @@ #define MAX_PLANE 5 #define MAX_FB_BUFFER 4 +#define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder, base) #define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc, base) #define to_exynos_plane(x) container_of(x, struct exynos_drm_plane, base) @@ -77,7 +78,7 @@ struct exynos_drm_plane { }; /* - * Exynos DRM Display Structure. + * Exynos DRM Encoder Structure. * - this structure is common to analog tv, digital tv and lcd panel. * * @create_connector: initialize and register a new connector @@ -88,37 +89,30 @@ struct exynos_drm_plane { * @disable: display device off. * @commit: apply changes to hw */ -struct exynos_drm_display; -struct exynos_drm_display_ops { - int (*create_connector)(struct exynos_drm_display *display, - struct drm_encoder *encoder); - void (*mode_fixup)(struct exynos_drm_display *display, +struct exynos_drm_encoder; +struct exynos_drm_encoder_ops { + int (*create_connector)(struct exynos_drm_encoder *encoder); + void (*mode_fixup)(struct exynos_drm_encoder *encoder, struct drm_connector *connector, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); - void (*mode_set)(struct exynos_drm_display *display, + void (*mode_set)(struct exynos_drm_encoder *encoder, struct drm_display_mode *mode); - void (*enable)(struct exynos_drm_display *display); - void (*disable)(struct exynos_drm_display *display); - void (*commit)(struct exynos_drm_display *display); + void (*enable)(struct exynos_drm_encoder *encoder); + void (*disable)(struct exynos_drm_encoder *encoder); + void (*commit)(struct exynos_drm_encoder *encoder); }; /* - * Exynos drm display structure, maps 1:1 with an encoder/connector + * exynos specific encoder structure. * - * @list: the list entry for this manager + * @drm_encoder: encoder object. * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. - * @encoder: encoder object this display maps to - * @connector: connector object this display maps to * @ops: pointer to callbacks for exynos drm specific functionality - * @ctx: A pointer to the display's implementation specific context */ -struct exynos_drm_display { - struct list_head list; - enum exynos_drm_output_type type; - struct drm_encoder *encoder; - struct drm_connector *connector; - struct exynos_drm_display_ops *ops; +struct exynos_drm_encoder { + struct drm_encoder base; + struct exynos_drm_encoder_ops *ops; }; /* @@ -265,12 +259,12 @@ int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file); void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); #ifdef CONFIG_DRM_EXYNOS_DPI -struct exynos_drm_display * exynos_dpi_probe(struct device *dev); -int exynos_dpi_remove(struct exynos_drm_display *display); +struct exynos_drm_encoder *exynos_dpi_probe(struct device *dev); +int exynos_dpi_remove(struct exynos_drm_encoder *encoder); #else -static inline struct exynos_drm_display * +static inline struct exynos_drm_encoder * exynos_dpi_probe(struct device *dev) { return NULL; } -static inline int exynos_dpi_remove(struct exynos_drm_display *display) +static inline int exynos_dpi_remove(struct exynos_drm_encoder *encoder) { return 0; } @@ -278,7 +272,8 @@ static inline int exynos_dpi_remove(struct exynos_drm_display *display) /* This function creates a encoder and a connector, and initializes them. */ int exynos_drm_create_enc_conn(struct drm_device *dev, - struct exynos_drm_display *display); + struct exynos_drm_encoder *encoder, + enum exynos_drm_output_type type); extern struct platform_driver fimd_driver; extern struct platform_driver exynos5433_decon_driver; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 281b97d3465b..fef3a6148d07 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -259,7 +259,7 @@ struct exynos_dsi_driver_data { }; struct exynos_dsi { - struct exynos_drm_display display; + struct exynos_drm_encoder encoder; struct mipi_dsi_host dsi_host; struct drm_connector connector; struct device_node *panel_node; @@ -295,9 +295,9 @@ struct exynos_dsi { #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host) #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector) -static inline struct exynos_dsi *display_to_dsi(struct exynos_drm_display *d) +static inline struct exynos_dsi *encoder_to_dsi(struct exynos_drm_encoder *e) { - return container_of(d, struct exynos_dsi, display); + return container_of(e, struct exynos_dsi, encoder); } enum reg_idx { @@ -1272,7 +1272,7 @@ static irqreturn_t exynos_dsi_irq(int irq, void *dev_id) static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id) { struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id; - struct drm_encoder *encoder = dsi->display.encoder; + struct drm_encoder *encoder = &dsi->encoder.base; if (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE) exynos_drm_crtc_te_handler(encoder->crtc); @@ -1518,9 +1518,9 @@ static void exynos_dsi_poweroff(struct exynos_dsi *dsi) dev_err(dsi->dev, "cannot disable regulators %d\n", ret); } -static void exynos_dsi_enable(struct exynos_drm_display *display) +static void exynos_dsi_enable(struct exynos_drm_encoder *encoder) { - struct exynos_dsi *dsi = display_to_dsi(display); + struct exynos_dsi *dsi = encoder_to_dsi(encoder); int ret; if (dsi->state & DSIM_STATE_ENABLED) @@ -1554,9 +1554,9 @@ static void exynos_dsi_enable(struct exynos_drm_display *display) dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; } -static void exynos_dsi_disable(struct exynos_drm_display *display) +static void exynos_dsi_disable(struct exynos_drm_encoder *encoder) { - struct exynos_dsi *dsi = display_to_dsi(display); + struct exynos_dsi *dsi = encoder_to_dsi(encoder); if (!(dsi->state & DSIM_STATE_ENABLED)) return; @@ -1582,10 +1582,10 @@ exynos_dsi_detect(struct drm_connector *connector, bool force) if (dsi->panel) drm_panel_attach(dsi->panel, &dsi->connector); } else if (!dsi->panel_node) { - struct exynos_drm_display *display; + struct exynos_drm_encoder *encoder; - display = platform_get_drvdata(to_platform_device(dsi->dev)); - exynos_dsi_disable(display); + encoder = platform_get_drvdata(to_platform_device(dsi->dev)); + exynos_dsi_disable(encoder); drm_panel_detach(dsi->panel); dsi->panel = NULL; } @@ -1628,7 +1628,7 @@ exynos_dsi_best_encoder(struct drm_connector *connector) { struct exynos_dsi *dsi = connector_to_dsi(connector); - return dsi->display.encoder; + return &dsi->encoder.base; } static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { @@ -1636,10 +1636,11 @@ static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { .best_encoder = exynos_dsi_best_encoder, }; -static int exynos_dsi_create_connector(struct exynos_drm_display *display, - struct drm_encoder *encoder) +static int exynos_dsi_create_connector( + struct exynos_drm_encoder *exynos_encoder) { - struct exynos_dsi *dsi = display_to_dsi(display); + struct exynos_dsi *dsi = encoder_to_dsi(exynos_encoder); + struct drm_encoder *encoder = &exynos_encoder->base; struct drm_connector *connector = &dsi->connector; int ret; @@ -1660,10 +1661,10 @@ static int exynos_dsi_create_connector(struct exynos_drm_display *display, return 0; } -static void exynos_dsi_mode_set(struct exynos_drm_display *display, +static void exynos_dsi_mode_set(struct exynos_drm_encoder *encoder, struct drm_display_mode *mode) { - struct exynos_dsi *dsi = display_to_dsi(display); + struct exynos_dsi *dsi = encoder_to_dsi(encoder); struct videomode *vm = &dsi->vm; vm->hactive = mode->hdisplay; @@ -1676,7 +1677,7 @@ static void exynos_dsi_mode_set(struct exynos_drm_display *display, vm->hsync_len = mode->hsync_end - mode->hsync_start; } -static struct exynos_drm_display_ops exynos_dsi_display_ops = { +static struct exynos_drm_encoder_ops exynos_dsi_encoder_ops = { .create_connector = exynos_dsi_create_connector, .mode_set = exynos_dsi_mode_set, .enable = exynos_dsi_enable, @@ -1803,22 +1804,22 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi) static int exynos_dsi_bind(struct device *dev, struct device *master, void *data) { - struct exynos_drm_display *display = dev_get_drvdata(dev); - struct exynos_dsi *dsi = display_to_dsi(display); + struct exynos_drm_encoder *encoder = dev_get_drvdata(dev); + struct exynos_dsi *dsi = encoder_to_dsi(encoder); struct drm_device *drm_dev = data; struct drm_bridge *bridge; int ret; - ret = exynos_drm_create_enc_conn(drm_dev, display); + ret = exynos_drm_create_enc_conn(drm_dev, encoder, + EXYNOS_DISPLAY_TYPE_LCD); if (ret) { DRM_ERROR("Encoder create [%d] failed with %d\n", - display->type, ret); + EXYNOS_DISPLAY_TYPE_LCD, ret); return ret; } bridge = of_drm_find_bridge(dsi->bridge_node); if (bridge) { - display->encoder->bridge = bridge; drm_bridge_attach(drm_dev, bridge); } @@ -1828,10 +1829,10 @@ static int exynos_dsi_bind(struct device *dev, struct device *master, static void exynos_dsi_unbind(struct device *dev, struct device *master, void *data) { - struct exynos_drm_display *display = dev_get_drvdata(dev); - struct exynos_dsi *dsi = display_to_dsi(display); + struct exynos_drm_encoder *encoder = dev_get_drvdata(dev); + struct exynos_dsi *dsi = encoder_to_dsi(encoder); - exynos_dsi_disable(display); + exynos_dsi_disable(encoder); mipi_dsi_host_unregister(&dsi->dsi_host); } @@ -1852,8 +1853,7 @@ static int exynos_dsi_probe(struct platform_device *pdev) if (!dsi) return -ENOMEM; - dsi->display.type = EXYNOS_DISPLAY_TYPE_LCD; - dsi->display.ops = &exynos_dsi_display_ops; + dsi->encoder.ops = &exynos_dsi_encoder_ops; /* To be checked as invalid one */ dsi->te_gpio = -ENOENT; @@ -1930,7 +1930,7 @@ static int exynos_dsi_probe(struct platform_device *pdev) return ret; } - platform_set_drvdata(pdev, &dsi->display); + platform_set_drvdata(pdev, &dsi->encoder); return component_add(dev, &exynos_dsi_component_ops); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 7ba3a2d17ed5..b9a1c937de5b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -18,20 +18,6 @@ #include "exynos_drm_drv.h" #include "exynos_drm_encoder.h" -#define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder,\ - drm_encoder) - -/* - * exynos specific encoder structure. - * - * @drm_encoder: encoder object. - * @display: the display structure that maps to this encoder - */ -struct exynos_drm_encoder { - struct drm_encoder drm_encoder; - struct exynos_drm_display *display; -}; - static bool exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, @@ -39,16 +25,16 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); - struct exynos_drm_display *display = exynos_encoder->display; struct drm_connector *connector; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->encoder != encoder) continue; - if (display->ops->mode_fixup) - display->ops->mode_fixup(display, connector, mode, - adjusted_mode); + if (exynos_encoder->ops->mode_fixup) + exynos_encoder->ops->mode_fixup(exynos_encoder, + connector, mode, + adjusted_mode); } return true; @@ -59,31 +45,28 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); - struct exynos_drm_display *display = exynos_encoder->display; - if (display->ops->mode_set) - display->ops->mode_set(display, adjusted_mode); + if (exynos_encoder->ops->mode_set) + exynos_encoder->ops->mode_set(exynos_encoder, adjusted_mode); } static void exynos_drm_encoder_enable(struct drm_encoder *encoder) { struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); - struct exynos_drm_display *display = exynos_encoder->display; - if (display->ops->enable) - display->ops->enable(display); + if (exynos_encoder->ops->enable) + exynos_encoder->ops->enable(exynos_encoder); - if (display->ops->commit) - display->ops->commit(display); + if (exynos_encoder->ops->commit) + exynos_encoder->ops->commit(exynos_encoder); } static void exynos_drm_encoder_disable(struct drm_encoder *encoder) { struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); - struct exynos_drm_display *display = exynos_encoder->display; - if (display->ops->disable) - display->ops->disable(display); + if (exynos_encoder->ops->disable) + exynos_encoder->ops->disable(exynos_encoder); } static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { @@ -93,16 +76,8 @@ static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { .disable = exynos_drm_encoder_disable, }; -static void exynos_drm_encoder_destroy(struct drm_encoder *encoder) -{ - struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); - - drm_encoder_cleanup(encoder); - kfree(exynos_encoder); -} - static struct drm_encoder_funcs exynos_encoder_funcs = { - .destroy = exynos_drm_encoder_destroy, + .destroy = drm_encoder_cleanup, }; void exynos_drm_encoder_setup(struct drm_device *dev) @@ -118,23 +93,16 @@ void exynos_drm_encoder_setup(struct drm_device *dev) encoder->possible_clones = clone_mask; } -struct drm_encoder * -exynos_drm_encoder_create(struct drm_device *dev, - struct exynos_drm_display *display, - unsigned long possible_crtcs) +int exynos_drm_encoder_create(struct drm_device *dev, + struct exynos_drm_encoder *exynos_encoder, + unsigned long possible_crtcs) { struct drm_encoder *encoder; - struct exynos_drm_encoder *exynos_encoder; if (!possible_crtcs) - return NULL; - - exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL); - if (!exynos_encoder) - return NULL; + return -EINVAL; - exynos_encoder->display = display; - encoder = &exynos_encoder->drm_encoder; + encoder = &exynos_encoder->base; encoder->possible_crtcs = possible_crtcs; DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); @@ -146,10 +114,5 @@ exynos_drm_encoder_create(struct drm_device *dev, DRM_DEBUG_KMS("encoder has been created\n"); - return encoder; -} - -struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder) -{ - return to_exynos_encoder(encoder)->display; + return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h index 26305d8dd93a..005f583473d1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h @@ -15,9 +15,7 @@ #define _EXYNOS_DRM_ENCODER_H_ void exynos_drm_encoder_setup(struct drm_device *dev); -struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev, - struct exynos_drm_display *mgr, - unsigned long possible_crtcs); -struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder); +int exynos_drm_encoder_create(struct drm_device *dev, struct exynos_drm_encoder + *encoder, unsigned long possible_crtcs); #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 88dea9d6dacf..9edd11d4f515 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -169,7 +169,7 @@ struct fimd_context { struct exynos_drm_panel_info panel; struct fimd_driver_data *driver_data; - struct exynos_drm_display *display; + struct exynos_drm_encoder *encoder; }; static const struct of_device_id fimd_driver_dt_match[] = { @@ -945,8 +945,9 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) if (IS_ERR(ctx->crtc)) return PTR_ERR(ctx->crtc); - if (ctx->display) - exynos_drm_create_enc_conn(drm_dev, ctx->display); + if (ctx->encoder) + exynos_drm_create_enc_conn(drm_dev, ctx->encoder, + EXYNOS_DISPLAY_TYPE_LCD); if (is_drm_iommu_supported(drm_dev)) fimd_clear_channels(ctx->crtc); @@ -967,8 +968,8 @@ static void fimd_unbind(struct device *dev, struct device *master, drm_iommu_detach_device(ctx->drm_dev, ctx->dev); - if (ctx->display) - exynos_dpi_remove(ctx->display); + if (ctx->encoder) + exynos_dpi_remove(ctx->encoder); } static const struct component_ops fimd_component_ops = { @@ -1075,10 +1076,9 @@ static int fimd_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - ctx->display = exynos_dpi_probe(dev); - if (IS_ERR(ctx->display)) { - return PTR_ERR(ctx->display); - } + ctx->encoder = exynos_dpi_probe(dev); + if (IS_ERR(ctx->encoder)) + return PTR_ERR(ctx->encoder); pm_runtime_enable(dev); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index ade59eeb8554..d7f9501ceb3a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -35,11 +35,10 @@ connector) struct vidi_context { - struct exynos_drm_display display; + struct exynos_drm_encoder encoder; struct platform_device *pdev; struct drm_device *drm_dev; struct exynos_drm_crtc *crtc; - struct drm_encoder *encoder; struct drm_connector connector; struct exynos_drm_plane planes[WINDOWS_NR]; struct edid *raw_edid; @@ -55,9 +54,9 @@ struct vidi_context { int pipe; }; -static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d) +static inline struct vidi_context *encoder_to_vidi(struct exynos_drm_encoder *e) { - return container_of(d, struct vidi_context, display); + return container_of(e, struct vidi_context, encoder); } static const char fake_edid_info[] = { @@ -254,9 +253,7 @@ static DEVICE_ATTR(connection, 0644, vidi_show_connection, int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, struct drm_file *file_priv) { - struct vidi_context *ctx = NULL; - struct drm_encoder *encoder; - struct exynos_drm_display *display; + struct vidi_context *ctx = dev_get_drvdata(drm_dev->dev); struct drm_exynos_vidi_connection *vidi = data; if (!vidi) { @@ -269,21 +266,6 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, return -EINVAL; } - list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list, - head) { - display = exynos_drm_get_display(encoder); - - if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) { - ctx = display_to_vidi(display); - break; - } - } - - if (!ctx) { - DRM_DEBUG_KMS("not found virtual device type encoder.\n"); - return -EINVAL; - } - if (ctx->connected == vidi->connection) { DRM_DEBUG_KMS("same connection request.\n"); return -EINVAL; @@ -376,7 +358,7 @@ static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector) { struct vidi_context *ctx = ctx_from_connector(connector); - return ctx->encoder; + return &ctx->encoder.base; } static struct drm_connector_helper_funcs vidi_connector_helper_funcs = { @@ -384,14 +366,13 @@ static struct drm_connector_helper_funcs vidi_connector_helper_funcs = { .best_encoder = vidi_best_encoder, }; -static int vidi_create_connector(struct exynos_drm_display *display, - struct drm_encoder *encoder) +static int vidi_create_connector(struct exynos_drm_encoder *exynos_encoder) { - struct vidi_context *ctx = display_to_vidi(display); + struct vidi_context *ctx = encoder_to_vidi(exynos_encoder); + struct drm_encoder *encoder = &exynos_encoder->base; struct drm_connector *connector = &ctx->connector; int ret; - ctx->encoder = encoder; connector->polled = DRM_CONNECTOR_POLL_HPD; ret = drm_connector_init(ctx->drm_dev, connector, @@ -409,7 +390,7 @@ static int vidi_create_connector(struct exynos_drm_display *display, } -static struct exynos_drm_display_ops vidi_display_ops = { +static struct exynos_drm_encoder_ops vidi_encoder_ops = { .create_connector = vidi_create_connector, }; @@ -442,7 +423,8 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) return PTR_ERR(ctx->crtc); } - ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display); + ret = exynos_drm_create_enc_conn(drm_dev, &ctx->encoder, + EXYNOS_DISPLAY_TYPE_VIDI); if (ret) { ctx->crtc->base.funcs->destroy(&ctx->crtc->base); return ret; @@ -470,8 +452,7 @@ static int vidi_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI; - ctx->display.ops = &vidi_display_ops; + ctx->encoder.ops = &vidi_encoder_ops; ctx->default_win = 0; ctx->pdev = pdev; diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 9b9396a3214d..1aed7eadcd79 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -87,11 +87,11 @@ struct hdmi_resources { }; struct hdmi_context { - struct exynos_drm_display display; + struct exynos_drm_encoder encoder; struct device *dev; struct drm_device *drm_dev; struct drm_connector connector; - struct drm_encoder *encoder; + bool hpd; bool powered; bool dvi_mode; @@ -115,9 +115,9 @@ struct hdmi_context { struct regmap *pmureg; }; -static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d) +static inline struct hdmi_context *encoder_to_hdmi(struct exynos_drm_encoder *e) { - return container_of(d, struct hdmi_context, display); + return container_of(e, struct hdmi_context, encoder); } struct hdmiphy_config { @@ -1031,7 +1031,7 @@ static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector) { struct hdmi_context *hdata = ctx_from_connector(connector); - return hdata->encoder; + return &hdata->encoder.base; } static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = { @@ -1040,14 +1040,12 @@ static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = { .best_encoder = hdmi_best_encoder, }; -static int hdmi_create_connector(struct exynos_drm_display *display, - struct drm_encoder *encoder) +static int hdmi_create_connector(struct exynos_drm_encoder *exynos_encoder) { - struct hdmi_context *hdata = display_to_hdmi(display); + struct hdmi_context *hdata = encoder_to_hdmi(exynos_encoder); struct drm_connector *connector = &hdata->connector; int ret; - hdata->encoder = encoder; connector->interlace_allowed = true; connector->polled = DRM_CONNECTOR_POLL_HPD; @@ -1060,12 +1058,12 @@ static int hdmi_create_connector(struct exynos_drm_display *display, drm_connector_helper_add(connector, &hdmi_connector_helper_funcs); drm_connector_register(connector); - drm_mode_connector_attach_encoder(connector, encoder); + drm_mode_connector_attach_encoder(connector, &exynos_encoder->base); return 0; } -static void hdmi_mode_fixup(struct exynos_drm_display *display, +static void hdmi_mode_fixup(struct exynos_drm_encoder *encoder, struct drm_connector *connector, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -1698,10 +1696,10 @@ static void hdmi_conf_apply(struct hdmi_context *hdata) hdmi_regs_dump(hdata, "start"); } -static void hdmi_mode_set(struct exynos_drm_display *display, +static void hdmi_mode_set(struct exynos_drm_encoder *encoder, struct drm_display_mode *mode) { - struct hdmi_context *hdata = display_to_hdmi(display); + struct hdmi_context *hdata = encoder_to_hdmi(encoder); struct drm_display_mode *m = mode; DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n", @@ -1713,9 +1711,9 @@ static void hdmi_mode_set(struct exynos_drm_display *display, hdata->cea_video_id = drm_match_cea_mode(mode); } -static void hdmi_commit(struct exynos_drm_display *display) +static void hdmi_commit(struct exynos_drm_encoder *encoder) { - struct hdmi_context *hdata = display_to_hdmi(display); + struct hdmi_context *hdata = encoder_to_hdmi(encoder); if (!hdata->powered) return; @@ -1723,9 +1721,9 @@ static void hdmi_commit(struct exynos_drm_display *display) hdmi_conf_apply(hdata); } -static void hdmi_enable(struct exynos_drm_display *display) +static void hdmi_enable(struct exynos_drm_encoder *encoder) { - struct hdmi_context *hdata = display_to_hdmi(display); + struct hdmi_context *hdata = encoder_to_hdmi(encoder); struct hdmi_resources *res = &hdata->res; if (hdata->powered) @@ -1746,14 +1744,14 @@ static void hdmi_enable(struct exynos_drm_display *display) clk_prepare_enable(res->sclk_hdmi); hdmiphy_poweron(hdata); - hdmi_commit(display); + hdmi_commit(encoder); } -static void hdmi_disable(struct exynos_drm_display *display) +static void hdmi_disable(struct exynos_drm_encoder *encoder) { - struct hdmi_context *hdata = display_to_hdmi(display); + struct hdmi_context *hdata = encoder_to_hdmi(encoder); struct hdmi_resources *res = &hdata->res; - struct drm_crtc *crtc = hdata->encoder->crtc; + struct drm_crtc *crtc = hdata->encoder.base.crtc; const struct drm_crtc_helper_funcs *funcs = NULL; if (!hdata->powered) @@ -1794,7 +1792,7 @@ static void hdmi_disable(struct exynos_drm_display *display) hdata->powered = false; } -static struct exynos_drm_display_ops hdmi_display_ops = { +static struct exynos_drm_encoder_ops hdmi_encoder_ops = { .create_connector = hdmi_create_connector, .mode_fixup = hdmi_mode_fixup, .mode_set = hdmi_mode_set, @@ -1933,7 +1931,8 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) hdata->drm_dev = drm_dev; - return exynos_drm_create_enc_conn(drm_dev, &hdata->display); + return exynos_drm_create_enc_conn(drm_dev, &hdata->encoder, + EXYNOS_DISPLAY_TYPE_HDMI); } static void hdmi_unbind(struct device *dev, struct device *master, void *data) @@ -1982,8 +1981,7 @@ static int hdmi_probe(struct platform_device *pdev) return -ENODEV; hdata->drv_data = match->data; - hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI; - hdata->display.ops = &hdmi_display_ops; + hdata->encoder.ops = &hdmi_encoder_ops; platform_set_drvdata(pdev, hdata); From c2c099f2d97a039c5e1714c803dd9d20458c388f Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 5 Aug 2015 20:24:17 -0300 Subject: [PATCH 36/53] drm/exynos: remove extra call to hdmi_commit() hdmi_commit() was getting called twice by exynos encoder core, once inside the .enable() call and another time by .commit() itself. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 1aed7eadcd79..11bac50f3a8e 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1711,16 +1711,6 @@ static void hdmi_mode_set(struct exynos_drm_encoder *encoder, hdata->cea_video_id = drm_match_cea_mode(mode); } -static void hdmi_commit(struct exynos_drm_encoder *encoder) -{ - struct hdmi_context *hdata = encoder_to_hdmi(encoder); - - if (!hdata->powered) - return; - - hdmi_conf_apply(hdata); -} - static void hdmi_enable(struct exynos_drm_encoder *encoder) { struct hdmi_context *hdata = encoder_to_hdmi(encoder); @@ -1744,7 +1734,7 @@ static void hdmi_enable(struct exynos_drm_encoder *encoder) clk_prepare_enable(res->sclk_hdmi); hdmiphy_poweron(hdata); - hdmi_commit(encoder); + hdmi_conf_apply(hdata); } static void hdmi_disable(struct exynos_drm_encoder *encoder) @@ -1798,7 +1788,6 @@ static struct exynos_drm_encoder_ops hdmi_encoder_ops = { .mode_set = hdmi_mode_set, .enable = hdmi_enable, .disable = hdmi_disable, - .commit = hdmi_commit, }; static void hdmi_hotplug_work_func(struct work_struct *work) From 07fd6e1f9985399f08af0f7981eaed362512a5af Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 5 Aug 2015 20:24:18 -0300 Subject: [PATCH 37/53] drm/exynos: remove extra call to exynos_dp_commit() exynos_dp_commit() was getting called twice by exynos encoder core, once inside the .enable() call and another time by .commit() itself. The remove of the second call caused the wake of a bug, the operations orders inside exynos_dp_commit was wrong and we had to move exynos_dp_start_video() to be the last operation in there. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_dp_core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 2118737ab462..6c84bfbcff97 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -795,9 +795,6 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp) /* Configure video slave mode */ exynos_dp_enable_video_master(dp, 0); - /* Enable video */ - exynos_dp_start_video(dp); - timeout_loop = 0; for (;;) { @@ -938,6 +935,9 @@ static void exynos_dp_commit(struct exynos_drm_encoder *encoder) if (drm_panel_enable(dp->panel)) DRM_ERROR("failed to enable the panel\n"); } + + /* Enable video */ + exynos_dp_start_video(dp); } static enum drm_connector_status exynos_dp_detect( @@ -1114,7 +1114,6 @@ static struct exynos_drm_encoder_ops exynos_dp_encoder_ops = { .create_connector = exynos_dp_create_connector, .enable = exynos_dp_enable, .disable = exynos_dp_disable, - .commit = exynos_dp_commit, }; static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev) From af8be3f6fe80262f29b5e353421392196ff626f0 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 5 Aug 2015 20:24:19 -0300 Subject: [PATCH 38/53] drm/exynos: remove exynos_encoder's .commit() op .commit() is not used anymore, Exynos encoders now follow the .enable()/.disable() semantics from drm atomic core, so remove this callback. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 -- drivers/gpu/drm/exynos/exynos_drm_encoder.c | 3 --- 2 files changed, 5 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 4931193eb4e2..76ed6a105d4f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -87,7 +87,6 @@ struct exynos_drm_plane { * would be called by encoder->mode_set(). * @enable: display device on. * @disable: display device off. - * @commit: apply changes to hw */ struct exynos_drm_encoder; struct exynos_drm_encoder_ops { @@ -100,7 +99,6 @@ struct exynos_drm_encoder_ops { struct drm_display_mode *mode); void (*enable)(struct exynos_drm_encoder *encoder); void (*disable)(struct exynos_drm_encoder *encoder); - void (*commit)(struct exynos_drm_encoder *encoder); }; /* diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index b9a1c937de5b..ce7b97e3550d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -56,9 +56,6 @@ static void exynos_drm_encoder_enable(struct drm_encoder *encoder) if (exynos_encoder->ops->enable) exynos_encoder->ops->enable(exynos_encoder); - - if (exynos_encoder->ops->commit) - exynos_encoder->ops->commit(exynos_encoder); } static void exynos_drm_encoder_disable(struct drm_encoder *encoder) From a2986e8032bddbe237ed16e2e26c71f5416cd5fd Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 5 Aug 2015 20:24:20 -0300 Subject: [PATCH 39/53] drm/exynos: remove exynos_drm_create_enc_conn() This functions was just hiding the encoder and connector creation in a way that was less clean than if we get rid of it. For example, exynos_encoder ops had .create_connector() defined only because we were handing off the encoder and connector creation to exynos_drm_create_enc_conn(). Without this function we can directly call the create_connector function internally in the code, without the need of any vtable access. It also does some refactoring in the code like creating a bind function for dpi devices. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 3 +-- drivers/gpu/drm/exynos/exynos_dp_core.c | 20 +++++++++++--- drivers/gpu/drm/exynos/exynos_drm_core.c | 30 --------------------- drivers/gpu/drm/exynos/exynos_drm_dpi.c | 26 ++++++++++++++++-- drivers/gpu/drm/exynos/exynos_drm_drv.h | 12 ++++----- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 20 +++++++++----- drivers/gpu/drm/exynos/exynos_drm_encoder.c | 11 +++++--- drivers/gpu/drm/exynos/exynos_drm_encoder.h | 4 ++- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 3 +-- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 20 +++++++------- drivers/gpu/drm/exynos/exynos_hdmi.c | 21 ++++++++++++--- 11 files changed, 101 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 1b89e947bec9..e1a2ce751871 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -682,8 +682,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) } if (ctx->encoder) - exynos_drm_create_enc_conn(drm_dev, ctx->encoder, - EXYNOS_DISPLAY_TYPE_LCD); + exynos_dpi_bind(drm_dev, ctx->encoder); return 0; diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 6c84bfbcff97..67c5cd19721d 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -32,6 +32,7 @@ #include #include "exynos_dp_core.h" +#include "exynos_drm_encoder.h" #define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \ connector) @@ -1111,7 +1112,6 @@ static void exynos_dp_disable(struct exynos_drm_encoder *encoder) } static struct exynos_drm_encoder_ops exynos_dp_encoder_ops = { - .create_connector = exynos_dp_create_connector, .enable = exynos_dp_enable, .disable = exynos_dp_disable, }; @@ -1192,6 +1192,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) struct exynos_dp_device *dp = dev_get_drvdata(dev); struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm_dev = data; + struct exynos_drm_encoder *exynos_encoder = &dp->encoder; struct resource *res; unsigned int irq_flags; int ret = 0; @@ -1284,8 +1285,21 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) dp->drm_dev = drm_dev; - return exynos_drm_create_enc_conn(drm_dev, &dp->encoder, - EXYNOS_DISPLAY_TYPE_LCD); + ret = exynos_drm_encoder_create(drm_dev, exynos_encoder, + EXYNOS_DISPLAY_TYPE_LCD); + if (ret) { + DRM_ERROR("failed to create encoder\n"); + return ret; + } + + ret = exynos_dp_create_connector(exynos_encoder); + if (ret) { + DRM_ERROR("failed to create connector ret = %d\n", ret); + drm_encoder_cleanup(&exynos_encoder->base); + return ret; + } + + return 0; } static void exynos_dp_unbind(struct device *dev, struct device *master, diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index e3864525fd7b..1f38a44a5e84 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c @@ -20,36 +20,6 @@ static LIST_HEAD(exynos_drm_subdrv_list); -int exynos_drm_create_enc_conn(struct drm_device *dev, - struct exynos_drm_encoder *exynos_encoder, - enum exynos_drm_output_type type) -{ - int ret; - unsigned long possible_crtcs = 0; - - ret = exynos_drm_crtc_get_pipe_from_type(dev, type); - if (ret < 0) - return ret; - - possible_crtcs |= 1 << ret; - - /* create and initialize a encoder for this sub driver. */ - ret = exynos_drm_encoder_create(dev, exynos_encoder, possible_crtcs); - if (ret) { - DRM_ERROR("failed to create encoder\n"); - return ret; - } - - ret = exynos_encoder->ops->create_connector(exynos_encoder); - if (ret) { - DRM_ERROR("failed to create connector ret = %d\n", ret); - drm_encoder_cleanup(&exynos_encoder->base); - return ret; - } - - return 0; -} - int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) { if (!subdrv) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 60a316183a4c..6850ce5a0e97 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -20,7 +20,8 @@ #include