Hi all,
This patch set adds full modularity to sub drivers, kms and non kms drivers.
For this, this patch sets consists into three patches. first patch modularizes kms drivers, second patch for non kms drivers, and third patch for vidi driver.
I hope we could resolve infinite loop issue and kernel lockup reported by other people. This patch set is RFC so there might be my missing points. Welcome to any comments.
This patch set is based on top of exynos-drm-next branch.
Thanks, Inki Dae
Inki Dae (3): drm/exynos: make kms drivers to be independent modules drm/exynos: make non kms drivers to be indenpendent modules drm/exynos: make vidi driver to be independent module
drivers/gpu/drm/exynos/Kconfig | 8 +- drivers/gpu/drm/exynos/exynos_dp_core.c | 13 +++ drivers/gpu/drm/exynos/exynos_drm_core.c | 166 +++++++++++++++++++++++---- drivers/gpu/drm/exynos/exynos_drm_drv.c | 105 +---------------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 42 ++----- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 13 +++ drivers/gpu/drm/exynos/exynos_drm_fimc.c | 13 +++ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 13 +++ drivers/gpu/drm/exynos/exynos_drm_g2d.c | 34 ++++++ drivers/gpu/drm/exynos/exynos_drm_gsc.c | 12 ++ drivers/gpu/drm/exynos/exynos_drm_ipp.c | 39 ++++++- drivers/gpu/drm/exynos/exynos_drm_rotator.c | 13 +++ drivers/gpu/drm/exynos/exynos_drm_vidi.c | 81 ++++++++----- drivers/gpu/drm/exynos/exynos_hdmi.c | 13 +++ drivers/gpu/drm/exynos/exynos_mixer.c | 13 +++ 15 files changed, 391 insertions(+), 187 deletions(-)
This patch makes kms drivers to be independent modules. 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.
Signed-off-by: Inki Dae inki.dae@samsung.com --- drivers/gpu/drm/exynos/Kconfig | 8 +++--- drivers/gpu/drm/exynos/exynos_dp_core.c | 13 +++++++++ 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 | 13 +++++++++ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 13 +++++++++ drivers/gpu/drm/exynos/exynos_hdmi.c | 13 +++++++++ drivers/gpu/drm/exynos/exynos_mixer.c | 13 +++++++++ 8 files changed, 72 insertions(+), 49 deletions(-)
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 7f9f6f9..3d5fa69 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -25,7 +25,7 @@ config DRM_EXYNOS_DMABUF Choose this option if you want to use DMABUF feature for DRM.
config DRM_EXYNOS_FIMD - bool "Exynos DRM FIMD" + tristate "Exynos DRM FIMD" depends on DRM_EXYNOS && !FB_S3C select FB_MODE_HELPERS select MFD_SYSCON @@ -41,7 +41,7 @@ config DRM_EXYNOS_DPI This enables support for Exynos parallel output.
config DRM_EXYNOS_DSI - bool "EXYNOS DRM MIPI-DSI driver support" + tristate "EXYNOS DRM MIPI-DSI driver support" depends on DRM_EXYNOS_FIMD select DRM_MIPI_DSI select DRM_PANEL @@ -50,7 +50,7 @@ config DRM_EXYNOS_DSI This enables support for Exynos MIPI-DSI device.
config DRM_EXYNOS_DP - bool "EXYNOS DRM DP driver support" + tristate "EXYNOS DRM DP driver support" depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) default DRM_EXYNOS select DRM_PANEL @@ -58,7 +58,7 @@ config DRM_EXYNOS_DP This enables support for DP device.
config DRM_EXYNOS_HDMI - bool "Exynos DRM HDMI" + tristate "Exynos DRM HDMI" depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV help Choose this option if you want to use Exynos HDMI for DRM. diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index ed818b9..b08d97b 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1408,6 +1408,19 @@ struct platform_driver dp_driver = { }, };
+static int exynos_dp_init(void) +{ + return platform_driver_register(&dp_driver); +} + +static void exynos_dp_exit(void) +{ + platform_driver_unregister(&dp_driver); +} + +module_init(exynos_dp_init); +module_exit(exynos_dp_exit); + 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..ebc3383 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1799,6 +1799,19 @@ struct platform_driver dsi_driver = { }, };
+static int exynos_dsi_driver_init(void) +{ + return platform_driver_register(&dsi_driver); +} + +static void exynos_dsi_driver_exit(void) +{ + platform_driver_unregister(&dsi_driver); +} + +module_init(exynos_dsi_driver_init); +module_exit(exynos_dsi_driver_exit); + 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..eed51c6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1240,3 +1240,16 @@ struct platform_driver fimd_driver = { .of_match_table = fimd_driver_dt_match, }, }; + +static int exynos_drm_fimd_init(void) +{ + return platform_driver_register(&fimd_driver); +} + +static void exynos_drm_fimd_exit(void) +{ + platform_driver_unregister(&fimd_driver); +} + +module_init(exynos_drm_fimd_init); +module_exit(exynos_drm_fimd_exit); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 563a19e..83198f7 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2537,3 +2537,16 @@ struct platform_driver hdmi_driver = { .of_match_table = hdmi_match_types, }, }; + +static int hdmi_init(void) +{ + return platform_driver_register(&hdmi_driver); +} + +static void hdmi_exit(void) +{ + platform_driver_unregister(&hdmi_driver); +} + +module_init(hdmi_init); +module_exit(hdmi_exit); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index a41c84e..4d812f1 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1349,3 +1349,16 @@ struct platform_driver mixer_driver = { .remove = mixer_remove, .id_table = mixer_driver_types, }; + +static int mixer_init(void) +{ + return platform_driver_register(&mixer_driver); +} + +static void mixer_exit(void) +{ + platform_driver_unregister(&mixer_driver); +} + +module_init(mixer_init); +module_exit(mixer_exit);
On 11/18/2014 04:26 PM, Inki Dae wrote:
It is hard to test if modules are working because I am not able to build modules :), see comments below.
Without corresponding changes in Makefiles you cannot build it as modules.
Here and in other modules you can use module_platform_driver macro.
It is hard to guess how and why it should work with modules. For example what should happen if fimd/dsi modules are loaded but hdmi/mixer not. When exynos_drv should wait with initialization for hdmi and when it should create drmdev.
DRM system is rather monolithic splitting its components to modules seems strange.
Regards Andrzej
2014-11-19 17:49 GMT+09:00 Andrzej Hajda a.hajda@samsung.com:
Right, hdmi/mixer cannot be probed, which means module doesn't work correctly.
Yes, good point. I missed a big point that DRM system should be monolithic, integrated driver. However I strongly think it's better to separate them into independent drivers so that entry point of each sub driver can be called itself. With this, the probe order of each sub driver can be handled by component and Exynos drm core properly. it's really not good for all register codes of sub drivers to be placed in exynos_drm_drv, and this was my plan for cleanning up Exynos drm long ago: but still remaining one more thing, applying super device node. So I will just modify for them to be built in kernel image by reverting the change of Kconfig, which means that all sub drivers cannot be configured as a separeated module like now.
Thanks, Inki Dae
This patch makes non kms drivers to be independent modules. 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.
Signed-off-by: Inki Dae inki.dae@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_core.c | 166 +++++++++++++++++++++++---- 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 | 13 +++ drivers/gpu/drm/exynos/exynos_drm_g2d.c | 34 ++++++ drivers/gpu/drm/exynos/exynos_drm_gsc.c | 12 ++ drivers/gpu/drm/exynos/exynos_drm_ipp.c | 39 ++++++- drivers/gpu/drm/exynos/exynos_drm_rotator.c | 13 +++ 8 files changed, 265 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..2ce63bc 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,151 @@ 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 -EPROBE_DEFER; + } + + 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_lock(&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..05000ee 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -1860,3 +1860,16 @@ struct platform_driver fimc_driver = { }, };
+static int fimc_driver_init(void) +{ + return platform_driver_register(&fimc_driver); +} + +static void fimc_driver_exit(void) +{ + platform_driver_unregister(&fimc_driver); +} + +module_init(fimc_driver_init); +module_exit(fimc_driver_exit); + diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 6ff8599..fa37603 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,36 @@ struct platform_driver g2d_driver = { .of_match_table = exynos_g2d_match, }, }; + +static int exynos_g2d_init(void) +{ + int ret; + + /* + * 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. + */ + if (!of_machine_is_compatible("samsung,exynos5250-g2d") && + !of_machine_is_compatible("samsung,exynos4212-g2d")) + 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..0cbed55 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -1799,3 +1799,15 @@ struct platform_driver gsc_driver = { }, };
+static int gsc_driver_init(void) +{ + return platform_driver_register(&gsc_driver); +} + +static void gsc_driver_exit(void) +{ + platform_driver_unregister(&gsc_driver); +} + +module_init(gsc_driver_init); +module_exit(gsc_driver_exit); 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..ffa0166 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c +++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c @@ -854,3 +854,16 @@ struct platform_driver rotator_driver = { .of_match_table = exynos_rotator_match, }, }; + +static int rotator_driver_init(void) +{ + return platform_driver_register(&rotator_driver); +} + +static void rotator_driver_exit(void) +{ + platform_driver_unregister(&rotator_driver); +} + +module_init(rotator_driver_init); +module_exit(rotator_driver_exit);
This patch makes non kms drivers to be independent modules. 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 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 | 13 +++ drivers/gpu/drm/exynos/exynos_drm_g2d.c | 42 +++++++ drivers/gpu/drm/exynos/exynos_drm_gsc.c | 12 ++ drivers/gpu/drm/exynos/exynos_drm_ipp.c | 39 ++++++- drivers/gpu/drm/exynos/exynos_drm_rotator.c | 13 +++ 8 files changed, 271 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..715a0ad 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_lock(&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..05000ee 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -1860,3 +1860,16 @@ struct platform_driver fimc_driver = { }, };
+static int fimc_driver_init(void) +{ + return platform_driver_register(&fimc_driver); +} + +static void fimc_driver_exit(void) +{ + platform_driver_unregister(&fimc_driver); +} + +module_init(fimc_driver_init); +module_exit(fimc_driver_exit); + diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 6ff8599..1f1dd20 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,44 @@ 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; + 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)) + 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..0cbed55 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -1799,3 +1799,15 @@ struct platform_driver gsc_driver = { }, };
+static int gsc_driver_init(void) +{ + return platform_driver_register(&gsc_driver); +} + +static void gsc_driver_exit(void) +{ + platform_driver_unregister(&gsc_driver); +} + +module_init(gsc_driver_init); +module_exit(gsc_driver_exit); 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..ffa0166 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c +++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c @@ -854,3 +854,16 @@ struct platform_driver rotator_driver = { .of_match_table = exynos_rotator_match, }, }; + +static int rotator_driver_init(void) +{ + return platform_driver_register(&rotator_driver); +} + +static void rotator_driver_exit(void) +{ + platform_driver_unregister(&rotator_driver); +} + +module_init(rotator_driver_init); +module_exit(rotator_driver_exit);
Hi Inki,
There are 3 comments below.
On 11/19/2014 12:19 PM, Inki Dae wrote:
The list_for_each_entry() could handle empty list, so list_empty() could be removed.
ditto
mutex_unlock(&list_lock);
Thank you. Best regards YJ
Hi YoungJun,
On 2014년 11월 19일 13:39, YoungJun Cho wrote:
This is required for some codes for checking which error type should be returned. So it would better to just check list_empty.
Ditto.
Oops, thanks :)
This patch makes vidi driver to be independent module. 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, which is required for modularity.
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);
dri-devel@lists.freedesktop.org