diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_drv.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.c | 170 |
1 files changed, 90 insertions, 80 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index ab7d182063c3..e5c4c6c8c967 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -15,7 +15,6 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> -#include <linux/anon_inodes.h> #include <linux/component.h> #include <drm/exynos_drm.h> @@ -39,8 +38,6 @@ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 -#define VBLANK_OFF_DELAY 50000 - static struct platform_device *exynos_drm_pdev; static DEFINE_MUTEX(drm_component_lock); @@ -88,44 +85,63 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) struct drm_plane *plane; unsigned long possible_crtcs = (1 << MAX_CRTC) - 1; - plane = exynos_plane_init(dev, possible_crtcs, false); - if (!plane) - goto err_mode_config_cleanup; - } - - /* init kms poll for handling hpd */ - drm_kms_helper_poll_init(dev); + plane = exynos_plane_init(dev, possible_crtcs, + DRM_PLANE_TYPE_OVERLAY); + if (!IS_ERR(plane)) + continue; - ret = drm_vblank_init(dev, MAX_CRTC); - if (ret) + ret = PTR_ERR(plane); goto err_mode_config_cleanup; + } /* setup possible_clones. */ exynos_drm_encoder_setup(dev); - drm_vblank_offdelay = VBLANK_OFF_DELAY; - platform_set_drvdata(dev->platformdev, dev); /* Try to bind all sub drivers. */ ret = component_bind_all(dev->dev, dev); if (ret) - goto err_cleanup_vblank; + goto err_mode_config_cleanup; + + ret = drm_vblank_init(dev, dev->mode_config.num_crtc); + if (ret) + goto err_unbind_all; /* Probe non kms sub drivers and virtual display driver. */ ret = exynos_drm_device_subdrv_probe(dev); if (ret) - goto err_unbind_all; + goto err_cleanup_vblank; + + /* + * enable drm irq mode. + * - with irq_enabled = true, we can use the vblank feature. + * + * P.S. note that we wouldn't use drm irq handler but + * just specific driver own one instead because + * drm framework supports only one irq handler. + */ + dev->irq_enabled = true; + + /* + * with vblank_disable_allowed = true, vblank interrupt will be disabled + * by drm timer once a current process gives up ownership of + * vblank event.(after drm_vblank_put function is called) + */ + dev->vblank_disable_allowed = true; + + /* init kms poll for handling hpd */ + drm_kms_helper_poll_init(dev); /* force connectors detection */ drm_helper_hpd_irq_event(dev); return 0; -err_unbind_all: - component_unbind_all(dev->dev, dev); err_cleanup_vblank: drm_vblank_cleanup(dev); +err_unbind_all: + component_unbind_all(dev->dev, dev); err_mode_config_cleanup: drm_mode_config_cleanup(dev); drm_release_iommu_mapping(dev); @@ -140,23 +156,19 @@ static int exynos_drm_unload(struct drm_device *dev) exynos_drm_device_subdrv_remove(dev); exynos_drm_fbdev_fini(dev); - drm_vblank_cleanup(dev); drm_kms_helper_poll_fini(dev); - drm_mode_config_cleanup(dev); + drm_vblank_cleanup(dev); + component_unbind_all(dev->dev, dev); + drm_mode_config_cleanup(dev); drm_release_iommu_mapping(dev); - kfree(dev->dev_private); - component_unbind_all(dev->dev, dev); + kfree(dev->dev_private); dev->dev_private = NULL; return 0; } -static const struct file_operations exynos_drm_gem_fops = { - .mmap = exynos_drm_gem_mmap_buffer, -}; - static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state) { struct drm_connector *connector; @@ -182,8 +194,12 @@ static int exynos_drm_resume(struct drm_device *dev) drm_modeset_lock_all(dev); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->funcs->dpms) - connector->funcs->dpms(connector, connector->dpms); + if (connector->funcs->dpms) { + int dpms = connector->dpms; + + connector->dpms = DRM_MODE_DPMS_OFF; + connector->funcs->dpms(connector, dpms); + } } drm_modeset_unlock_all(dev); @@ -195,7 +211,6 @@ static int exynos_drm_resume(struct drm_device *dev) static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) { struct drm_exynos_file_private *file_priv; - struct file *anon_filp; int ret; file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); @@ -208,21 +223,8 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) if (ret) goto err_file_priv_free; - anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops, - NULL, 0); - if (IS_ERR(anon_filp)) { - ret = PTR_ERR(anon_filp); - goto err_subdrv_close; - } - - anon_filp->f_mode = FMODE_READ | FMODE_WRITE; - file_priv->anon_filp = anon_filp; - return ret; -err_subdrv_close: - exynos_drm_subdrv_close(dev, file); - err_file_priv_free: kfree(file_priv); file->driver_priv = NULL; @@ -238,7 +240,6 @@ static void exynos_drm_preclose(struct drm_device *dev, static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) { struct exynos_drm_private *private = dev->dev_private; - struct drm_exynos_file_private *file_priv; struct drm_pending_vblank_event *v, *vt; struct drm_pending_event *e, *et; unsigned long flags; @@ -264,10 +265,6 @@ static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) } spin_unlock_irqrestore(&dev->event_lock, flags); - file_priv = file->driver_priv; - if (file_priv->anon_filp) - fput(file_priv->anon_filp); - kfree(file->driver_priv); file->driver_priv = NULL; } @@ -286,11 +283,6 @@ static const struct vm_operations_struct exynos_drm_gem_vm_ops = { static const struct drm_ioctl_desc exynos_ioctls[] = { DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl, DRM_UNLOCKED | DRM_AUTH), - DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MAP_OFFSET, - exynos_drm_gem_map_offset_ioctl, DRM_UNLOCKED | - DRM_AUTH), - DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MMAP, - exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH), DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET, exynos_drm_gem_get_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION, @@ -334,6 +326,7 @@ static struct drm_driver exynos_drm_driver = { .preclose = exynos_drm_preclose, .lastclose = exynos_drm_lastclose, .postclose = exynos_drm_postclose, + .set_busid = drm_platform_set_busid, .get_vblank_counter = drm_vblank_count, .enable_vblank = exynos_drm_crtc_enable_vblank, .disable_vblank = exynos_drm_crtc_disable_vblank, @@ -362,7 +355,7 @@ static int exynos_drm_sys_suspend(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev); pm_message_t message; - if (pm_runtime_suspended(dev)) + if (pm_runtime_suspended(dev) || !drm_dev) return 0; message.event = PM_EVENT_SUSPEND; @@ -373,7 +366,7 @@ static int exynos_drm_sys_resume(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); - if (pm_runtime_suspended(dev)) + if (pm_runtime_suspended(dev) || !drm_dev) return 0; return exynos_drm_resume(drm_dev); @@ -489,21 +482,26 @@ void exynos_drm_component_del(struct device *dev, mutex_unlock(&drm_component_lock); } -static int compare_of(struct device *dev, void *data) +static int compare_dev(struct device *dev, void *data) { return dev == (struct device *)data; } -static int exynos_drm_add_components(struct device *dev, struct master *m) +static struct component_match *exynos_drm_match_add(struct device *dev) { + struct component_match *match = NULL; struct component_dev *cdev; unsigned int attach_cnt = 0; mutex_lock(&drm_component_lock); - list_for_each_entry(cdev, &drm_component_list, list) { - int ret; + /* 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 * encoder/connector device objects exist. @@ -518,16 +516,10 @@ static int exynos_drm_add_components(struct device *dev, struct master *m) /* * fimd and dpi modules have same device object so add * only crtc device object in this case. - * - * TODO. if dpi module follows driver-model driver then - * below codes can be removed. */ if (cdev->crtc_dev == cdev->conn_dev) { - ret = component_master_add_child(m, compare_of, - cdev->crtc_dev); - if (ret < 0) - return ret; - + component_match_add(dev, &match, compare_dev, + cdev->crtc_dev); goto out_lock; } @@ -537,11 +529,8 @@ static int exynos_drm_add_components(struct device *dev, struct master *m) * connector/encoder need pipe number of crtc when they * are created. */ - ret = component_master_add_child(m, compare_of, cdev->crtc_dev); - ret |= component_master_add_child(m, compare_of, - cdev->conn_dev); - if (ret < 0) - return ret; + component_match_add(dev, &match, compare_dev, cdev->crtc_dev); + component_match_add(dev, &match, compare_dev, cdev->conn_dev); out_lock: mutex_lock(&drm_component_lock); @@ -549,7 +538,7 @@ out_lock: mutex_unlock(&drm_component_lock); - return attach_cnt ? 0 : -ENODEV; + return attach_cnt ? match : ERR_PTR(-EPROBE_DEFER); } static int exynos_drm_bind(struct device *dev) @@ -563,13 +552,13 @@ static void exynos_drm_unbind(struct device *dev) } static const struct component_master_ops exynos_drm_ops = { - .add_components = exynos_drm_add_components, .bind = exynos_drm_bind, .unbind = exynos_drm_unbind, }; static int exynos_drm_platform_probe(struct platform_device *pdev) { + struct component_match *match; int ret; pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); @@ -602,10 +591,21 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) goto err_unregister_mixer_drv; #endif + match = exynos_drm_match_add(&pdev->dev); + if (IS_ERR(match)) { + ret = PTR_ERR(match); + goto err_unregister_hdmi_drv; + } + + ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, + match); + if (ret < 0) + goto err_unregister_hdmi_drv; + #ifdef CONFIG_DRM_EXYNOS_G2D ret = platform_driver_register(&g2d_driver); if (ret < 0) - goto err_unregister_hdmi_drv; + goto err_del_component_master; #endif #ifdef CONFIG_DRM_EXYNOS_FIMC @@ -636,11 +636,7 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) goto err_unregister_ipp_drv; #endif - ret = component_master_add(&pdev->dev, &exynos_drm_ops); - if (ret < 0) - DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n"); - - return 0; + return ret; #ifdef CONFIG_DRM_EXYNOS_IPP err_unregister_ipp_drv: @@ -665,9 +661,11 @@ err_unregister_g2d_drv: #ifdef CONFIG_DRM_EXYNOS_G2D platform_driver_unregister(&g2d_driver); -err_unregister_hdmi_drv: +err_del_component_master: #endif + component_master_del(&pdev->dev, &exynos_drm_ops); +err_unregister_hdmi_drv: #ifdef CONFIG_DRM_EXYNOS_HDMI platform_driver_unregister(&hdmi_driver); err_unregister_mixer_drv: @@ -748,6 +746,18 @@ static int exynos_drm_init(void) { int ret; + /* + * Register device object only in case of Exynos SoC. + * + * Below codes resolves temporarily infinite loop issue incurred + * by Exynos drm driver when using multi-platform kernel. + * So these codes will be replaced with more generic way later. + */ + if (!of_machine_is_compatible("samsung,exynos3") && + !of_machine_is_compatible("samsung,exynos4") && + !of_machine_is_compatible("samsung,exynos5")) + return -ENODEV; + exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, NULL, 0); if (IS_ERR(exynos_drm_pdev)) |