diff options
author | Tony Lindgren <tony@atomide.com> | 2016-03-30 20:36:06 +0300 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2016-03-30 20:36:06 +0300 |
commit | 1809de7e7d37c585e01a1bcc583ea92b78fc759d (patch) | |
tree | 76c5b35c2b04eafce86a1a729c02ab705eba44bc /drivers/gpu/drm/tilcdc/tilcdc_drv.c | |
parent | ebf24414809200915b9ddf7f109bba7c278c8210 (diff) | |
parent | 3ca4a238106dedc285193ee47f494a6584b6fd2f (diff) | |
download | linux-1809de7e7d37c585e01a1bcc583ea92b78fc759d.tar.xz |
Merge tag 'for-v4.6-rc/omap-fixes-a' of git://git.kernel.org/pub/scm/linux/kernel/git/pjw/omap-pending into omap-for-v4.6/fixes
ARM: OMAP2+: first hwmod fix for v4.6-rc
Fix a longstanding bug in the hwmod code that could cause
hardware SYSCONFIG register values to not match the kernel's
idea of what they should be, and that could result in lower
performance during IP block idle entry.
Basic build, boot, and PM test logs are available here:
http://www.pwsan.com/omap/testlogs/omap-hwmod-fixes-a-for-v4.6-rc/20160326231727/
Diffstat (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c')
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_drv.c | 138 |
1 files changed, 75 insertions, 63 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index d7f5b897c6c5..709bc903524d 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -18,6 +18,8 @@ /* LCDC DRM driver, based on da8xx-fb */ #include <linux/component.h> +#include <linux/pinctrl/consumer.h> +#include <linux/suspend.h> #include "tilcdc_drv.h" #include "tilcdc_regs.h" @@ -110,6 +112,8 @@ 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_remove_external_encoders(dev); drm_fbdev_cma_fini(priv->fbdev); @@ -139,11 +143,11 @@ static int tilcdc_unload(struct drm_device *dev) pm_runtime_disable(dev->dev); - kfree(priv); - 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; @@ -154,8 +158,12 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) u32 bpp = 0; int ret; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { + 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) { dev_err(dev->dev, "failed to allocate private data\n"); return -ENOMEM; } @@ -168,7 +176,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) priv->wq = alloc_ordered_workqueue("tilcdc", 0); if (!priv->wq) { ret = -ENOMEM; - goto fail_free_priv; + goto fail_unset_priv; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -192,13 +200,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) goto fail_iounmap; } - priv->disp_clk = clk_get(dev->dev, "dpll_disp_ck"); - if (IS_ERR(priv->clk)) { - dev_err(dev->dev, "failed to get display clock\n"); - ret = -ENODEV; - goto fail_put_clk; - } - #ifdef CONFIG_CPU_FREQ priv->lcd_fck_rate = clk_get_rate(priv->clk); priv->freq_transition.notifier_call = cpufreq_transition; @@ -206,7 +207,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) CPUFREQ_TRANSITION_NOTIFIER); if (ret) { dev_err(dev->dev, "failed to register cpufreq notifier\n"); - goto fail_put_disp_clk; + goto fail_put_clk; } #endif @@ -227,7 +228,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock); pm_runtime_enable(dev->dev); - pm_runtime_irq_safe(dev->dev); /* Determine LCD IP Version */ pm_runtime_get_sync(dev->dev); @@ -330,11 +330,9 @@ fail_cpufreq_unregister: #ifdef CONFIG_CPU_FREQ cpufreq_unregister_notifier(&priv->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); -fail_put_disp_clk: - clk_put(priv->disp_clk); -#endif fail_put_clk: +#endif clk_put(priv->clk); fail_iounmap: @@ -344,17 +342,10 @@ fail_free_wq: flush_workqueue(priv->wq); destroy_workqueue(priv->wq); -fail_free_priv: +fail_unset_priv: dev->dev_private = NULL; - kfree(priv); - return ret; -} -static void tilcdc_preclose(struct drm_device *dev, struct drm_file *file) -{ - struct tilcdc_drm_private *priv = dev->dev_private; - - tilcdc_crtc_cancel_page_flip(priv->crtc, file); + return ret; } static void tilcdc_lastclose(struct drm_device *dev) @@ -380,10 +371,14 @@ 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) + if (priv->rev == 1) { tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_V1_UNDERFLOW_INT_ENA); - else - tilcdc_set(dev, LCDC_INT_ENABLE_SET_REG, LCDC_V2_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; } @@ -398,43 +393,21 @@ static void tilcdc_irq_uninstall(struct drm_device *dev) 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_clear(dev, LCDC_INT_ENABLE_SET_REG, + 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_V2_END_OF_FRAME1_INT_ENA | - LCDC_FRAME_DONE); + LCDC_V2_END_OF_FRAME0_INT_ENA | + LCDC_FRAME_DONE | LCDC_SYNC_LOST); } - -} - -static void enable_vblank(struct drm_device *dev, bool enable) -{ - struct tilcdc_drm_private *priv = dev->dev_private; - u32 reg, mask; - - if (priv->rev == 1) { - reg = LCDC_DMA_CTRL_REG; - mask = LCDC_V1_END_OF_FRAME_INT_ENA; - } else { - reg = LCDC_INT_ENABLE_SET_REG; - mask = LCDC_V2_END_OF_FRAME0_INT_ENA | - LCDC_V2_END_OF_FRAME1_INT_ENA | LCDC_FRAME_DONE; - } - - if (enable) - tilcdc_set(dev, reg, mask); - else - tilcdc_clear(dev, reg, mask); } static int tilcdc_enable_vblank(struct drm_device *dev, unsigned int pipe) { - enable_vblank(dev, true); return 0; } static void tilcdc_disable_vblank(struct drm_device *dev, unsigned int pipe) { - enable_vblank(dev, false); + return; } #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_PM_SLEEP) @@ -461,13 +434,22 @@ static const struct { /* new in revision 2: */ REG(2, false, LCDC_RAW_STAT_REG), REG(2, false, LCDC_MASKED_STAT_REG), - REG(2, false, LCDC_INT_ENABLE_SET_REG), + REG(2, true, LCDC_INT_ENABLE_SET_REG), REG(2, false, LCDC_INT_ENABLE_CLR_REG), REG(2, false, LCDC_END_OF_INT_IND_REG), REG(2, true, LCDC_CLK_ENABLE_REG), - REG(2, true, LCDC_INT_ENABLE_SET_REG), #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 @@ -554,10 +536,10 @@ static const struct file_operations fops = { }; static struct drm_driver tilcdc_driver = { - .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET, + .driver_features = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | + DRIVER_PRIME), .load = tilcdc_load, .unload = tilcdc_unload, - .preclose = tilcdc_preclose, .lastclose = tilcdc_lastclose, .set_busid = drm_platform_set_busid, .irq_handler = tilcdc_irq, @@ -572,6 +554,16 @@ static struct drm_driver tilcdc_driver = { .dumb_create = drm_gem_cma_dumb_create, .dumb_map_offset = drm_gem_cma_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, + + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, #ifdef CONFIG_DEBUG_FS .debugfs_init = tilcdc_debugfs_init, .debugfs_cleanup = tilcdc_debugfs_cleanup, @@ -597,11 +589,24 @@ static int tilcdc_pm_suspend(struct device *dev) drm_kms_helper_poll_disable(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 */ + 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; } @@ -611,10 +616,17 @@ static int tilcdc_pm_resume(struct device *dev) struct tilcdc_drm_private *priv = ddev->dev_private; unsigned i, n = 0; - /* 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++]); + /* 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++]); + } drm_kms_helper_poll_enable(ddev); |