Hi all,
This patch set separeates sub drivers into independent drivers.
patch 1/4: - make all kms drivers - fimd, hdmi, dp and dsi - to be independent drivers.
patch 2/4: - make all non kms drivers - g2d and ipp - to be independent drivers.
patch 3/4: - make vidi driver to be independent driver.
patch 4/4: - just clean up codes for checking if it's Exynos SoC.
This patch series had been posted like below with different subject, v1: http://www.spinics.net/lists/linux-samsung-soc/msg39116.html v2: http://www.spinics.net/lists/linux-samsung-soc/msg39145.html, and only one modified patch was posted.
DRM driver should be single driver so it's not reasonable for sub drivers to be built as independent modules. So I changed previous subjects to new ones by reverting existing Kconfig. With this change, all sub drivers will be built-in kernel image.
Thanks, Inki Dae
Inki Dae (4): drm/exynos: make kms drivers to be independent drivers drm/exynos: make non kms drivers to be indenpendent drivers drm/exynos: make vidi driver to be independent driver drm/exynos: clean up machine compatible string check
drivers/gpu/drm/exynos/exynos_dp_core.c | 2 + drivers/gpu/drm/exynos/exynos_drm_core.c | 164 +++++++++++++++++++++++---- drivers/gpu/drm/exynos/exynos_drm_drv.c | 125 ++++---------------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 42 ++----- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 + drivers/gpu/drm/exynos/exynos_drm_fimc.c | 1 + drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 + drivers/gpu/drm/exynos/exynos_drm_g2d.c | 48 ++++++++ drivers/gpu/drm/exynos/exynos_drm_gsc.c | 1 + drivers/gpu/drm/exynos/exynos_drm_ipp.c | 39 ++++++- drivers/gpu/drm/exynos/exynos_drm_rotator.c | 2 + drivers/gpu/drm/exynos/exynos_drm_vidi.c | 81 ++++++++----- drivers/gpu/drm/exynos/exynos_hdmi.c | 2 + drivers/gpu/drm/exynos/exynos_mixer.c | 2 + 14 files changed, 326 insertions(+), 187 deletions(-)
This patch makes kms drivers to be independent drivers. For this, it removes all register codes to kms drivers from exynos_drm_drv module and adds module_init/exit for each kms driver so that each kms driver can be called independently.
Changelog v3: - Use module_platform_driver macro instead module_init/exit. - Configure all kms drivers to be built in kernel image.
Changelog v2: - none
Signed-off-by: Inki Dae inki.dae@samsung.com --- drivers/gpu/drm/exynos/exynos_dp_core.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_drv.c | 43 +++--------------------------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 5 ---- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 ++ drivers/gpu/drm/exynos/exynos_hdmi.c | 2 ++ drivers/gpu/drm/exynos/exynos_mixer.c | 2 ++ 7 files changed, 13 insertions(+), 45 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index ed818b9..30ebf5d 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1408,6 +1408,8 @@ struct platform_driver dp_driver = { }, };
+module_platform_driver(dp_driver); + MODULE_AUTHOR("Jingoo Han jg1.han@samsung.com"); MODULE_DESCRIPTION("Samsung SoC DP Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index eab12f0..02d4772 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -484,12 +484,6 @@ 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 @@ -545,22 +539,6 @@ 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, @@ -587,22 +565,14 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) 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; - } + if (IS_ERR(match)) + return PTR_ERR(match);
ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, match); if (ret < 0) - goto err_unregister_kms_drivers; + return ret;
for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { ret = platform_driver_register(exynos_drm_non_kms_drivers[j]); @@ -632,10 +602,6 @@ err_unregister_non_kms_drivers: 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; }
@@ -654,9 +620,6 @@ static int exynos_drm_platform_remove(struct platform_device *pdev)
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; }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 262a459..352a9f9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -331,11 +331,6 @@ int exynos_drm_component_add(struct device *dev, void exynos_drm_component_del(struct device *dev, enum exynos_drm_device_type dev_type);
-extern struct platform_driver fimd_driver; -extern struct platform_driver dp_driver; -extern struct platform_driver dsi_driver; -extern struct platform_driver mixer_driver; -extern struct platform_driver hdmi_driver; extern struct platform_driver exynos_drm_common_hdmi_driver; extern struct platform_driver vidi_driver; extern struct platform_driver g2d_driver; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 66d427e..6e34ed5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1799,6 +1799,8 @@ struct platform_driver dsi_driver = { }, };
+module_platform_driver(dsi_driver); + MODULE_AUTHOR("Tomasz Figa t.figa@samsung.com"); MODULE_AUTHOR("Andrzej Hajda a.hajda@samsung.com"); MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 0673a39..3e47625 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1240,3 +1240,5 @@ struct platform_driver fimd_driver = { .of_match_table = fimd_driver_dt_match, }, }; + +module_platform_driver(fimd_driver); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 563a19e..d9bfb33 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2537,3 +2537,5 @@ struct platform_driver hdmi_driver = { .of_match_table = hdmi_match_types, }, }; + +module_platform_driver(hdmi_driver); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index a41c84e..599c0cc 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1349,3 +1349,5 @@ struct platform_driver mixer_driver = { .remove = mixer_remove, .id_table = mixer_driver_types, }; + +module_platform_driver(mixer_driver);
On 11/20/2014 11:24 AM, Inki Dae wrote:
This patch makes kms drivers to be independent drivers. For this, it removes all register codes to kms drivers from exynos_drm_drv module and adds module_init/exit for each kms driver so that each kms driver can be called independently.
Changelog v3:
- Use module_platform_driver macro instead module_init/exit.
- Configure all kms drivers to be built in kernel image.
Changelog v2:
- none
Signed-off-by: Inki Dae inki.dae@samsung.com
drivers/gpu/drm/exynos/exynos_dp_core.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_drv.c | 43 +++--------------------------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 5 ---- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 ++ drivers/gpu/drm/exynos/exynos_hdmi.c | 2 ++ drivers/gpu/drm/exynos/exynos_mixer.c | 2 ++ 7 files changed, 13 insertions(+), 45 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index ed818b9..30ebf5d 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1408,6 +1408,8 @@ struct platform_driver dp_driver = { }, };
+module_platform_driver(dp_driver);
If you try to build exynosdrm as module you will receive errors due to multiple definitions of init_module, ie module_init/module_*_driver macros can be used once per module.
Anyway I am afraid exynosdrm seems to be still fragile to order of successful probes of their components. It can be easily observed on the system with two display pipelines with one of them probe deferring. For example universal with fimd/dpi + vidi: 1. fimd defers probe because panel is not yet probed. 2. vidi probes ok. 3. drmdev is initialized. 4. fimd probes ok, but it is too late!!!
So you can reproduce the scenario on any target when one of the components defers and vidi is present (vidi never defers I suppose).
Regards Andrzej
MODULE_AUTHOR("Jingoo Han jg1.han@samsung.com"); MODULE_DESCRIPTION("Samsung SoC DP Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index eab12f0..02d4772 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -484,12 +484,6 @@ 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
@@ -545,22 +539,6 @@ 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, @@ -587,22 +565,14 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) 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;
- }
if (IS_ERR(match))
return PTR_ERR(match);
ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, match); if (ret < 0)
goto err_unregister_kms_drivers;
return ret;
for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { ret = platform_driver_register(exynos_drm_non_kms_drivers[j]);
@@ -632,10 +602,6 @@ err_unregister_non_kms_drivers: 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;
}
@@ -654,9 +620,6 @@ static int exynos_drm_platform_remove(struct platform_device *pdev)
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;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 262a459..352a9f9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -331,11 +331,6 @@ int exynos_drm_component_add(struct device *dev, void exynos_drm_component_del(struct device *dev, enum exynos_drm_device_type dev_type);
-extern struct platform_driver fimd_driver; -extern struct platform_driver dp_driver; -extern struct platform_driver dsi_driver; -extern struct platform_driver mixer_driver; -extern struct platform_driver hdmi_driver; extern struct platform_driver exynos_drm_common_hdmi_driver; extern struct platform_driver vidi_driver; extern struct platform_driver g2d_driver; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 66d427e..6e34ed5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1799,6 +1799,8 @@ struct platform_driver dsi_driver = { }, };
+module_platform_driver(dsi_driver);
MODULE_AUTHOR("Tomasz Figa t.figa@samsung.com"); MODULE_AUTHOR("Andrzej Hajda a.hajda@samsung.com"); MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 0673a39..3e47625 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1240,3 +1240,5 @@ struct platform_driver fimd_driver = { .of_match_table = fimd_driver_dt_match, }, };
+module_platform_driver(fimd_driver); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 563a19e..d9bfb33 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2537,3 +2537,5 @@ struct platform_driver hdmi_driver = { .of_match_table = hdmi_match_types, }, };
+module_platform_driver(hdmi_driver); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index a41c84e..599c0cc 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1349,3 +1349,5 @@ struct platform_driver mixer_driver = { .remove = mixer_remove, .id_table = mixer_driver_types, };
+module_platform_driver(mixer_driver);
On 2014년 11월 20일 22:19, Andrzej Hajda wrote:
On 11/20/2014 11:24 AM, Inki Dae wrote:
This patch makes kms drivers to be independent drivers. For this, it removes all register codes to kms drivers from exynos_drm_drv module and adds module_init/exit for each kms driver so that each kms driver can be called independently.
Changelog v3:
- Use module_platform_driver macro instead module_init/exit.
- Configure all kms drivers to be built in kernel image.
Changelog v2:
- none
Signed-off-by: Inki Dae inki.dae@samsung.com
drivers/gpu/drm/exynos/exynos_dp_core.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_drv.c | 43 +++--------------------------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 5 ---- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 ++ drivers/gpu/drm/exynos/exynos_hdmi.c | 2 ++ drivers/gpu/drm/exynos/exynos_mixer.c | 2 ++ 7 files changed, 13 insertions(+), 45 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index ed818b9..30ebf5d 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1408,6 +1408,8 @@ struct platform_driver dp_driver = { }, };
+module_platform_driver(dp_driver);
If you try to build exynosdrm as module you will receive errors due to multiple definitions of init_module, ie module_init/module_*_driver macros can be used once per module.
Ah, right. we had ever tried same way before but failed in same problem. I didn't realize that. Anyway, I will try to find out a better way. I'd really like to remove all register codes of sub drivers from exynos_drm_drv somehow.
Anyway I am afraid exynosdrm seems to be still fragile to order of successful probes of their components. It can be easily observed on the system with two display pipelines with one of them probe deferring. For example universal with fimd/dpi + vidi:
- fimd defers probe because panel is not yet probed.
- vidi probes ok.
- drmdev is initialized.
- fimd probes ok, but it is too late!!!
So you can reproduce the scenario on any target when one of the components defers and vidi is present (vidi never defers I suppose).
Thanks for checking, Inki Dae
Regards Andrzej
MODULE_AUTHOR("Jingoo Han jg1.han@samsung.com"); MODULE_DESCRIPTION("Samsung SoC DP Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index eab12f0..02d4772 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -484,12 +484,6 @@ 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
@@ -545,22 +539,6 @@ 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, @@ -587,22 +565,14 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) 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;
- }
if (IS_ERR(match))
return PTR_ERR(match);
ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, match); if (ret < 0)
goto err_unregister_kms_drivers;
return ret;
for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { ret = platform_driver_register(exynos_drm_non_kms_drivers[j]);
@@ -632,10 +602,6 @@ err_unregister_non_kms_drivers: 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;
}
@@ -654,9 +620,6 @@ static int exynos_drm_platform_remove(struct platform_device *pdev)
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;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 262a459..352a9f9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -331,11 +331,6 @@ int exynos_drm_component_add(struct device *dev, void exynos_drm_component_del(struct device *dev, enum exynos_drm_device_type dev_type);
-extern struct platform_driver fimd_driver; -extern struct platform_driver dp_driver; -extern struct platform_driver dsi_driver; -extern struct platform_driver mixer_driver; -extern struct platform_driver hdmi_driver; extern struct platform_driver exynos_drm_common_hdmi_driver; extern struct platform_driver vidi_driver; extern struct platform_driver g2d_driver; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 66d427e..6e34ed5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1799,6 +1799,8 @@ struct platform_driver dsi_driver = { }, };
+module_platform_driver(dsi_driver);
MODULE_AUTHOR("Tomasz Figa t.figa@samsung.com"); MODULE_AUTHOR("Andrzej Hajda a.hajda@samsung.com"); MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 0673a39..3e47625 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1240,3 +1240,5 @@ struct platform_driver fimd_driver = { .of_match_table = fimd_driver_dt_match, }, };
+module_platform_driver(fimd_driver); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 563a19e..d9bfb33 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2537,3 +2537,5 @@ struct platform_driver hdmi_driver = { .of_match_table = hdmi_match_types, }, };
+module_platform_driver(hdmi_driver); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index a41c84e..599c0cc 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1349,3 +1349,5 @@ struct platform_driver mixer_driver = { .remove = mixer_remove, .id_table = mixer_driver_types, };
+module_platform_driver(mixer_driver);
-- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hello Inki,
On Thu, Nov 20, 2014 at 2:56 PM, Inki Dae inki.dae@samsung.com wrote:
If you try to build exynosdrm as module you will receive errors due to multiple definitions of init_module, ie module_init/module_*_driver macros can be used once per module.
Ah, right. we had ever tried same way before but failed in same problem. I didn't realize that. Anyway, I will try to find out a better way. I'd really like to remove all register codes of sub drivers from exynos_drm_drv somehow.
Maybe as an immediate fix we can move the platform driver registration out of probe as suggested by Andrzej?
I posted an RFC patch a couple of days ago [0] that fixes both the deadlock and the infinite loop bug so it would be great if you can review/test so I can post a proper patch.
And then we can look how to better refactor the exynos drm driver.
Best regards, Javier
[0]: http://www.spinics.net/lists/linux-samsung-soc/msg39106.html
Hi Javier,
On 2014년 11월 20일 23:06, Javier Martinez Canillas wrote:
Hello Inki,
On Thu, Nov 20, 2014 at 2:56 PM, Inki Dae inki.dae@samsung.com wrote:
If you try to build exynosdrm as module you will receive errors due to multiple definitions of init_module, ie module_init/module_*_driver macros can be used once per module.
Ah, right. we had ever tried same way before but failed in same problem. I didn't realize that. Anyway, I will try to find out a better way. I'd really like to remove all register codes of sub drivers from exynos_drm_drv somehow.
Maybe as an immediate fix we can move the platform driver registration out of probe as suggested by Andrzej?
I posted an RFC patch a couple of days ago [0] that fixes both the deadlock and the infinite loop bug so it would be great if you can review/test so I can post a proper patch.
Fantastical timing.:) I gave you a same opinion almost simultaneous. Check your email thread.
Thanks, Inki Dae
And then we can look how to better refactor the exynos drm driver.
Best regards, Javier
On 11/20/2014 02:56 PM, Inki Dae wrote:
On 2014년 11월 20일 22:19, Andrzej Hajda wrote:
On 11/20/2014 11:24 AM, Inki Dae wrote:
This patch makes kms drivers to be independent drivers. For this, it removes all register codes to kms drivers from exynos_drm_drv module and adds module_init/exit for each kms driver so that each kms driver can be called independently.
Changelog v3:
- Use module_platform_driver macro instead module_init/exit.
- Configure all kms drivers to be built in kernel image.
Changelog v2:
- none
Signed-off-by: Inki Dae inki.dae@samsung.com
drivers/gpu/drm/exynos/exynos_dp_core.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_drv.c | 43 +++--------------------------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 5 ---- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 ++ drivers/gpu/drm/exynos/exynos_hdmi.c | 2 ++ drivers/gpu/drm/exynos/exynos_mixer.c | 2 ++ 7 files changed, 13 insertions(+), 45 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index ed818b9..30ebf5d 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1408,6 +1408,8 @@ struct platform_driver dp_driver = { }, };
+module_platform_driver(dp_driver);
If you try to build exynosdrm as module you will receive errors due to multiple definitions of init_module, ie module_init/module_*_driver macros can be used once per module.
Ah, right. we had ever tried same way before but failed in same problem. I didn't realize that. Anyway, I will try to find out a better way. I'd really like to remove all register codes of sub drivers from exynos_drm_drv somehow.
I have proposed once solution with sparse arrays, using linker scripts [1]. Something similar is used with clock controllers as I remember. I do not see other possibilities to fully separate components of exynos_drm_drv.
[1]: http://permalink.gmane.org/gmane.comp.video.dri.devel/103816
Regards Andrzej
Anyway I am afraid exynosdrm seems to be still fragile to order of successful probes of their components. It can be easily observed on the system with two display pipelines with one of them probe deferring. For example universal with fimd/dpi + vidi:
- fimd defers probe because panel is not yet probed.
- vidi probes ok.
- drmdev is initialized.
- fimd probes ok, but it is too late!!!
So you can reproduce the scenario on any target when one of the components defers and vidi is present (vidi never defers I suppose).
Thanks for checking, Inki Dae
Regards Andrzej
MODULE_AUTHOR("Jingoo Han jg1.han@samsung.com"); MODULE_DESCRIPTION("Samsung SoC DP Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index eab12f0..02d4772 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -484,12 +484,6 @@ 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
@@ -545,22 +539,6 @@ 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, @@ -587,22 +565,14 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) 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;
- }
if (IS_ERR(match))
return PTR_ERR(match);
ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, match); if (ret < 0)
goto err_unregister_kms_drivers;
return ret;
for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { ret = platform_driver_register(exynos_drm_non_kms_drivers[j]);
@@ -632,10 +602,6 @@ err_unregister_non_kms_drivers: 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;
}
@@ -654,9 +620,6 @@ static int exynos_drm_platform_remove(struct platform_device *pdev)
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;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 262a459..352a9f9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -331,11 +331,6 @@ int exynos_drm_component_add(struct device *dev, void exynos_drm_component_del(struct device *dev, enum exynos_drm_device_type dev_type);
-extern struct platform_driver fimd_driver; -extern struct platform_driver dp_driver; -extern struct platform_driver dsi_driver; -extern struct platform_driver mixer_driver; -extern struct platform_driver hdmi_driver; extern struct platform_driver exynos_drm_common_hdmi_driver; extern struct platform_driver vidi_driver; extern struct platform_driver g2d_driver; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 66d427e..6e34ed5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1799,6 +1799,8 @@ struct platform_driver dsi_driver = { }, };
+module_platform_driver(dsi_driver);
MODULE_AUTHOR("Tomasz Figa t.figa@samsung.com"); MODULE_AUTHOR("Andrzej Hajda a.hajda@samsung.com"); MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 0673a39..3e47625 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1240,3 +1240,5 @@ struct platform_driver fimd_driver = { .of_match_table = fimd_driver_dt_match, }, };
+module_platform_driver(fimd_driver); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 563a19e..d9bfb33 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2537,3 +2537,5 @@ struct platform_driver hdmi_driver = { .of_match_table = hdmi_match_types, }, };
+module_platform_driver(hdmi_driver); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index a41c84e..599c0cc 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1349,3 +1349,5 @@ struct platform_driver mixer_driver = { .remove = mixer_remove, .id_table = mixer_driver_types, };
+module_platform_driver(mixer_driver);
-- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 2014년 11월 20일 23:23, Andrzej Hajda wrote:
On 11/20/2014 02:56 PM, Inki Dae wrote:
On 2014년 11월 20일 22:19, Andrzej Hajda wrote:
On 11/20/2014 11:24 AM, Inki Dae wrote:
This patch makes kms drivers to be independent drivers. For this, it removes all register codes to kms drivers from exynos_drm_drv module and adds module_init/exit for each kms driver so that each kms driver can be called independently.
Changelog v3:
- Use module_platform_driver macro instead module_init/exit.
- Configure all kms drivers to be built in kernel image.
Changelog v2:
- none
Signed-off-by: Inki Dae inki.dae@samsung.com
drivers/gpu/drm/exynos/exynos_dp_core.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_drv.c | 43 +++--------------------------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 5 ---- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 ++ drivers/gpu/drm/exynos/exynos_hdmi.c | 2 ++ drivers/gpu/drm/exynos/exynos_mixer.c | 2 ++ 7 files changed, 13 insertions(+), 45 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index ed818b9..30ebf5d 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1408,6 +1408,8 @@ struct platform_driver dp_driver = { }, };
+module_platform_driver(dp_driver);
If you try to build exynosdrm as module you will receive errors due to multiple definitions of init_module, ie module_init/module_*_driver macros can be used once per module.
Ah, right. we had ever tried same way before but failed in same problem. I didn't realize that. Anyway, I will try to find out a better way. I'd really like to remove all register codes of sub drivers from exynos_drm_drv somehow.
I have proposed once solution with sparse arrays, using linker scripts [1]. Something similar is used with clock controllers as I remember. I do not see other possibilities to fully separate components of exynos_drm_drv.
I know this patch. I wasn't sure that the use of the private linker section is reasonable and overuse it. Actually, Mr. Park opposed this way. It might be a good idea if no problem for device drivers use the private linker section. Is there any device driver using the private linker section?
Thanks, Inki Dae
Regards Andrzej
Anyway I am afraid exynosdrm seems to be still fragile to order of successful probes of their components. It can be easily observed on the system with two display pipelines with one of them probe deferring. For example universal with fimd/dpi + vidi:
- fimd defers probe because panel is not yet probed.
- vidi probes ok.
- drmdev is initialized.
- fimd probes ok, but it is too late!!!
So you can reproduce the scenario on any target when one of the components defers and vidi is present (vidi never defers I suppose).
Thanks for checking, Inki Dae
Regards Andrzej
MODULE_AUTHOR("Jingoo Han jg1.han@samsung.com"); MODULE_DESCRIPTION("Samsung SoC DP Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index eab12f0..02d4772 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -484,12 +484,6 @@ 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
@@ -545,22 +539,6 @@ 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, @@ -587,22 +565,14 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) 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;
- }
if (IS_ERR(match))
return PTR_ERR(match);
ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, match); if (ret < 0)
goto err_unregister_kms_drivers;
return ret;
for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { ret = platform_driver_register(exynos_drm_non_kms_drivers[j]);
@@ -632,10 +602,6 @@ err_unregister_non_kms_drivers: 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;
}
@@ -654,9 +620,6 @@ static int exynos_drm_platform_remove(struct platform_device *pdev)
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;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 262a459..352a9f9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -331,11 +331,6 @@ int exynos_drm_component_add(struct device *dev, void exynos_drm_component_del(struct device *dev, enum exynos_drm_device_type dev_type);
-extern struct platform_driver fimd_driver; -extern struct platform_driver dp_driver; -extern struct platform_driver dsi_driver; -extern struct platform_driver mixer_driver; -extern struct platform_driver hdmi_driver; extern struct platform_driver exynos_drm_common_hdmi_driver; extern struct platform_driver vidi_driver; extern struct platform_driver g2d_driver; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 66d427e..6e34ed5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1799,6 +1799,8 @@ struct platform_driver dsi_driver = { }, };
+module_platform_driver(dsi_driver);
MODULE_AUTHOR("Tomasz Figa t.figa@samsung.com"); MODULE_AUTHOR("Andrzej Hajda a.hajda@samsung.com"); MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 0673a39..3e47625 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1240,3 +1240,5 @@ struct platform_driver fimd_driver = { .of_match_table = fimd_driver_dt_match, }, };
+module_platform_driver(fimd_driver); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 563a19e..d9bfb33 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2537,3 +2537,5 @@ struct platform_driver hdmi_driver = { .of_match_table = hdmi_match_types, }, };
+module_platform_driver(hdmi_driver); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index a41c84e..599c0cc 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1349,3 +1349,5 @@ struct platform_driver mixer_driver = { .remove = mixer_remove, .id_table = mixer_driver_types, };
+module_platform_driver(mixer_driver);
-- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 11/20/2014 03:37 PM, Inki Dae wrote:
On 2014년 11월 20일 23:23, Andrzej Hajda wrote:
On 11/20/2014 02:56 PM, Inki Dae wrote:
On 2014년 11월 20일 22:19, Andrzej Hajda wrote:
On 11/20/2014 11:24 AM, Inki Dae wrote:
This patch makes kms drivers to be independent drivers. For this, it removes all register codes to kms drivers from exynos_drm_drv module and adds module_init/exit for each kms driver so that each kms driver can be called independently.
Changelog v3:
- Use module_platform_driver macro instead module_init/exit.
- Configure all kms drivers to be built in kernel image.
Changelog v2:
- none
Signed-off-by: Inki Dae inki.dae@samsung.com
drivers/gpu/drm/exynos/exynos_dp_core.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_drv.c | 43 +++--------------------------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 5 ---- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 ++ drivers/gpu/drm/exynos/exynos_hdmi.c | 2 ++ drivers/gpu/drm/exynos/exynos_mixer.c | 2 ++ 7 files changed, 13 insertions(+), 45 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index ed818b9..30ebf5d 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1408,6 +1408,8 @@ struct platform_driver dp_driver = { }, };
+module_platform_driver(dp_driver);
If you try to build exynosdrm as module you will receive errors due to multiple definitions of init_module, ie module_init/module_*_driver macros can be used once per module.
Ah, right. we had ever tried same way before but failed in same problem. I didn't realize that. Anyway, I will try to find out a better way. I'd really like to remove all register codes of sub drivers from exynos_drm_drv somehow.
I have proposed once solution with sparse arrays, using linker scripts [1]. Something similar is used with clock controllers as I remember. I do not see other possibilities to fully separate components of exynos_drm_drv.
I know this patch. I wasn't sure that the use of the private linker section is reasonable and overuse it. Actually, Mr. Park opposed this way. It might be a good idea if no problem for device drivers use the private linker section. Is there any device driver using the private linker section?
No, there are no dev drivers using it, but it is hardly used anyway.
Quick look at include/asm-generic/vmlinux.lds.h shows following sparse arrays: #define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc) #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip) #define CLK_OF_TABLES() OF_TABLE(CONFIG_COMMON_CLK, clk) #define RESERVEDMEM_OF_TABLES() OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem) #define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method) #define EARLYCON_OF_TABLES() OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
The number of arrays slowly grows over time, so some day they can start appear in drivers as well :)
Such array in driver doesn't look like much different to me, it is just a workaround for language limitations, but it would be good to have an opinion of people more involved in linker scripts.
On the other side having list of component drivers in exynos_drm_drv and registering them in module init maybe is not pretty, but it does the same thing and is quite clear and standard.
Regards Andrzej
Thanks, Inki Dae
Regards Andrzej
Anyway I am afraid exynosdrm seems to be still fragile to order of successful probes of their components. It can be easily observed on the system with two display pipelines with one of them probe deferring. For example universal with fimd/dpi + vidi:
- fimd defers probe because panel is not yet probed.
- vidi probes ok.
- drmdev is initialized.
- fimd probes ok, but it is too late!!!
So you can reproduce the scenario on any target when one of the components defers and vidi is present (vidi never defers I suppose).
Thanks for checking, Inki Dae
Regards Andrzej
MODULE_AUTHOR("Jingoo Han jg1.han@samsung.com"); MODULE_DESCRIPTION("Samsung SoC DP Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index eab12f0..02d4772 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -484,12 +484,6 @@ 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
@@ -545,22 +539,6 @@ 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, @@ -587,22 +565,14 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) 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;
- }
if (IS_ERR(match))
return PTR_ERR(match);
ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, match); if (ret < 0)
goto err_unregister_kms_drivers;
return ret;
for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { ret = platform_driver_register(exynos_drm_non_kms_drivers[j]);
@@ -632,10 +602,6 @@ err_unregister_non_kms_drivers: 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;
}
@@ -654,9 +620,6 @@ static int exynos_drm_platform_remove(struct platform_device *pdev)
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;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 262a459..352a9f9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -331,11 +331,6 @@ int exynos_drm_component_add(struct device *dev, void exynos_drm_component_del(struct device *dev, enum exynos_drm_device_type dev_type);
-extern struct platform_driver fimd_driver; -extern struct platform_driver dp_driver; -extern struct platform_driver dsi_driver; -extern struct platform_driver mixer_driver; -extern struct platform_driver hdmi_driver; extern struct platform_driver exynos_drm_common_hdmi_driver; extern struct platform_driver vidi_driver; extern struct platform_driver g2d_driver; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 66d427e..6e34ed5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1799,6 +1799,8 @@ struct platform_driver dsi_driver = { }, };
+module_platform_driver(dsi_driver);
MODULE_AUTHOR("Tomasz Figa t.figa@samsung.com"); MODULE_AUTHOR("Andrzej Hajda a.hajda@samsung.com"); MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 0673a39..3e47625 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1240,3 +1240,5 @@ struct platform_driver fimd_driver = { .of_match_table = fimd_driver_dt_match, }, };
+module_platform_driver(fimd_driver); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 563a19e..d9bfb33 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2537,3 +2537,5 @@ struct platform_driver hdmi_driver = { .of_match_table = hdmi_match_types, }, };
+module_platform_driver(hdmi_driver); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index a41c84e..599c0cc 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1349,3 +1349,5 @@ struct platform_driver mixer_driver = { .remove = mixer_remove, .id_table = mixer_driver_types, };
+module_platform_driver(mixer_driver);
-- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
This patch makes non kms drivers to be independent drivers. For this, it removes all register codes to non kms drivers from exynos_drm_drv module and adds module_init/exit for each non kms driver so that each non kms driver can be called independently.
In addition, this patch adds non kms register/unregister functions to exynos_drm_core module and also modifies existing codes relevant to sub driver.
The idea is that non kms driver is registered by entry point, module_init, of each non kms driver and sets its own sub driver to registered non kms driver object when the sub driver is probed. For this, this patch adds a new structure, exynos_drm_non_kms_dev, to exynos_drm_core module.
Changelog v3: - fix the use of mutex lock. - fix g2d device node check. - use module_platform_driver macro instead of module_init/exit.
Changelog v2: - check if available g2d device node. - return 0 instead of -EPROBE_DEFER in case of no non kms device registered. This case is not error.
Signed-off-by: Inki Dae inki.dae@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_core.c | 164 +++++++++++++++++++++++---- drivers/gpu/drm/exynos/exynos_drm_drv.c | 50 +------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 28 ++--- drivers/gpu/drm/exynos/exynos_drm_fimc.c | 1 + drivers/gpu/drm/exynos/exynos_drm_g2d.c | 48 ++++++++ drivers/gpu/drm/exynos/exynos_drm_gsc.c | 1 + drivers/gpu/drm/exynos/exynos_drm_ipp.c | 39 ++++++- drivers/gpu/drm/exynos/exynos_drm_rotator.c | 2 + 8 files changed, 243 insertions(+), 90 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 4c9f972..6c38308 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c @@ -19,6 +19,13 @@ #include "exynos_drm_fbdev.h"
static LIST_HEAD(exynos_drm_subdrv_list); +DEFINE_MUTEX(list_lock); + +struct exynos_drm_non_kms_dev { + struct list_head list; + struct exynos_drm_subdrv *subdrv; + unsigned int device_type; +};
int exynos_drm_create_enc_conn(struct drm_device *dev, struct exynos_drm_display *display) @@ -55,12 +62,66 @@ err_destroy_encoder: return ret; }
+int exynos_drm_non_kms_register(unsigned int device_type) +{ + struct exynos_drm_non_kms_dev *dev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->device_type = device_type; + + mutex_lock(&list_lock); + list_add_tail(&dev->list, &exynos_drm_subdrv_list); + mutex_unlock(&list_lock); + + return 0; +} + +void exynos_drm_non_kms_unregister(unsigned int device_type) +{ + struct exynos_drm_non_kms_dev *dev, *next; + + mutex_lock(&list_lock); + list_for_each_entry_safe(dev, next, &exynos_drm_subdrv_list, list) { + mutex_unlock(&list_lock); + if (dev->device_type == device_type) { + list_del_init(&dev->list); + kfree(dev); + mutex_lock(&list_lock); + break; + } + mutex_lock(&list_lock); + } + mutex_unlock(&list_lock); +} + int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) { + struct exynos_drm_non_kms_dev *dev; + if (!subdrv) return -EINVAL;
- list_add_tail(&subdrv->list, &exynos_drm_subdrv_list); + mutex_lock(&list_lock); + if (list_empty(&exynos_drm_subdrv_list)) { + mutex_unlock(&list_lock); + return -ENODEV; + } + mutex_unlock(&list_lock); + + mutex_lock(&list_lock); + list_for_each_entry(dev, &exynos_drm_subdrv_list, list) { + mutex_unlock(&list_lock); + if (dev->device_type == subdrv->device_type) { + dev->subdrv = subdrv; + mutex_lock(&list_lock); + break; + } + mutex_lock(&list_lock); + } + mutex_unlock(&list_lock);
return 0; } @@ -68,94 +129,149 @@ EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv) { + struct exynos_drm_non_kms_dev *dev; + if (!subdrv) return -EINVAL;
- list_del(&subdrv->list); + mutex_lock(&list_lock); + list_for_each_entry(dev, &exynos_drm_subdrv_list, list) { + mutex_unlock(&list_lock); + if (dev->device_type == subdrv->device_type) { + dev->subdrv = NULL; + break; + } + mutex_lock(&list_lock); + } + mutex_unlock(&list_lock);
return 0; } EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
-int exynos_drm_device_subdrv_probe(struct drm_device *dev) +int exynos_drm_device_subdrv_probe(struct drm_device *drm_dev) { - struct exynos_drm_subdrv *subdrv, *n; + struct exynos_drm_non_kms_dev *dev, *n; int err;
- if (!dev) + if (!drm_dev) return -EINVAL;
- list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { + mutex_lock(&list_lock); + if (list_empty(&exynos_drm_subdrv_list)) { + mutex_unlock(&list_lock); + return 0; + } + + list_for_each_entry(dev, &exynos_drm_subdrv_list, list) { + mutex_unlock(&list_lock); + /* Retry to probe if there is sub driver not registered yet. */ + if (!dev->subdrv) + return -EPROBE_DEFER; + mutex_lock(&list_lock); + } + + list_for_each_entry_safe(dev, n, &exynos_drm_subdrv_list, list) { + struct exynos_drm_subdrv *subdrv = dev->subdrv; + + mutex_unlock(&list_lock); if (subdrv->probe) { - subdrv->drm_dev = dev; + subdrv->drm_dev = drm_dev;
/* * this probe callback would be called by sub driver * after setting of all resources to this sub driver, * such as clock, irq and register map are done. */ - err = subdrv->probe(dev, subdrv->dev); + err = subdrv->probe(drm_dev, subdrv->dev); if (err) { DRM_DEBUG("exynos drm subdrv probe failed.\n"); - list_del(&subdrv->list); + list_del_init(&dev->list); + mutex_lock(&list_lock); continue; } } + mutex_lock(&list_lock); } + mutex_unlock(&list_lock);
return 0; } EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_probe);
-int exynos_drm_device_subdrv_remove(struct drm_device *dev) +int exynos_drm_device_subdrv_remove(struct drm_device *drm_dev) { - struct exynos_drm_subdrv *subdrv; + struct exynos_drm_non_kms_dev *dev;
- if (!dev) { + if (!drm_dev) { WARN(1, "Unexpected drm device unregister!\n"); return -EINVAL; }
- list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { + mutex_lock(&list_lock); + list_for_each_entry(dev, &exynos_drm_subdrv_list, list) { + struct exynos_drm_subdrv *subdrv = dev->subdrv; + + mutex_unlock(&list_lock); if (subdrv->remove) - subdrv->remove(dev, subdrv->dev); + subdrv->remove(drm_dev, subdrv->dev); + mutex_lock(&list_lock); } + mutex_unlock(&list_lock);
return 0; } EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_remove);
-int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file) +int exynos_drm_subdrv_open(struct drm_device *drm_dev, struct drm_file *file) { - struct exynos_drm_subdrv *subdrv; + struct exynos_drm_non_kms_dev *dev; int ret;
- list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { + mutex_lock(&list_lock); + list_for_each_entry(dev, &exynos_drm_subdrv_list, list) { + struct exynos_drm_subdrv *subdrv = dev->subdrv; + + mutex_unlock(&list_lock); if (subdrv->open) { - ret = subdrv->open(dev, subdrv->dev, file); + ret = subdrv->open(drm_dev, subdrv->dev, file); if (ret) goto err; } + mutex_lock(&list_lock); } + mutex_unlock(&list_lock);
return 0;
err: - list_for_each_entry_reverse(subdrv, &subdrv->list, list) { + mutex_lock(&list_lock); + list_for_each_entry_reverse(dev, &exynos_drm_subdrv_list, list) { + struct exynos_drm_subdrv *subdrv = dev->subdrv; + + mutex_unlock(&list_lock); if (subdrv->close) - subdrv->close(dev, subdrv->dev, file); + subdrv->close(drm_dev, subdrv->dev, file); + mutex_lock(&list_lock); } + mutex_unlock(&list_lock); return ret; } EXPORT_SYMBOL_GPL(exynos_drm_subdrv_open);
-void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file) +void exynos_drm_subdrv_close(struct drm_device *drm_dev, struct drm_file *file) { - struct exynos_drm_subdrv *subdrv; + struct exynos_drm_non_kms_dev *dev; + + mutex_lock(&list_lock); + list_for_each_entry(dev, &exynos_drm_subdrv_list, list) { + struct exynos_drm_subdrv *subdrv = dev->subdrv;
- list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { + mutex_unlock(&list_lock); if (subdrv->close) - subdrv->close(dev, subdrv->dev, file); + subdrv->close(drm_dev, subdrv->dev, file); + mutex_lock(&list_lock); } + mutex_unlock(&list_lock); } EXPORT_SYMBOL_GPL(exynos_drm_subdrv_close); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 02d4772..7f1186e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -539,28 +539,10 @@ static const struct component_master_ops exynos_drm_ops = { .unbind = exynos_drm_unbind, };
-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, i, j; + int ret;
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls); @@ -574,31 +556,13 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) if (ret < 0) return ret;
- 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; - /* 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; + goto err_del_component_master;
return ret;
-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_del_component_master: component_master_del(&pdev->dev, &exynos_drm_ops);
@@ -607,17 +571,7 @@ err_del_component_master:
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 - - 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);
return 0; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 352a9f9..5b3305c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -41,6 +41,13 @@ enum exynos_drm_output_type { EXYNOS_DISPLAY_TYPE_VIDI, };
+/* This enumerates non kms device type. */ +enum exynos_drm_non_kms_type { + EXYNOS_DRM_NON_KMS_NONE, + EXYNOS_DRM_NON_KMS_G2D, + EXYNOS_DRM_NON_KMS_IPP, +}; + /* * Exynos drm common overlay structure. * @@ -259,10 +266,10 @@ struct exynos_drm_private { /* * Exynos drm sub driver structure. * - * @list: sub driver has its own list object to register to exynos drm driver. * @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(). + * @device_type: non kms device type. * @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 @@ -271,9 +278,9 @@ struct exynos_drm_private { * @close: this would be called with drm device file close. */ struct exynos_drm_subdrv { - struct list_head list; struct device *dev; struct drm_device *drm_dev; + unsigned int device_type;
int (*probe)(struct drm_device *drm_dev, struct device *dev); void (*remove)(struct drm_device *drm_dev, struct device *dev); @@ -294,15 +301,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);
-#ifdef CONFIG_DRM_EXYNOS_IPP -int exynos_platform_device_ipp_register(void); -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); int exynos_dpi_remove(struct device *dev); @@ -331,11 +329,9 @@ int exynos_drm_component_add(struct device *dev, void exynos_drm_component_del(struct device *dev, enum exynos_drm_device_type dev_type);
+extern int exynos_drm_non_kms_register(unsigned int device_type); +extern void exynos_drm_non_kms_unregister(unsigned int device_type); + extern struct platform_driver exynos_drm_common_hdmi_driver; extern struct platform_driver vidi_driver; -extern struct platform_driver g2d_driver; -extern struct platform_driver fimc_driver; -extern struct platform_driver rotator_driver; -extern struct platform_driver gsc_driver; -extern struct platform_driver ipp_driver; #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index 68d38eb..eb65c76 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -1860,3 +1860,4 @@ struct platform_driver fimc_driver = { }, };
+module_platform_driver(fimc_driver); diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 6ff8599..e17f9ab 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -1464,6 +1464,7 @@ static int g2d_probe(struct platform_device *pdev) platform_set_drvdata(pdev, g2d);
subdrv = &g2d->subdrv; + subdrv->device_type = EXYNOS_DRM_NON_KMS_G2D; subdrv->dev = dev; subdrv->probe = g2d_subdrv_probe; subdrv->remove = g2d_subdrv_remove; @@ -1585,3 +1586,50 @@ struct platform_driver g2d_driver = { .of_match_table = exynos_g2d_match, }, }; + +static const char * const strings[] = { + "samsung,exynos4212-g2d", + "samsung,exynos5250-g2d", +}; + +static int exynos_g2d_init(void) +{ + struct device_node *np; + bool node_exist = false; + int ret, i; + + /* + * Register non kms driver only in case that g2d device node exists + * and the device node is enabled. + * + * TODO. this code should be replaced with super device node. + */ + for (i = 0; i < ARRAY_SIZE(strings); i++) { + np = of_find_compatible_node(NULL, NULL, strings[i]); + if (np && of_device_is_available(np)) { + node_exist = true; + break; + } + } + + if (!node_exist) + return -ENODEV; + + ret = exynos_drm_non_kms_register(EXYNOS_DRM_NON_KMS_G2D); + if (ret) + return ret; + + ret = platform_driver_register(&g2d_driver); + if (ret) + exynos_drm_non_kms_unregister(EXYNOS_DRM_NON_KMS_G2D); + + return ret; +} + +static void exynos_g2d_exit(void) +{ + platform_driver_unregister(&g2d_driver); +} + +module_init(exynos_g2d_init); +module_exit(exynos_g2d_exit); diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index c6a013f..b814c37 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -1799,3 +1799,4 @@ struct platform_driver gsc_driver = { }, };
+module_platform_driver(gsc_driver); diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 00d74b1..559ee65 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -102,7 +102,7 @@ static LIST_HEAD(exynos_drm_ippdrv_list); static DEFINE_MUTEX(exynos_drm_ippdrv_lock); static BLOCKING_NOTIFIER_HEAD(exynos_drm_ippnb_list);
-int exynos_platform_device_ipp_register(void) +static int exynos_platform_device_ipp_register(void) { struct platform_device *pdev;
@@ -118,7 +118,7 @@ int exynos_platform_device_ipp_register(void) return 0; }
-void exynos_platform_device_ipp_unregister(void) +static void exynos_platform_device_ipp_unregister(void) { if (exynos_drm_ipp_pdev) { platform_device_unregister(exynos_drm_ipp_pdev); @@ -1718,6 +1718,7 @@ static int ipp_probe(struct platform_device *pdev)
/* set sub driver informations */ subdrv = &ctx->subdrv; + subdrv->device_type = EXYNOS_DRM_NON_KMS_IPP; subdrv->dev = dev; subdrv->probe = ipp_subdrv_probe; subdrv->remove = ipp_subdrv_remove; @@ -1773,3 +1774,37 @@ struct platform_driver ipp_driver = { }, };
+static int ipp_driver_init(void) +{ + int ret; + + ret = exynos_drm_non_kms_register(EXYNOS_DRM_NON_KMS_IPP); + if (ret) + return ret; + + ret = exynos_platform_device_ipp_register(); + if (ret) + goto err_unregister_non_kms; + + ret = platform_driver_register(&ipp_driver); + if (ret) + goto err_unregister_ipp_device; + + return ret; + +err_unregister_ipp_device: + exynos_platform_device_ipp_unregister(); +err_unregister_non_kms: + exynos_drm_non_kms_unregister(EXYNOS_DRM_NON_KMS_IPP); + + return ret; +} + +static void ipp_driver_exit(void) +{ + platform_driver_unregister(&ipp_driver); +} + +module_init(ipp_driver_init); +module_exit(ipp_driver_exit); + diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c index b6a37d4..f5e3a2d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c +++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c @@ -854,3 +854,5 @@ struct platform_driver rotator_driver = { .of_match_table = exynos_rotator_match, }, }; + +module_platform_driver(rotator_driver);
This patch makes vidi driver to be independent driver. For this, it removes register codes to vidi driver from exynos_drm_drv module and adds module_init/exit for vidi driver so that this driver can be called independently.
In addition, this patch adds component support to vidi driver so that this driver can be bound independently.
Changelog v3: - none
Changelog v2: - none
Signed-off-by: Inki Dae inki.dae@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 12 +---- drivers/gpu/drm/exynos/exynos_drm_drv.h | 9 ---- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 81 +++++++++++++++++++----------- 3 files changed, 54 insertions(+), 48 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 7f1186e..3ac39b6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -608,19 +608,12 @@ static int exynos_drm_init(void) if (IS_ERR(exynos_drm_pdev)) return PTR_ERR(exynos_drm_pdev);
- ret = exynos_drm_probe_vidi(); - if (ret < 0) - goto err_unregister_pd; - ret = platform_driver_register(&exynos_drm_platform_driver); if (ret) - goto err_remove_vidi; + goto err_unregister_pd;
return 0;
-err_remove_vidi: - exynos_drm_remove_vidi(); - err_unregister_pd: platform_device_unregister(exynos_drm_pdev);
@@ -630,9 +623,6 @@ err_unregister_pd: static void exynos_drm_exit(void) { platform_driver_unregister(&exynos_drm_platform_driver); - - exynos_drm_remove_vidi(); - 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 5b3305c..7c2ba06 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -310,14 +310,6 @@ exynos_dpi_probe(struct device *dev) { return NULL; } static inline int exynos_dpi_remove(struct device *dev) { return 0; } #endif
-#ifdef CONFIG_DRM_EXYNOS_VIDI -int exynos_drm_probe_vidi(void); -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, struct exynos_drm_display *display); @@ -333,5 +325,4 @@ extern int exynos_drm_non_kms_register(unsigned int device_type); extern void exynos_drm_non_kms_unregister(unsigned int device_type);
extern struct platform_driver exynos_drm_common_hdmi_driver; -extern struct platform_driver vidi_driver; #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 50faf91..e1153aa 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -14,6 +14,7 @@
#include <linux/kernel.h> #include <linux/platform_device.h> +#include <linux/component.h>
#include <drm/exynos_drm.h>
@@ -48,10 +49,10 @@ struct vidi_win_data {
struct vidi_context { struct drm_device *drm_dev; + struct platform_device *pdev; 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; @@ -561,14 +562,13 @@ static struct exynos_drm_display vidi_display = { .ops = &vidi_display_ops, };
-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 exynos_drm_manager *mgr = get_vidi_mgr(dev); - struct vidi_context *ctx = mgr->ctx; - struct drm_crtc *crtc = ctx->crtc; + struct drm_crtc *crtc = vidi_manager.crtc; + struct drm_device *drm_dev = data; int ret;
- vidi_mgr_initialize(mgr, drm_dev); + vidi_mgr_initialize(&vidi_manager, drm_dev);
ret = exynos_drm_crtc_create(&vidi_manager); if (ret) { @@ -586,20 +586,42 @@ 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;
+ ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC, + vidi_manager.type); + if (ret) + return ret; + + ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, + vidi_display.type); + if (ret) + goto err_del_crtc_component; + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + if (!ctx) { + ret = -ENOMEM; + goto err_del_conn_component; + }
ctx->default_win = 0;
INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
+ ctx->pdev = pdev; vidi_manager.ctx = ctx; vidi_display.ctx = ctx;
@@ -607,23 +629,21 @@ static int vidi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, &vidi_manager);
- 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); + if (ret < 0) DRM_INFO("failed to create connection sysfs.\n"); - }
- return 0; + ret = component_add(&pdev->dev, &vidi_component_ops); + if (ret) + goto err_del_conn_component; + + return ret; + +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) @@ -638,6 +658,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; }
@@ -650,7 +674,7 @@ struct platform_driver vidi_driver = { }, };
-int exynos_drm_probe_vidi(void) +static int exynos_drm_vidi_init(void) { struct platform_device *pdev; int ret; @@ -668,12 +692,13 @@ int exynos_drm_probe_vidi(void) return ret; }
-void exynos_drm_remove_vidi(void) +void exynos_drm_vidi_exit(void) { struct vidi_context *ctx = vidi_manager.ctx; - struct exynos_drm_subdrv *subdrv = &ctx->subdrv; - struct platform_device *pdev = to_platform_device(subdrv->dev);
platform_driver_unregister(&vidi_driver); - platform_device_unregister(pdev); + platform_device_unregister(ctx->pdev); } + +module_init(exynos_drm_vidi_init); +module_exit(exynos_drm_vidi_exit);
Use 'for' statemant instead of hard-coded 'if' statement.
Changelog v3: - none
Changelog v2: - none
Signed-off-by: Inki Dae inki.dae@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 3ac39b6..4579186 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -587,9 +587,16 @@ static struct platform_driver exynos_drm_platform_driver = { }, };
+static const char * const strings[] = { + "samsung,exynos3", + "samsung,exynos4", + "samsung,exynos5", +}; + static int exynos_drm_init(void) { - int ret; + bool is_exynos = false; + int ret, i;
/* * Register device object only in case of Exynos SoC. @@ -598,9 +605,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,
dri-devel@lists.freedesktop.org