From d0b2f91bede3bd5e3d24dd6803e56eee959c1797 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 20 Oct 2016 00:10:27 -0300 Subject: Linux-libre 4.8.2-gnu --- drivers/gpu/drm/imx/imx-drm-core.c | 145 ++++++++++++++++++++++++++----------- 1 file changed, 102 insertions(+), 43 deletions(-) (limited to 'drivers/gpu/drm/imx/imx-drm-core.c') diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 82656654f..7bf90e9e6 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -15,10 +15,14 @@ */ #include #include +#include #include #include #include +#include #include +#include +#include #include #include #include @@ -41,6 +45,7 @@ struct imx_drm_device { struct imx_drm_crtc *crtc[MAX_CRTC]; unsigned int pipes; struct drm_fbdev_cma *fbhelper; + struct drm_atomic_state *state; }; struct imx_drm_crtc { @@ -85,45 +90,6 @@ static int imx_drm_driver_unload(struct drm_device *drm) return 0; } -static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc) -{ - struct imx_drm_device *imxdrm = crtc->dev->dev_private; - unsigned i; - - for (i = 0; i < MAX_CRTC; i++) - if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc) - return imxdrm->crtc[i]; - - return NULL; -} - -int imx_drm_set_bus_config(struct drm_encoder *encoder, u32 bus_format, - int hsync_pin, int vsync_pin, u32 bus_flags) -{ - struct imx_drm_crtc_helper_funcs *helper; - struct imx_drm_crtc *imx_crtc; - - imx_crtc = imx_drm_find_crtc(encoder->crtc); - if (!imx_crtc) - return -EINVAL; - - helper = &imx_crtc->imx_drm_helper_funcs; - if (helper->set_interface_pix_fmt) - return helper->set_interface_pix_fmt(encoder->crtc, - bus_format, hsync_pin, vsync_pin, - bus_flags); - return 0; -} -EXPORT_SYMBOL_GPL(imx_drm_set_bus_config); - -int imx_drm_set_bus_format(struct drm_encoder *encoder, u32 bus_format) -{ - return imx_drm_set_bus_config(encoder, bus_format, 2, 3, - DRM_BUS_FLAG_DE_HIGH | - DRM_BUS_FLAG_PIXDATA_NEGEDGE); -} -EXPORT_SYMBOL_GPL(imx_drm_set_bus_format); - int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) { return drm_crtc_vblank_get(imx_drm_crtc->crtc); @@ -205,9 +171,90 @@ static void imx_drm_output_poll_changed(struct drm_device *drm) drm_fbdev_cma_hotplug_event(imxdrm->fbhelper); } +static int imx_drm_atomic_check(struct drm_device *dev, + struct drm_atomic_state *state) +{ + int ret; + + ret = drm_atomic_helper_check_modeset(dev, state); + if (ret) + return ret; + + ret = drm_atomic_helper_check_planes(dev, state); + if (ret) + return ret; + + /* + * Check modeset again in case crtc_state->mode_changed is + * updated in plane's ->atomic_check callback. + */ + ret = drm_atomic_helper_check_modeset(dev, state); + if (ret) + return ret; + + return ret; +} + static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = { .fb_create = drm_fb_cma_create, .output_poll_changed = imx_drm_output_poll_changed, + .atomic_check = imx_drm_atomic_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_plane_state *plane_state; + struct drm_gem_cma_object *cma_obj; + struct fence *excl; + unsigned shared_count; + struct fence **shared; + unsigned int i, j; + int ret; + + /* Wait for fences. */ + for_each_crtc_in_state(state, crtc, crtc_state, i) { + plane_state = crtc->primary->state; + if (plane_state->fb) { + cma_obj = drm_fb_cma_get_gem_obj(plane_state->fb, 0); + if (cma_obj->base.dma_buf) { + ret = reservation_object_get_fences_rcu( + cma_obj->base.dma_buf->resv, &excl, + &shared_count, &shared); + if (unlikely(ret)) + DRM_ERROR("failed to get fences " + "for buffer\n"); + + if (excl) { + fence_wait(excl, false); + fence_put(excl); + } + for (j = 0; j < shared_count; i++) { + fence_wait(shared[j], false); + fence_put(shared[j]); + } + } + } + } + + drm_atomic_helper_commit_modeset_disables(dev, state); + + drm_atomic_helper_commit_planes(dev, state, true); + + drm_atomic_helper_commit_modeset_enables(dev, state); + + drm_atomic_helper_commit_hw_done(state); + + drm_atomic_helper_wait_for_vblanks(dev, state); + + drm_atomic_helper_cleanup_planes(dev, state); +} + +static struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = { + .atomic_commit_tail = imx_drm_atomic_commit_tail, }; /* @@ -249,6 +296,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) drm->mode_config.max_width = 4096; drm->mode_config.max_height = 4096; drm->mode_config.funcs = &imx_drm_mode_config_funcs; + drm->mode_config.helper_private = &imx_drm_mode_config_helpers; drm_mode_config_init(drm); @@ -279,6 +327,8 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) } } + drm_mode_config_reset(drm); + /* * All components are now initialised, so setup the fb helper. * The fb helper takes copies of key hardware information, so the @@ -289,7 +339,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); legacyfb_depth = 16; } - drm_helper_disable_unused_functions(drm); imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, drm->mode_config.num_crtc, MAX_CRTC); if (IS_ERR(imxdrm->fbhelper)) { @@ -403,11 +452,11 @@ static const struct drm_ioctl_desc imx_drm_ioctls[] = { }; static struct drm_driver imx_drm_driver = { - .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | + DRIVER_ATOMIC, .load = imx_drm_driver_load, .unload = imx_drm_driver_unload, .lastclose = imx_drm_driver_lastclose, - .set_busid = drm_platform_set_busid, .gem_free_object_unlocked = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, .dumb_create = drm_gem_cma_dumb_create, @@ -492,6 +541,7 @@ static int imx_drm_platform_remove(struct platform_device *pdev) static int imx_drm_suspend(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); + struct imx_drm_device *imxdrm; /* The drm_dev is NULL before .load hook is called */ if (drm_dev == NULL) @@ -499,17 +549,26 @@ static int imx_drm_suspend(struct device *dev) drm_kms_helper_poll_disable(drm_dev); + imxdrm = drm_dev->dev_private; + imxdrm->state = drm_atomic_helper_suspend(drm_dev); + if (IS_ERR(imxdrm->state)) { + drm_kms_helper_poll_enable(drm_dev); + return PTR_ERR(imxdrm->state); + } + return 0; } static int imx_drm_resume(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); + struct imx_drm_device *imx_drm; if (drm_dev == NULL) return 0; - drm_helper_resume_force_mode(drm_dev); + imx_drm = drm_dev->dev_private; + drm_atomic_helper_resume(drm_dev, imx_drm->state); drm_kms_helper_poll_enable(drm_dev); return 0; -- cgit v1.2.3-54-g00ecf