From 5cbb37df378dbedfa2b5f542b6d50937736f2427 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Thu, 6 Nov 2014 19:23:35 +0900 Subject: [PATCH 01/58] drm/exynos: resolve infinite loop issue on multi-platform This patch resolves temporarily infinite loop issue incurred when Exynos drm driver is enabled and multi-platform kernel is used by registering Exynos drm device object only in case of Exynos SoC. So this patch will be replaced with more generic way later. Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index c57466edf45b..d41aae0dcc60 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -741,6 +741,18 @@ static int exynos_drm_init(void) { int ret; + /* + * Register device object only in case of Exynos SoC. + * + * Below codes resolves temporarily infinite loop issue incurred + * by Exynos drm driver when using multi-platform kernel. + * So these codes will be replaced with more generic way later. + */ + if (!of_machine_is_compatible("samsung,exynos3") && + !of_machine_is_compatible("samsung,exynos4") && + !of_machine_is_compatible("samsung,exynos5")) + return -ENODEV; + exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, NULL, 0); if (IS_ERR(exynos_drm_pdev)) From fbdf093d62de4974cd30f170cf76aa14e26b13e4 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Thu, 6 Nov 2014 23:00:37 +0900 Subject: [PATCH 02/58] drm/exynos: resolve infinite loop issue on non multi-platform This patch resovles the infinite loop issue incurred when Exyno drm driver is enabled but all kms drivers are disabled on Exynos board by returning -EPROBE_DEFER only in case that there is kms device registered. Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index d41aae0dcc60..b8abbc4a3d8b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -495,6 +495,12 @@ static struct component_match *exynos_drm_match_add(struct device *dev) mutex_lock(&drm_component_lock); + /* Do not retry to probe if there is no any kms driver regitered. */ + if (list_empty(&drm_component_list)) { + mutex_unlock(&drm_component_lock); + return ERR_PTR(-ENODEV); + } + list_for_each_entry(cdev, &drm_component_list, list) { /* * Add components to master only in case that crtc and From 2d15118750fd69a50cf286d3fc275546fa0b5857 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Fri, 7 Nov 2014 20:31:08 +0900 Subject: [PATCH 03/58] drm/exynos: g2d: fix null pointer dereference This patch fixes a null pointer dereference issue incurred by calling g2d_remove when exynos_drm_platform_probe is failed. cmdlist_pool of g2d is allocated when g2d sub driver is probed. So if exynos_drm_platform_probe is failed, the g2d sub driver is not probed and the cmdlist_pool is still NULL. Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index df7a77d3eff8..6ff8599f6cbf 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -302,9 +302,12 @@ static void g2d_fini_cmdlist(struct g2d_data *g2d) struct exynos_drm_subdrv *subdrv = &g2d->subdrv; kfree(g2d->cmdlist_node); - dma_free_attrs(subdrv->drm_dev->dev, G2D_CMDLIST_POOL_SIZE, - g2d->cmdlist_pool_virt, - g2d->cmdlist_pool, &g2d->cmdlist_dma_attrs); + + if (g2d->cmdlist_pool_virt && g2d->cmdlist_pool) { + dma_free_attrs(subdrv->drm_dev->dev, G2D_CMDLIST_POOL_SIZE, + g2d->cmdlist_pool_virt, + g2d->cmdlist_pool, &g2d->cmdlist_dma_attrs); + } } static struct g2d_cmdlist_node *g2d_get_cmdlist(struct g2d_data *g2d) From e9fbdcb45a36c775383dd98d53b4452cdb5e53c0 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Fri, 7 Nov 2014 21:32:34 +0900 Subject: [PATCH 04/58] drm/exynos: fix possible infinite loop issue This patch fixes possible infinite loop issue by postponing registration to non kms drivers after component_master_add_with_match call, which can be incurred in all cases that non kms driver is probed and then component bind is failed This patch should be applied on top of below patches, http://comments.gmane.org/gmane.comp.video.dri.devel/117740 http://www.spinics.net/lists/linux-samsung-soc/msg38624.html Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 31 ++++++++++++------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index b8abbc4a3d8b..e5c4c6c8c967 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -591,10 +591,21 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) goto err_unregister_mixer_drv; #endif + match = exynos_drm_match_add(&pdev->dev); + if (IS_ERR(match)) { + ret = PTR_ERR(match); + goto err_unregister_hdmi_drv; + } + + ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, + match); + if (ret < 0) + goto err_unregister_hdmi_drv; + #ifdef CONFIG_DRM_EXYNOS_G2D ret = platform_driver_register(&g2d_driver); if (ret < 0) - goto err_unregister_hdmi_drv; + goto err_del_component_master; #endif #ifdef CONFIG_DRM_EXYNOS_FIMC @@ -625,23 +636,9 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) goto err_unregister_ipp_drv; #endif - match = exynos_drm_match_add(&pdev->dev); - if (IS_ERR(match)) { - ret = PTR_ERR(match); - goto err_unregister_resources; - } - - ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, - match); - if (ret < 0) - goto err_unregister_resources; - return ret; -err_unregister_resources: - #ifdef CONFIG_DRM_EXYNOS_IPP - exynos_platform_device_ipp_unregister(); err_unregister_ipp_drv: platform_driver_unregister(&ipp_driver); err_unregister_gsc_drv: @@ -664,9 +661,11 @@ err_unregister_g2d_drv: #ifdef CONFIG_DRM_EXYNOS_G2D platform_driver_unregister(&g2d_driver); -err_unregister_hdmi_drv: +err_del_component_master: #endif + component_master_del(&pdev->dev, &exynos_drm_ops); +err_unregister_hdmi_drv: #ifdef CONFIG_DRM_EXYNOS_HDMI platform_driver_unregister(&hdmi_driver); err_unregister_mixer_drv: From 421ee18d4e040d673f5ce2972efa75c2ce0826d9 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Thu, 13 Nov 2014 16:05:12 +0900 Subject: [PATCH 05/58] drm/exynos: fix null pointer dereference issue This patch fixes null pointer dereference issue incurred when ipp driver is enabled and Exynos drm driver is closed. Non kms driver should register its own sub driver to setup necessary resources, which is done by load(). So null pointer dereference occurs when ipp driver is enabled and Exynos drm driver is closed because ipp core device is registered after component_master_add_with_match call. This patch makes exynos_drm_device_subdrv_probe() to be called after all non kms drivers are registered. Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index e5c4c6c8c967..f0bcdc61778b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -108,11 +108,6 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) if (ret) goto err_unbind_all; - /* Probe non kms sub drivers and virtual display driver. */ - ret = exynos_drm_device_subdrv_probe(dev); - if (ret) - goto err_cleanup_vblank; - /* * enable drm irq mode. * - with irq_enabled = true, we can use the vblank feature. @@ -138,8 +133,6 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) return 0; -err_cleanup_vblank: - drm_vblank_cleanup(dev); err_unbind_all: component_unbind_all(dev->dev, dev); err_mode_config_cleanup: @@ -153,8 +146,6 @@ err_free_private: static int exynos_drm_unload(struct drm_device *dev) { - exynos_drm_device_subdrv_remove(dev); - exynos_drm_fbdev_fini(dev); drm_kms_helper_poll_fini(dev); @@ -636,9 +627,16 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) goto err_unregister_ipp_drv; #endif + /* Probe non kms sub drivers and virtual display driver. */ + ret = exynos_drm_device_subdrv_probe(platform_get_drvdata(pdev)); + if (ret) + goto err_unregister_resources; + return ret; +err_unregister_resources: #ifdef CONFIG_DRM_EXYNOS_IPP + exynos_platform_device_ipp_unregister(); err_unregister_ipp_drv: platform_driver_unregister(&ipp_driver); err_unregister_gsc_drv: @@ -691,6 +689,8 @@ err_unregister_fimd_drv: static int exynos_drm_platform_remove(struct platform_device *pdev) { + exynos_drm_device_subdrv_remove(platform_get_drvdata(pdev)); + #ifdef CONFIG_DRM_EXYNOS_IPP exynos_platform_device_ipp_unregister(); platform_driver_unregister(&ipp_driver); From 7239067795dc03be5b152034558bed0bb9c73ab3 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 13 Nov 2014 16:37:57 +0900 Subject: [PATCH 06/58] drm/exynos: remove ifdeferry from initialization code The patch replaces separate calls to driver (de)registration by loops over the array of drivers. As a result it significantly decreases number of ifdefs. Additionally it moves device registration related ifdefs to header file. Changelog v2: - Rebased. - Consider non kms driver in respect to infinite loop issue. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 202 ++++++++---------------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 25 ++- 2 files changed, 75 insertions(+), 152 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index f0bcdc61778b..8aee62902ec6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -547,85 +547,74 @@ static const struct component_master_ops exynos_drm_ops = { .unbind = exynos_drm_unbind, }; +static struct platform_driver *const exynos_drm_kms_drivers[] = { +#ifdef CONFIG_DRM_EXYNOS_FIMD + &fimd_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_DP + &dp_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_DSI + &dsi_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_HDMI + &mixer_driver, + &hdmi_driver, +#endif +}; + +static struct platform_driver *const exynos_drm_non_kms_drivers[] = { +#ifdef CONFIG_DRM_EXYNOS_G2D + &g2d_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_FIMC + &fimc_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_ROTATOR + &rotator_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_GSC + &gsc_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_IPP + &ipp_driver, +#endif +}; + static int exynos_drm_platform_probe(struct platform_device *pdev) { struct component_match *match; - int ret; + int ret, i, j; pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls); -#ifdef CONFIG_DRM_EXYNOS_FIMD - ret = platform_driver_register(&fimd_driver); - if (ret < 0) - return ret; -#endif - -#ifdef CONFIG_DRM_EXYNOS_DP - ret = platform_driver_register(&dp_driver); - if (ret < 0) - goto err_unregister_fimd_drv; -#endif - -#ifdef CONFIG_DRM_EXYNOS_DSI - ret = platform_driver_register(&dsi_driver); - if (ret < 0) - goto err_unregister_dp_drv; -#endif - -#ifdef CONFIG_DRM_EXYNOS_HDMI - ret = platform_driver_register(&mixer_driver); - if (ret < 0) - goto err_unregister_dsi_drv; - ret = platform_driver_register(&hdmi_driver); - if (ret < 0) - goto err_unregister_mixer_drv; -#endif + for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) { + ret = platform_driver_register(exynos_drm_kms_drivers[i]); + if (ret < 0) + goto err_unregister_kms_drivers; + } match = exynos_drm_match_add(&pdev->dev); if (IS_ERR(match)) { ret = PTR_ERR(match); - goto err_unregister_hdmi_drv; + goto err_unregister_kms_drivers; } ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, match); if (ret < 0) - goto err_unregister_hdmi_drv; + goto err_unregister_kms_drivers; -#ifdef CONFIG_DRM_EXYNOS_G2D - ret = platform_driver_register(&g2d_driver); - if (ret < 0) - goto err_del_component_master; -#endif - -#ifdef CONFIG_DRM_EXYNOS_FIMC - ret = platform_driver_register(&fimc_driver); - if (ret < 0) - goto err_unregister_g2d_drv; -#endif - -#ifdef CONFIG_DRM_EXYNOS_ROTATOR - ret = platform_driver_register(&rotator_driver); - if (ret < 0) - goto err_unregister_fimc_drv; -#endif - -#ifdef CONFIG_DRM_EXYNOS_GSC - ret = platform_driver_register(&gsc_driver); - if (ret < 0) - goto err_unregister_rotator_drv; -#endif - -#ifdef CONFIG_DRM_EXYNOS_IPP - ret = platform_driver_register(&ipp_driver); - if (ret < 0) - goto err_unregister_gsc_drv; + for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { + ret = platform_driver_register(exynos_drm_non_kms_drivers[j]); + if (ret < 0) + goto err_del_component_master; + } ret = exynos_platform_device_ipp_register(); if (ret < 0) - goto err_unregister_ipp_drv; -#endif + goto err_unregister_non_kms_drivers; /* Probe non kms sub drivers and virtual display driver. */ ret = exynos_drm_device_subdrv_probe(platform_get_drvdata(pdev)); @@ -637,98 +626,39 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) err_unregister_resources: #ifdef CONFIG_DRM_EXYNOS_IPP exynos_platform_device_ipp_unregister(); -err_unregister_ipp_drv: - platform_driver_unregister(&ipp_driver); -err_unregister_gsc_drv: #endif +err_unregister_non_kms_drivers: + while (--j >= 0) + platform_driver_unregister(exynos_drm_non_kms_drivers[j]); -#ifdef CONFIG_DRM_EXYNOS_GSC - platform_driver_unregister(&gsc_driver); -err_unregister_rotator_drv: -#endif - -#ifdef CONFIG_DRM_EXYNOS_ROTATOR - platform_driver_unregister(&rotator_driver); -err_unregister_fimc_drv: -#endif - -#ifdef CONFIG_DRM_EXYNOS_FIMC - platform_driver_unregister(&fimc_driver); -err_unregister_g2d_drv: -#endif - -#ifdef CONFIG_DRM_EXYNOS_G2D - platform_driver_unregister(&g2d_driver); err_del_component_master: -#endif component_master_del(&pdev->dev, &exynos_drm_ops); -err_unregister_hdmi_drv: -#ifdef CONFIG_DRM_EXYNOS_HDMI - platform_driver_unregister(&hdmi_driver); -err_unregister_mixer_drv: - platform_driver_unregister(&mixer_driver); -err_unregister_dsi_drv: -#endif +err_unregister_kms_drivers: + while (--i >= 0) + platform_driver_unregister(exynos_drm_kms_drivers[i]); -#ifdef CONFIG_DRM_EXYNOS_DSI - platform_driver_unregister(&dsi_driver); -err_unregister_dp_drv: -#endif - -#ifdef CONFIG_DRM_EXYNOS_DP - platform_driver_unregister(&dp_driver); -err_unregister_fimd_drv: -#endif - -#ifdef CONFIG_DRM_EXYNOS_FIMD - platform_driver_unregister(&fimd_driver); -#endif return ret; } static int exynos_drm_platform_remove(struct platform_device *pdev) { + int i; + exynos_drm_device_subdrv_remove(platform_get_drvdata(pdev)); #ifdef CONFIG_DRM_EXYNOS_IPP exynos_platform_device_ipp_unregister(); - platform_driver_unregister(&ipp_driver); #endif -#ifdef CONFIG_DRM_EXYNOS_GSC - platform_driver_unregister(&gsc_driver); -#endif + for (i = ARRAY_SIZE(exynos_drm_non_kms_drivers) - 1; i >= 0; --i) + platform_driver_unregister(exynos_drm_non_kms_drivers[i]); -#ifdef CONFIG_DRM_EXYNOS_ROTATOR - platform_driver_unregister(&rotator_driver); -#endif - -#ifdef CONFIG_DRM_EXYNOS_FIMC - platform_driver_unregister(&fimc_driver); -#endif - -#ifdef CONFIG_DRM_EXYNOS_G2D - platform_driver_unregister(&g2d_driver); -#endif - -#ifdef CONFIG_DRM_EXYNOS_HDMI - platform_driver_unregister(&mixer_driver); - platform_driver_unregister(&hdmi_driver); -#endif - -#ifdef CONFIG_DRM_EXYNOS_FIMD - platform_driver_unregister(&fimd_driver); -#endif - -#ifdef CONFIG_DRM_EXYNOS_DSI - platform_driver_unregister(&dsi_driver); -#endif - -#ifdef CONFIG_DRM_EXYNOS_DP - platform_driver_unregister(&dp_driver); -#endif component_master_del(&pdev->dev, &exynos_drm_ops); + + for (i = ARRAY_SIZE(exynos_drm_kms_drivers) - 1; i >= 0; --i) + platform_driver_unregister(exynos_drm_kms_drivers[i]); + return 0; } @@ -763,11 +693,9 @@ static int exynos_drm_init(void) if (IS_ERR(exynos_drm_pdev)) return PTR_ERR(exynos_drm_pdev); -#ifdef CONFIG_DRM_EXYNOS_VIDI ret = exynos_drm_probe_vidi(); if (ret < 0) goto err_unregister_pd; -#endif ret = platform_driver_register(&exynos_drm_platform_driver); if (ret) @@ -776,11 +704,9 @@ static int exynos_drm_init(void) return 0; err_remove_vidi: -#ifdef CONFIG_DRM_EXYNOS_VIDI exynos_drm_remove_vidi(); err_unregister_pd: -#endif platform_device_unregister(exynos_drm_pdev); return ret; @@ -789,9 +715,9 @@ err_unregister_pd: static void exynos_drm_exit(void) { platform_driver_unregister(&exynos_drm_platform_driver); -#ifdef CONFIG_DRM_EXYNOS_VIDI + exynos_drm_remove_vidi(); -#endif + platform_device_unregister(exynos_drm_pdev); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index d22e640f59a0..3c81c4b60399 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -323,15 +323,14 @@ int exynos_platform_device_hdmi_register(void); */ void exynos_platform_device_hdmi_unregister(void); -/* - * this function registers exynos drm ipp platform device. - */ +#ifdef CONFIG_DRM_EXYNOS_IPP int exynos_platform_device_ipp_register(void); - -/* - * this function unregisters exynos drm ipp platform device if it exists. - */ void exynos_platform_device_ipp_unregister(void); +#else +static inline int exynos_platform_device_ipp_register(void) { return 0; } +static inline void exynos_platform_device_ipp_unregister(void) {} +#endif + #ifdef CONFIG_DRM_EXYNOS_DPI struct exynos_drm_display * exynos_dpi_probe(struct device *dev); @@ -342,15 +341,13 @@ exynos_dpi_probe(struct device *dev) { return NULL; } static inline int exynos_dpi_remove(struct device *dev) { return 0; } #endif -/* - * this function registers exynos drm vidi platform device/driver. - */ +#ifdef CONFIG_DRM_EXYNOS_VIDI int exynos_drm_probe_vidi(void); - -/* - * this function unregister exynos drm vidi platform device/driver. - */ void exynos_drm_remove_vidi(void); +#else +static inline int exynos_drm_probe_vidi(void) { return 0; } +static inline void exynos_drm_remove_vidi(void) {} +#endif /* This function creates a encoder and a connector, and initializes them. */ int exynos_drm_create_enc_conn(struct drm_device *dev, From 2900c69c52079a0340db0f012d2b2e92db7544c4 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 7 Oct 2014 14:01:08 +0200 Subject: [PATCH 07/58] drm/exynos: dsi: remove global variable exynos_dsi_display exynos_dsi_display is used by internal Exynos DRM framework for representing pair encoder->connecter. As it should be mapped 1:1 to dsi private context it seems more reasonable to embed it directly in that context. As a result further code simplification will be possible. Moreover it will be possible to handle multiple DSI devices in the system. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 38 ++++++++++++------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index f43d25896f3b..c0141b60e8fd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -268,6 +268,7 @@ struct exynos_dsi_driver_data { }; struct exynos_dsi { + struct exynos_drm_display display; struct mipi_dsi_host dsi_host; struct drm_connector connector; struct drm_encoder *encoder; @@ -1531,10 +1532,6 @@ static struct exynos_drm_display_ops exynos_dsi_display_ops = { .dpms = exynos_dsi_dpms }; -static struct exynos_drm_display exynos_dsi_display = { - .type = EXYNOS_DISPLAY_TYPE_LCD, - .ops = &exynos_dsi_display_ops, -}; MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); /* of_* functions will be removed after merge of of_graph patches */ @@ -1640,28 +1637,28 @@ end: 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->ctx; struct drm_device *drm_dev = data; - struct exynos_dsi *dsi; int ret; - ret = exynos_drm_create_enc_conn(drm_dev, &exynos_dsi_display); + ret = exynos_drm_create_enc_conn(drm_dev, display); if (ret) { DRM_ERROR("Encoder create [%d] failed with %d\n", - exynos_dsi_display.type, ret); + display->type, ret); return ret; } - dsi = exynos_dsi_display.ctx; - return mipi_dsi_host_register(&dsi->dsi_host); } static void exynos_dsi_unbind(struct device *dev, struct device *master, void *data) { - struct exynos_dsi *dsi = exynos_dsi_display.ctx; + struct exynos_drm_display *display = dev_get_drvdata(dev); + struct exynos_dsi *dsi = display->ctx; - exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF); + exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF); mipi_dsi_host_unregister(&dsi->dsi_host); } @@ -1673,22 +1670,23 @@ static const struct component_ops exynos_dsi_component_ops = { static int exynos_dsi_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct resource *res; struct exynos_dsi *dsi; int ret; - ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, - exynos_dsi_display.type); + dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); + if (!dsi) + return -ENOMEM; + + dsi->display.type = EXYNOS_DISPLAY_TYPE_LCD; + dsi->display.ops = &exynos_dsi_display_ops; + + ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CONNECTOR, + dsi->display.type); if (ret) return ret; - dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL); - if (!dsi) { - dev_err(&pdev->dev, "failed to allocate dsi object.\n"); - ret = -ENOMEM; - goto err_del_component; - } - /* To be checked as invalid one */ dsi->te_gpio = -ENOENT; From e2d2a1e0a264725fd0a62b91422d33ba2263a341 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 7 Oct 2014 14:01:09 +0200 Subject: [PATCH 08/58] drm/exynos: dsi: simplify device pointer evaluation The patch replaces multiple evaluation of device address with local variable. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index c0141b60e8fd..926682c7af27 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1695,9 +1695,9 @@ static int exynos_dsi_probe(struct platform_device *pdev) INIT_LIST_HEAD(&dsi->transfer_list); dsi->dsi_host.ops = &exynos_dsi_ops; - dsi->dsi_host.dev = &pdev->dev; + dsi->dsi_host.dev = dev; - dsi->dev = &pdev->dev; + dsi->dev = dev; dsi->driver_data = exynos_dsi_get_driver_data(pdev); ret = exynos_dsi_parse_dt(dsi); @@ -1706,70 +1706,70 @@ static int exynos_dsi_probe(struct platform_device *pdev) dsi->supplies[0].supply = "vddcore"; dsi->supplies[1].supply = "vddio"; - ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(dsi->supplies), + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dsi->supplies), dsi->supplies); if (ret) { - dev_info(&pdev->dev, "failed to get regulators: %d\n", ret); + dev_info(dev, "failed to get regulators: %d\n", ret); return -EPROBE_DEFER; } - dsi->pll_clk = devm_clk_get(&pdev->dev, "pll_clk"); + dsi->pll_clk = devm_clk_get(dev, "pll_clk"); if (IS_ERR(dsi->pll_clk)) { - dev_info(&pdev->dev, "failed to get dsi pll input clock\n"); + dev_info(dev, "failed to get dsi pll input clock\n"); ret = PTR_ERR(dsi->pll_clk); goto err_del_component; } - dsi->bus_clk = devm_clk_get(&pdev->dev, "bus_clk"); + dsi->bus_clk = devm_clk_get(dev, "bus_clk"); if (IS_ERR(dsi->bus_clk)) { - dev_info(&pdev->dev, "failed to get dsi bus clock\n"); + dev_info(dev, "failed to get dsi bus clock\n"); ret = PTR_ERR(dsi->bus_clk); goto err_del_component; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dsi->reg_base = devm_ioremap_resource(&pdev->dev, res); + dsi->reg_base = devm_ioremap_resource(dev, res); if (IS_ERR(dsi->reg_base)) { - dev_err(&pdev->dev, "failed to remap io region\n"); + dev_err(dev, "failed to remap io region\n"); ret = PTR_ERR(dsi->reg_base); goto err_del_component; } - dsi->phy = devm_phy_get(&pdev->dev, "dsim"); + dsi->phy = devm_phy_get(dev, "dsim"); if (IS_ERR(dsi->phy)) { - dev_info(&pdev->dev, "failed to get dsim phy\n"); + dev_info(dev, "failed to get dsim phy\n"); ret = PTR_ERR(dsi->phy); goto err_del_component; } dsi->irq = platform_get_irq(pdev, 0); if (dsi->irq < 0) { - dev_err(&pdev->dev, "failed to request dsi irq resource\n"); + dev_err(dev, "failed to request dsi irq resource\n"); ret = dsi->irq; goto err_del_component; } irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN); - ret = devm_request_threaded_irq(&pdev->dev, dsi->irq, NULL, + ret = devm_request_threaded_irq(dev, dsi->irq, NULL, exynos_dsi_irq, IRQF_ONESHOT, - dev_name(&pdev->dev), dsi); + dev_name(dev), dsi); if (ret) { - dev_err(&pdev->dev, "failed to request dsi irq\n"); + dev_err(dev, "failed to request dsi irq\n"); goto err_del_component; } - exynos_dsi_display.ctx = dsi; + dsi->display.ctx = dsi; - platform_set_drvdata(pdev, &exynos_dsi_display); + platform_set_drvdata(pdev, &dsi->display); - ret = component_add(&pdev->dev, &exynos_dsi_component_ops); + ret = component_add(dev, &exynos_dsi_component_ops); if (ret) goto err_del_component; return ret; err_del_component: - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); + exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR); return ret; } From e5169723da013eec25e1d52faa8c5058abe1b23e Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 7 Oct 2014 14:01:10 +0200 Subject: [PATCH 09/58] drm/exynos: dsi: remove redundant encoder field The patch removes redundant encoder field from private DSI context. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 926682c7af27..c9d1a00971f1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -271,7 +271,6 @@ struct exynos_dsi { struct exynos_drm_display display; struct mipi_dsi_host dsi_host; struct drm_connector connector; - struct drm_encoder *encoder; struct device_node *panel_node; struct drm_panel *panel; struct device *dev; @@ -1105,7 +1104,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->encoder; + struct drm_encoder *encoder = dsi->display.encoder; if (dsi->state & DSIM_STATE_ENABLED) exynos_drm_crtc_te_handler(encoder->crtc); @@ -1475,7 +1474,7 @@ exynos_dsi_best_encoder(struct drm_connector *connector) { struct exynos_dsi *dsi = connector_to_dsi(connector); - return dsi->encoder; + return dsi->display.encoder; } static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { @@ -1491,8 +1490,6 @@ static int exynos_dsi_create_connector(struct exynos_drm_display *display, struct drm_connector *connector = &dsi->connector; int ret; - dsi->encoder = encoder; - connector->polled = DRM_CONNECTOR_POLL_HPD; ret = drm_connector_init(encoder->dev, connector, From 5cd5db80402c91d4b5f4ea5f5cf4be5b21864935 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 7 Oct 2014 14:01:11 +0200 Subject: [PATCH 10/58] drm/exynos: dsi: stop using display->ctx pointer The patch replaces accesses to display->ctx pointer by container_of construct. It will allow to remove ctx field in the future. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index c9d1a00971f1..5e38d158089b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -304,6 +304,11 @@ 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) +{ + return container_of(d, struct exynos_dsi, display); +} + static struct exynos_dsi_driver_data exynos3_dsi_driver_data = { .plltmr_reg = 0x50, .has_freqband = 1, @@ -1397,7 +1402,7 @@ static void exynos_dsi_disable(struct exynos_dsi *dsi) static void exynos_dsi_dpms(struct exynos_drm_display *display, int mode) { - struct exynos_dsi *dsi = display->ctx; + struct exynos_dsi *dsi = display_to_dsi(display); if (dsi->panel) { switch (mode) { @@ -1486,7 +1491,7 @@ static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { static int exynos_dsi_create_connector(struct exynos_drm_display *display, struct drm_encoder *encoder) { - struct exynos_dsi *dsi = display->ctx; + struct exynos_dsi *dsi = display_to_dsi(display); struct drm_connector *connector = &dsi->connector; int ret; @@ -1510,7 +1515,7 @@ static int exynos_dsi_create_connector(struct exynos_drm_display *display, static void exynos_dsi_mode_set(struct exynos_drm_display *display, struct drm_display_mode *mode) { - struct exynos_dsi *dsi = display->ctx; + struct exynos_dsi *dsi = display_to_dsi(display); struct videomode *vm = &dsi->vm; vm->hactive = mode->hdisplay; @@ -1635,7 +1640,7 @@ 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->ctx; + struct exynos_dsi *dsi = display_to_dsi(display); struct drm_device *drm_dev = data; int ret; @@ -1653,7 +1658,7 @@ 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->ctx; + struct exynos_dsi *dsi = display_to_dsi(display); exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF); @@ -1755,8 +1760,6 @@ static int exynos_dsi_probe(struct platform_device *pdev) goto err_del_component; } - dsi->display.ctx = dsi; - platform_set_drvdata(pdev, &dsi->display); ret = component_add(dev, &exynos_dsi_component_ops); From ff9c87ce9b9d10d50f42127c0753654af6332157 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 31 Oct 2014 14:17:35 +0000 Subject: [PATCH 11/58] drm/exynos: remove uneeded declaration of struct dma_iommu_mapping It is not even used in this header anymore. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_iommu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h index 72376d41c512..35d25889b476 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.h +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.h @@ -40,7 +40,6 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) #else -struct dma_iommu_mapping; static inline int drm_create_iommu_mapping(struct drm_device *drm_dev) { return 0; From b5b1a4bb1598e3c11d5c74adfcab2055954ebee7 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 31 Oct 2014 14:17:36 +0000 Subject: [PATCH 12/58] drm/exynos: remove extra declaration of struct exynos_drm_manager The struct is defined in the same file, declare it here is just unnecessary. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_encoder.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h index b7a1620a7e79..26305d8dd93a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h @@ -14,8 +14,6 @@ #ifndef _EXYNOS_DRM_ENCODER_H_ #define _EXYNOS_DRM_ENCODER_H_ -struct exynos_drm_manager; - 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, From f859d6e8594e0a9e11b76407b7f4834f612f0c6d Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 31 Oct 2014 14:17:37 +0000 Subject: [PATCH 13/58] drm/exynos: remove extra declaration of struct exynos_overlay The struct is defined in the same file, declare it here is just unnecessary Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 3c81c4b60399..3905e309e782 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -37,7 +37,6 @@ #define wait_for(COND, MS) _wait_for(COND, MS) struct drm_device; -struct exynos_drm_overlay; struct drm_connector; /* This enumerates device type. */ From d2c1bba3f6fca60c924996c51d7453c5ddb5cedd Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 31 Oct 2014 14:17:38 +0000 Subject: [PATCH 14/58] drm/exynos: Replace repeated declaration by include Re-declare struct is not a good practice, let's use the original drm declarations. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 3905e309e782..780698139e67 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -15,6 +15,7 @@ #ifndef _EXYNOS_DRM_DRV_H_ #define _EXYNOS_DRM_DRV_H_ +#include #include #define MAX_CRTC 3 @@ -36,9 +37,6 @@ #define wait_for(COND, MS) _wait_for(COND, MS) -struct drm_device; -struct drm_connector; - /* This enumerates device type. */ enum exynos_drm_device_type { EXYNOS_DEVICE_TYPE_NONE, From cc2d861c5f3421a1b0ba498cb9f0ecb5b3a3eb1c Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 13 Nov 2014 17:24:06 +0900 Subject: [PATCH 15/58] drm/exynos: Replace repeated declarations by #include "exynos_drm_drv.h" Re-declare struct is not a good practice, let's use the original drm and exynos declarations. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index 690dcddab725..e353d353836f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -15,10 +15,7 @@ #ifndef _EXYNOS_DRM_CRTC_H_ #define _EXYNOS_DRM_CRTC_H_ -struct drm_device; -struct drm_crtc; -struct exynos_drm_manager; -struct exynos_drm_overlay; +#include "exynos_drm_drv.h" int exynos_drm_crtc_create(struct exynos_drm_manager *manager); int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe); From 5d0e6fec7f012a9518ff042fd6102dda6c79089e Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 31 Oct 2014 14:17:40 +0000 Subject: [PATCH 16/58] drm/exynos: remove unused wait_for macro This is a leftover, all code using this macro have been removed/ changed already. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 780698139e67..9e4a7e11b6c8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -23,20 +23,6 @@ #define MAX_FB_BUFFER 4 #define DEFAULT_ZPOS -1 -#define _wait_for(COND, MS) ({ \ - unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ - int ret__ = 0; \ - while (!(COND)) { \ - if (time_after(jiffies, timeout__)) { \ - ret__ = -ETIMEDOUT; \ - break; \ - } \ - } \ - ret__; \ -}) - -#define wait_for(COND, MS) _wait_for(COND, MS) - /* This enumerates device type. */ enum exynos_drm_device_type { EXYNOS_DEVICE_TYPE_NONE, From 4a5827fbc26edfce0d8d0839fdf22cd436f0ae5b Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 13 Nov 2014 17:25:53 +0900 Subject: [PATCH 17/58] drm/exynos: Save up space using bool var as bitfields Save a few bytes by compiling them all in the same byte. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 9e4a7e11b6c8..f77e6aafd3ec 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -66,10 +66,10 @@ enum exynos_drm_output_type { * @dma_addr: array of bus(accessed by dma) address to the memory region * allocated for a overlay. * @zpos: order of overlay layer(z position). - * @default_win: a window to be enabled. - * @color_key: color key on or off. * @index_color: if using color key feature then this value would be used * as index color. + * @default_win: a window to be enabled. + * @color_key: color key on or off. * @local_path: in case of lcd type, local path mode on or off. * @transparency: transparency on or off. * @activated: activated or not. @@ -97,13 +97,13 @@ struct exynos_drm_overlay { uint32_t pixel_format; dma_addr_t dma_addr[MAX_FB_BUFFER]; int zpos; - - bool default_win; - bool color_key; unsigned int index_color; - bool local_path; - bool transparency; - bool activated; + + bool default_win:1; + bool color_key:1; + bool local_path:1; + bool transparency:1; + bool activated:1; }; /* From 60cb85862e7c12eff855fece28034f7cd3fa6edd Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 31 Oct 2014 14:17:42 +0000 Subject: [PATCH 18/58] drm/exynos: update documentation to reflect code changes Description of the @create_connector callback was missing, and the @manager was no longer needed. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index f77e6aafd3ec..e762cbb67aea 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -110,6 +110,7 @@ struct exynos_drm_overlay { * Exynos DRM Display Structure. * - 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 @@ -262,8 +263,6 @@ struct exynos_drm_private { * @dev: pointer to device object for subdrv device driver. * @drm_dev: pointer to drm_device and this pointer would be set * when sub driver calls exynos_drm_subdrv_register(). - * @manager: subdrv has its own manager to control a hardware appropriately - * and we can access a hardware drawing on this manager. * @probe: this callback would be called by exynos drm driver after * subdrv is registered to it. * @remove: this callback is used to release resources created From 975588477220cfb32375ace1caafbdbbb9d75e70 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 31 Oct 2014 14:17:43 +0000 Subject: [PATCH 19/58] drm/exynos: remove leftover hdmi function declarations They are not implemented anywhere, so wipe them out. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index e762cbb67aea..262a4590ddb2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -294,17 +294,6 @@ int exynos_drm_device_subdrv_remove(struct drm_device *dev); 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); -/* - * this function registers exynos drm hdmi platform device. It ensures only one - * instance of the device is created. - */ -int exynos_platform_device_hdmi_register(void); - -/* - * this function unregisters exynos drm hdmi platform device if it exists. - */ -void exynos_platform_device_hdmi_unregister(void); - #ifdef CONFIG_DRM_EXYNOS_IPP int exynos_platform_device_ipp_register(void); void exynos_platform_device_ipp_unregister(void); From b128aefe0b0409c77123586e5243bee415f84f5b Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Wed, 12 Nov 2014 15:12:10 +0530 Subject: [PATCH 20/58] drm/exynos: dp: Remove support for unused dptx-phy Now that we have moved to generic phy based bindings, we don't need to have any code related to older dptx-phy. Nobody is using this dptx-phy anymore, so removing the same. Signed-off-by: Vivek Gautam Acked-by: Jingoo Han Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_dp_core.c | 74 ++++++------------------- drivers/gpu/drm/exynos/exynos_dp_core.h | 2 - 2 files changed, 17 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 6adb1e5cfb08..ed818b9a615a 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1052,28 +1052,14 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display, static void exynos_dp_phy_init(struct exynos_dp_device *dp) { - if (dp->phy) { + if (dp->phy) phy_power_on(dp->phy); - } else if (dp->phy_addr) { - u32 reg; - - reg = __raw_readl(dp->phy_addr); - reg |= dp->enable_mask; - __raw_writel(reg, dp->phy_addr); - } } static void exynos_dp_phy_exit(struct exynos_dp_device *dp) { - if (dp->phy) { + if (dp->phy) phy_power_off(dp->phy); - } else if (dp->phy_addr) { - u32 reg; - - reg = __raw_readl(dp->phy_addr); - reg &= ~(dp->enable_mask); - __raw_writel(reg, dp->phy_addr); - } } static void exynos_dp_poweron(struct exynos_drm_display *display) @@ -1210,44 +1196,6 @@ static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev) return dp_video_config; } -static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp) -{ - struct device_node *dp_phy_node = of_node_get(dp->dev->of_node); - u32 phy_base; - int ret = 0; - - dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy"); - if (!dp_phy_node) { - dp->phy = devm_phy_get(dp->dev, "dp"); - return PTR_ERR_OR_ZERO(dp->phy); - } - - if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) { - dev_err(dp->dev, "failed to get reg for dptx-phy\n"); - ret = -EINVAL; - goto err; - } - - if (of_property_read_u32(dp_phy_node, "samsung,enable-mask", - &dp->enable_mask)) { - dev_err(dp->dev, "failed to get enable-mask for dptx-phy\n"); - ret = -EINVAL; - goto err; - } - - dp->phy_addr = ioremap(phy_base, SZ_4); - if (!dp->phy_addr) { - dev_err(dp->dev, "failed to ioremap dp-phy\n"); - ret = -ENOMEM; - goto err; - } - -err: - of_node_put(dp_phy_node); - - return ret; -} - static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp) { int ret; @@ -1277,9 +1225,21 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) if (IS_ERR(dp->video_info)) return PTR_ERR(dp->video_info); - ret = exynos_dp_dt_parse_phydata(dp); - if (ret) - return ret; + dp->phy = devm_phy_get(dp->dev, "dp"); + if (IS_ERR(dp->phy)) { + dev_err(dp->dev, "no DP phy configured\n"); + ret = PTR_ERR(dp->phy); + if (ret) { + /* + * phy itself is not enabled, so we can move forward + * assigning NULL to phy pointer. + */ + if (ret == -ENOSYS || ret == -ENODEV) + dp->phy = NULL; + else + return ret; + } + } if (!dp->panel) { ret = exynos_dp_dt_parse_panel(dp); diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h index a1aee6931bd7..6426201667bc 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.h +++ b/drivers/gpu/drm/exynos/exynos_dp_core.h @@ -153,8 +153,6 @@ struct exynos_dp_device { struct clk *clock; unsigned int irq; void __iomem *reg_base; - void __iomem *phy_addr; - unsigned int enable_mask; struct video_info *video_info; struct link_train link_train; From 4bc6d6445e0c0b724d4232fcc1f127bde3a4ddbd Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Fri, 7 Nov 2014 15:12:24 +0900 Subject: [PATCH 21/58] drm/exynos: dsi: support Exynos4415 SoC This patch supports Exynos4415 SoC. Signed-off-by: YoungJun Cho Acked-by: Kyungmin Park Signed-off-by: Inki Dae --- Documentation/devicetree/bindings/video/exynos_dsim.txt | 1 + drivers/gpu/drm/exynos/exynos_drm_dsi.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/video/exynos_dsim.txt b/Documentation/devicetree/bindings/video/exynos_dsim.txt index e74243b4b317..ca2b4aacd9af 100644 --- a/Documentation/devicetree/bindings/video/exynos_dsim.txt +++ b/Documentation/devicetree/bindings/video/exynos_dsim.txt @@ -4,6 +4,7 @@ Required properties: - compatible: value should be one of the following "samsung,exynos3250-mipi-dsi" /* for Exynos3250/3472 SoCs */ "samsung,exynos4210-mipi-dsi" /* for Exynos4 SoCs */ + "samsung,exynos4415-mipi-dsi" /* for Exynos4415 SoC */ "samsung,exynos5410-mipi-dsi" /* for Exynos5410/5420/5440 SoCs */ - reg: physical base address and length of the registers set for the device - interrupts: should contain DSI interrupt diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 5e38d158089b..e0e8c388b107 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -321,6 +321,11 @@ static struct exynos_dsi_driver_data exynos4_dsi_driver_data = { .has_clklane_stop = 1, }; +static struct exynos_dsi_driver_data exynos4415_dsi_driver_data = { + .plltmr_reg = 0x58, + .has_clklane_stop = 1, +}; + static struct exynos_dsi_driver_data exynos5_dsi_driver_data = { .plltmr_reg = 0x58, }; @@ -330,6 +335,8 @@ static struct of_device_id exynos_dsi_of_match[] = { .data = &exynos3_dsi_driver_data }, { .compatible = "samsung,exynos4210-mipi-dsi", .data = &exynos4_dsi_driver_data }, + { .compatible = "samsung,exynos4415-mipi-dsi", + .data = &exynos4415_dsi_driver_data }, { .compatible = "samsung,exynos5410-mipi-dsi", .data = &exynos5_dsi_driver_data }, { } From dcb622aa882b1108c005ebf629014acbf22690e3 Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Fri, 7 Nov 2014 15:12:25 +0900 Subject: [PATCH 22/58] drm/exynos: fimd: support Exynos4415 SoC This patch supports Exynos4415 SoC. Signed-off-by: YoungJun Cho Acked-by: Kyungmin Park Signed-off-by: Inki Dae --- .../devicetree/bindings/video/samsung-fimd.txt | 1 + drivers/gpu/drm/exynos/exynos_drm_fimd.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/video/samsung-fimd.txt b/Documentation/devicetree/bindings/video/samsung-fimd.txt index 4e6c77c85546..cf1af6371021 100644 --- a/Documentation/devicetree/bindings/video/samsung-fimd.txt +++ b/Documentation/devicetree/bindings/video/samsung-fimd.txt @@ -11,6 +11,7 @@ Required properties: "samsung,s5pv210-fimd"; /* for S5PV210 SoC */ "samsung,exynos3250-fimd"; /* for Exynos3250/3472 SoCs */ "samsung,exynos4210-fimd"; /* for Exynos4 SoCs */ + "samsung,exynos4415-fimd"; /* for Exynos4415 SoC */ "samsung,exynos5250-fimd"; /* for Exynos5 SoCs */ - reg: physical base address and length of the FIMD registers set. diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 085b066a9993..5dfbbdba9591 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -120,6 +120,15 @@ static struct fimd_driver_data exynos4_fimd_driver_data = { .has_shadowcon = 1, }; +static struct fimd_driver_data exynos4415_fimd_driver_data = { + .timing_base = 0x20000, + .lcdblk_offset = 0x210, + .lcdblk_vt_shift = 10, + .lcdblk_bypass_shift = 1, + .has_shadowcon = 1, + .has_vidoutcon = 1, +}; + static struct fimd_driver_data exynos5_fimd_driver_data = { .timing_base = 0x20000, .lcdblk_offset = 0x214, @@ -180,6 +189,8 @@ static const struct of_device_id fimd_driver_dt_match[] = { .data = &exynos3_fimd_driver_data }, { .compatible = "samsung,exynos4210-fimd", .data = &exynos4_fimd_driver_data }, + { .compatible = "samsung,exynos4415-fimd", + .data = &exynos4415_fimd_driver_data }, { .compatible = "samsung,exynos5250-fimd", .data = &exynos5_fimd_driver_data }, {}, From bd953de94393ef2a00e893aa948cc7c4cb190d00 Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Wed, 1 Oct 2014 15:19:07 +0900 Subject: [PATCH 23/58] drm/exynos: fimd: remove unnecessary waiting vblank routine The exynos_drm_crtc_dpms() waits until pended page flip queue is empty, calls the drm_vblank_off() then calls manager->ops->dpms() when mode is DRM_MODE_DPMS_OFF. The fimd_dpms() is one of manager->ops->dpms()s and finally calls fimd_window_suspend(). But there is no active window and vblank is already off when it is called. So addtional waiting vblank is not necessary any more. Signed-off-by: YoungJun Cho Acked-by: Inki Dae Acked-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 5dfbbdba9591..1f46c89f0e08 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -814,7 +814,6 @@ static void fimd_window_suspend(struct exynos_drm_manager *mgr) if (win_data->enabled) fimd_win_disable(mgr, i); } - fimd_wait_for_vblank(mgr); } static void fimd_window_resume(struct exynos_drm_manager *mgr) From b301ae24bb22cb6cf762b174426105c85621b1b7 Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Wed, 1 Oct 2014 15:19:10 +0900 Subject: [PATCH 24/58] drm/exynos: fimd: move handle vblank position in TE handler For providing VBLANK information, drm_handle_vblank() should be called properly, but it is blocked by wait_vsync_event condition which is set by manager_ops->wait_for_vblank(). So moves it out from wait_vsync_event routine. Signed-off-by: YoungJun Cho Acked-by: Inki Dae Acked-by: Kyungmin Park Acked-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 1f46c89f0e08..7593f629c9fb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -982,10 +982,10 @@ static void fimd_te_handler(struct exynos_drm_manager *mgr) if (atomic_read(&ctx->wait_vsync_event)) { atomic_set(&ctx->wait_vsync_event, 0); wake_up(&ctx->wait_vsync_queue); - - if (!atomic_read(&ctx->triggering)) - drm_handle_vblank(ctx->drm_dev, ctx->pipe); } + + if (!atomic_read(&ctx->triggering)) + drm_handle_vblank(ctx->drm_dev, ctx->pipe); } static struct exynos_drm_manager_ops fimd_manager_ops = { From d41bb38f228d98a2e411d59be14a2aee876d8db1 Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Wed, 1 Oct 2014 15:19:13 +0900 Subject: [PATCH 25/58] drm/exynos: dsi: move DSIM_STATE_ENABLED set position The command mode panel should draw image earlier than the display on command execution to prevent showing garbage GRAM screen data. So should set dsi->state as DSIM_STATE_ENABLED between calling exynos_dsi_set_display_enable() and drm_panel_enable() to transmit image data before executing display on command. And moves the display on command execution routine from prepare() to enable() in drm_panel_funcs also. Signed-off-by: YoungJun Cho Acked-by: Inki Dae Acked-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index e0e8c388b107..44461aa35ccd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1381,16 +1381,17 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) exynos_dsi_set_display_mode(dsi); exynos_dsi_set_display_enable(dsi, true); + dsi->state |= DSIM_STATE_ENABLED; + ret = drm_panel_enable(dsi->panel); if (ret < 0) { + dsi->state &= ~DSIM_STATE_ENABLED; exynos_dsi_set_display_enable(dsi, false); drm_panel_unprepare(dsi->panel); exynos_dsi_poweroff(dsi); return ret; } - dsi->state |= DSIM_STATE_ENABLED; - return 0; } From 030794a368946b98a8252d3172f5f2a1b0e4fb0e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 7 Nov 2014 14:53:58 +0100 Subject: [PATCH 26/58] drm/exynos: Fix DSI resuming fail because power domain being off During system resume from suspend to RAM the Exynos DRM driver forced CRTC mode thus turning display on (DPMS_ON). This lead to runtime resuming of DSI which failed because whole LCD power domain was off and it was not allowed to turn on because of system resume in progress. Forcing mode should not be needed and removing it solves this particular problem. This necessary fix for following scenario reproduced on Exynos DRM: 1. Power domain is off before suspending the system. 2. System is suspended to RAM. 3. Resuming starts. The Exynos DRM driver resume callback is called. 4. The Exynos DRM driver calls drm_helper_resume_force_mode() which turns on the screen by calling exynos_dsi_dpms with DRM_MODE_DPMS_ON. 5. The Exynos DSI driver calls pm_runtime_get. The driver runtime resumes and this should turn LCD power domain on. 6. Unfortunately the domain cannot be turned on because system resume is in progress and genpd->prepared_count is positive. Steps to reproduce: 1. Add runtime PM to Exynos DSI driver. 2. Build Exynos DRM/FB without FRAMEBUFFER_CONSOLE. 3. Enable the connector and screen (e.g. with modeset-vsync). 4. echo 3 > /sys/devices/platform/exynos-drm/graphics/fb0/blank 5. echo mem > /sys/power/state 6. Resume. [ 77.712469] PM: early resume of devices complete after 3.854 msecs [ 77.712739] exynos-dsi 11c80000.dsi: pm_genpd_resume() [ 77.712758] exynos4-fimc 11800000.fimc: pm_genpd_resume() [ 77.712774] exynos4-fimc 11810000.fimc: pm_genpd_resume() [ 77.712787] exynos-drm-fimc 11820000.fimc: pm_genpd_resume() [ 77.712802] exynos-drm-fimc 11830000.fimc: pm_genpd_resume() [ 77.712815] s5p-mipi-csis 11880000.csis: pm_genpd_resume() [ 77.712829] s5p-mipi-csis 11890000.csis: pm_genpd_resume() [ 77.712843] exynos-fimc-lite 12390000.fimc-lite: pm_genpd_resume() [ 77.712856] exynos-fimc-lite 123a0000.fimc-lite: pm_genpd_resume() [ 77.713788] exynos4-fb 11c00000.fimd: pm_genpd_resume() [ 77.713912] wake disabled for irq 184 [ 77.713923] wake disabled for irq 185 [ 77.714082] wake disabled for irq 173 [ 77.715676] wake disabled for irq 176 [ 77.718540] exynos4-fb 11c00000.fimd: pm_genpd_runtime_resume() [ 77.718567] exynos4-fb 11c00000.fimd: state restore latency exceeded, new value 1708 ns [ 77.718636] exynos-dsi 11c80000.dsi: pm_genpd_runtime_resume() [ 77.892366] exynos-dsi 11c80000.dsi: PLL failed to stabilize [ 77.892377] exynos-dsi 11c80000.dsi: failed to configure DSI PLL [ 78.192168] exynos-dsi 11c80000.dsi: timeout waiting for reset [ 78.211578] exynos-dsi 11c80000.dsi: waiting for bus lanes timed out [ 78.307173] exynos-dsi 11c80000.dsi: xfer timed out: d1 00 (null) [ 78.307190] panel_s6e8aa0 11c80000.dsi.0: error -110 reading dcs seq(0xd1) [ 78.307199] panel_s6e8aa0 11c80000.dsi.0: read id failed Signed-off-by: Krzysztof Kozlowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 8aee62902ec6..eab12f084709 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -194,8 +194,6 @@ static int exynos_drm_resume(struct drm_device *dev) } drm_modeset_unlock_all(dev); - drm_helper_resume_force_mode(dev); - return 0; } From 3c3c9c1d904dca30f89882b97822fdf025b115c9 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 14 Nov 2014 11:36:02 +0900 Subject: [PATCH 27/58] drm/exynos: add has_vtsel flag The exynos fimd provides video type selection bits from system register but exynos3 series don't has it, so needs has_vtsel flag and we can distinguish whether set video type selection bits. Signed-off-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 7593f629c9fb..0673a39a5b03 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -96,6 +96,7 @@ struct fimd_driver_data { unsigned int has_clksel:1; unsigned int has_limited_fmt:1; unsigned int has_vidoutcon:1; + unsigned int has_vtsel:1; }; static struct fimd_driver_data s3c64xx_fimd_driver_data = { @@ -118,6 +119,7 @@ static struct fimd_driver_data exynos4_fimd_driver_data = { .lcdblk_vt_shift = 10, .lcdblk_bypass_shift = 1, .has_shadowcon = 1, + .has_vtsel = 1, }; static struct fimd_driver_data exynos4415_fimd_driver_data = { @@ -127,6 +129,7 @@ static struct fimd_driver_data exynos4415_fimd_driver_data = { .lcdblk_bypass_shift = 1, .has_shadowcon = 1, .has_vidoutcon = 1, + .has_vtsel = 1, }; static struct fimd_driver_data exynos5_fimd_driver_data = { @@ -136,6 +139,7 @@ static struct fimd_driver_data exynos5_fimd_driver_data = { .lcdblk_bypass_shift = 15, .has_shadowcon = 1, .has_vidoutcon = 1, + .has_vtsel = 1, }; struct fimd_win_data { @@ -354,7 +358,8 @@ static void fimd_commit(struct exynos_drm_manager *mgr) writel(0, timing_base + I80IFCONFBx(0)); /* set video type selection to I80 interface */ - if (ctx->sysreg && regmap_update_bits(ctx->sysreg, + if (driver_data->has_vtsel && ctx->sysreg && + regmap_update_bits(ctx->sysreg, driver_data->lcdblk_offset, 0x3 << driver_data->lcdblk_vt_shift, 0x1 << driver_data->lcdblk_vt_shift)) { From 9b67eb7365725ed00dde4714d71d4afe205329b2 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Mon, 17 Nov 2014 22:00:08 +0900 Subject: [PATCH 28/58] drm/exynos: move triggering checking It's better to be checking whether triggerring in fimd_trigger function. Also it will return if in triggerring on fimd_te_handler, then it can't execute remain codes. Signed-off-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 0673a39a5b03..ec2d1702b93b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -949,6 +949,13 @@ static void fimd_trigger(struct device *dev) void *timing_base = ctx->regs + driver_data->timing_base; u32 reg; + /* + * Skips to trigger if in triggering state, because multiple triggering + * requests can cause panel reset. + */ + if (atomic_read(&ctx->triggering)) + return; + atomic_set(&ctx->triggering, 1); reg = readl(ctx->regs + VIDINTCON0); @@ -969,13 +976,6 @@ static void fimd_te_handler(struct exynos_drm_manager *mgr) if (ctx->pipe < 0 || !ctx->drm_dev) return; - /* - * Skips to trigger if in triggering state, because multiple triggering - * requests can cause panel reset. - */ - if (atomic_read(&ctx->triggering)) - return; - /* * If there is a page flip request, triggers and handles the page flip * event so that current fb can be updated into panel GRAM. From 74944a58f9def188d506d3eef19fd34f293219f7 Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 17 Nov 2014 22:00:09 +0900 Subject: [PATCH 29/58] drm/exynos: fimd: move shadow unprotection position The C#_EN_F in SHADOWCON register is updated per frame. So it should be protected by fimd_shadow_protect_win(). Signed-off-by: YoungJun Cho Acked-by: Inki Dae Acked-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index ec2d1702b93b..77ba961e1ddd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -751,15 +751,15 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) val |= WINCONx_ENWIN; writel(val, ctx->regs + WINCON(win)); - /* Enable DMA channel and unprotect windows */ - fimd_shadow_protect_win(ctx, win, false); - if (ctx->driver_data->has_shadowcon) { val = readl(ctx->regs + SHADOWCON); val |= SHADOWCON_CHx_ENABLE(win); writel(val, ctx->regs + SHADOWCON); } + /* Enable DMA channel and unprotect windows */ + fimd_shadow_protect_win(ctx, win, false); + win_data->enabled = true; if (ctx->i80_if) From f181a543c76fdcf240ef39d24520141070701bdc Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 17 Nov 2014 22:00:10 +0900 Subject: [PATCH 30/58] drm/exynos: fimd: add fimd_enable_video_output() to cleanup This bit is used for video output and logic signal control. So it is better for readability. Signed-off-by: YoungJun Cho Acked-by: Inki Dae Acked-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 27 ++++++++++++++---------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 77ba961e1ddd..5cfd25147374 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -229,6 +229,19 @@ static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr) DRM_DEBUG_KMS("vblank wait timed out.\n"); } +static void fimd_enable_video_output(struct fimd_context *ctx, int win, + bool enable) +{ + u32 val = readl(ctx->regs + WINCON(win)); + + if (enable) + val |= WINCONx_ENWIN; + else + val &= ~WINCONx_ENWIN; + + writel(val, ctx->regs + WINCON(win)); +} + static void fimd_clear_channel(struct exynos_drm_manager *mgr) { struct fimd_context *ctx = mgr->ctx; @@ -241,9 +254,7 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr) u32 val = readl(ctx->regs + WINCON(win)); if (val & WINCONx_ENWIN) { - /* wincon */ - val &= ~WINCONx_ENWIN; - writel(val, ctx->regs + WINCON(win)); + fimd_enable_video_output(ctx, win, false); /* unprotect windows */ if (ctx->driver_data->has_shadowcon) { @@ -746,10 +757,7 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) if (win != 0) fimd_win_set_colkey(ctx, win); - /* wincon */ - val = readl(ctx->regs + WINCON(win)); - val |= WINCONx_ENWIN; - writel(val, ctx->regs + WINCON(win)); + fimd_enable_video_output(ctx, win, true); if (ctx->driver_data->has_shadowcon) { val = readl(ctx->regs + SHADOWCON); @@ -790,10 +798,7 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) /* protect windows */ fimd_shadow_protect_win(ctx, win, true); - /* wincon */ - val = readl(ctx->regs + WINCON(win)); - val &= ~WINCONx_ENWIN; - writel(val, ctx->regs + WINCON(win)); + fimd_enable_video_output(ctx, win, false); /* unprotect windows */ if (ctx->driver_data->has_shadowcon) { From 999d8b31fac3629b8179d7a40b7930deedadeb99 Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 17 Nov 2014 22:00:11 +0900 Subject: [PATCH 31/58] drm/exynos: fimd: add fimd_enable_shadow_channel_path() to cleanup This function is valid only the SoC has SHADOWCON register and it should be used together with fimd_enable_video_output() to match the ENWIN_F bit in WINCON# and C#_EN_F bit in SHADOWCON. Signed-off-by: YoungJun Cho Acked-by: Inki Dae Acked-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 40 +++++++++++++----------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 5cfd25147374..fd7b46959903 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -242,6 +242,19 @@ static void fimd_enable_video_output(struct fimd_context *ctx, int win, writel(val, ctx->regs + WINCON(win)); } +static void fimd_enable_shadow_channel_path(struct fimd_context *ctx, int win, + bool enable) +{ + u32 val = readl(ctx->regs + SHADOWCON); + + if (enable) + val |= SHADOWCON_CHx_ENABLE(win); + else + val &= ~SHADOWCON_CHx_ENABLE(win); + + writel(val, ctx->regs + SHADOWCON); +} + static void fimd_clear_channel(struct exynos_drm_manager *mgr) { struct fimd_context *ctx = mgr->ctx; @@ -256,12 +269,10 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr) if (val & WINCONx_ENWIN) { fimd_enable_video_output(ctx, win, false); - /* unprotect windows */ - if (ctx->driver_data->has_shadowcon) { - val = readl(ctx->regs + SHADOWCON); - val &= ~SHADOWCON_CHx_ENABLE(win); - writel(val, ctx->regs + SHADOWCON); - } + if (ctx->driver_data->has_shadowcon) + fimd_enable_shadow_channel_path(ctx, win, + false); + ch_enabled = 1; } } @@ -759,11 +770,8 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) fimd_enable_video_output(ctx, win, true); - if (ctx->driver_data->has_shadowcon) { - val = readl(ctx->regs + SHADOWCON); - val |= SHADOWCON_CHx_ENABLE(win); - writel(val, ctx->regs + SHADOWCON); - } + if (ctx->driver_data->has_shadowcon) + fimd_enable_shadow_channel_path(ctx, win, true); /* Enable DMA channel and unprotect windows */ fimd_shadow_protect_win(ctx, win, false); @@ -779,7 +787,6 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) struct fimd_context *ctx = mgr->ctx; struct fimd_win_data *win_data; int win = zpos; - u32 val; if (win == DEFAULT_ZPOS) win = ctx->default_win; @@ -800,13 +807,10 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) fimd_enable_video_output(ctx, win, false); - /* unprotect windows */ - if (ctx->driver_data->has_shadowcon) { - val = readl(ctx->regs + SHADOWCON); - val &= ~SHADOWCON_CHx_ENABLE(win); - writel(val, ctx->regs + SHADOWCON); - } + if (ctx->driver_data->has_shadowcon) + fimd_enable_shadow_channel_path(ctx, win, false); + /* unprotect windows */ fimd_shadow_protect_win(ctx, win, false); win_data->enabled = false; From 1c905d9508932ed85eee5469519aedc2d820458e Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 17 Nov 2014 22:00:12 +0900 Subject: [PATCH 32/58] drm/exynos: fimd: modify I80 i/f irq relevant routine For the I80 interface, the video interrupt pending register(VIDINTCON1) should be handled in fimd_irq_handler() and the video interrupt control register(VIDINTCON0) should be handled in fimd_enable_vblank() and fimd_disable_vblank() like RGB interface. So this patch moves each set / unset routines into proper positions. Signed-off-by: YoungJun Cho Acked-by: Inki Dae Acked-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 53 ++++++++++++------------ 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index fd7b46959903..3c632370e983 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -469,12 +469,19 @@ static int fimd_enable_vblank(struct exynos_drm_manager *mgr) val = readl(ctx->regs + VIDINTCON0); val |= VIDINTCON0_INT_ENABLE; - val |= VIDINTCON0_INT_FRAME; - val &= ~VIDINTCON0_FRAMESEL0_MASK; - val |= VIDINTCON0_FRAMESEL0_VSYNC; - val &= ~VIDINTCON0_FRAMESEL1_MASK; - val |= VIDINTCON0_FRAMESEL1_NONE; + if (ctx->i80_if) { + val |= VIDINTCON0_INT_I80IFDONE; + val |= VIDINTCON0_INT_SYSMAINCON; + val &= ~VIDINTCON0_INT_SYSSUBCON; + } else { + val |= VIDINTCON0_INT_FRAME; + + val &= ~VIDINTCON0_FRAMESEL0_MASK; + val |= VIDINTCON0_FRAMESEL0_VSYNC; + val &= ~VIDINTCON0_FRAMESEL1_MASK; + val |= VIDINTCON0_FRAMESEL1_NONE; + } writel(val, ctx->regs + VIDINTCON0); } @@ -493,9 +500,15 @@ static void fimd_disable_vblank(struct exynos_drm_manager *mgr) if (test_and_clear_bit(0, &ctx->irq_flags)) { val = readl(ctx->regs + VIDINTCON0); - val &= ~VIDINTCON0_INT_FRAME; val &= ~VIDINTCON0_INT_ENABLE; + if (ctx->i80_if) { + val &= ~VIDINTCON0_INT_I80IFDONE; + val &= ~VIDINTCON0_INT_SYSMAINCON; + val &= ~VIDINTCON0_INT_SYSSUBCON; + } else + val &= ~VIDINTCON0_INT_FRAME; + writel(val, ctx->regs + VIDINTCON0); } } @@ -959,19 +972,15 @@ static void fimd_trigger(struct device *dev) u32 reg; /* - * Skips to trigger if in triggering state, because multiple triggering - * requests can cause panel reset. - */ + * Skips triggering if in triggering state, because multiple triggering + * requests can cause panel reset. + */ if (atomic_read(&ctx->triggering)) return; + /* Enters triggering mode */ atomic_set(&ctx->triggering, 1); - reg = readl(ctx->regs + VIDINTCON0); - reg |= (VIDINTCON0_INT_ENABLE | VIDINTCON0_INT_I80IFDONE | - VIDINTCON0_INT_SYSMAINCON); - writel(reg, ctx->regs + VIDINTCON0); - reg = readl(timing_base + TRIGCON); reg |= (TRGMODE_I80_RGB_ENABLE_I80 | SWTRGCMD_I80_RGB_ENABLE); writel(reg, timing_base + TRIGCON); @@ -1036,21 +1045,13 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) if (ctx->pipe < 0 || !ctx->drm_dev) goto out; + drm_handle_vblank(ctx->drm_dev, ctx->pipe); + exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + if (ctx->i80_if) { - /* unset I80 frame done interrupt */ - val = readl(ctx->regs + VIDINTCON0); - val &= ~(VIDINTCON0_INT_I80IFDONE | VIDINTCON0_INT_SYSMAINCON); - writel(val, ctx->regs + VIDINTCON0); - - /* exit triggering mode */ + /* Exits triggering mode */ atomic_set(&ctx->triggering, 0); - - drm_handle_vblank(ctx->drm_dev, ctx->pipe); - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); } else { - drm_handle_vblank(ctx->drm_dev, ctx->pipe); - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); - /* set wait vsync event to zero and wake up queue. */ if (atomic_read(&ctx->wait_vsync_event)) { atomic_set(&ctx->wait_vsync_event, 0); From 87ab85b3ccbc266154268407f85777a74f8bf820 Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 17 Nov 2014 22:00:13 +0900 Subject: [PATCH 33/58] drm/exynos: fimd: add triggering unset routine in fimd_trigger() There is a case like set config which requires triggering but vblank is not enabled yet. So triggering unset routine is required to exit from triggering mode. Signed-off-by: YoungJun Cho Acked-by: Inki Dae Acked-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 3c632370e983..e488b80bef5e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -984,6 +984,13 @@ static void fimd_trigger(struct device *dev) reg = readl(timing_base + TRIGCON); reg |= (TRGMODE_I80_RGB_ENABLE_I80 | SWTRGCMD_I80_RGB_ENABLE); writel(reg, timing_base + TRIGCON); + + /* + * Exits triggering mode if vblank is not enabled yet, because when the + * VIDINTCON0 register is not set, it can not exit from triggering mode. + */ + if (!test_bit(0, &ctx->irq_flags)) + atomic_set(&ctx->triggering, 0); } static void fimd_te_handler(struct exynos_drm_manager *mgr) From adf67abff09110b527431512bf05461a60ef2a72 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Mon, 17 Nov 2014 22:00:14 +0900 Subject: [PATCH 34/58] drm/exynos: use irq_flags instead of triggering The drm_handle_vblank should be called whenever be vsync, te interrupt means vsync on i80 interface. Signed-off-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index e488b80bef5e..a8ab3ecb202e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1014,7 +1014,7 @@ static void fimd_te_handler(struct exynos_drm_manager *mgr) wake_up(&ctx->wait_vsync_queue); } - if (!atomic_read(&ctx->triggering)) + if (test_bit(0, &ctx->irq_flags)) drm_handle_vblank(ctx->drm_dev, ctx->pipe); } @@ -1052,13 +1052,15 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) if (ctx->pipe < 0 || !ctx->drm_dev) goto out; - drm_handle_vblank(ctx->drm_dev, ctx->pipe); - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); - if (ctx->i80_if) { + exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + /* 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); + /* set wait vsync event to zero and wake up queue. */ if (atomic_read(&ctx->wait_vsync_event)) { atomic_set(&ctx->wait_vsync_event, 0); From ecb84157b5716f80e6569cd379f3bf560116a803 Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 17 Nov 2014 22:00:15 +0900 Subject: [PATCH 35/58] drm/exynos: dsi: move TE irq handler registration position The drm_helper_hpd_irq_event() does dpms control and the panel is initialized and displayed on by it. So the exynos_dsi_te_irq_handler() should be registered beforehand. Signed-off-by: YoungJun Cho Acked-by: Inki Dae Acked-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 44461aa35ccd..156a6389172a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1207,9 +1207,6 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host, dsi->mode_flags = device->mode_flags; dsi->panel_node = device->dev.of_node; - if (dsi->connector.dev) - drm_helper_hpd_irq_event(dsi->connector.dev); - /* * This is a temporary solution and should be made by more generic way. * @@ -1223,6 +1220,9 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host, return ret; } + if (dsi->connector.dev) + drm_helper_hpd_irq_event(dsi->connector.dev); + return 0; } From 0cef83a5fd3aa72ed7bd8661042cd8405062fcef Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 17 Nov 2014 22:00:16 +0900 Subject: [PATCH 36/58] drm/exynos: dsi: set TE GPIO IRQ status as IRQ_NOAUTOEN The exynos_dsi_te_irq_handler() works only dsi(DPMS) is on. So it is enough to enable and disable TE GPIO IRQ in exynos_dsi_enable(disable)_irq() like DSI IRQ. Signed-off-by: YoungJun Cho Acked-by: Inki Dae a Acked-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 156a6389172a..05fe93dc57a8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1155,6 +1155,7 @@ static int exynos_dsi_init(struct exynos_dsi *dsi) static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi) { int ret; + int te_gpio_irq; dsi->te_gpio = of_get_named_gpio(dsi->panel_node, "te-gpios", 0); if (!gpio_is_valid(dsi->te_gpio)) { @@ -1169,14 +1170,10 @@ static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi) goto out; } - /* - * This TE GPIO IRQ should not be set to IRQ_NOAUTOEN, because panel - * calls drm_panel_init() first then calls mipi_dsi_attach() in probe(). - * It means that te_gpio is invalid when exynos_dsi_enable_irq() is - * called by drm_panel_init() before panel is attached. - */ - ret = request_threaded_irq(gpio_to_irq(dsi->te_gpio), - exynos_dsi_te_irq_handler, NULL, + te_gpio_irq = gpio_to_irq(dsi->te_gpio); + + irq_set_status_flags(te_gpio_irq, IRQ_NOAUTOEN); + ret = request_threaded_irq(te_gpio_irq, exynos_dsi_te_irq_handler, NULL, IRQF_TRIGGER_RISING, "TE", dsi); if (ret) { dev_err(dsi->dev, "request interrupt failed with %d\n", ret); From 8103ef1b5f471fe5e50cd4e1fc17cf3be4682d79 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 24 Nov 2014 14:12:46 +0900 Subject: [PATCH 37/58] drm/exynos/mixer: embed manager into private context exynos_drm_manager is used by internal Exynos DRM framework for representing crtc. As it should be mapped 1:1 to fimd private context it seems more reasonable to embed it directly in that context. As a result further code simplification will be possible. Moreover it will be possible to handle multiple mixer devices in the system. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 100 +++++++++++++------------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index a41c84ee3a2d..1b1fd82ec262 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -40,8 +40,6 @@ #include "exynos_drm_iommu.h" #include "exynos_mixer.h" -#define get_mixer_manager(dev) platform_get_drvdata(to_platform_device(dev)) - #define MIXER_WIN_NR 3 #define MIXER_DEFAULT_WIN 0 @@ -86,6 +84,7 @@ enum mixer_version_id { }; struct mixer_context { + struct exynos_drm_manager manager; struct platform_device *pdev; struct device *dev; struct drm_device *drm_dev; @@ -1187,11 +1186,6 @@ static struct exynos_drm_manager_ops mixer_manager_ops = { .win_disable = mixer_win_disable, }; -static struct exynos_drm_manager mixer_manager = { - .type = EXYNOS_DISPLAY_TYPE_HDMI, - .ops = &mixer_manager_ops, -}; - static struct mixer_drv_data exynos5420_mxr_drv_data = { .version = MXR_VER_128_0_0_184, .is_vp_enabled = 0, @@ -1249,13 +1243,45 @@ MODULE_DEVICE_TABLE(of, mixer_match_types); static int mixer_bind(struct device *dev, struct device *manager, void *data) { - struct platform_device *pdev = to_platform_device(dev); + struct mixer_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; - struct mixer_context *ctx; - struct mixer_drv_data *drv; int ret; - dev_info(dev, "probe start\n"); + ret = mixer_initialize(&ctx->manager, drm_dev); + if (ret) + return ret; + + ret = exynos_drm_crtc_create(&ctx->manager); + if (ret) { + mixer_mgr_remove(&ctx->manager); + return ret; + } + + pm_runtime_enable(dev); + + return 0; +} + +static void mixer_unbind(struct device *dev, struct device *master, void *data) +{ + struct mixer_context *ctx = dev_get_drvdata(dev); + + mixer_mgr_remove(&ctx->manager); + + pm_runtime_disable(dev); +} + +static const struct component_ops mixer_component_ops = { + .bind = mixer_bind, + .unbind = mixer_unbind, +}; + +static int mixer_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mixer_drv_data *drv; + struct mixer_context *ctx; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) { @@ -1265,8 +1291,12 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) mutex_init(&ctx->mixer_mutex); + ctx->manager.type = EXYNOS_DISPLAY_TYPE_HDMI; + ctx->manager.ops = &mixer_manager_ops; + if (dev->of_node) { const struct of_device_id *match; + match = of_match_node(mixer_match_types, dev->of_node); drv = (struct mixer_drv_data *)match->data; } else { @@ -1281,58 +1311,30 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) ctx->mxr_ver = drv->version; init_waitqueue_head(&ctx->wait_vsync_queue); atomic_set(&ctx->wait_vsync_event, 0); + ctx->manager.ctx = ctx; - mixer_manager.ctx = ctx; - ret = mixer_initialize(&mixer_manager, drm_dev); - if (ret) - return ret; - - platform_set_drvdata(pdev, &mixer_manager); - ret = exynos_drm_crtc_create(&mixer_manager); - if (ret) { - mixer_mgr_remove(&mixer_manager); - return ret; - } - - pm_runtime_enable(dev); - - return 0; -} - -static void mixer_unbind(struct device *dev, struct device *master, void *data) -{ - struct exynos_drm_manager *mgr = dev_get_drvdata(dev); - - dev_info(dev, "remove successful\n"); - - mixer_mgr_remove(mgr); - - pm_runtime_disable(dev); -} - -static const struct component_ops mixer_component_ops = { - .bind = mixer_bind, - .unbind = mixer_unbind, -}; - -static int mixer_probe(struct platform_device *pdev) -{ - int ret; + platform_set_drvdata(pdev, ctx); ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC, - mixer_manager.type); + ctx->manager.type); if (ret) return ret; ret = component_add(&pdev->dev, &mixer_component_ops); - if (ret) + if (ret) { exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); + return ret; + } + + pm_runtime_enable(dev); return ret; } static int mixer_remove(struct platform_device *pdev) { + pm_runtime_disable(&pdev->dev); + component_del(&pdev->dev, &mixer_component_ops); exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); From 8f0be8304defc33d32ed26a7b1eec54270b995a7 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 24 Nov 2014 14:14:49 +0900 Subject: [PATCH 38/58] drm/exynos/mixer: stop using manager->ctx pointer The patch replaces accesses to manager->ctx pointer by container_of construct. It will allow to remove ctx field in the future. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 30 +++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 1b1fd82ec262..820b76234ef4 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -103,6 +103,11 @@ struct mixer_context { atomic_t wait_vsync_event; }; +static inline struct mixer_context *mgr_to_mixer(struct exynos_drm_manager *mgr) +{ + return container_of(mgr, struct mixer_context, manager); +} + struct mixer_drv_data { enum mixer_version_id version; bool is_vp_enabled; @@ -853,7 +858,7 @@ static int mixer_initialize(struct exynos_drm_manager *mgr, struct drm_device *drm_dev) { int ret; - struct mixer_context *mixer_ctx = mgr->ctx; + struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); struct exynos_drm_private *priv; priv = drm_dev->dev_private; @@ -884,7 +889,7 @@ static int mixer_initialize(struct exynos_drm_manager *mgr, static void mixer_mgr_remove(struct exynos_drm_manager *mgr) { - struct mixer_context *mixer_ctx = mgr->ctx; + struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); if (is_drm_iommu_supported(mixer_ctx->drm_dev)) drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev); @@ -892,7 +897,7 @@ static void mixer_mgr_remove(struct exynos_drm_manager *mgr) static int mixer_enable_vblank(struct exynos_drm_manager *mgr) { - struct mixer_context *mixer_ctx = mgr->ctx; + struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); struct mixer_resources *res = &mixer_ctx->mixer_res; if (!mixer_ctx->powered) { @@ -909,7 +914,7 @@ static int mixer_enable_vblank(struct exynos_drm_manager *mgr) static void mixer_disable_vblank(struct exynos_drm_manager *mgr) { - struct mixer_context *mixer_ctx = mgr->ctx; + struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); struct mixer_resources *res = &mixer_ctx->mixer_res; /* disable vsync interrupt */ @@ -919,7 +924,7 @@ static void mixer_disable_vblank(struct exynos_drm_manager *mgr) static void mixer_win_mode_set(struct exynos_drm_manager *mgr, struct exynos_drm_overlay *overlay) { - struct mixer_context *mixer_ctx = mgr->ctx; + struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); struct hdmi_win_data *win_data; int win; @@ -970,7 +975,7 @@ static void mixer_win_mode_set(struct exynos_drm_manager *mgr, static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos) { - struct mixer_context *mixer_ctx = mgr->ctx; + struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos; DRM_DEBUG_KMS("win: %d\n", win); @@ -992,7 +997,7 @@ static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos) static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos) { - struct mixer_context *mixer_ctx = mgr->ctx; + struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); struct mixer_resources *res = &mixer_ctx->mixer_res; int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos; unsigned long flags; @@ -1020,7 +1025,7 @@ static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos) static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr) { - struct mixer_context *mixer_ctx = mgr->ctx; + struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); mutex_lock(&mixer_ctx->mixer_mutex); if (!mixer_ctx->powered) { @@ -1047,7 +1052,7 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr) static void mixer_window_suspend(struct exynos_drm_manager *mgr) { - struct mixer_context *ctx = mgr->ctx; + struct mixer_context *ctx = mgr_to_mixer(mgr); struct hdmi_win_data *win_data; int i; @@ -1061,7 +1066,7 @@ static void mixer_window_suspend(struct exynos_drm_manager *mgr) static void mixer_window_resume(struct exynos_drm_manager *mgr) { - struct mixer_context *ctx = mgr->ctx; + struct mixer_context *ctx = mgr_to_mixer(mgr); struct hdmi_win_data *win_data; int i; @@ -1076,7 +1081,7 @@ static void mixer_window_resume(struct exynos_drm_manager *mgr) static void mixer_poweron(struct exynos_drm_manager *mgr) { - struct mixer_context *ctx = mgr->ctx; + struct mixer_context *ctx = mgr_to_mixer(mgr); struct mixer_resources *res = &ctx->mixer_res; mutex_lock(&ctx->mixer_mutex); @@ -1110,7 +1115,7 @@ static void mixer_poweron(struct exynos_drm_manager *mgr) static void mixer_poweroff(struct exynos_drm_manager *mgr) { - struct mixer_context *ctx = mgr->ctx; + struct mixer_context *ctx = mgr_to_mixer(mgr); struct mixer_resources *res = &ctx->mixer_res; mutex_lock(&ctx->mixer_mutex); @@ -1311,7 +1316,6 @@ static int mixer_probe(struct platform_device *pdev) ctx->mxr_ver = drv->version; init_waitqueue_head(&ctx->wait_vsync_queue); atomic_set(&ctx->wait_vsync_event, 0); - ctx->manager.ctx = ctx; platform_set_drvdata(pdev, ctx); From f01833cd2b36767d350c4f8b3eaaf48c4d2f7da3 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 17 Nov 2014 09:54:16 +0100 Subject: [PATCH 39/58] drm/exynos/vidi: embed manager into private context exynos_drm_manager is used by internal Exynos DRM framework for representing crtc. As it should be mapped 1:1 to vidi private context it seems more reasonable to embed it directly in that context. As a result further code simplification will be possible. Moreover it will be possible to handle multiple mixer devices in the system. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 44 ++++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 50faf913e574..f47939c4a303 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -28,7 +28,6 @@ /* vidi has totally three virtual windows. */ #define WINDOWS_NR 3 -#define get_vidi_mgr(dev) platform_get_drvdata(to_platform_device(dev)) #define ctx_from_connector(c) container_of(c, struct vidi_context, \ connector) @@ -47,6 +46,7 @@ struct vidi_win_data { }; struct vidi_context { + struct exynos_drm_manager manager; struct drm_device *drm_dev; struct drm_crtc *crtc; struct drm_encoder *encoder; @@ -316,11 +316,6 @@ static struct exynos_drm_manager_ops vidi_manager_ops = { .win_disable = vidi_win_disable, }; -static struct exynos_drm_manager vidi_manager = { - .type = EXYNOS_DISPLAY_TYPE_VIDI, - .ops = &vidi_manager_ops, -}; - static void vidi_fake_vblank_handler(struct work_struct *work) { struct vidi_context *ctx = container_of(work, struct vidi_context, @@ -349,9 +344,8 @@ static void vidi_fake_vblank_handler(struct work_struct *work) static int vidi_show_connection(struct device *dev, struct device_attribute *attr, char *buf) { + struct vidi_context *ctx = dev_get_drvdata(dev); int rc; - struct exynos_drm_manager *mgr = get_vidi_mgr(dev); - struct vidi_context *ctx = mgr->ctx; mutex_lock(&ctx->lock); @@ -366,8 +360,7 @@ static int vidi_store_connection(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct exynos_drm_manager *mgr = get_vidi_mgr(dev); - struct vidi_context *ctx = mgr->ctx; + struct vidi_context *ctx = dev_get_drvdata(dev); int ret; ret = kstrtoint(buf, 0, &ctx->connected); @@ -563,14 +556,13 @@ static struct exynos_drm_display vidi_display = { static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev) { - struct exynos_drm_manager *mgr = get_vidi_mgr(dev); - struct vidi_context *ctx = mgr->ctx; + struct vidi_context *ctx = dev_get_drvdata(dev); struct drm_crtc *crtc = ctx->crtc; int ret; - vidi_mgr_initialize(mgr, drm_dev); + vidi_mgr_initialize(&ctx->manager, drm_dev); - ret = exynos_drm_crtc_create(&vidi_manager); + ret = exynos_drm_crtc_create(&ctx->manager); if (ret) { DRM_ERROR("failed to create crtc.\n"); return ret; @@ -596,16 +588,18 @@ static int vidi_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; + ctx->manager.type = EXYNOS_DISPLAY_TYPE_VIDI; + ctx->manager.ops = &vidi_manager_ops; ctx->default_win = 0; INIT_WORK(&ctx->work, vidi_fake_vblank_handler); - vidi_manager.ctx = ctx; + ctx->manager.ctx = ctx; vidi_display.ctx = ctx; mutex_init(&ctx->lock); - platform_set_drvdata(pdev, &vidi_manager); + platform_set_drvdata(pdev, ctx); subdrv = &ctx->subdrv; subdrv->dev = &pdev->dev; @@ -628,8 +622,7 @@ static int vidi_probe(struct platform_device *pdev) static int vidi_remove(struct platform_device *pdev) { - struct exynos_drm_manager *mgr = platform_get_drvdata(pdev); - struct vidi_context *ctx = mgr->ctx; + struct vidi_context *ctx = platform_get_drvdata(pdev); if (ctx->raw_edid != (struct edid *)fake_edid_info) { kfree(ctx->raw_edid); @@ -668,12 +661,19 @@ int exynos_drm_probe_vidi(void) return ret; } +static int exynos_drm_remove_vidi_device(struct device *dev, void *data) +{ + platform_device_unregister(to_platform_device(dev)); + + return 0; +} + void exynos_drm_remove_vidi(void) { - struct vidi_context *ctx = vidi_manager.ctx; - struct exynos_drm_subdrv *subdrv = &ctx->subdrv; - struct platform_device *pdev = to_platform_device(subdrv->dev); + int ret = driver_for_each_device(&vidi_driver.driver, NULL, NULL, + exynos_drm_remove_vidi_device); + /* silence compiler warning */ + (void)ret; platform_driver_unregister(&vidi_driver); - platform_device_unregister(pdev); } From e1819aad14ad6bd799ae5c1f97412b1dd55d2065 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 17 Nov 2014 09:54:17 +0100 Subject: [PATCH 40/58] drm/exynos/vidi: stop using manager->ctx pointer The patch replaces accesses to manager->ctx pointer by container_of construct. It will allow to remove ctx field in the future. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 26 ++++++++++++++---------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index f47939c4a303..f048a903eb8d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -66,6 +66,11 @@ struct vidi_context { int pipe; }; +static inline struct vidi_context *manager_to_vidi(struct exynos_drm_manager *m) +{ + return container_of(m, struct vidi_context, manager); +} + static const char fake_edid_info[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78, @@ -93,7 +98,7 @@ static const char fake_edid_info[] = { static void vidi_apply(struct exynos_drm_manager *mgr) { - struct vidi_context *ctx = mgr->ctx; + struct vidi_context *ctx = manager_to_vidi(mgr); struct exynos_drm_manager_ops *mgr_ops = mgr->ops; struct vidi_win_data *win_data; int i; @@ -110,7 +115,7 @@ static void vidi_apply(struct exynos_drm_manager *mgr) static void vidi_commit(struct exynos_drm_manager *mgr) { - struct vidi_context *ctx = mgr->ctx; + struct vidi_context *ctx = manager_to_vidi(mgr); if (ctx->suspended) return; @@ -118,7 +123,7 @@ static void vidi_commit(struct exynos_drm_manager *mgr) static int vidi_enable_vblank(struct exynos_drm_manager *mgr) { - struct vidi_context *ctx = mgr->ctx; + struct vidi_context *ctx = manager_to_vidi(mgr); if (ctx->suspended) return -EPERM; @@ -140,7 +145,7 @@ static int vidi_enable_vblank(struct exynos_drm_manager *mgr) static void vidi_disable_vblank(struct exynos_drm_manager *mgr) { - struct vidi_context *ctx = mgr->ctx; + struct vidi_context *ctx = manager_to_vidi(mgr); if (ctx->suspended) return; @@ -152,7 +157,7 @@ static void vidi_disable_vblank(struct exynos_drm_manager *mgr) static void vidi_win_mode_set(struct exynos_drm_manager *mgr, struct exynos_drm_overlay *overlay) { - struct vidi_context *ctx = mgr->ctx; + struct vidi_context *ctx = manager_to_vidi(mgr); struct vidi_win_data *win_data; int win; unsigned long offset; @@ -204,7 +209,7 @@ static void vidi_win_mode_set(struct exynos_drm_manager *mgr, static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos) { - struct vidi_context *ctx = mgr->ctx; + struct vidi_context *ctx = manager_to_vidi(mgr); struct vidi_win_data *win_data; int win = zpos; @@ -229,7 +234,7 @@ static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos) static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos) { - struct vidi_context *ctx = mgr->ctx; + struct vidi_context *ctx = manager_to_vidi(mgr); struct vidi_win_data *win_data; int win = zpos; @@ -247,7 +252,7 @@ static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos) static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable) { - struct vidi_context *ctx = mgr->ctx; + struct vidi_context *ctx = manager_to_vidi(mgr); DRM_DEBUG_KMS("%s\n", __FILE__); @@ -271,7 +276,7 @@ static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable) static void vidi_dpms(struct exynos_drm_manager *mgr, int mode) { - struct vidi_context *ctx = mgr->ctx; + struct vidi_context *ctx = manager_to_vidi(mgr); DRM_DEBUG_KMS("%d\n", mode); @@ -297,7 +302,7 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode) static int vidi_mgr_initialize(struct exynos_drm_manager *mgr, struct drm_device *drm_dev) { - struct vidi_context *ctx = mgr->ctx; + struct vidi_context *ctx = manager_to_vidi(mgr); struct exynos_drm_private *priv = drm_dev->dev_private; mgr->drm_dev = ctx->drm_dev = drm_dev; @@ -594,7 +599,6 @@ static int vidi_probe(struct platform_device *pdev) INIT_WORK(&ctx->work, vidi_fake_vblank_handler); - ctx->manager.ctx = ctx; vidi_display.ctx = ctx; mutex_init(&ctx->lock); From e152dbd77bc6388c910a3fd2d2acd2439d24631a Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 17 Nov 2014 09:54:18 +0100 Subject: [PATCH 41/58] drm/exynos/fimd: embed manager into private context exynos_drm_manager is used by internal Exynos DRM framework for representing crtc. As it should be mapped 1:1 to fimd private context it seems more reasonable to embed it directly in that context. As a result further code simplification will be possible. Moreover it will be possible to handle multiple FIMD devices in the system. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 62 ++++++++++-------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index a8ab3ecb202e..9a5e999d33f5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -84,8 +84,6 @@ /* FIMD has totally five hardware windows. */ #define WINDOWS_NR 5 -#define get_fimd_manager(mgr) platform_get_drvdata(to_platform_device(dev)) - struct fimd_driver_data { unsigned int timing_base; unsigned int lcdblk_offset; @@ -159,6 +157,7 @@ struct fimd_win_data { }; struct fimd_context { + struct exynos_drm_manager manager; struct device *dev; struct drm_device *drm_dev; struct clk *bus_clk; @@ -965,8 +964,7 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode) static void fimd_trigger(struct device *dev) { - struct exynos_drm_manager *mgr = get_fimd_manager(dev); - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = dev_get_drvdata(dev); struct fimd_driver_data *driver_data = ctx->driver_data; void *timing_base = ctx->regs + driver_data->timing_base; u32 reg; @@ -1032,11 +1030,6 @@ static struct exynos_drm_manager_ops fimd_manager_ops = { .te_handler = fimd_te_handler, }; -static struct exynos_drm_manager fimd_manager = { - .type = EXYNOS_DISPLAY_TYPE_LCD, - .ops = &fimd_manager_ops, -}; - static irqreturn_t fimd_irq_handler(int irq, void *dev_id) { struct fimd_context *ctx = (struct fimd_context *)dev_id; @@ -1074,11 +1067,11 @@ out: static int fimd_bind(struct device *dev, struct device *master, void *data) { - struct fimd_context *ctx = fimd_manager.ctx; + struct fimd_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; - fimd_mgr_initialize(&fimd_manager, drm_dev); - exynos_drm_crtc_create(&fimd_manager); + fimd_mgr_initialize(&ctx->manager, drm_dev); + exynos_drm_crtc_create(&ctx->manager); if (ctx->display) exynos_drm_create_enc_conn(drm_dev, ctx->display); @@ -1089,15 +1082,14 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) static void fimd_unbind(struct device *dev, struct device *master, void *data) { - struct exynos_drm_manager *mgr = dev_get_drvdata(dev); - struct fimd_context *ctx = fimd_manager.ctx; + struct fimd_context *ctx = dev_get_drvdata(dev); - fimd_dpms(mgr, DRM_MODE_DPMS_OFF); + fimd_dpms(&ctx->manager, DRM_MODE_DPMS_OFF); if (ctx->display) exynos_dpi_remove(dev); - fimd_mgr_remove(mgr); + fimd_mgr_remove(&ctx->manager); } static const struct component_ops fimd_component_ops = { @@ -1113,21 +1105,20 @@ static int fimd_probe(struct platform_device *pdev) struct resource *res; int ret = -EINVAL; - ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC, - fimd_manager.type); - if (ret) - return ret; - - if (!dev->of_node) { - ret = -ENODEV; - goto err_del_component; - } + if (!dev->of_node) + return -ENODEV; ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) { - ret = -ENOMEM; - goto err_del_component; - } + if (!ctx) + return -ENOMEM; + + ctx->manager.type = EXYNOS_DISPLAY_TYPE_LCD; + ctx->manager.ops = &fimd_manager_ops; + + ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC, + ctx->manager.type); + if (ret) + return ret; ctx->dev = dev; ctx->suspended = true; @@ -1215,28 +1206,27 @@ static int fimd_probe(struct platform_device *pdev) init_waitqueue_head(&ctx->wait_vsync_queue); atomic_set(&ctx->wait_vsync_event, 0); + ctx->manager.ctx = ctx; - platform_set_drvdata(pdev, &fimd_manager); - - fimd_manager.ctx = ctx; + platform_set_drvdata(pdev, ctx); ctx->display = exynos_dpi_probe(dev); if (IS_ERR(ctx->display)) return PTR_ERR(ctx->display); - pm_runtime_enable(&pdev->dev); + pm_runtime_enable(dev); - ret = component_add(&pdev->dev, &fimd_component_ops); + ret = component_add(dev, &fimd_component_ops); if (ret) goto err_disable_pm_runtime; return ret; err_disable_pm_runtime: - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); err_del_component: - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); + exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CRTC); return ret; } From 400c8ac8fc78f51dc7eb187dcf2320fb616c8215 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 17 Nov 2014 09:54:19 +0100 Subject: [PATCH 42/58] drm/exynos/fimd: stop using manager->ctx pointer The patch replaces accesses to manager->ctx pointer by container_of construct. As fimd was the last user of ctx the patch removes this field as well. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 - drivers/gpu/drm/exynos/exynos_drm_fimd.c | 40 +++++++++++++----------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 262a4590ddb2..f408e49cf0b4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -211,7 +211,6 @@ struct exynos_drm_manager { struct drm_crtc *crtc; int pipe; struct exynos_drm_manager_ops *ops; - void *ctx; }; struct exynos_drm_g2d_private { diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 9a5e999d33f5..b94466146090 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -185,6 +185,11 @@ struct fimd_context { struct exynos_drm_display *display; }; +static inline struct fimd_context *mgr_to_fimd(struct exynos_drm_manager *mgr) +{ + return container_of(mgr, struct fimd_context, manager); +} + static const struct of_device_id fimd_driver_dt_match[] = { { .compatible = "samsung,s3c6400-fimd", .data = &s3c64xx_fimd_driver_data }, @@ -211,7 +216,7 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data( static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); if (ctx->suspended) return; @@ -256,7 +261,7 @@ static void fimd_enable_shadow_channel_path(struct fimd_context *ctx, int win, static void fimd_clear_channel(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); int win, ch_enabled = 0; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -289,7 +294,7 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr) static int fimd_mgr_initialize(struct exynos_drm_manager *mgr, struct drm_device *drm_dev) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); struct exynos_drm_private *priv; priv = drm_dev->dev_private; @@ -311,7 +316,7 @@ static int fimd_mgr_initialize(struct exynos_drm_manager *mgr, static void fimd_mgr_remove(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); /* detach this sub driver from iommu mapping if supported. */ if (is_drm_iommu_supported(ctx->drm_dev)) @@ -351,14 +356,14 @@ static bool fimd_mode_fixup(struct exynos_drm_manager *mgr, static void fimd_mode_set(struct exynos_drm_manager *mgr, const struct drm_display_mode *in_mode) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); drm_mode_copy(&ctx->mode, in_mode); } static void fimd_commit(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); struct drm_display_mode *mode = &ctx->mode; struct fimd_driver_data *driver_data = ctx->driver_data; void *timing_base = ctx->regs + driver_data->timing_base; @@ -458,7 +463,7 @@ static void fimd_commit(struct exynos_drm_manager *mgr) static int fimd_enable_vblank(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); u32 val; if (ctx->suspended) @@ -490,7 +495,7 @@ static int fimd_enable_vblank(struct exynos_drm_manager *mgr) static void fimd_disable_vblank(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); u32 val; if (ctx->suspended) @@ -515,7 +520,7 @@ static void fimd_disable_vblank(struct exynos_drm_manager *mgr) static void fimd_win_mode_set(struct exynos_drm_manager *mgr, struct exynos_drm_overlay *overlay) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_win_data *win_data; int win; unsigned long offset; @@ -673,7 +678,7 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx, static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_win_data *win_data; int win = zpos; unsigned long val, alpha, size; @@ -796,7 +801,7 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_win_data *win_data; int win = zpos; @@ -830,7 +835,7 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) static void fimd_window_suspend(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_win_data *win_data; int i; @@ -844,7 +849,7 @@ static void fimd_window_suspend(struct exynos_drm_manager *mgr) static void fimd_window_resume(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_win_data *win_data; int i; @@ -857,7 +862,7 @@ static void fimd_window_resume(struct exynos_drm_manager *mgr) static void fimd_apply(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_win_data *win_data; int i; @@ -874,7 +879,7 @@ static void fimd_apply(struct exynos_drm_manager *mgr) static int fimd_poweron(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); int ret; if (!ctx->suspended) @@ -922,7 +927,7 @@ bus_clk_err: static int fimd_poweroff(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); if (ctx->suspended) return 0; @@ -993,7 +998,7 @@ static void fimd_trigger(struct device *dev) static void fimd_te_handler(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = mgr->ctx; + struct fimd_context *ctx = mgr_to_fimd(mgr); /* Checks the crtc is detached already from encoder */ if (ctx->pipe < 0 || !ctx->drm_dev) @@ -1206,7 +1211,6 @@ static int fimd_probe(struct platform_device *pdev) init_waitqueue_head(&ctx->wait_vsync_queue); atomic_set(&ctx->wait_vsync_event, 0); - ctx->manager.ctx = ctx; platform_set_drvdata(pdev, ctx); From 930865fbe290411a84da0617a3927e78ba939311 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 17 Nov 2014 09:54:20 +0100 Subject: [PATCH 43/58] drm/exynos/hdmi: embed display into private context exynos_drm_display is used by internal Exynos DRM framework for representing encoder:connector pair. As it should be mapped 1:1 to hdmi private context it seems more reasonable to embed it directly in that context. As a result further code simplification will be possible. Moreover it will be possible to handle multiple hdmi devices in the system. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 51 ++++++++++++---------------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 563a19e62eb2..2851f89ede0e 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -49,7 +49,6 @@ #include #include -#define get_hdmi_display(dev) platform_get_drvdata(to_platform_device(dev)) #define ctx_from_connector(c) container_of(c, struct hdmi_context, connector) #define HOTPLUG_DEBOUNCE_MS 1100 @@ -182,6 +181,7 @@ struct hdmi_conf_regs { }; struct hdmi_context { + struct exynos_drm_display display; struct device *dev; struct drm_device *drm_dev; struct drm_connector connector; @@ -2143,11 +2143,6 @@ static struct exynos_drm_display_ops hdmi_display_ops = { .commit = hdmi_commit, }; -static struct exynos_drm_display hdmi_display = { - .type = EXYNOS_DISPLAY_TYPE_HDMI, - .ops = &hdmi_display_ops, -}; - static void hdmi_hotplug_work_func(struct work_struct *work) { struct hdmi_context *hdata; @@ -2302,12 +2297,11 @@ MODULE_DEVICE_TABLE (of, hdmi_match_types); static int hdmi_bind(struct device *dev, struct device *master, void *data) { struct drm_device *drm_dev = data; - struct hdmi_context *hdata; + struct hdmi_context *hdata = dev_get_drvdata(dev); - hdata = hdmi_display.ctx; hdata->drm_dev = drm_dev; - return exynos_drm_create_enc_conn(drm_dev, &hdmi_display); + return exynos_drm_create_enc_conn(drm_dev, &hdata->display); } static void hdmi_unbind(struct device *dev, struct device *master, void *data) @@ -2349,31 +2343,28 @@ static int hdmi_probe(struct platform_device *pdev) struct resource *res; int ret; + 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; + + hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI; + hdata->display.ops = &hdmi_display_ops; + ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, - hdmi_display.type); + hdata->display.type); if (ret) return ret; - if (!dev->of_node) { - ret = -ENODEV; - goto err_del_component; - } - - pdata = drm_hdmi_dt_parse_pdata(dev); - if (!pdata) { - ret = -EINVAL; - goto err_del_component; - } - - hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL); - if (!hdata) { - ret = -ENOMEM; - goto err_del_component; - } - mutex_init(&hdata->hdmi_mutex); - platform_set_drvdata(pdev, &hdmi_display); + platform_set_drvdata(pdev, hdata); match = of_match_node(hdmi_match_types, dev->of_node); if (!match) { @@ -2485,7 +2476,7 @@ out_get_phy_port: } pm_runtime_enable(dev); - hdmi_display.ctx = hdata; + hdata->display.ctx = hdata; ret = component_add(&pdev->dev, &hdmi_component_ops); if (ret) @@ -2510,7 +2501,7 @@ err_del_component: static int hdmi_remove(struct platform_device *pdev) { - struct hdmi_context *hdata = hdmi_display.ctx; + struct hdmi_context *hdata = platform_get_drvdata(pdev); cancel_delayed_work_sync(&hdata->hotplug_work); From 0d8424f83c31f1839826ea17ffc3ddf3f1b332a4 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 17 Nov 2014 09:54:21 +0100 Subject: [PATCH 44/58] drm/exynos/hdmi: stop using display->ctx pointer The patch replaces accesses to display->ctx pointer by container_of construct. It will allow to remove ctx field in the future. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 2851f89ede0e..5765a161abdd 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -213,6 +213,11 @@ struct hdmi_context { enum hdmi_type type; }; +static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d) +{ + return container_of(d, struct hdmi_context, display); +} + struct hdmiphy_config { int pixel_clock; u8 conf[32]; @@ -1123,7 +1128,7 @@ static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = { static int hdmi_create_connector(struct exynos_drm_display *display, struct drm_encoder *encoder) { - struct hdmi_context *hdata = display->ctx; + struct hdmi_context *hdata = display_to_hdmi(display); struct drm_connector *connector = &hdata->connector; int ret; @@ -2000,7 +2005,7 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata, static void hdmi_mode_set(struct exynos_drm_display *display, struct drm_display_mode *mode) { - struct hdmi_context *hdata = display->ctx; + struct hdmi_context *hdata = display_to_hdmi(display); struct drm_display_mode *m = mode; DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n", @@ -2019,7 +2024,7 @@ static void hdmi_mode_set(struct exynos_drm_display *display, static void hdmi_commit(struct exynos_drm_display *display) { - struct hdmi_context *hdata = display->ctx; + struct hdmi_context *hdata = display_to_hdmi(display); mutex_lock(&hdata->hdmi_mutex); if (!hdata->powered) { @@ -2033,7 +2038,7 @@ static void hdmi_commit(struct exynos_drm_display *display) static void hdmi_poweron(struct exynos_drm_display *display) { - struct hdmi_context *hdata = display->ctx; + struct hdmi_context *hdata = display_to_hdmi(display); struct hdmi_resources *res = &hdata->res; mutex_lock(&hdata->hdmi_mutex); @@ -2064,7 +2069,7 @@ static void hdmi_poweron(struct exynos_drm_display *display) static void hdmi_poweroff(struct exynos_drm_display *display) { - struct hdmi_context *hdata = display->ctx; + struct hdmi_context *hdata = display_to_hdmi(display); struct hdmi_resources *res = &hdata->res; mutex_lock(&hdata->hdmi_mutex); @@ -2099,7 +2104,7 @@ out: static void hdmi_dpms(struct exynos_drm_display *display, int mode) { - struct hdmi_context *hdata = display->ctx; + struct hdmi_context *hdata = display_to_hdmi(display); struct drm_encoder *encoder = hdata->encoder; struct drm_crtc *crtc = encoder->crtc; struct drm_crtc_helper_funcs *funcs = NULL; @@ -2476,7 +2481,6 @@ out_get_phy_port: } pm_runtime_enable(dev); - hdata->display.ctx = hdata; ret = component_add(&pdev->dev, &hdmi_component_ops); if (ret) From 7340426affacb4b5988f9cf1c3dbfc28e9679360 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 17 Nov 2014 09:54:22 +0100 Subject: [PATCH 45/58] drm/exynos/vidi: embed display into private context exynos_drm_display is used by internal Exynos DRM framework for representing encoder:connector pair. As it should be mapped 1:1 to vidi private context it seems more reasonable to embed it directly in that context. As a result further code simplification will be possible. Moreover it will be possible to handle multiple vidi devices in the system. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index f048a903eb8d..f58dd52f6d60 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -47,6 +47,7 @@ struct vidi_win_data { struct vidi_context { struct exynos_drm_manager manager; + struct exynos_drm_display display; struct drm_device *drm_dev; struct drm_crtc *crtc; struct drm_encoder *encoder; @@ -554,11 +555,6 @@ static struct exynos_drm_display_ops vidi_display_ops = { .create_connector = vidi_create_connector, }; -static struct exynos_drm_display vidi_display = { - .type = EXYNOS_DISPLAY_TYPE_VIDI, - .ops = &vidi_display_ops, -}; - static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev) { struct vidi_context *ctx = dev_get_drvdata(dev); @@ -573,7 +569,7 @@ static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev) return ret; } - ret = exynos_drm_create_enc_conn(drm_dev, &vidi_display); + ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display); if (ret) { crtc->funcs->destroy(crtc); DRM_ERROR("failed to create encoder and connector.\n"); @@ -595,11 +591,13 @@ static int vidi_probe(struct platform_device *pdev) ctx->manager.type = EXYNOS_DISPLAY_TYPE_VIDI; ctx->manager.ops = &vidi_manager_ops; + ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI; + ctx->display.ops = &vidi_display_ops; ctx->default_win = 0; INIT_WORK(&ctx->work, vidi_fake_vblank_handler); - vidi_display.ctx = ctx; + ctx->display.ctx = ctx; mutex_init(&ctx->lock); From 2f26bd7227b80d002dfcd3f60e71bfad168e6517 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 17 Nov 2014 09:54:23 +0100 Subject: [PATCH 46/58] drm/exynos/vidi: stop using display->ctx pointer The patch replaces accesses to display->ctx pointer by container_of construct. It will allow to remove ctx field in the future. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index f58dd52f6d60..3b6fdd614584 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -72,6 +72,11 @@ static inline struct vidi_context *manager_to_vidi(struct exynos_drm_manager *m) return container_of(m, struct vidi_context, manager); } +static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d) +{ + return container_of(d, struct vidi_context, display); +} + static const char fake_edid_info[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78, @@ -419,7 +424,7 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, display = exynos_drm_get_display(encoder); if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) { - ctx = display->ctx; + ctx = display_to_vidi(display); break; } } @@ -529,7 +534,7 @@ static struct drm_connector_helper_funcs vidi_connector_helper_funcs = { static int vidi_create_connector(struct exynos_drm_display *display, struct drm_encoder *encoder) { - struct vidi_context *ctx = display->ctx; + struct vidi_context *ctx = display_to_vidi(display); struct drm_connector *connector = &ctx->connector; int ret; @@ -597,8 +602,6 @@ static int vidi_probe(struct platform_device *pdev) INIT_WORK(&ctx->work, vidi_fake_vblank_handler); - ctx->display.ctx = ctx; - mutex_init(&ctx->lock); platform_set_drvdata(pdev, ctx); From 1df6e5fb79f614141f4358587b18695d7acda024 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 17 Nov 2014 09:54:24 +0100 Subject: [PATCH 47/58] drm/exynos/dp: embed display into private context exynos_drm_display is used by internal Exynos DRM framework for representing encoder:connector pair. As it should be mapped 1:1 to dp private context it seems more reasonable to embed it directly in that context. As a result further code simplification will be possible. Moreover it will be possible to handle multiple dp devices in the system. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_dp_core.c | 42 +++++++++++-------------- drivers/gpu/drm/exynos/exynos_dp_core.h | 3 ++ 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index ed818b9a615a..47c6e4798baf 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -30,7 +30,6 @@ #include #include -#include "exynos_drm_drv.h" #include "exynos_dp_core.h" #define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \ @@ -1133,11 +1132,6 @@ static struct exynos_drm_display_ops exynos_dp_display_ops = { .commit = exynos_dp_commit, }; -static struct exynos_drm_display exynos_dp_display = { - .type = EXYNOS_DISPLAY_TYPE_LCD, - .ops = &exynos_dp_display_ops, -}; - static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev) { struct device_node *dp_node = dev->of_node; @@ -1211,10 +1205,10 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp) 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 resource *res; - struct exynos_dp_device *dp = exynos_dp_display.ctx; unsigned int irq_flags; int ret = 0; @@ -1306,17 +1300,15 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) dp->drm_dev = drm_dev; - platform_set_drvdata(pdev, &exynos_dp_display); - - return exynos_drm_create_enc_conn(drm_dev, &exynos_dp_display); + return exynos_drm_create_enc_conn(drm_dev, &dp->display); } static void exynos_dp_unbind(struct device *dev, struct device *master, void *data) { - struct exynos_drm_display *display = dev_get_drvdata(dev); + struct exynos_dp_device *dp = dev_get_drvdata(dev); - exynos_dp_dpms(display, DRM_MODE_DPMS_OFF); + exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF); } static const struct component_ops exynos_dp_ops = { @@ -1331,16 +1323,20 @@ static int exynos_dp_probe(struct platform_device *pdev) struct exynos_dp_device *dp; int ret; - ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, - exynos_dp_display.type); - if (ret) - return ret; - dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), GFP_KERNEL); if (!dp) return -ENOMEM; + dp->display.type = EXYNOS_DISPLAY_TYPE_LCD; + dp->display.ops = &exynos_dp_display_ops; + platform_set_drvdata(pdev, dp); + + ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, + dp->display.type); + if (ret) + return ret; + panel_node = of_parse_phandle(dev->of_node, "panel", 0); if (panel_node) { dp->panel = of_drm_find_panel(panel_node); @@ -1349,7 +1345,7 @@ static int exynos_dp_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - exynos_dp_display.ctx = dp; + dp->display.ctx = dp; ret = component_add(&pdev->dev, &exynos_dp_ops); if (ret) @@ -1370,19 +1366,17 @@ static int exynos_dp_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int exynos_dp_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct exynos_drm_display *display = platform_get_drvdata(pdev); + struct exynos_dp_device *dp = dev_get_drvdata(dev); - exynos_dp_dpms(display, DRM_MODE_DPMS_OFF); + exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF); return 0; } static int exynos_dp_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct exynos_drm_display *display = platform_get_drvdata(pdev); + struct exynos_dp_device *dp = dev_get_drvdata(dev); - exynos_dp_dpms(display, DRM_MODE_DPMS_ON); + exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_ON); return 0; } #endif diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h index 6426201667bc..164f171168e7 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.h +++ b/drivers/gpu/drm/exynos/exynos_dp_core.h @@ -17,6 +17,8 @@ #include #include +#include "exynos_drm_drv.h" + #define DP_TIMEOUT_LOOP_COUNT 100 #define MAX_CR_LOOP 5 #define MAX_EQ_LOOP 5 @@ -145,6 +147,7 @@ struct link_train { }; struct exynos_dp_device { + struct exynos_drm_display display; struct device *dev; struct drm_device *drm_dev; struct drm_connector connector; From 63b3be327048402a39068f188726e3729e061fda Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 17 Nov 2014 09:54:25 +0100 Subject: [PATCH 48/58] drm/exynos/dp: stop using display->ctx pointer The patch replaces accesses to display->ctx pointer by container_of construct. It will allow to remove ctx field in the future. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_dp_core.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 47c6e4798baf..34d46aa75416 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -35,6 +35,12 @@ #define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \ connector) +static inline struct exynos_dp_device * +display_to_dp(struct exynos_drm_display *d) +{ + return container_of(d, struct exynos_dp_device, display); +} + struct bridge_init { struct i2c_client *client; struct device_node *node; @@ -881,7 +887,7 @@ static void exynos_dp_hotplug(struct work_struct *work) static void exynos_dp_commit(struct exynos_drm_display *display) { - struct exynos_dp_device *dp = display->ctx; + struct exynos_dp_device *dp = display_to_dp(display); int ret; /* Keep the panel disabled while we configure video */ @@ -1019,7 +1025,7 @@ static int exynos_drm_attach_lcd_bridge(struct drm_device *dev, static int exynos_dp_create_connector(struct exynos_drm_display *display, struct drm_encoder *encoder) { - struct exynos_dp_device *dp = display->ctx; + struct exynos_dp_device *dp = display_to_dp(display); struct drm_connector *connector = &dp->connector; int ret; @@ -1063,7 +1069,7 @@ static void exynos_dp_phy_exit(struct exynos_dp_device *dp) static void exynos_dp_poweron(struct exynos_drm_display *display) { - struct exynos_dp_device *dp = display->ctx; + struct exynos_dp_device *dp = display_to_dp(display); if (dp->dpms_mode == DRM_MODE_DPMS_ON) return; @@ -1084,7 +1090,7 @@ static void exynos_dp_poweron(struct exynos_drm_display *display) static void exynos_dp_poweroff(struct exynos_drm_display *display) { - struct exynos_dp_device *dp = display->ctx; + struct exynos_dp_device *dp = display_to_dp(display); if (dp->dpms_mode != DRM_MODE_DPMS_ON) return; @@ -1109,7 +1115,7 @@ static void exynos_dp_poweroff(struct exynos_drm_display *display) static void exynos_dp_dpms(struct exynos_drm_display *display, int mode) { - struct exynos_dp_device *dp = display->ctx; + struct exynos_dp_device *dp = display_to_dp(display); switch (mode) { case DRM_MODE_DPMS_ON: @@ -1345,8 +1351,6 @@ static int exynos_dp_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - dp->display.ctx = dp; - ret = component_add(&pdev->dev, &exynos_dp_ops); if (ret) exynos_drm_component_del(&pdev->dev, From 4cfde1f2af076547ebe86f8632e65119f28438b8 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 17 Nov 2014 09:54:26 +0100 Subject: [PATCH 49/58] drm/exynos/dpi: embed display into private context exynos_drm_display is used by internal Exynos DRM framework for representing encoder:connector pair. As it should be mapped 1:1 to dpi private context it seems more reasonable to embed it directly in that context. As a result further code simplification will be possible. Moreover it will be possible to handle multiple dpi devices in the system. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dpi.c | 39 +++++++++++++----------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 +- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 +- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 3dc678ed9949..3acfc288d17c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -22,6 +22,7 @@ #include "exynos_drm_drv.h" struct exynos_dpi { + struct exynos_drm_display display; struct device *dev; struct device_node *panel_node; @@ -35,6 +36,11 @@ struct exynos_dpi { #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) +{ + return container_of(d, struct exynos_dpi, display); +} + static enum drm_connector_status exynos_dpi_detect(struct drm_connector *connector, bool force) { @@ -165,11 +171,6 @@ static struct exynos_drm_display_ops exynos_dpi_display_ops = { .dpms = exynos_dpi_dpms }; -static struct exynos_drm_display exynos_dpi_display = { - .type = EXYNOS_DISPLAY_TYPE_LCD, - .ops = &exynos_dpi_display_ops, -}; - /* of_* functions will be removed after merge of of_graph patches */ static struct device_node * of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg) @@ -299,20 +300,22 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev) struct exynos_dpi *ctx; int ret; - ret = exynos_drm_component_add(dev, - EXYNOS_DEVICE_TYPE_CONNECTOR, - exynos_dpi_display.type); - if (ret) - return ERR_PTR(ret); - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) - goto err_del_component; + return ERR_PTR(-ENOMEM); + ctx->display.type = EXYNOS_DISPLAY_TYPE_LCD; + ctx->display.ops = &exynos_dpi_display_ops; ctx->dev = dev; - exynos_dpi_display.ctx = ctx; + ctx->display.ctx = ctx; ctx->dpms_mode = DRM_MODE_DPMS_OFF; + ret = exynos_drm_component_add(dev, + EXYNOS_DEVICE_TYPE_CONNECTOR, + ctx->display.type); + if (ret) + return ERR_PTR(ret); + ret = exynos_dpi_parse_dt(ctx); if (ret < 0) { devm_kfree(dev, ctx); @@ -328,7 +331,7 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev) } } - return &exynos_dpi_display; + return &ctx->display; err_del_component: exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR); @@ -336,16 +339,16 @@ err_del_component: return NULL; } -int exynos_dpi_remove(struct device *dev) +int exynos_dpi_remove(struct exynos_drm_display *display) { - struct exynos_dpi *ctx = exynos_dpi_display.ctx; + struct exynos_dpi *ctx = display_to_dpi(display); - exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF); + exynos_dpi_dpms(&ctx->display, DRM_MODE_DPMS_OFF); if (ctx->panel) drm_panel_detach(ctx->panel); - exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR); + exynos_drm_component_del(ctx->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index f408e49cf0b4..b023f5fea25f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -304,7 +304,7 @@ static inline void exynos_platform_device_ipp_unregister(void) {} #ifdef CONFIG_DRM_EXYNOS_DPI struct exynos_drm_display * exynos_dpi_probe(struct device *dev); -int exynos_dpi_remove(struct device *dev); +int exynos_dpi_remove(struct exynos_drm_display *display); #else static inline struct exynos_drm_display * exynos_dpi_probe(struct device *dev) { return NULL; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index b94466146090..ef80a3537f35 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1092,7 +1092,7 @@ static void fimd_unbind(struct device *dev, struct device *master, fimd_dpms(&ctx->manager, DRM_MODE_DPMS_OFF); if (ctx->display) - exynos_dpi_remove(dev); + exynos_dpi_remove(ctx->display); fimd_mgr_remove(&ctx->manager); } From 5af3d9bb78f130819204ef44ac9d2b635e49fc35 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 17 Nov 2014 09:54:27 +0100 Subject: [PATCH 50/58] drm/exynos/dpi: stop using display->ctx pointer The patch replaces accesses to display->ctx pointer by container_of construct. The field is removed as well as dpi was the last user of it. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dpi.c | 5 ++--- drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 3acfc288d17c..37678cf4425a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -106,7 +106,7 @@ static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = { static int exynos_dpi_create_connector(struct exynos_drm_display *display, struct drm_encoder *encoder) { - struct exynos_dpi *ctx = display->ctx; + struct exynos_dpi *ctx = display_to_dpi(display); struct drm_connector *connector = &ctx->connector; int ret; @@ -147,7 +147,7 @@ static void exynos_dpi_poweroff(struct exynos_dpi *ctx) static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode) { - struct exynos_dpi *ctx = display->ctx; + struct exynos_dpi *ctx = display_to_dpi(display); switch (mode) { case DRM_MODE_DPMS_ON: @@ -307,7 +307,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->display.ctx = ctx; ctx->dpms_mode = DRM_MODE_DPMS_OFF; ret = exynos_drm_component_add(dev, diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index b023f5fea25f..2e4e91bf9b07 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -152,7 +152,6 @@ struct exynos_drm_display { struct drm_encoder *encoder; struct drm_connector *connector; struct exynos_drm_display_ops *ops; - void *ctx; }; /* From b67139571ec0956eb94a354572df73cf24d4521c Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 20 Nov 2014 21:42:55 -0200 Subject: [PATCH 51/58] Revert "drm/exynos: fix null pointer dereference issue" This reverts commit cea24824ab432f8acabb254d6805e9aa756de6af. Moving subdriver probe to exynos_drm_platform_probe() was making exynos_drm_device_subdrv_probe() fail because the platform data wasn't set yet. It only gets set in exynos_drm_load. We need to find a smarter way to fix this issue. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index eab12f084709..2ca0c5dcf80e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -108,6 +108,11 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) if (ret) goto err_unbind_all; + /* Probe non kms sub drivers and virtual display driver. */ + ret = exynos_drm_device_subdrv_probe(dev); + if (ret) + goto err_cleanup_vblank; + /* * enable drm irq mode. * - with irq_enabled = true, we can use the vblank feature. @@ -133,6 +138,8 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) return 0; +err_cleanup_vblank: + drm_vblank_cleanup(dev); err_unbind_all: component_unbind_all(dev->dev, dev); err_mode_config_cleanup: @@ -146,6 +153,8 @@ err_free_private: static int exynos_drm_unload(struct drm_device *dev) { + exynos_drm_device_subdrv_remove(dev); + exynos_drm_fbdev_fini(dev); drm_kms_helper_poll_fini(dev); @@ -614,14 +623,8 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) if (ret < 0) goto err_unregister_non_kms_drivers; - /* Probe non kms sub drivers and virtual display driver. */ - ret = exynos_drm_device_subdrv_probe(platform_get_drvdata(pdev)); - if (ret) - goto err_unregister_resources; - return ret; -err_unregister_resources: #ifdef CONFIG_DRM_EXYNOS_IPP exynos_platform_device_ipp_unregister(); #endif @@ -643,8 +646,6 @@ static int exynos_drm_platform_remove(struct platform_device *pdev) { int i; - exynos_drm_device_subdrv_remove(platform_get_drvdata(pdev)); - #ifdef CONFIG_DRM_EXYNOS_IPP exynos_platform_device_ipp_unregister(); #endif From 820687befec471aff3bb59bd69302d34a776e807 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 24 Nov 2014 16:37:26 +0900 Subject: [PATCH 52/58] drm/exynos: move Exynos platform drivers registration to init Registering the Exynos DRM subdevices platform drivers in the probe function is causing an infinite loop. Fix this by moving it to the exynos_drm_init() function to register the drivers on module init. Registering drivers in the probe functions causes a deadlock in the parent device lock. See Grant Likely explanation on the topic: "I think the problem is that exynos_drm_init() is registering a normal (non-OF) platform device, so the parent will be /sys/devices/platform. It immediately gets bound against exynos_drm_platform_driver which calls the exynos drm_platform_probe() hook. The driver core obtains device_lock() on the device *and on the device parent*. Inside the probe hook, additional platform_drivers get registered. Each time one does, it tries to bind against every platform device in the system, which includes the ones created by OF. When it attempts to bind, it obtains device_lock() on the device *and on the device parent*. Before the change to move of-generated platform devices into /sys/devices/platform, the devices had different parents. Now both devices have /sys/devices/platform as the parent, so yes they are going to deadlock. The real problem is registering drivers from within a probe hook. That is completely wrong for the above deadlock reason. __driver_attach() will deadlock. Those registrations must be pulled out of .probe(). Registering devices in .probe() is okay because __device_attach() doesn't try to obtain device_lock() on the parent." INFO: task swapper/0:1 blocked for more than 120 seconds. Not tainted 3.18.0-rc3-next-20141105 #794 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. swapper/0 D c052534c 0 1 0 0x00000000 [] (__schedule) from [] (schedule_preempt_disabled+0x14/0x20) [] (schedule_preempt_disabled) from [] (mutex_lock_nested+0x1c4/0x464 [] (mutex_lock_nested) from [] (__driver_attach+0x48/0x98) [] (__driver_attach) from [] (bus_for_each_dev+0x54/0x88) [] (bus_for_each_dev) from [] (bus_add_driver+0xe4/0x200) [] (bus_add_driver) from [] (driver_register+0x78/0xf4) [] (driver_register) from [] (exynos_drm_platform_probe+0x34/0x234) [] (exynos_drm_platform_probe) from [] (platform_drv_probe+0x48/0xa4) [] (platform_drv_probe) from [] (driver_probe_device+0x13c/0x37c) [] (driver_probe_device) from [] (__driver_attach+0x94/0x98) [] (__driver_attach) from [] (bus_for_each_dev+0x54/0x88) [] (bus_for_each_dev) from [] (bus_add_driver+0xe4/0x200) [] (bus_add_driver) from [] (driver_register+0x78/0xf4) [] (driver_register) from [] (exynos_drm_init+0x70/0xa0) [] (exynos_drm_init) from [] (do_one_initcall+0xac/0x1f0) [] (do_one_initcall) from [] (kernel_init_freeable+0x10c/0x1d8) [] (kernel_init_freeable) from [] (kernel_init+0x8/0xec) [] (kernel_init) from [] (ret_from_fork+0x14/0x2c) 3 locks held by swapper/0/1: #0: (&dev->mutex){......}, at: [] __driver_attach+0x48/0x98 #1: (&dev->mutex){......}, at: [] __driver_attach+0x58/0x98 #2: (&dev->mutex){......}, at: [] __driver_attach+0x48/0x98 Changelog v2: - call platform_driver_register after all kms and non kms drivers are registered - rebased it to exynos-drm-next Signed-off-by: Javier Martinez Canillas Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 105 +++++++++++------------- 1 file changed, 48 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 2ca0c5dcf80e..c5cb8b6c85a9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -591,73 +591,22 @@ static struct platform_driver *const exynos_drm_non_kms_drivers[] = { static int exynos_drm_platform_probe(struct platform_device *pdev) { struct component_match *match; - int ret, i, j; pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls); - for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) { - ret = platform_driver_register(exynos_drm_kms_drivers[i]); - if (ret < 0) - goto err_unregister_kms_drivers; - } - match = exynos_drm_match_add(&pdev->dev); if (IS_ERR(match)) { - ret = PTR_ERR(match); - goto err_unregister_kms_drivers; + return PTR_ERR(match); } - ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, - match); - if (ret < 0) - goto err_unregister_kms_drivers; - - for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { - ret = platform_driver_register(exynos_drm_non_kms_drivers[j]); - if (ret < 0) - goto err_del_component_master; - } - - ret = exynos_platform_device_ipp_register(); - if (ret < 0) - goto err_unregister_non_kms_drivers; - - return ret; - -#ifdef CONFIG_DRM_EXYNOS_IPP - exynos_platform_device_ipp_unregister(); -#endif -err_unregister_non_kms_drivers: - while (--j >= 0) - platform_driver_unregister(exynos_drm_non_kms_drivers[j]); - -err_del_component_master: - component_master_del(&pdev->dev, &exynos_drm_ops); - -err_unregister_kms_drivers: - while (--i >= 0) - platform_driver_unregister(exynos_drm_kms_drivers[i]); - - return ret; + return component_master_add_with_match(&pdev->dev, &exynos_drm_ops, + match); } static int exynos_drm_platform_remove(struct platform_device *pdev) { - int i; - -#ifdef CONFIG_DRM_EXYNOS_IPP - exynos_platform_device_ipp_unregister(); -#endif - - for (i = ARRAY_SIZE(exynos_drm_non_kms_drivers) - 1; i >= 0; --i) - platform_driver_unregister(exynos_drm_non_kms_drivers[i]); - component_master_del(&pdev->dev, &exynos_drm_ops); - - for (i = ARRAY_SIZE(exynos_drm_kms_drivers) - 1; i >= 0; --i) - platform_driver_unregister(exynos_drm_kms_drivers[i]); - return 0; } @@ -673,7 +622,7 @@ static struct platform_driver exynos_drm_platform_driver = { static int exynos_drm_init(void) { - int ret; + int ret, i, j; /* * Register device object only in case of Exynos SoC. @@ -696,13 +645,43 @@ static int exynos_drm_init(void) if (ret < 0) goto err_unregister_pd; + for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) { + ret = platform_driver_register(exynos_drm_kms_drivers[i]); + if (ret < 0) + goto err_unregister_kms_drivers; + } + + for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { + ret = platform_driver_register(exynos_drm_non_kms_drivers[j]); + if (ret < 0) + goto err_unregister_non_kms_drivers; + } + +#ifdef CONFIG_DRM_EXYNOS_IPP + ret = exynos_platform_device_ipp_register(); + if (ret < 0) + goto err_unregister_non_kms_drivers; +#endif + ret = platform_driver_register(&exynos_drm_platform_driver); if (ret) - goto err_remove_vidi; + goto err_unregister_resources; return 0; -err_remove_vidi: +err_unregister_resources: +#ifdef CONFIG_DRM_EXYNOS_IPP + exynos_platform_device_ipp_unregister(); +#endif + +err_unregister_non_kms_drivers: + while (--j >= 0) + platform_driver_unregister(exynos_drm_non_kms_drivers[j]); + +err_unregister_kms_drivers: + while (--i >= 0) + platform_driver_unregister(exynos_drm_kms_drivers[i]); + exynos_drm_remove_vidi(); err_unregister_pd: @@ -713,6 +692,18 @@ err_unregister_pd: static void exynos_drm_exit(void) { + int i; + +#ifdef CONFIG_DRM_EXYNOS_IPP + exynos_platform_device_ipp_unregister(); +#endif + + for (i = ARRAY_SIZE(exynos_drm_non_kms_drivers) - 1; i >= 0; --i) + platform_driver_unregister(exynos_drm_non_kms_drivers[i]); + + for (i = ARRAY_SIZE(exynos_drm_kms_drivers) - 1; i >= 0; --i) + platform_driver_unregister(exynos_drm_kms_drivers[i]); + platform_driver_unregister(&exynos_drm_platform_driver); exynos_drm_remove_vidi(); From 4846e452084945891a770809f94b23f33eebcd8c Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Mon, 24 Nov 2014 17:08:00 +0900 Subject: [PATCH 53/58] drm/exynos: clean up machine compatible string check Use 'for' statemant instead of hard-coded 'if' statement. Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index c5cb8b6c85a9..495826f73c2a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -610,6 +610,12 @@ static int exynos_drm_platform_remove(struct platform_device *pdev) return 0; } +static const char * const strings[] = { + "samsung,exynos3", + "samsung,exynos4", + "samsung,exynos5", +}; + static struct platform_driver exynos_drm_platform_driver = { .probe = exynos_drm_platform_probe, .remove = exynos_drm_platform_remove, @@ -622,6 +628,7 @@ static struct platform_driver exynos_drm_platform_driver = { static int exynos_drm_init(void) { + bool is_exynos = false; int ret, i, j; /* @@ -631,9 +638,14 @@ static int exynos_drm_init(void) * by Exynos drm driver when using multi-platform kernel. * So these codes will be replaced with more generic way later. */ - if (!of_machine_is_compatible("samsung,exynos3") && - !of_machine_is_compatible("samsung,exynos4") && - !of_machine_is_compatible("samsung,exynos5")) + for (i = 0; i < ARRAY_SIZE(strings); i++) { + if (of_machine_is_compatible(strings[i])) { + is_exynos = true; + break; + } + } + + if (!is_exynos) return -ENODEV; exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, From be19d9336995241f5c98d0abebff440fef03455e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Nov 2014 14:11:15 +0100 Subject: [PATCH 54/58] drm/exynos/ipp: fix error return code Propagate the returned error code on failure. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_ipp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 00d74b18f7cb..d5ad17dfc24d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -426,18 +426,21 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, c_node->start_work = ipp_create_cmd_work(); if (IS_ERR(c_node->start_work)) { DRM_ERROR("failed to create start work.\n"); + ret = PTR_ERR(c_node->start_work); goto err_remove_id; } c_node->stop_work = ipp_create_cmd_work(); if (IS_ERR(c_node->stop_work)) { DRM_ERROR("failed to create stop work.\n"); + ret = PTR_ERR(c_node->stop_work); goto err_free_start; } c_node->event_work = ipp_create_event_work(); if (IS_ERR(c_node->event_work)) { DRM_ERROR("failed to create event work.\n"); + ret = PTR_ERR(c_node->event_work); goto err_free_stop; } From 33e2192fb1e329c26847c92edbd90f7e93eecacf Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Mon, 24 Nov 2014 16:58:48 +0900 Subject: [PATCH 55/58] drm/exynos: fix exynos_drm_component_del This patch resolves the issue that component object isn't removed correctly. A given component object couldn't be placed to head of drm_component_list so all component objects added to the drm_component_list should be checked to remove the given component object. Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 495826f73c2a..d71fb54582d2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -473,8 +473,6 @@ void exynos_drm_component_del(struct device *dev, list_del(&cdev->list); kfree(cdev); } - - break; } mutex_unlock(&drm_component_lock); From 1d50aa9c6fb01356238ec21039f145fc2d81f7e7 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Mon, 24 Nov 2014 14:55:41 +0900 Subject: [PATCH 56/58] drm/exynos: vidi: add component support This patch adds component support for vidi driver. vidi driver is a kms driver so it doesn't need to be registered to exynos_drm_subdrv_list. For this, it changes for the component framework to be used for vidi driver. This patch fixes below error also, # echo 1 > /sys/devices/platform/exynos-drm-vidi/connection [ 55.618529] ------------[ cut here ]------------ [ 55.621960] WARNING: CPU: 0 PID: 1397 at drivers/gpu/drm/drm_irq.c:1203 exynos_drm_crtc_dpms+0x88/0x17c() [ 55.631268] Modules linked in: [ 55.634278] CPU: 0 PID: 1397 Comm: sh Not tainted 3.18.0-rc2-146253-g31449d7 #1154 [ 55.641885] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 55.649597] [] (show_stack) from [] (dump_stack+0x84/0xc4) [ 55.656802] [] (dump_stack) from [] (warn_slowpath_common+0x6c/0x88) [ 55.664866] [] (warn_slowpath_common) from [] (warn_slowpath_null+0x1c/0x24) [ 55.673632] [] (warn_slowpath_null) from [] (exynos_drm_crtc_dpms+0x88/0x17c) [ 55.682482] [] (exynos_drm_crtc_dpms) from [] (exynos_drm_crtc_commit+0x14/0x44) [ 55.691622] [] (exynos_drm_crtc_commit) from [] (drm_crtc_helper_set_mode+0x3d0/0x51c) [ 55.701233] [] (drm_crtc_helper_set_mode) from [] (drm_crtc_helper_set_config+0x87c/0x9dc) [ 55.711230] [] (drm_crtc_helper_set_config) from [] (drm_mode_set_config_internal+0x58/0xd4) [ 55.721380] [] (drm_mode_set_config_internal) from [] (restore_fbdev_mode+0xcc/0xec) [ 55.730834] [] (restore_fbdev_mode) from [] (drm_fb_helper_restore_fbdev_mode_unlocked+0x1c/0x30) [ 55.741424] [] (drm_fb_helper_restore_fbdev_mode_unlocked) from [] (drm_fb_helper_set_par+0x1c/0x60) [ 55.752271] [] (drm_fb_helper_set_par) from [] (drm_fb_helper_hotplug_event+0x88/0xc4) [ 55.761906] [] (drm_fb_helper_hotplug_event) from [] (drm_helper_hpd_irq_event+0xc8/0x134) [ 55.771898] [] (drm_helper_hpd_irq_event) from [] (vidi_store_connection+0x90/0xc8) [ 55.781268] [] (vidi_store_connection) from [] (kernfs_fop_write+0xc0/0x180) [ 55.790045] [] (kernfs_fop_write) from [] (vfs_write+0xa0/0x1ac) [ 55.797757] [] (vfs_write) from [] (SyS_write+0x44/0x9c) [ 55.804790] [] (SyS_write) from [] (ret_fast_syscall+0x0/0x30) [ 55.812328] ---[ end trace 3c0fe4386702d4dd ]--- This issue occurs when modeset to vidi is tried in case that drm_vblank_init is called prior to crtc creation of vidi driver. In this case, crtc number of vidi is invalid so any requests with the crtc number will fail. This patch guarantees drm_vblank_init to be called after all kms drivers are ready by using component framework. Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 61 +++++++++++++++++------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 3b6fdd614584..45899fb63272 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -14,6 +14,7 @@ #include #include +#include #include @@ -48,11 +49,11 @@ struct vidi_win_data { struct vidi_context { struct exynos_drm_manager manager; struct exynos_drm_display display; + struct platform_device *pdev; struct drm_device *drm_dev; struct drm_crtc *crtc; struct drm_encoder *encoder; struct drm_connector connector; - struct exynos_drm_subdrv subdrv; struct vidi_win_data win_data[WINDOWS_NR]; struct edid *raw_edid; unsigned int clkdiv; @@ -560,9 +561,10 @@ static struct exynos_drm_display_ops vidi_display_ops = { .create_connector = vidi_create_connector, }; -static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev) +static int vidi_bind(struct device *dev, struct device *master, void *data) { struct vidi_context *ctx = dev_get_drvdata(dev); + struct drm_device *drm_dev = data; struct drm_crtc *crtc = ctx->crtc; int ret; @@ -584,9 +586,18 @@ static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev) return 0; } + +static void vidi_unbind(struct device *dev, struct device *master, void *data) +{ +} + +static const struct component_ops vidi_component_ops = { + .bind = vidi_bind, + .unbind = vidi_unbind, +}; + static int vidi_probe(struct platform_device *pdev) { - struct exynos_drm_subdrv *subdrv; struct vidi_context *ctx; int ret; @@ -599,6 +610,17 @@ static int vidi_probe(struct platform_device *pdev) ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI; ctx->display.ops = &vidi_display_ops; ctx->default_win = 0; + ctx->pdev = pdev; + + ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC, + ctx->manager.type); + if (ret) + return ret; + + ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, + ctx->display.type); + if (ret) + goto err_del_crtc_component; INIT_WORK(&ctx->work, vidi_fake_vblank_handler); @@ -606,23 +628,26 @@ static int vidi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - subdrv = &ctx->subdrv; - subdrv->dev = &pdev->dev; - subdrv->probe = vidi_subdrv_probe; - - ret = exynos_drm_subdrv_register(subdrv); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register drm vidi device\n"); - return ret; - } - ret = device_create_file(&pdev->dev, &dev_attr_connection); if (ret < 0) { - exynos_drm_subdrv_unregister(subdrv); - DRM_INFO("failed to create connection sysfs.\n"); + DRM_ERROR("failed to create connection sysfs.\n"); + goto err_del_conn_component; } - return 0; + ret = component_add(&pdev->dev, &vidi_component_ops); + if (ret) + goto err_remove_file; + + return ret; + +err_remove_file: + device_remove_file(&pdev->dev, &dev_attr_connection); +err_del_conn_component: + exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); +err_del_crtc_component: + exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); + + return ret; } static int vidi_remove(struct platform_device *pdev) @@ -636,6 +661,10 @@ static int vidi_remove(struct platform_device *pdev) return -EINVAL; } + component_del(&pdev->dev, &vidi_component_ops); + exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); + exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); + return 0; } From 1c9ff4ab43a83f2b412f81ad4db862e5533c745d Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 24 Nov 2014 15:19:49 -0200 Subject: [PATCH 57/58] drm/exynos: Fix exynos_dpi_remove() parameter exynos_dpi_remove() should receive a exynos_drm_display but when DRM_EXYNOS_DPI was disabled it was receiving a struct device resulting in ia compiler warning. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 2e4e91bf9b07..2e5063488c50 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -307,7 +307,10 @@ int exynos_dpi_remove(struct exynos_drm_display *display); #else static inline struct exynos_drm_display * exynos_dpi_probe(struct device *dev) { return NULL; } -static inline int exynos_dpi_remove(struct device *dev) { return 0; } +static inline int exynos_dpi_remove(struct exynos_drm_display *display) +{ + return 0; +} #endif #ifdef CONFIG_DRM_EXYNOS_VIDI From 5baf5d44fbcde002d7f3f8148e69305f520770dd Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 24 Nov 2014 16:23:30 -0200 Subject: [PATCH 58/58] drm/exynos: avoid leak if exynos_dpi_probe() fails The component must be deleted if the probe fails. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index ef80a3537f35..e5810d13bf9c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1215,8 +1215,10 @@ 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); + if (IS_ERR(ctx->display)) { + ret = PTR_ERR(ctx->display); + goto err_del_component; + } pm_runtime_enable(dev);