diff options
Diffstat (limited to 'drivers/gpu/drm/tilcdc')
| -rw-r--r-- | drivers/gpu/drm/tilcdc/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 171 | ||||
| -rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_drv.c | 48 | ||||
| -rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_drv.h | 25 | ||||
| -rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_panel.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_regs.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_slave.c | 79 | ||||
| -rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_tfp410.c | 3 |
8 files changed, 252 insertions, 78 deletions
diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig index 7a4d1010690..7c3ef79fcb3 100644 --- a/drivers/gpu/drm/tilcdc/Kconfig +++ b/drivers/gpu/drm/tilcdc/Kconfig @@ -2,6 +2,7 @@ config DRM_TILCDC tristate "DRM Support for TI LCDC Display Controller" depends on DRM && OF && ARM select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select DRM_KMS_CMA_HELPER select DRM_GEM_CMA_HELPER select VIDEOMODE_HELPERS diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 5dd3c7d031d..d642d4a0213 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -15,7 +15,7 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <linux/kfifo.h> +#include "drm_flip_work.h" #include "tilcdc_drv.h" #include "tilcdc_regs.h" @@ -35,51 +35,46 @@ struct tilcdc_crtc { struct drm_framebuffer *scanout[2]; /* for deferred fb unref's: */ - DECLARE_KFIFO_PTR(unref_fifo, struct drm_framebuffer *); - struct work_struct work; + struct drm_flip_work unref_work; }; #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base) -static void unref_worker(struct work_struct *work) +static void unref_worker(struct drm_flip_work *work, void *val) { - struct tilcdc_crtc *tilcdc_crtc = container_of(work, struct tilcdc_crtc, work); + struct tilcdc_crtc *tilcdc_crtc = + container_of(work, struct tilcdc_crtc, unref_work); struct drm_device *dev = tilcdc_crtc->base.dev; - struct drm_framebuffer *fb; mutex_lock(&dev->mode_config.mutex); - while (kfifo_get(&tilcdc_crtc->unref_fifo, &fb)) - drm_framebuffer_unreference(fb); + drm_framebuffer_unreference(val); mutex_unlock(&dev->mode_config.mutex); } static void set_scanout(struct drm_crtc *crtc, int n) { static const uint32_t base_reg[] = { - LCDC_DMA_FB_BASE_ADDR_0_REG, LCDC_DMA_FB_BASE_ADDR_1_REG, + LCDC_DMA_FB_BASE_ADDR_0_REG, + LCDC_DMA_FB_BASE_ADDR_1_REG, }; static const uint32_t ceil_reg[] = { - LCDC_DMA_FB_CEILING_ADDR_0_REG, LCDC_DMA_FB_CEILING_ADDR_1_REG, + LCDC_DMA_FB_CEILING_ADDR_0_REG, + LCDC_DMA_FB_CEILING_ADDR_1_REG, }; static const uint32_t stat[] = { LCDC_END_OF_FRAME0, LCDC_END_OF_FRAME1, }; struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); struct drm_device *dev = crtc->dev; + struct tilcdc_drm_private *priv = dev->dev_private; pm_runtime_get_sync(dev->dev); tilcdc_write(dev, base_reg[n], tilcdc_crtc->start); tilcdc_write(dev, ceil_reg[n], tilcdc_crtc->end); if (tilcdc_crtc->scanout[n]) { - if (kfifo_put(&tilcdc_crtc->unref_fifo, - (const struct drm_framebuffer **)&tilcdc_crtc->scanout[n])) { - struct tilcdc_drm_private *priv = dev->dev_private; - queue_work(priv->wq, &tilcdc_crtc->work); - } else { - dev_err(dev->dev, "unref fifo full!\n"); - drm_framebuffer_unreference(tilcdc_crtc->scanout[n]); - } + drm_flip_work_queue(&tilcdc_crtc->unref_work, tilcdc_crtc->scanout[n]); + drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq); } - tilcdc_crtc->scanout[n] = crtc->fb; + tilcdc_crtc->scanout[n] = crtc->primary->fb; drm_framebuffer_reference(tilcdc_crtc->scanout[n]); tilcdc_crtc->dirty &= ~stat[n]; pm_runtime_put_sync(dev->dev); @@ -89,7 +84,7 @@ static void update_scanout(struct drm_crtc *crtc) { struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); struct drm_device *dev = crtc->dev; - struct drm_framebuffer *fb = crtc->fb; + struct drm_framebuffer *fb = crtc->primary->fb; struct drm_gem_cma_object *gem; unsigned int depth, bpp; @@ -146,14 +141,15 @@ static void tilcdc_crtc_destroy(struct drm_crtc *crtc) WARN_ON(tilcdc_crtc->dpms == DRM_MODE_DPMS_ON); drm_crtc_cleanup(crtc); - WARN_ON(!kfifo_is_empty(&tilcdc_crtc->unref_fifo)); - kfifo_free(&tilcdc_crtc->unref_fifo); + drm_flip_work_cleanup(&tilcdc_crtc->unref_work); + kfree(tilcdc_crtc); } static int tilcdc_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event) + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags) { struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); struct drm_device *dev = crtc->dev; @@ -163,7 +159,7 @@ static int tilcdc_crtc_page_flip(struct drm_crtc *crtc, return -EBUSY; } - crtc->fb = fb; + crtc->primary->fb = fb; tilcdc_crtc->event = event; update_scanout(crtc); @@ -194,7 +190,8 @@ static void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode) tilcdc_crtc->frame_done = false; stop(crtc); - /* if necessary wait for framedone irq which will still come + /* + * if necessary wait for framedone irq which will still come * before putting things to sleep.. */ if (priv->rev == 2) { @@ -289,17 +286,24 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc, reg = tilcdc_read(dev, LCDC_RASTER_TIMING_2_REG) & ~0x000fff00; reg |= LCDC_AC_BIAS_FREQUENCY(info->ac_bias) | LCDC_AC_BIAS_TRANSITIONS_PER_INT(info->ac_bias_intrpt); + + /* + * subtract one from hfp, hbp, hsw because the hardware uses + * a value of 0 as 1 + */ if (priv->rev == 2) { - reg |= (hfp & 0x300) >> 8; - reg |= (hbp & 0x300) >> 4; - reg |= (hsw & 0x3c0) << 21; + /* clear bits we're going to set */ + reg &= ~0x78000033; + reg |= ((hfp-1) & 0x300) >> 8; + reg |= ((hbp-1) & 0x300) >> 4; + reg |= ((hsw-1) & 0x3c0) << 21; } tilcdc_write(dev, LCDC_RASTER_TIMING_2_REG, reg); reg = (((mode->hdisplay >> 4) - 1) << 4) | - ((hbp & 0xff) << 24) | - ((hfp & 0xff) << 16) | - ((hsw & 0x3f) << 10); + (((hbp-1) & 0xff) << 24) | + (((hfp-1) & 0xff) << 16) | + (((hsw-1) & 0x3f) << 10); if (priv->rev == 2) reg |= (((mode->hdisplay >> 4) - 1) & 0x40) >> 3; tilcdc_write(dev, LCDC_RASTER_TIMING_0_REG, reg); @@ -307,9 +311,24 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc, reg = ((mode->vdisplay - 1) & 0x3ff) | ((vbp & 0xff) << 24) | ((vfp & 0xff) << 16) | - ((vsw & 0x3f) << 10); + (((vsw-1) & 0x3f) << 10); tilcdc_write(dev, LCDC_RASTER_TIMING_1_REG, reg); + /* + * be sure to set Bit 10 for the V2 LCDC controller, + * otherwise limited to 1024 pixels width, stopping + * 1920x1080 being suppoted. + */ + if (priv->rev == 2) { + if ((mode->vdisplay - 1) & 0x400) { + tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, + LCDC_LPP_B10); + } else { + tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, + LCDC_LPP_B10); + } + } + /* Configure display type: */ reg = tilcdc_read(dev, LCDC_RASTER_CTRL_REG) & ~(LCDC_TFT_MODE | LCDC_MONO_8BIT_MODE | LCDC_MONOCHROME_MODE | @@ -320,7 +339,7 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc, if (priv->rev == 2) { unsigned int depth, bpp; - drm_fb_get_bpp_depth(crtc->fb->pixel_format, &depth, &bpp); + drm_fb_get_bpp_depth(crtc->primary->fb->pixel_format, &depth, &bpp); switch (bpp) { case 16: break; @@ -353,7 +372,12 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc, else tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_EDGE); - if (mode->flags & DRM_MODE_FLAG_NHSYNC) + /* + * use value from adjusted_mode here as this might have been + * changed as part of the fixup for slave encoders to solve the + * issue where tilcdc timings are not VESA compliant + */ + if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_HSYNC); else tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_HSYNC); @@ -384,10 +408,6 @@ static int tilcdc_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, return 0; } -static void tilcdc_crtc_load_lut(struct drm_crtc *crtc) -{ -} - static const struct drm_crtc_funcs tilcdc_crtc_funcs = { .destroy = tilcdc_crtc_destroy, .set_config = drm_crtc_helper_set_config, @@ -401,7 +421,6 @@ static const struct drm_crtc_helper_funcs tilcdc_crtc_helper_funcs = { .commit = tilcdc_crtc_commit, .mode_set = tilcdc_crtc_mode_set, .mode_set_base = tilcdc_crtc_mode_set_base, - .load_lut = tilcdc_crtc_load_lut, }; int tilcdc_crtc_max_width(struct drm_crtc *crtc) @@ -422,7 +441,12 @@ int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct tilcdc_drm_private *priv = crtc->dev->dev_private; unsigned int bandwidth; + uint32_t hbp, hfp, hsw, vbp, vfp, vsw; + /* + * check to see if the width is within the range that + * the LCD Controller physically supports + */ if (mode->hdisplay > tilcdc_crtc_max_width(crtc)) return MODE_VIRTUAL_X; @@ -433,10 +457,70 @@ int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode) if (mode->vdisplay > 2048) return MODE_VIRTUAL_Y; + DBG("Processing mode %dx%d@%d with pixel clock %d", + mode->hdisplay, mode->vdisplay, + drm_mode_vrefresh(mode), mode->clock); + + hbp = mode->htotal - mode->hsync_end; + hfp = mode->hsync_start - mode->hdisplay; + hsw = mode->hsync_end - mode->hsync_start; + vbp = mode->vtotal - mode->vsync_end; + vfp = mode->vsync_start - mode->vdisplay; + vsw = mode->vsync_end - mode->vsync_start; + + if ((hbp-1) & ~0x3ff) { + DBG("Pruning mode: Horizontal Back Porch out of range"); + return MODE_HBLANK_WIDE; + } + + if ((hfp-1) & ~0x3ff) { + DBG("Pruning mode: Horizontal Front Porch out of range"); + return MODE_HBLANK_WIDE; + } + + if ((hsw-1) & ~0x3ff) { + DBG("Pruning mode: Horizontal Sync Width out of range"); + return MODE_HSYNC_WIDE; + } + + if (vbp & ~0xff) { + DBG("Pruning mode: Vertical Back Porch out of range"); + return MODE_VBLANK_WIDE; + } + + if (vfp & ~0xff) { + DBG("Pruning mode: Vertical Front Porch out of range"); + return MODE_VBLANK_WIDE; + } + + if ((vsw-1) & ~0x3f) { + DBG("Pruning mode: Vertical Sync Width out of range"); + return MODE_VSYNC_WIDE; + } + + /* + * some devices have a maximum allowed pixel clock + * configured from the DT + */ + if (mode->clock > priv->max_pixelclock) { + DBG("Pruning mode: pixel clock too high"); + return MODE_CLOCK_HIGH; + } + + /* + * some devices further limit the max horizontal resolution + * configured from the DT + */ + if (mode->hdisplay > priv->max_width) + return MODE_BAD_WIDTH; + /* filter out modes that would require too much memory bandwidth: */ - bandwidth = mode->hdisplay * mode->vdisplay * drm_mode_vrefresh(mode); - if (bandwidth > priv->max_bandwidth) + bandwidth = mode->hdisplay * mode->vdisplay * + drm_mode_vrefresh(mode); + if (bandwidth > priv->max_bandwidth) { + DBG("Pruning mode: exceeds defined bandwidth limit"); return MODE_BAD; + } return MODE_OK; } @@ -580,14 +664,13 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev) tilcdc_crtc->dpms = DRM_MODE_DPMS_OFF; init_waitqueue_head(&tilcdc_crtc->frame_done_wq); - ret = kfifo_alloc(&tilcdc_crtc->unref_fifo, 16, GFP_KERNEL); + ret = drm_flip_work_init(&tilcdc_crtc->unref_work, 16, + "unref", unref_worker); if (ret) { dev_err(dev->dev, "could not allocate unref FIFO\n"); goto fail; } - INIT_WORK(&tilcdc_crtc->work, unref_worker); - ret = drm_crtc_init(dev, crtc, &tilcdc_crtc_funcs); if (ret < 0) goto fail; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 2b5461bcd9f..b20b69488dc 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -26,6 +26,7 @@ #include "drm_fb_helper.h" static LIST_HEAD(module_list); +static bool slave_probing; void tilcdc_module_init(struct tilcdc_module *mod, const char *name, const struct tilcdc_module_ops *funcs) @@ -41,6 +42,11 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod) list_del(&mod->list); } +void tilcdc_slave_probedefer(bool defered) +{ + slave_probing = defered; +} + static struct of_device_id tilcdc_of_match[]; static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev, @@ -157,7 +163,9 @@ 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; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -210,7 +218,20 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) #endif if (of_property_read_u32(node, "max-bandwidth", &priv->max_bandwidth)) - priv->max_bandwidth = 1280 * 1024 * 60; + priv->max_bandwidth = TILCDC_DEFAULT_MAX_BANDWIDTH; + + DBG("Maximum Bandwidth Value %d", priv->max_bandwidth); + + if (of_property_read_u32(node, "ti,max-width", &priv->max_width)) + priv->max_width = TILCDC_DEFAULT_MAX_WIDTH; + + DBG("Maximum Horizontal Pixel Width Value %dpixels", priv->max_width); + + if (of_property_read_u32(node, "ti,max-pixelclock", + &priv->max_pixelclock)) + priv->max_pixelclock = TILCDC_DEFAULT_MAX_PIXELCLOCK; + + DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock); pm_runtime_enable(dev->dev); @@ -247,7 +268,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) } pm_runtime_get_sync(dev->dev); - ret = drm_irq_install(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"); @@ -256,7 +277,15 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) platform_set_drvdata(pdev, dev); - priv->fbdev = drm_fbdev_cma_init(dev, 16, + + 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; + } + + priv->fbdev = drm_fbdev_cma_init(dev, bpp, dev->mode_config.num_crtc, dev->mode_config.num_connector); @@ -282,7 +311,7 @@ static void tilcdc_lastclose(struct drm_device *dev) drm_fbdev_cma_restore_mode(priv->fbdev); } -static irqreturn_t tilcdc_irq(DRM_IRQ_ARGS) +static irqreturn_t tilcdc_irq(int irq, void *arg) { struct drm_device *dev = arg; struct tilcdc_drm_private *priv = dev->dev_private; @@ -415,7 +444,7 @@ static int tilcdc_mm_show(struct seq_file *m, void *arg) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; - return drm_mm_dump_table(m, dev->mm_private); + return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm); } static struct drm_info_list tilcdc_debugfs_list[] = { @@ -468,7 +497,6 @@ static const struct file_operations fops = { #endif .poll = drm_poll, .read = drm_read, - .fasync = drm_fasync, .llseek = no_llseek, .mmap = drm_gem_cma_mmap, }; @@ -490,7 +518,7 @@ static struct drm_driver tilcdc_driver = { .gem_vm_ops = &drm_gem_cma_vm_ops, .dumb_create = drm_gem_cma_dumb_create, .dumb_map_offset = drm_gem_cma_dumb_map_offset, - .dumb_destroy = drm_gem_cma_dumb_destroy, + .dumb_destroy = drm_gem_dumb_destroy, #ifdef CONFIG_DEBUG_FS .debugfs_init = tilcdc_debugfs_init, .debugfs_cleanup = tilcdc_debugfs_cleanup, @@ -557,12 +585,16 @@ static int tilcdc_pdev_probe(struct platform_device *pdev) return -ENXIO; } + /* defer probing if slave is in deferred probing */ + if (slave_probing == true) + return -EPROBE_DEFER; + return drm_platform_init(&tilcdc_driver, pdev); } static int tilcdc_pdev_remove(struct platform_device *pdev) { - drm_platform_exit(&tilcdc_driver, pdev); + drm_put_dev(platform_get_drvdata(pdev)); return 0; } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index 8242b5a4307..093803683b2 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -34,6 +34,18 @@ #include <drm/drm_gem_cma_helper.h> #include <drm/drm_fb_cma_helper.h> +/* Defaulting to pixel clock defined on AM335x */ +#define TILCDC_DEFAULT_MAX_PIXELCLOCK 126000 +/* Defaulting to max width as defined on AM335x */ +#define TILCDC_DEFAULT_MAX_WIDTH 2048 +/* + * This may need some tweaking, but want to allow at least 1280x1024@60 + * with optimized DDR & EMIF settings tweaked 1920x1080@24 appears to + * be supportable + */ +#define TILCDC_DEFAULT_MAX_BANDWIDTH (1280*1024*60) + + struct tilcdc_drm_private { void __iomem *mmio; @@ -43,6 +55,16 @@ struct tilcdc_drm_private { /* don't attempt resolutions w/ higher W * H * Hz: */ uint32_t max_bandwidth; + /* + * Pixel Clock will be restricted to some value as + * defined in the device datasheet measured in KHz + */ + uint32_t max_pixelclock; + /* + * Max allowable width is limited on a per device basis + * measured in pixels + */ + uint32_t max_width; /* register contents saved across suspend/resume: */ u32 saved_register[12]; @@ -89,12 +111,13 @@ 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, const struct tilcdc_module_ops *funcs); void tilcdc_module_cleanup(struct tilcdc_module *mod); - +void tilcdc_slave_probedefer(bool defered); /* Panel config that needs to be set in the crtc, but is not coming from * the mode timings. The display module is expected to call diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c index 09176654fdd..86c67329b60 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c @@ -393,6 +393,8 @@ static int panel_probe(struct platform_device *pdev) goto fail; } + mod->preferred_bpp = panel_mod->info->bpp; + panel_mod->backlight = of_find_backlight_by_node(node); if (panel_mod->backlight) dev_info(&pdev->dev, "found backlight\n"); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_regs.h b/drivers/gpu/drm/tilcdc/tilcdc_regs.h index 17fd1b45428..1bf5e2553ac 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_regs.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_regs.h @@ -80,6 +80,7 @@ #define LCDC_INVERT_PIXEL_CLOCK BIT(22) #define LCDC_INVERT_HSYNC BIT(21) #define LCDC_INVERT_VSYNC BIT(20) +#define LCDC_LPP_B10 BIT(26) /* LCDC Block */ #define LCDC_PID_REG 0x0 diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave.c b/drivers/gpu/drm/tilcdc/tilcdc_slave.c index db1d2fc9dfb..595068ba2d5 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_slave.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_slave.c @@ -16,7 +16,6 @@ */ #include <linux/i2c.h> -#include <linux/of_i2c.h> #include <linux/pinctrl/pinmux.h> #include <linux/pinctrl/consumer.h> #include <drm/drm_encoder_slave.h> @@ -73,13 +72,38 @@ static void slave_encoder_prepare(struct drm_encoder *encoder) tilcdc_crtc_set_panel_info(encoder->crtc, &slave_info); } +static bool slave_encoder_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + /* + * tilcdc does not generate VESA-complient sync but aligns + * VS on the second edge of HS instead of first edge. + * We use adjusted_mode, to fixup sync by aligning both rising + * edges and add HSKEW offset to let the slave encoder fix it up. + */ + adjusted_mode->hskew = mode->hsync_end - mode->hsync_start; + adjusted_mode->flags |= DRM_MODE_FLAG_HSKEW; + + if (mode->flags & DRM_MODE_FLAG_NHSYNC) { + adjusted_mode->flags |= DRM_MODE_FLAG_PHSYNC; + adjusted_mode->flags &= ~DRM_MODE_FLAG_NHSYNC; + } else { + adjusted_mode->flags |= DRM_MODE_FLAG_NHSYNC; + adjusted_mode->flags &= ~DRM_MODE_FLAG_PHSYNC; + } + + return drm_i2c_encoder_mode_fixup(encoder, mode, adjusted_mode); +} + + static const struct drm_encoder_funcs slave_encoder_funcs = { .destroy = slave_encoder_destroy, }; static const struct drm_encoder_helper_funcs slave_encoder_helper_funcs = { .dpms = drm_i2c_encoder_dpms, - .mode_fixup = drm_i2c_encoder_mode_fixup, + .mode_fixup = slave_encoder_fixup, .prepare = slave_encoder_prepare, .commit = drm_i2c_encoder_commit, .mode_set = drm_i2c_encoder_mode_set, @@ -298,6 +322,7 @@ static int slave_probe(struct platform_device *pdev) struct tilcdc_module *mod; struct pinctrl *pinctrl; uint32_t i2c_phandle; + struct i2c_adapter *slavei2c; int ret = -EINVAL; /* bail out early if no DT data: */ @@ -306,42 +331,48 @@ static int slave_probe(struct platform_device *pdev) return -ENXIO; } - slave_mod = kzalloc(sizeof(*slave_mod), GFP_KERNEL); - if (!slave_mod) - return -ENOMEM; - - mod = &slave_mod->base; - - tilcdc_module_init(mod, "slave", &slave_module_ops); - - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) - dev_warn(&pdev->dev, "pins are not configured\n"); - + /* Bail out early if i2c not specified */ if (of_property_read_u32(node, "i2c", &i2c_phandle)) { dev_err(&pdev->dev, "could not get i2c bus phandle\n"); - goto fail; + return ret; } i2c_node = of_find_node_by_phandle(i2c_phandle); if (!i2c_node) { dev_err(&pdev->dev, "could not get i2c bus node\n"); - goto fail; + return ret; } - slave_mod->i2c = of_find_i2c_adapter_by_node(i2c_node); - if (!slave_mod->i2c) { + /* but defer the probe if it can't be initialized it might come later */ + slavei2c = of_find_i2c_adapter_by_node(i2c_node); + of_node_put(i2c_node); + + if (!slavei2c) { + ret = -EPROBE_DEFER; + tilcdc_slave_probedefer(true); dev_err(&pdev->dev, "could not get i2c\n"); - goto fail; + return ret; } - of_node_put(i2c_node); + slave_mod = kzalloc(sizeof(*slave_mod), GFP_KERNEL); + if (!slave_mod) + return -ENOMEM; - return 0; + mod = &slave_mod->base; -fail: - slave_destroy(mod); - return ret; + mod->preferred_bpp = slave_info.bpp; + + slave_mod->i2c = slavei2c; + + tilcdc_module_init(mod, "slave", &slave_module_ops); + + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) + dev_warn(&pdev->dev, "pins are not configured\n"); + + tilcdc_slave_probedefer(false); + + return 0; } static int slave_remove(struct platform_device *pdev) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c index a36788fbcd9..c38b56b268a 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c @@ -16,7 +16,6 @@ */ #include <linux/i2c.h> -#include <linux/of_i2c.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/pinctrl/pinmux.h> @@ -354,6 +353,8 @@ 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"); |
