From 8fe5616b20e5742bb5fee0e77dffe2fc76ac92a0 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 14 Jun 2016 11:43:30 +0300 Subject: drm/tilcdc: Restore old dpms state in pm_resume() Restore old dpms state in pm_resume(). The dpms is turned off in pm_suspend() and it should be restored to its original state in pm_resume(). Without this patch the display is left blanked after a suspend/resume cycle. Fixes commit 614b3cfeb8d2 ("drm/tilcdc: disable the lcd controller/dma engine when suspend invoked") Signed-off-by: Jyri Sarha --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index d27809372d54..ed68324504f6 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -597,6 +597,7 @@ static int tilcdc_pm_suspend(struct device *dev) } /* Disable the LCDC controller, to avoid locking up the PRCM */ + priv->saved_dpms_state = tilcdc_crtc_current_dpms_state(priv->crtc); tilcdc_crtc_dpms(priv->crtc, DRM_MODE_DPMS_OFF); /* Save register state: */ @@ -627,6 +628,8 @@ static int tilcdc_pm_resume(struct device *dev) priv->saved_register[n++]); } + tilcdc_crtc_dpms(priv->crtc, priv->saved_dpms_state); + drm_kms_helper_poll_enable(ddev); return 0; -- cgit From 20a98acba5baf925d0d6fb334f1c55aa2ca7a708 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 23 Jun 2016 11:07:16 +0300 Subject: drm/tilcdc: Fix tilcdc component master unloading Fix tilcdc component master unloading. If a subcomponent module (tda998x in this case) is unloaded before its master (tilcdc in this case), it calls drm_put_dev() and it should not be called again by the master when its module is unloaded. However component_master_del() must still be called and the check if the drm_put_dev() has been called must be in component_master_ops unbind() callback, not in platform_driver remove() callback. Signed-off-by: Jyri Sarha --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index ed68324504f6..16163a7e9ed1 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -651,6 +651,12 @@ static int tilcdc_bind(struct device *dev) static void tilcdc_unbind(struct device *dev) { + struct drm_device *ddev = dev_get_drvdata(dev); + + /* Check if a subcomponent has already triggered the unloading. */ + if (!ddev->dev_private) + return; + drm_put_dev(dev_get_drvdata(dev)); } @@ -683,17 +689,15 @@ static int tilcdc_pdev_probe(struct platform_device *pdev) static int tilcdc_pdev_remove(struct platform_device *pdev) { - struct drm_device *ddev = dev_get_drvdata(&pdev->dev); - struct tilcdc_drm_private *priv = ddev->dev_private; - - /* Check if a subcomponent has already triggered the unloading. */ - if (!priv) - return 0; + int ret; - if (priv->is_componentized) - component_master_del(&pdev->dev, &tilcdc_comp_ops); - else + ret = tilcdc_get_external_components(&pdev->dev, NULL); + if (ret < 0) + return ret; + else if (ret == 0) drm_put_dev(platform_get_drvdata(pdev)); + else + component_master_del(&pdev->dev, &tilcdc_comp_ops); return 0; } -- cgit From edc43303888c13904a1c990592eb64f17e8e7eb1 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 30 Dec 2015 17:40:24 +0200 Subject: drm/tilcdc: Add atomic mode config funcs Add atomic mode config funcs. The atomic_commit implementation is a copy-paste from drm_atomic_helper_commit(), leaving out the async test. The similar copy-paste implementation appears to be used in many other drivers too. The standard drm_atomic_helper_check() is used for checking. The drm_atomic_helper_check() can not be used in drm_mode_config_funcs atomic_check() callback because the plane's check implementation may update crtc state's ->mode_changed flag. Because of this the drm_atomic_helper_check_modeset() has to be called once more after drm_atomic_helper_check_planes() (see drm_atomic_helper_check_modeset() documentation). Signed-off-by: Jyri Sarha --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 71 +++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 16163a7e9ed1..a8c47794a3f1 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "tilcdc_drv.h" #include "tilcdc_regs.h" @@ -59,9 +61,78 @@ static void tilcdc_fb_output_poll_changed(struct drm_device *dev) drm_fbdev_cma_hotplug_event(priv->fbdev); } +int tilcdc_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; + + /* + * tilcdc ->atomic_check can update ->mode_changed if pixel format + * changes, hence will we check modeset changes again. + */ + ret = drm_atomic_helper_check_modeset(dev, state); + if (ret) + return ret; + + return ret; +} + +static int tilcdc_commit(struct drm_device *dev, + struct drm_atomic_state *state, + bool async) +{ + int ret; + + ret = drm_atomic_helper_prepare_planes(dev, state); + if (ret) + return ret; + + drm_atomic_helper_swap_state(state, true); + + /* + * Everything below can be run asynchronously without the need to grab + * any modeset locks at all under one condition: It must be guaranteed + * that the asynchronous work has either been cancelled (if the driver + * supports it, which at least requires that the framebuffers get + * cleaned up with drm_atomic_helper_cleanup_planes()) or completed + * before the new state gets committed on the software side with + * drm_atomic_helper_swap_state(). + * + * This scheme allows new atomic state updates to be prepared and + * checked in parallel to the asynchronous completion of the previous + * update. Which is important since compositors need to figure out the + * composition of the next frame right after having submitted the + * current layout. + */ + + drm_atomic_helper_commit_modeset_disables(dev, state); + + drm_atomic_helper_commit_planes(dev, state, false); + + drm_atomic_helper_commit_modeset_enables(dev, state); + + drm_atomic_helper_wait_for_vblanks(dev, state); + + drm_atomic_helper_cleanup_planes(dev, state); + + drm_atomic_state_free(state); + + return 0; +} + static const struct drm_mode_config_funcs mode_config_funcs = { .fb_create = tilcdc_fb_create, .output_poll_changed = tilcdc_fb_output_poll_changed, + .atomic_check = tilcdc_atomic_check, + .atomic_commit = tilcdc_commit, }; static int modeset_init(struct drm_device *dev) -- cgit From 522a76f895d775a1c9ed6ff4a631d9054a949ef3 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 29 Dec 2015 17:27:32 +0200 Subject: drm/tilcdc: Add drm_mode_config_reset() call to tilcdc_load() Add drm_mode_config_reset() call to tilcdc_load(). This is need to initialize atomic state variables at load time. Signed-off-by: Jyri Sarha --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index a8c47794a3f1..11acd96ba265 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -366,6 +366,9 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) } drm_helper_disable_unused_functions(dev); + + drm_mode_config_reset(dev); + priv->fbdev = drm_fbdev_cma_init(dev, bpp, dev->mode_config.num_crtc, dev->mode_config.num_connector); -- cgit From 305198de894345b788522feacded0ca78f9db5d2 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 7 Apr 2016 15:05:16 +0300 Subject: drm/tilcdc: Set DRIVER_ATOMIC and use atomic crtc helpers Set DRIVER_ATOMIC and use atomic helpers and rename commit and prepare crtc helpers to enable and disable. This makes the final jump to mode setting, but there is lot of obsolete code to clean up. Signed-off-by: Jyri Sarha --- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 20 +++++++++++++------- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 3e272f973929..9a21a7f80420 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -17,6 +17,7 @@ #include "drm_flip_work.h" #include +#include #include "tilcdc_drv.h" #include "tilcdc_regs.h" @@ -293,12 +294,12 @@ static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc, return true; } -static void tilcdc_crtc_prepare(struct drm_crtc *crtc) +static void tilcdc_crtc_disable(struct drm_crtc *crtc) { tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); } -static void tilcdc_crtc_commit(struct drm_crtc *crtc) +static void tilcdc_crtc_enable(struct drm_crtc *crtc) { tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON); } @@ -704,18 +705,23 @@ static int tilcdc_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, } static const struct drm_crtc_funcs tilcdc_crtc_funcs = { - .destroy = tilcdc_crtc_destroy, - .set_config = drm_crtc_helper_set_config, - .page_flip = tilcdc_crtc_page_flip, + .destroy = tilcdc_crtc_destroy, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, }; static const struct drm_crtc_helper_funcs tilcdc_crtc_helper_funcs = { .dpms = tilcdc_crtc_dpms, .mode_fixup = tilcdc_crtc_mode_fixup, - .prepare = tilcdc_crtc_prepare, - .commit = tilcdc_crtc_commit, + .prepare = tilcdc_crtc_disable, + .commit = tilcdc_crtc_enable, .mode_set = tilcdc_crtc_mode_set, .mode_set_base = tilcdc_crtc_mode_set_base, + .enable = tilcdc_crtc_enable, + .disable = tilcdc_crtc_disable, .atomic_check = tilcdc_crtc_atomic_check, .mode_set_nofb = tilcdc_crtc_mode_set_nofb, }; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 11acd96ba265..576e4e1c17e4 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -611,7 +611,7 @@ static const struct file_operations fops = { static struct drm_driver tilcdc_driver = { .driver_features = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | - DRIVER_PRIME), + DRIVER_PRIME | DRIVER_ATOMIC), .load = tilcdc_load, .unload = tilcdc_unload, .lastclose = tilcdc_lastclose, -- cgit From afaf833dd5d7793e9441f122bbe3e37a09a0c743 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 21 Jun 2016 16:00:44 +0300 Subject: drm/tilcdc: Enable and disable interrupts in crtc start() and stop() Enable and disable interrupts in crtc start() and stop(). None of the interrupts can fire if CRTC is disabled, so it is cleaner - when considering suspend/resume code etc. - to enable the interrupts when CRTC is turned on and to disable them when CRTC is turned off. Signed-off-by: Jyri Sarha --- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 39 +++++++++++++++++++++++++++++ drivers/gpu/drm/tilcdc/tilcdc_drv.c | 48 ------------------------------------ 2 files changed, 39 insertions(+), 48 deletions(-) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 3d6000cd5048..773bee27a2d0 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -89,6 +89,41 @@ static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb) tilcdc_crtc->curr_fb = fb; } +static void tilcdc_crtc_enable_irqs(struct drm_device *dev) +{ + struct tilcdc_drm_private *priv = dev->dev_private; + + tilcdc_clear_irqstatus(dev, 0xffffffff); + + if (priv->rev == 1) { + tilcdc_set(dev, LCDC_RASTER_CTRL_REG, + LCDC_V1_UNDERFLOW_INT_ENA); + } else { + tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG, + LCDC_V2_UNDERFLOW_INT_ENA | + LCDC_V2_END_OF_FRAME0_INT_ENA | + LCDC_FRAME_DONE | LCDC_SYNC_LOST); + } +} + +static void tilcdc_crtc_disable_irqs(struct drm_device *dev) +{ + struct tilcdc_drm_private *priv = dev->dev_private; + + /* disable irqs that we might have enabled: */ + if (priv->rev == 1) { + tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, + LCDC_V1_UNDERFLOW_INT_ENA | LCDC_V1_PL_INT_ENA); + tilcdc_clear(dev, LCDC_DMA_CTRL_REG, + LCDC_V1_END_OF_FRAME_INT_ENA); + } else { + tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG, + LCDC_V2_UNDERFLOW_INT_ENA | LCDC_V2_PL_INT_ENA | + LCDC_V2_END_OF_FRAME0_INT_ENA | + LCDC_FRAME_DONE | LCDC_SYNC_LOST); + } +} + static void reset(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -108,6 +143,8 @@ static void start(struct drm_crtc *crtc) reset(crtc); + tilcdc_crtc_enable_irqs(dev); + tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_DUAL_FRAME_BUFFER_ENABLE); tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_PALETTE_LOAD_MODE(DATA_ONLY)); tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); @@ -138,6 +175,8 @@ static void stop(struct drm_crtc *crtc) } drm_crtc_vblank_off(crtc); + + tilcdc_crtc_disable_irqs(dev); } static void tilcdc_crtc_destroy(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 576e4e1c17e4..d612d03460ae 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -192,9 +192,7 @@ static int tilcdc_unload(struct drm_device *dev) drm_mode_config_cleanup(dev); drm_vblank_cleanup(dev); - pm_runtime_get_sync(dev->dev); drm_irq_uninstall(dev); - pm_runtime_put_sync(dev->dev); #ifdef CONFIG_CPU_FREQ cpufreq_unregister_notifier(&priv->freq_transition, @@ -350,9 +348,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) goto fail_external_cleanup; } - pm_runtime_get_sync(dev->dev); ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); - pm_runtime_put_sync(dev->dev); if (ret < 0) { dev_err(dev->dev, "failed to install IRQ handler\n"); goto fail_vblank_cleanup; @@ -382,9 +378,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) return 0; fail_irq_uninstall: - pm_runtime_get_sync(dev->dev); drm_irq_uninstall(dev); - pm_runtime_put_sync(dev->dev); fail_vblank_cleanup: drm_vblank_cleanup(dev); @@ -435,45 +429,6 @@ static irqreturn_t tilcdc_irq(int irq, void *arg) return tilcdc_crtc_irq(priv->crtc); } -static void tilcdc_irq_preinstall(struct drm_device *dev) -{ - tilcdc_clear_irqstatus(dev, 0xffffffff); -} - -static int tilcdc_irq_postinstall(struct drm_device *dev) -{ - struct tilcdc_drm_private *priv = dev->dev_private; - - /* enable FIFO underflow irq: */ - if (priv->rev == 1) { - tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_V1_UNDERFLOW_INT_ENA); - } else { - tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG, - LCDC_V2_UNDERFLOW_INT_ENA | - LCDC_V2_END_OF_FRAME0_INT_ENA | - LCDC_FRAME_DONE | LCDC_SYNC_LOST); - } - - return 0; -} - -static void tilcdc_irq_uninstall(struct drm_device *dev) -{ - struct tilcdc_drm_private *priv = dev->dev_private; - - /* disable irqs that we might have enabled: */ - if (priv->rev == 1) { - tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, - LCDC_V1_UNDERFLOW_INT_ENA | LCDC_V1_PL_INT_ENA); - tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_V1_END_OF_FRAME_INT_ENA); - } else { - tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG, - LCDC_V2_UNDERFLOW_INT_ENA | LCDC_V2_PL_INT_ENA | - LCDC_V2_END_OF_FRAME0_INT_ENA | - LCDC_FRAME_DONE | LCDC_SYNC_LOST); - } -} - static int tilcdc_enable_vblank(struct drm_device *dev, unsigned int pipe) { return 0; @@ -616,9 +571,6 @@ static struct drm_driver tilcdc_driver = { .unload = tilcdc_unload, .lastclose = tilcdc_lastclose, .irq_handler = tilcdc_irq, - .irq_preinstall = tilcdc_irq_preinstall, - .irq_postinstall = tilcdc_irq_postinstall, - .irq_uninstall = tilcdc_irq_uninstall, .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = tilcdc_enable_vblank, .disable_vblank = tilcdc_disable_vblank, -- cgit From 514d1a1f47eb94348b6abf168b913af194cdf1a9 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 16 Jun 2016 11:28:23 +0300 Subject: drm/tilcdc: Use drm_atomic_helper_resume/suspend() Use drm_atomic_helper_resume/suspend() and get rid off all the obsolete register level context restoring code. Signed-off-by: Jyri Sarha --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 56 +++++-------------------------------- drivers/gpu/drm/tilcdc/tilcdc_drv.h | 6 ++-- 2 files changed, 9 insertions(+), 53 deletions(-) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index d612d03460ae..a9624b2e1815 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -215,8 +215,6 @@ static int tilcdc_unload(struct drm_device *dev) return 0; } -static size_t tilcdc_num_regs(void); - static int tilcdc_load(struct drm_device *dev, unsigned long flags) { struct platform_device *pdev = dev->platformdev; @@ -228,11 +226,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) int ret; priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL); - if (priv) - priv->saved_register = - devm_kcalloc(dev->dev, tilcdc_num_regs(), - sizeof(*priv->saved_register), GFP_KERNEL); - if (!priv || !priv->saved_register) { + if (!priv) { dev_err(dev->dev, "failed to allocate private data\n"); return -ENOMEM; } @@ -439,7 +433,7 @@ static void tilcdc_disable_vblank(struct drm_device *dev, unsigned int pipe) return; } -#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_PM_SLEEP) +#if defined(CONFIG_DEBUG_FS) static const struct { const char *name; uint8_t rev; @@ -470,15 +464,6 @@ static const struct { #undef REG }; -static size_t tilcdc_num_regs(void) -{ - return ARRAY_SIZE(registers); -} -#else -static size_t tilcdc_num_regs(void) -{ - return 0; -} #endif #ifdef CONFIG_DEBUG_FS @@ -610,29 +595,12 @@ static int tilcdc_pm_suspend(struct device *dev) { struct drm_device *ddev = dev_get_drvdata(dev); struct tilcdc_drm_private *priv = ddev->dev_private; - unsigned i, n = 0; - drm_kms_helper_poll_disable(ddev); + priv->saved_state = drm_atomic_helper_suspend(ddev); /* Select sleep pin state */ pinctrl_pm_select_sleep_state(dev); - if (pm_runtime_suspended(dev)) { - priv->ctx_valid = false; - return 0; - } - - /* Disable the LCDC controller, to avoid locking up the PRCM */ - priv->saved_dpms_state = tilcdc_crtc_current_dpms_state(priv->crtc); - tilcdc_crtc_dpms(priv->crtc, DRM_MODE_DPMS_OFF); - - /* Save register state: */ - for (i = 0; i < ARRAY_SIZE(registers); i++) - if (registers[i].save && (priv->rev >= registers[i].rev)) - priv->saved_register[n++] = tilcdc_read(ddev, registers[i].reg); - - priv->ctx_valid = true; - return 0; } @@ -640,25 +608,15 @@ static int tilcdc_pm_resume(struct device *dev) { struct drm_device *ddev = dev_get_drvdata(dev); struct tilcdc_drm_private *priv = ddev->dev_private; - unsigned i, n = 0; + int ret = 0; /* Select default pin state */ pinctrl_pm_select_default_state(dev); - if (priv->ctx_valid == true) { - /* Restore register state: */ - for (i = 0; i < ARRAY_SIZE(registers); i++) - if (registers[i].save && - (priv->rev >= registers[i].rev)) - tilcdc_write(ddev, registers[i].reg, - priv->saved_register[n++]); - } + if (priv->saved_state) + ret = drm_atomic_helper_resume(ddev, priv->saved_state); - tilcdc_crtc_dpms(priv->crtc, priv->saved_dpms_state); - - drm_kms_helper_poll_enable(ddev); - - return 0; + return ret; } #endif diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index 0619c3c88527..5e645ce2b509 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -65,10 +65,8 @@ struct tilcdc_drm_private { */ uint32_t max_width; - /* register contents saved across suspend/resume: */ - u32 *saved_register; - int saved_dpms_state; - bool ctx_valid; + /* The context for pm susped/resume cycle is stored here */ + struct drm_atomic_state *saved_state; #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; -- cgit From 47bfd6c01efe639d4c44b1e3fce3816d36b23d46 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 22 Jun 2016 16:27:54 +0300 Subject: drm/tilcdc: Get rid of legacy dpms mechanism Get rid of legacy dpms mechanism. This simplifies the code quite a bit. The old start() and stop() functions become tilcdc_crtc_enable() and *_disable(). The functions are added with all the necessary mechanisms from the old dpms function and they are used directly as the crtc helper enable() and disable() callbacks. Signed-off-by: Jyri Sarha --- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 109 ++++++++++++++--------------------- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 8 ++- drivers/gpu/drm/tilcdc/tilcdc_drv.h | 3 +- 3 files changed, 50 insertions(+), 70 deletions(-) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 773bee27a2d0..400d8c45b075 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -30,7 +30,7 @@ struct tilcdc_crtc { struct drm_plane primary; const struct tilcdc_panel_info *info; struct drm_pending_vblank_event *event; - int dpms; + bool enabled; wait_queue_head_t frame_done_wq; bool frame_done; spinlock_t irq_lock; @@ -137,9 +137,15 @@ static void reset(struct drm_crtc *crtc) tilcdc_clear(dev, LCDC_CLK_RESET_REG, LCDC_CLK_MAIN_RESET); } -static void start(struct drm_crtc *crtc) +static void tilcdc_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; + struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); + + if (tilcdc_crtc->enabled) + return; + + pm_runtime_get_sync(dev->dev); reset(crtc); @@ -150,14 +156,19 @@ static void start(struct drm_crtc *crtc) tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); drm_crtc_vblank_on(crtc); + + tilcdc_crtc->enabled = true; } -static void stop(struct drm_crtc *crtc) +void tilcdc_crtc_disable(struct drm_crtc *crtc) { struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); struct drm_device *dev = crtc->dev; struct tilcdc_drm_private *priv = dev->dev_private; + if (!tilcdc_crtc->enabled) + return; + tilcdc_crtc->frame_done = false; tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); @@ -177,13 +188,37 @@ static void stop(struct drm_crtc *crtc) drm_crtc_vblank_off(crtc); tilcdc_crtc_disable_irqs(dev); + + pm_runtime_put_sync(dev->dev); + + if (tilcdc_crtc->next_fb) { + drm_flip_work_queue(&tilcdc_crtc->unref_work, + tilcdc_crtc->next_fb); + tilcdc_crtc->next_fb = NULL; + } + + if (tilcdc_crtc->curr_fb) { + drm_flip_work_queue(&tilcdc_crtc->unref_work, + tilcdc_crtc->curr_fb); + tilcdc_crtc->curr_fb = NULL; + } + + drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq); + tilcdc_crtc->last_vblank = ktime_set(0, 0); + + tilcdc_crtc->enabled = false; +} + +static bool tilcdc_crtc_is_on(struct drm_crtc *crtc) +{ + return crtc->state && crtc->state->enable && crtc->state->active; } static void tilcdc_crtc_destroy(struct drm_crtc *crtc) { struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); - tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + tilcdc_crtc_disable(crtc); of_node_put(crtc->port); drm_crtc_cleanup(crtc); @@ -237,52 +272,6 @@ int tilcdc_crtc_page_flip(struct drm_crtc *crtc, return 0; } -void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode) -{ - struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); - struct drm_device *dev = crtc->dev; - struct tilcdc_drm_private *priv = dev->dev_private; - - /* we really only care about on or off: */ - if (mode != DRM_MODE_DPMS_ON) - mode = DRM_MODE_DPMS_OFF; - - if (tilcdc_crtc->dpms == mode) - return; - - tilcdc_crtc->dpms = mode; - - if (mode == DRM_MODE_DPMS_ON) { - pm_runtime_get_sync(dev->dev); - start(crtc); - } else { - stop(crtc); - pm_runtime_put_sync(dev->dev); - - if (tilcdc_crtc->next_fb) { - drm_flip_work_queue(&tilcdc_crtc->unref_work, - tilcdc_crtc->next_fb); - tilcdc_crtc->next_fb = NULL; - } - - if (tilcdc_crtc->curr_fb) { - drm_flip_work_queue(&tilcdc_crtc->unref_work, - tilcdc_crtc->curr_fb); - tilcdc_crtc->curr_fb = NULL; - } - - drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq); - tilcdc_crtc->last_vblank = ktime_set(0, 0); - } -} - -int tilcdc_crtc_current_dpms_state(struct drm_crtc *crtc) -{ - struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); - - return tilcdc_crtc->dpms; -} - static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -312,16 +301,6 @@ static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc, return true; } -static void tilcdc_crtc_disable(struct drm_crtc *crtc) -{ - tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); -} - -static void tilcdc_crtc_enable(struct drm_crtc *crtc) -{ - tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON); -} - static void tilcdc_crtc_mode_set_nofb(struct drm_crtc *crtc) { struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); @@ -655,18 +634,15 @@ void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc, void tilcdc_crtc_update_clk(struct drm_crtc *crtc) { - struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); struct drm_device *dev = crtc->dev; struct tilcdc_drm_private *priv = dev->dev_private; - int dpms = tilcdc_crtc->dpms; unsigned long lcd_clk; const unsigned clkdiv = 2; /* using a fixed divider of 2 */ int ret; pm_runtime_get_sync(dev->dev); - if (dpms == DRM_MODE_DPMS_ON) - tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + tilcdc_crtc_disable(crtc); /* mode.clock is in KHz, set_rate wants parameter in Hz */ ret = clk_set_rate(priv->clk, crtc->mode.clock * 1000 * clkdiv); @@ -690,8 +666,8 @@ void tilcdc_crtc_update_clk(struct drm_crtc *crtc) LCDC_V2_DMA_CLK_EN | LCDC_V2_LIDD_CLK_EN | LCDC_V2_CORE_CLK_EN); - if (dpms == DRM_MODE_DPMS_ON) - tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON); + if (tilcdc_crtc_is_on(crtc)) + tilcdc_crtc_enable(crtc); out: pm_runtime_put_sync(dev->dev); @@ -802,7 +778,6 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev) if (ret < 0) goto fail; - tilcdc_crtc->dpms = DRM_MODE_DPMS_OFF; init_waitqueue_head(&tilcdc_crtc->frame_done_wq); drm_flip_work_init(&tilcdc_crtc->unref_work, diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index a9624b2e1815..3404d245d28d 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -113,12 +113,18 @@ static int tilcdc_commit(struct drm_device *dev, * current layout. */ + /* Keep HW on while we commit the state. */ + pm_runtime_get_sync(dev->dev); + drm_atomic_helper_commit_modeset_disables(dev, state); drm_atomic_helper_commit_planes(dev, state, false); drm_atomic_helper_commit_modeset_enables(dev, state); + /* Now HW should remain on if need becase the crtc is enabled */ + pm_runtime_put_sync(dev->dev); + drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); @@ -183,7 +189,7 @@ static int tilcdc_unload(struct drm_device *dev) { struct tilcdc_drm_private *priv = dev->dev_private; - tilcdc_crtc_dpms(priv->crtc, DRM_MODE_DPMS_OFF); + tilcdc_crtc_disable(priv->crtc); tilcdc_remove_external_encoders(dev); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index 5e645ce2b509..a02eb3736d75 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -170,8 +170,7 @@ void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc, bool simulate_vesa_sync); int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode); int tilcdc_crtc_max_width(struct drm_crtc *crtc); -void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode); -int tilcdc_crtc_current_dpms_state(struct drm_crtc *crtc); +void tilcdc_crtc_disable(struct drm_crtc *crtc); int tilcdc_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, -- cgit From 2b58e98d42af854037439f51bd89f83dbfa8e30d Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Mon, 29 Aug 2016 17:12:03 +0800 Subject: drm/atomic-helper: Add NO_DISABLE_AFTER_MODESET flag support for plane commit Drivers may set the NO_DISABLE_AFTER_MODESET flag in the 'flags' parameter of the helper drm_atomic_helper_commit_planes() if the relevant display controllers(e.g., IPUv3 for imx-drm) require to disable a CRTC's planes when the CRTC is disabled. The helper would skip the ->atomic_disable call for a plane if the CRTC of the old plane state needs a modesetting operation. Of course, the drivers need to disable the planes in their CRTC disable callbacks since no one else would do that. Suggested-by: Daniel Vetter Cc: Philipp Zabel Cc: David Airlie Cc: Russell King Cc: Peter Senna Tschudin Cc: Lucas Stach Signed-off-by: Liu Ying Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1472461923-14364-1-git-send-email-gnuiyl@gmail.com --- drivers/gpu/drm/arm/malidp_drv.c | 3 +- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 2 +- drivers/gpu/drm/drm_atomic_helper.c | 43 ++++++++++++++++++++-------- drivers/gpu/drm/exynos/exynos_drm_drv.c | 2 +- drivers/gpu/drm/imx/imx-drm-core.c | 3 +- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 6 ++-- drivers/gpu/drm/msm/msm_atomic.c | 2 +- drivers/gpu/drm/omapdrm/omap_drv.c | 2 +- drivers/gpu/drm/rcar-du/rcar_du_kms.c | 3 +- drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 3 +- drivers/gpu/drm/sti/sti_drv.c | 2 +- drivers/gpu/drm/tegra/drm.c | 3 +- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 2 +- drivers/gpu/drm/vc4/vc4_kms.c | 2 +- drivers/gpu/drm/virtio/virtgpu_display.c | 3 +- include/drm/drm_atomic_helper.h | 6 +++- 16 files changed, 59 insertions(+), 28 deletions(-) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 82171d223f2d..c383d724527f 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -91,7 +91,8 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state) drm_atomic_helper_commit_modeset_disables(drm, state); drm_atomic_helper_commit_modeset_enables(drm, state); - drm_atomic_helper_commit_planes(drm, state, true); + drm_atomic_helper_commit_planes(drm, state, + DRM_PLANE_COMMIT_ACTIVE_ONLY); malidp_atomic_commit_hw_done(state); diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index d4a3d61b7b06..8e7483d90c47 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -457,7 +457,7 @@ atmel_hlcdc_dc_atomic_complete(struct atmel_hlcdc_dc_commit *commit) /* Apply the atomic update. */ drm_atomic_helper_commit_modeset_disables(dev, old_state); - drm_atomic_helper_commit_planes(dev, old_state, false); + drm_atomic_helper_commit_planes(dev, old_state, 0); drm_atomic_helper_commit_modeset_enables(dev, old_state); drm_atomic_helper_wait_for_vblanks(dev, old_state); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 5f82290f2f0f..6fdd7ba47896 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1148,7 +1148,8 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); * * drm_atomic_helper_commit_modeset_enables(dev, state); * - * drm_atomic_helper_commit_planes(dev, state, true); + * drm_atomic_helper_commit_planes(dev, state, + * DRM_PLANE_COMMIT_ACTIVE_ONLY); * * for committing the atomic update to hardware. See the kerneldoc entries for * these three functions for more details. @@ -1159,7 +1160,7 @@ void drm_atomic_helper_commit_tail(struct drm_atomic_state *state) drm_atomic_helper_commit_modeset_disables(dev, state); - drm_atomic_helper_commit_planes(dev, state, false); + drm_atomic_helper_commit_planes(dev, state, 0); drm_atomic_helper_commit_modeset_enables(dev, state); @@ -1678,7 +1679,7 @@ bool plane_crtc_active(struct drm_plane_state *state) * drm_atomic_helper_commit_planes - commit plane state * @dev: DRM device * @old_state: atomic state object with old state structures - * @active_only: Only commit on active CRTC if set + * @flags: flags for committing plane state * * This function commits the new plane state using the plane and atomic helper * functions for planes and crtcs. It assumes that the atomic state has already @@ -1698,25 +1699,34 @@ bool plane_crtc_active(struct drm_plane_state *state) * most drivers don't need to be immediately notified of plane updates for a * disabled CRTC. * - * Unless otherwise needed, drivers are advised to set the @active_only - * parameters to true in order not to receive plane update notifications related - * to a disabled CRTC. This avoids the need to manually ignore plane updates in + * Unless otherwise needed, drivers are advised to set the ACTIVE_ONLY flag in + * @flags in order not to receive plane update notifications related to a + * disabled CRTC. This avoids the need to manually ignore plane updates in * driver code when the driver and/or hardware can't or just don't need to deal * with updates on disabled CRTCs, for example when supporting runtime PM. * - * The drm_atomic_helper_commit() default implementation only sets @active_only - * to false to most closely match the behaviour of the legacy helpers. This should - * not be copied blindly by drivers. + * Drivers may set the NO_DISABLE_AFTER_MODESET flag in @flags if the relevant + * display controllers require to disable a CRTC's planes when the CRTC is + * disabled. This function would skip the ->atomic_disable call for a plane if + * the CRTC of the old plane state needs a modesetting operation. Of course, + * the drivers need to disable the planes in their CRTC disable callbacks + * since no one else would do that. + * + * The drm_atomic_helper_commit() default implementation doesn't set the + * ACTIVE_ONLY flag to most closely match the behaviour of the legacy helpers. + * This should not be copied blindly by drivers. */ void drm_atomic_helper_commit_planes(struct drm_device *dev, struct drm_atomic_state *old_state, - bool active_only) + uint32_t flags) { struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; struct drm_plane *plane; struct drm_plane_state *old_plane_state; int i; + bool active_only = flags & DRM_PLANE_COMMIT_ACTIVE_ONLY; + bool no_disable = flags & DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET; for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { const struct drm_crtc_helper_funcs *funcs; @@ -1760,10 +1770,19 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, /* * Special-case disabling the plane if drivers support it. */ - if (disabling && funcs->atomic_disable) + if (disabling && funcs->atomic_disable) { + struct drm_crtc_state *crtc_state; + + crtc_state = old_plane_state->crtc->state; + + if (drm_atomic_crtc_needs_modeset(crtc_state) && + no_disable) + continue; + funcs->atomic_disable(plane, old_plane_state); - else if (plane->state->crtc || disabling) + } else if (plane->state->crtc || disabling) { funcs->atomic_update(plane, old_plane_state); + } } for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 877d2efa28e2..486943e70f70 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -105,7 +105,7 @@ static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit) atomic_inc(&exynos_crtc->pending_update); } - drm_atomic_helper_commit_planes(dev, state, false); + drm_atomic_helper_commit_planes(dev, state, 0); exynos_atomic_wait_for_commit(state); diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 438bac8fbc2b..56dfc4cd50c6 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -193,7 +193,8 @@ static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state) drm_atomic_helper_commit_modeset_disables(dev, state); - drm_atomic_helper_commit_planes(dev, state, true); + drm_atomic_helper_commit_planes(dev, state, + DRM_PLANE_COMMIT_ACTIVE_ONLY); drm_atomic_helper_commit_modeset_enables(dev, state); diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 0e769abd0c2c..72c1ae4e02d4 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -70,13 +70,15 @@ static void mtk_atomic_complete(struct mtk_drm_private *private, * * drm_atomic_helper_commit_modeset_disables(dev, state); * drm_atomic_helper_commit_modeset_enables(dev, state); - * drm_atomic_helper_commit_planes(dev, state, true); + * drm_atomic_helper_commit_planes(dev, state, + * DRM_PLANE_COMMIT_ACTIVE_ONLY); * * See the kerneldoc entries for these three functions for more details. */ drm_atomic_helper_commit_modeset_disables(drm, state); drm_atomic_helper_commit_modeset_enables(drm, state); - drm_atomic_helper_commit_planes(drm, state, true); + drm_atomic_helper_commit_planes(drm, state, + DRM_PLANE_COMMIT_ACTIVE_ONLY); drm_atomic_helper_wait_for_vblanks(drm, state); diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 4a8a6f1f1151..5df252cebf1c 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -118,7 +118,7 @@ static void complete_commit(struct msm_commit *c, bool async) drm_atomic_helper_commit_modeset_disables(dev, state); - drm_atomic_helper_commit_planes(dev, state, false); + drm_atomic_helper_commit_planes(dev, state, 0); drm_atomic_helper_commit_modeset_enables(dev, state); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 3dd78f2045f9..e1cfba51cff6 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -96,7 +96,7 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit) dispc_runtime_get(); drm_atomic_helper_commit_modeset_disables(dev, old_state); - drm_atomic_helper_commit_planes(dev, old_state, false); + drm_atomic_helper_commit_planes(dev, old_state, 0); drm_atomic_helper_commit_modeset_enables(dev, old_state); omap_atomic_wait_for_completion(dev, old_state); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index f03eb55318c1..bd9c3bb9252c 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -257,7 +257,8 @@ static void rcar_du_atomic_complete(struct rcar_du_commit *commit) /* Apply the atomic update. */ drm_atomic_helper_commit_modeset_disables(dev, old_state); drm_atomic_helper_commit_modeset_enables(dev, old_state); - drm_atomic_helper_commit_planes(dev, old_state, true); + drm_atomic_helper_commit_planes(dev, old_state, + DRM_PLANE_COMMIT_ACTIVE_ONLY); drm_atomic_helper_wait_for_vblanks(dev, old_state); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 55c52734c52d..7ca8f347d79f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -233,7 +233,8 @@ rockchip_atomic_commit_tail(struct drm_atomic_state *state) drm_atomic_helper_commit_modeset_enables(dev, state); - drm_atomic_helper_commit_planes(dev, state, true); + drm_atomic_helper_commit_planes(dev, state, + DRM_PLANE_COMMIT_ACTIVE_ONLY); drm_atomic_helper_commit_hw_done(state); diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index f8311b2bc84e..7cd3804c6dee 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -178,7 +178,7 @@ static void sti_atomic_complete(struct sti_private *private, */ drm_atomic_helper_commit_modeset_disables(drm, state); - drm_atomic_helper_commit_planes(drm, state, false); + drm_atomic_helper_commit_planes(drm, state, 0); drm_atomic_helper_commit_modeset_enables(drm, state); drm_atomic_helper_wait_for_vblanks(drm, state); diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 755264d9db22..4b9f1c79cd7b 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -57,7 +57,8 @@ static void tegra_atomic_complete(struct tegra_drm *tegra, drm_atomic_helper_commit_modeset_disables(drm, state); drm_atomic_helper_commit_modeset_enables(drm, state); - drm_atomic_helper_commit_planes(drm, state, true); + drm_atomic_helper_commit_planes(drm, state, + DRM_PLANE_COMMIT_ACTIVE_ONLY); drm_atomic_helper_wait_for_vblanks(drm, state); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 3404d245d28d..4405e4bc8056 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -118,7 +118,7 @@ static int tilcdc_commit(struct drm_device *dev, drm_atomic_helper_commit_modeset_disables(dev, state); - drm_atomic_helper_commit_planes(dev, state, false); + drm_atomic_helper_commit_planes(dev, state, 0); drm_atomic_helper_commit_modeset_enables(dev, state); diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 4ac894d993cd..c1f65c6c8e60 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -44,7 +44,7 @@ vc4_atomic_complete_commit(struct vc4_commit *c) drm_atomic_helper_commit_modeset_disables(dev, state); - drm_atomic_helper_commit_planes(dev, state, false); + drm_atomic_helper_commit_planes(dev, state, 0); drm_atomic_helper_commit_modeset_enables(dev, state); diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 4e192aa2d021..7cf3678623c3 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -338,7 +338,8 @@ static void vgdev_atomic_commit_tail(struct drm_atomic_state *state) drm_atomic_helper_commit_modeset_disables(dev, state); drm_atomic_helper_commit_modeset_enables(dev, state); - drm_atomic_helper_commit_planes(dev, state, true); + drm_atomic_helper_commit_planes(dev, state, + DRM_PLANE_COMMIT_ACTIVE_ONLY); drm_atomic_helper_commit_hw_done(state); diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 1abf2c0227a6..f86682825d68 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -65,9 +65,13 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, int drm_atomic_helper_prepare_planes(struct drm_device *dev, struct drm_atomic_state *state); + +#define DRM_PLANE_COMMIT_ACTIVE_ONLY BIT(0) +#define DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET BIT(1) + void drm_atomic_helper_commit_planes(struct drm_device *dev, struct drm_atomic_state *state, - bool active_only); + uint32_t flags); void drm_atomic_helper_cleanup_planes(struct drm_device *dev, struct drm_atomic_state *old_state); void drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state); -- cgit From 63b07a8d8177675c5a4297de477fd511e9be7896 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 11 Aug 2016 11:22:12 +0300 Subject: drm/tilcdc: Remove drm_helper_disable_unused_functions() call drm_helper_disable_unused_functions() should not be called by atomic drivers. Signed-off-by: Jyri Sarha Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 4405e4bc8056..1f29a9314d11 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -361,8 +361,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) break; } - drm_helper_disable_unused_functions(dev); - drm_mode_config_reset(dev); priv->fbdev = drm_fbdev_cma_init(dev, bpp, -- cgit From bcc5a6f5fc9f0d53aa896768d6f86d7e64d0b783 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 11 Aug 2016 19:09:43 +0300 Subject: drm/tilcdc: Add blue-and-red-crossed devicetree property Add "blue-and-red-wiring"-device tree property and update devicetree binding document. The red and blue components are reversed between 24 and 16 bit modes on am335x LCDC output pins. To get 24 RGB format the red and blue wires has to be crossed and this in turn causes 16 colors output to be in BGR format. With straight wiring the 16 color is RGB and 24 bit is BGR. The new property describes whether the red and blue wires are crossed or not. If the property is not present or its value is not recognized the legacy mode is assumed. The legacy configuration supports RGB565, RGB888 and XRGB8888 formats. However, depending on wiring, the red and blue colors are swapped in either 16 or 24-bit color modes. For more details see section 3.1.1 in AM335x Silicon Errata: http://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=sprz360 Signed-off-by: Jyri Sarha Reviewed-by: Tomi Valkeinen --- .../devicetree/bindings/display/tilcdc/tilcdc.txt | 22 ++++++++++++ drivers/gpu/drm/tilcdc/tilcdc_drv.c | 41 ++++++++++++++++++++++ drivers/gpu/drm/tilcdc/tilcdc_drv.h | 4 +++ drivers/gpu/drm/tilcdc/tilcdc_plane.c | 9 ++--- 4 files changed, 70 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt index 6efa4c55d118..a5007aa437f3 100644 --- a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt +++ b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt @@ -17,6 +17,18 @@ Optional properties: the lcd controller. - max-pixelclock: The maximum pixel clock that can be supported by the lcd controller in KHz. + - blue-and-red-wiring: Recognized values "default", "straight" or + "crossed". This property deals with the LCDC revision 2 (found on + AM335x) color errata [1]. + - "straight" indicates normal wiring that supports RGB565, + BGR888, and XBGR8888 color formats. + - "crossed" indicates wiring that has blue and red wires + crossed. This setup supports BGR565, RGB888 and XRGB8888 + formats. + - If the property is not present or its value is not recognized + the legacy mode is assumed. This configuration supports RGB565, + RGB888 and XRGB8888 formats. However, depending on wiring, the red + and blue colors are swapped in either 16 or 24-bit color modes. Optional nodes: @@ -28,6 +40,14 @@ Optional nodes: Documentation/devicetree/bindings/display/tilcdc/tfp410.txt for connecting tfp410 DVI encoder or lcd panel to lcdc +[1] There is an errata about AM335x color wiring. For 16-bit color mode + the wires work as they should (LCD_DATA[0:4] is for Blue[3:7]), + but for 24 bit color modes the wiring of blue and red components is + crossed and LCD_DATA[0:4] is for Red[3:7] and LCD_DATA[11:15] is + for Blue[3-7]. For more details see section 3.1.1 in AM335x + Silicon Errata: + http://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=sprz360 + Example: fb: fb@4830e000 { @@ -37,6 +57,8 @@ Example: interrupts = <36>; ti,hwmods = "lcdc"; + blue-and-red-wiring = "crossed"; + port { lcdc_0: endpoint@0 { remote-endpoint = <&hdmi_0>; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 1f29a9314d11..f7c3ca858bb8 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -33,6 +33,20 @@ static LIST_HEAD(module_list); +static const u32 tilcdc_rev1_formats[] = { DRM_FORMAT_RGB565 }; + +static const u32 tilcdc_straight_formats[] = { DRM_FORMAT_RGB565, + DRM_FORMAT_BGR888, + DRM_FORMAT_XBGR8888 }; + +static const u32 tilcdc_crossed_formats[] = { DRM_FORMAT_BGR565, + DRM_FORMAT_RGB888, + DRM_FORMAT_XRGB8888 }; + +static const u32 tilcdc_legacy_formats[] = { DRM_FORMAT_RGB565, + DRM_FORMAT_RGB888, + DRM_FORMAT_XRGB8888 }; + void tilcdc_module_init(struct tilcdc_module *mod, const char *name, const struct tilcdc_module_ops *funcs) { @@ -318,6 +332,33 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) pm_runtime_put_sync(dev->dev); + if (priv->rev == 1) { + DBG("Revision 1 LCDC supports only RGB565 format"); + priv->pixelformats = tilcdc_rev1_formats; + priv->num_pixelformats = ARRAY_SIZE(tilcdc_rev1_formats); + } else { + const char *str = "\0"; + + of_property_read_string(node, "blue-and-red-wiring", &str); + if (0 == strcmp(str, "crossed")) { + DBG("Configured for crossed blue and red wires"); + priv->pixelformats = tilcdc_crossed_formats; + priv->num_pixelformats = + ARRAY_SIZE(tilcdc_crossed_formats); + } else if (0 == strcmp(str, "straight")) { + DBG("Configured for straight blue and red wires"); + priv->pixelformats = tilcdc_straight_formats; + priv->num_pixelformats = + ARRAY_SIZE(tilcdc_straight_formats); + } else { + DBG("Blue and red wiring '%s' unknown, use legacy mode", + str); + priv->pixelformats = tilcdc_legacy_formats; + priv->num_pixelformats = + ARRAY_SIZE(tilcdc_legacy_formats); + } + } + ret = modeset_init(dev); if (ret < 0) { dev_err(dev->dev, "failed to initialize mode setting\n"); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index 13001df7dbe8..0e19c1400386 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -65,6 +65,10 @@ struct tilcdc_drm_private { */ uint32_t max_width; + /* Supported pixel formats */ + const uint32_t *pixelformats; + uint32_t num_pixelformats; + /* The context for pm susped/resume cycle is stored here */ struct drm_atomic_state *saved_state; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_plane.c b/drivers/gpu/drm/tilcdc/tilcdc_plane.c index 41911e3110e8..74c65fa859b2 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_plane.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_plane.c @@ -24,10 +24,6 @@ #include "tilcdc_drv.h" -static const u32 tilcdc_formats[] = { DRM_FORMAT_RGB565, - DRM_FORMAT_RGB888, - DRM_FORMAT_XRGB8888 }; - static struct drm_plane_funcs tilcdc_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, @@ -114,12 +110,13 @@ static const struct drm_plane_helper_funcs plane_helper_funcs = { int tilcdc_plane_init(struct drm_device *dev, struct drm_plane *plane) { + struct tilcdc_drm_private *priv = dev->dev_private; int ret; ret = drm_plane_init(dev, plane, 1, &tilcdc_plane_funcs, - tilcdc_formats, - ARRAY_SIZE(tilcdc_formats), + priv->pixelformats, + priv->num_pixelformats, true); if (ret) { dev_err(dev->dev, "Failed to initialize plane: %d\n", ret); -- cgit From c56653855250ca6072d6e0ad7fe537c1a6628c70 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Sat, 13 Aug 2016 21:08:20 +0300 Subject: drm/tilcdc: Choose console BPP that supports RGB Choose console BPP that supports RGB and remove the old fbdev bpp selection code. LCDC on AM335x has red and blue wires switched between 24 bit and 16 bit colors. If 24 format is wired for RGB colors, the 16 bit format is wired for BGR. drm_fbdev_cma_init() does not currently like anything else but RGB formats, so we must choose such bytes per pixel value that supports RGB. Signed-off-by: Jyri Sarha Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 14 +++++--------- drivers/gpu/drm/tilcdc/tilcdc_drv.h | 1 - drivers/gpu/drm/tilcdc/tilcdc_external.c | 7 +++---- drivers/gpu/drm/tilcdc/tilcdc_external.h | 2 +- drivers/gpu/drm/tilcdc/tilcdc_panel.c | 2 -- drivers/gpu/drm/tilcdc/tilcdc_tfp410.c | 2 -- 6 files changed, 9 insertions(+), 19 deletions(-) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index f7c3ca858bb8..f8892e9ad169 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -240,7 +240,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) struct platform_device *pdev = dev->platformdev; struct device_node *node = pdev->dev.of_node; struct tilcdc_drm_private *priv; - struct tilcdc_module *mod; struct resource *res; u32 bpp = 0; int ret; @@ -336,6 +335,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) DBG("Revision 1 LCDC supports only RGB565 format"); priv->pixelformats = tilcdc_rev1_formats; priv->num_pixelformats = ARRAY_SIZE(tilcdc_rev1_formats); + bpp = 16; } else { const char *str = "\0"; @@ -345,17 +345,20 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) priv->pixelformats = tilcdc_crossed_formats; priv->num_pixelformats = ARRAY_SIZE(tilcdc_crossed_formats); + bpp = 32; /* Choose bpp with RGB support for fbdef */ } else if (0 == strcmp(str, "straight")) { DBG("Configured for straight blue and red wires"); priv->pixelformats = tilcdc_straight_formats; priv->num_pixelformats = ARRAY_SIZE(tilcdc_straight_formats); + bpp = 16; /* Choose bpp with RGB support for fbdef */ } else { DBG("Blue and red wiring '%s' unknown, use legacy mode", str); priv->pixelformats = tilcdc_legacy_formats; priv->num_pixelformats = ARRAY_SIZE(tilcdc_legacy_formats); + bpp = 16; /* This is just a guess */ } } @@ -372,7 +375,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) if (ret < 0) goto fail_mode_config_cleanup; - ret = tilcdc_add_external_encoders(dev, &bpp); + ret = tilcdc_add_external_encoders(dev); if (ret < 0) goto fail_component_cleanup; } @@ -395,13 +398,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) goto fail_vblank_cleanup; } - list_for_each_entry(mod, &module_list, list) { - DBG("%s: preferred_bpp: %d", mod->name, mod->preferred_bpp); - bpp = mod->preferred_bpp; - if (bpp > 0) - break; - } - drm_mode_config_reset(dev); priv->fbdev = drm_fbdev_cma_init(dev, bpp, diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index 0e19c1400386..a6e5e6d4970c 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -116,7 +116,6 @@ struct tilcdc_module { const char *name; struct list_head list; const struct tilcdc_module_ops *funcs; - unsigned int preferred_bpp; }; void tilcdc_module_init(struct tilcdc_module *mod, const char *name, diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c index 849b23ebc455..68e895021005 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_external.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c @@ -52,7 +52,7 @@ static int tilcdc_external_mode_valid(struct drm_connector *connector, return MODE_OK; } -static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp, +static int tilcdc_add_external_encoder(struct drm_device *dev, struct drm_connector *connector) { struct tilcdc_drm_private *priv = dev->dev_private; @@ -64,7 +64,6 @@ static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp, /* Only tda998x is supported at the moment. */ tilcdc_crtc_set_simulate_vesa_sync(priv->crtc, true); tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_tda998x); - *bpp = panel_info_tda998x.bpp; connector_funcs = devm_kzalloc(dev->dev, sizeof(*connector_funcs), GFP_KERNEL); @@ -94,7 +93,7 @@ static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp, return 0; } -int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp) +int tilcdc_add_external_encoders(struct drm_device *dev) { struct tilcdc_drm_private *priv = dev->dev_private; struct drm_connector *connector; @@ -108,7 +107,7 @@ int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp) if (connector == priv->connectors[i]) found = true; if (!found) { - ret = tilcdc_add_external_encoder(dev, bpp, connector); + ret = tilcdc_add_external_encoder(dev, connector); if (ret) return ret; } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.h b/drivers/gpu/drm/tilcdc/tilcdc_external.h index 6aabe2788760..c700e0c1623e 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_external.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_external.h @@ -18,7 +18,7 @@ #ifndef __TILCDC_EXTERNAL_H__ #define __TILCDC_EXTERNAL_H__ -int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp); +int tilcdc_add_external_encoders(struct drm_device *dev); void tilcdc_remove_external_encoders(struct drm_device *dev); int tilcdc_get_external_components(struct device *dev, struct component_match **match); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c index 4ac1d25eb79b..7b3650901930 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c @@ -397,8 +397,6 @@ static int panel_probe(struct platform_device *pdev) goto fail_timings; } - mod->preferred_bpp = panel_mod->info->bpp; - return 0; fail_timings: diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c index 741c7b5b8302..c6a70da6473d 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c @@ -327,8 +327,6 @@ static int tfp410_probe(struct platform_device *pdev) goto fail; } - mod->preferred_bpp = dvi_info.bpp; - i2c_node = of_find_node_by_phandle(i2c_phandle); if (!i2c_node) { dev_err(&pdev->dev, "could not get i2c bus node\n"); -- cgit From a6b7ebaadb5c8d869908e803e5616922a5096253 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 5 Sep 2016 20:39:32 +0300 Subject: drm/tilcdc: Take crtc modeset lock while updating the crtc clock rate Take crtc modeset lock while updating the crtc clock rate. To avoid a race in tilcdc_crtc_update_clk(), we do not want crtc mode to change while we update crtc clock. Signed-off-by: Jyri Sarha Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index f8892e9ad169..b1ac61eac056 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -184,10 +184,13 @@ static int cpufreq_transition(struct notifier_block *nb, { struct tilcdc_drm_private *priv = container_of(nb, struct tilcdc_drm_private, freq_transition); + if (val == CPUFREQ_POSTCHANGE) { if (priv->lcd_fck_rate != clk_get_rate(priv->clk)) { + drm_modeset_lock_crtc(priv->crtc, NULL); priv->lcd_fck_rate = clk_get_rate(priv->clk); tilcdc_crtc_update_clk(priv->crtc); + drm_modeset_unlock_crtc(priv->crtc); } } -- cgit From 642e51677d29c9f21891b571be4473ec482acaf0 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 6 Sep 2016 16:19:54 +0300 Subject: drm/tilcdc: Clean up LCDC functional clock rate setting code Clean up LCDC functional clock rate setting code. The LCDC functional clock is set by two functions: mode_set_nofb() and cpufreq_transition(). When tilcdc_crtc_mode_set_nofb() is called in atomic commit phase the drm atomic helpers have taken all the necessary drm locks and turned off the crtc, while tilcdc_commit() is keeping LCDC powered on. For mode_set_nofb() just a simple clock setting function without any locking or power management code is enough. The new tilcdc_crtc_set_clk() is implemented for that purpose. cpufreq_transition() on the other hand is called from outside DRM and it needs to take the necessary locks and turn off the CRTC while keeping the LCDC powered. The reimplemented tilcdc_crtc_update_clk() is for that purpose and it uses the new tilcdc_crtc_set_clk() to actually set the clock. Signed-off-by: Jyri Sarha Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 77 +++++++++++++++++++++--------------- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 11 +----- drivers/gpu/drm/tilcdc/tilcdc_drv.h | 1 - 3 files changed, 47 insertions(+), 42 deletions(-) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 208768922030..5579d97b08e6 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -35,6 +35,8 @@ struct tilcdc_crtc { bool frame_done; spinlock_t irq_lock; + unsigned int lcd_fck_rate; + ktime_t last_vblank; struct drm_framebuffer *curr_fb; @@ -304,6 +306,37 @@ static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc, return true; } +static void tilcdc_crtc_set_clk(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct tilcdc_drm_private *priv = dev->dev_private; + struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); + const unsigned clkdiv = 2; /* using a fixed divider of 2 */ + int ret; + + /* mode.clock is in KHz, set_rate wants parameter in Hz */ + ret = clk_set_rate(priv->clk, crtc->mode.clock * 1000 * clkdiv); + if (ret < 0) { + dev_err(dev->dev, "failed to set display clock rate to: %d\n", + crtc->mode.clock); + return; + } + + tilcdc_crtc->lcd_fck_rate = clk_get_rate(priv->clk); + + DBG("lcd_clk=%u, mode clock=%d, div=%u", + tilcdc_crtc->lcd_fck_rate, crtc->mode.clock, clkdiv); + + /* Configure the LCD clock divisor. */ + tilcdc_write(dev, LCDC_CTRL_REG, LCDC_CLK_DIVISOR(clkdiv) | + LCDC_RASTER_MODE); + + if (priv->rev == 2) + tilcdc_set(dev, LCDC_CLK_ENABLE_REG, + LCDC_V2_DMA_CLK_EN | LCDC_V2_LIDD_CLK_EN | + LCDC_V2_CORE_CLK_EN); +} + static void tilcdc_crtc_mode_set_nofb(struct drm_crtc *crtc) { struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); @@ -466,7 +499,7 @@ static void tilcdc_crtc_mode_set_nofb(struct drm_crtc *crtc) set_scanout(crtc, fb); - tilcdc_crtc_update_clk(crtc); + tilcdc_crtc_set_clk(crtc); crtc->hwmode = crtc->state->adjusted_mode; } @@ -635,41 +668,21 @@ void tilcdc_crtc_update_clk(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct tilcdc_drm_private *priv = dev->dev_private; - unsigned long lcd_clk; - const unsigned clkdiv = 2; /* using a fixed divider of 2 */ - int ret; + struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); - pm_runtime_get_sync(dev->dev); + drm_modeset_lock_crtc(crtc, NULL); + if (tilcdc_crtc->lcd_fck_rate != clk_get_rate(priv->clk)) { + if (tilcdc_crtc_is_on(crtc)) { + pm_runtime_get_sync(dev->dev); + tilcdc_crtc_disable(crtc); - tilcdc_crtc_disable(crtc); + tilcdc_crtc_set_clk(crtc); - /* mode.clock is in KHz, set_rate wants parameter in Hz */ - ret = clk_set_rate(priv->clk, crtc->mode.clock * 1000 * clkdiv); - if (ret < 0) { - dev_err(dev->dev, "failed to set display clock rate to: %d\n", - crtc->mode.clock); - goto out; + tilcdc_crtc_enable(crtc); + pm_runtime_put_sync(dev->dev); + } } - - lcd_clk = clk_get_rate(priv->clk); - - DBG("lcd_clk=%lu, mode clock=%d, div=%u", - lcd_clk, crtc->mode.clock, clkdiv); - - /* Configure the LCD clock divisor. */ - tilcdc_write(dev, LCDC_CTRL_REG, LCDC_CLK_DIVISOR(clkdiv) | - LCDC_RASTER_MODE); - - if (priv->rev == 2) - tilcdc_set(dev, LCDC_CLK_ENABLE_REG, - LCDC_V2_DMA_CLK_EN | LCDC_V2_LIDD_CLK_EN | - LCDC_V2_CORE_CLK_EN); - - if (tilcdc_crtc_is_on(crtc)) - tilcdc_crtc_enable(crtc); - -out: - pm_runtime_put_sync(dev->dev); + drm_modeset_unlock_crtc(crtc); } #define SYNC_LOST_COUNT_LIMIT 50 diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index b1ac61eac056..52ff3e120bb9 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -185,14 +185,8 @@ static int cpufreq_transition(struct notifier_block *nb, struct tilcdc_drm_private *priv = container_of(nb, struct tilcdc_drm_private, freq_transition); - if (val == CPUFREQ_POSTCHANGE) { - if (priv->lcd_fck_rate != clk_get_rate(priv->clk)) { - drm_modeset_lock_crtc(priv->crtc, NULL); - priv->lcd_fck_rate = clk_get_rate(priv->clk); - tilcdc_crtc_update_clk(priv->crtc); - drm_modeset_unlock_crtc(priv->crtc); - } - } + if (val == CPUFREQ_POSTCHANGE) + tilcdc_crtc_update_clk(priv->crtc); return 0; } @@ -286,7 +280,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) } #ifdef CONFIG_CPU_FREQ - priv->lcd_fck_rate = clk_get_rate(priv->clk); priv->freq_transition.notifier_call = cpufreq_transition; ret = cpufreq_register_notifier(&priv->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index a6e5e6d4970c..9780c37ec4cd 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -74,7 +74,6 @@ struct tilcdc_drm_private { #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; - unsigned int lcd_fck_rate; #endif struct workqueue_struct *wq; -- cgit From 7eff0410276374c560e797e7676b7111fed24a3c Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 6 Sep 2016 22:16:27 +0300 Subject: drm/tilcdc: Remove unnecessary tilcdc_crtc_disable() from tilcdc_unload() Remove unnecessary tilcdc_crtc_disable() from tilcdc_unload(). The tilcdc_crtc_disable() called via tilcdc_crtc_destroy() by drm_mode_config_cleanup() couple of lines later. The early call to tilcdc_crtc_disable() was a wrong fix (that worked) for calling drm_flip_work_cleanup() before flushing the flip-work queue. Signed-off-by: Jyri Sarha Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 52ff3e120bb9..1981ae9c80a1 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -200,8 +200,6 @@ static int tilcdc_unload(struct drm_device *dev) { struct tilcdc_drm_private *priv = dev->dev_private; - tilcdc_crtc_disable(priv->crtc); - tilcdc_remove_external_encoders(dev); drm_fbdev_cma_fini(priv->fbdev); -- cgit From 30457676e2289378094ed67b26ce3bfe312a0246 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 10 Sep 2016 12:32:57 +0000 Subject: drm/tilcdc: Fix non static symbol warning Fixes the following sparse warning: drivers/gpu/drm/tilcdc/tilcdc_drv.c:64:5: warning: symbol 'tilcdc_atomic_check' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Jyri Sarha --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 1981ae9c80a1..4b93cab91168 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -75,8 +75,8 @@ static void tilcdc_fb_output_poll_changed(struct drm_device *dev) drm_fbdev_cma_hotplug_event(priv->fbdev); } -int tilcdc_atomic_check(struct drm_device *dev, - struct drm_atomic_state *state) +static int tilcdc_atomic_check(struct drm_device *dev, + struct drm_atomic_state *state) { int ret; -- cgit From 7b993855dfd5d87e07ac84285d3d9bb0c743dede Mon Sep 17 00:00:00 2001 From: Daniel Schultz Date: Fri, 23 Sep 2016 12:52:49 +0200 Subject: drm/tilcdc: fix wrong error handling When 'component_bind_all' fails it should not try to unbind components in the error handling. This will produce a null pointer kernel panic when no component exist. This patch changes the order of the error handling. Now, it will only unbind components if the are bound. Otherwise, the module will jump to an error label below. Signed-off-by: Daniel Schultz Reviewed-by: Sean Paul Signed-off-by: Jyri Sarha --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 4b93cab91168..a694977c32f4 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -412,13 +412,13 @@ fail_irq_uninstall: fail_vblank_cleanup: drm_vblank_cleanup(dev); -fail_mode_config_cleanup: - drm_mode_config_cleanup(dev); - fail_component_cleanup: if (priv->is_componentized) component_unbind_all(dev->dev, dev); +fail_mode_config_cleanup: + drm_mode_config_cleanup(dev); + fail_external_cleanup: tilcdc_remove_external_encoders(dev); -- cgit