diff options
Diffstat (limited to 'drivers/gpu/drm/stm/ltdc.c')
-rw-r--r-- | drivers/gpu/drm/stm/ltdc.c | 67 |
1 files changed, 47 insertions, 20 deletions
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 32fd6a3b37fb..14eb8c40953b 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -232,6 +232,11 @@ static const enum ltdc_pix_fmt ltdc_pix_fmt_a1[NB_PF] = { PF_ARGB4444 /* 0x07 */ }; +static const u64 ltdc_format_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + static inline u32 reg_read(void __iomem *base, u32 reg) { return readl_relaxed(base + reg); @@ -426,8 +431,8 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, /* Enable IRQ */ reg_set(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); - /* Immediately commit the planes */ - reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); + /* Commit shadow registers = update planes at next vblank */ + reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); /* Enable LTDC */ reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); @@ -555,7 +560,7 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) if (vm.flags & DISPLAY_FLAGS_VSYNC_HIGH) val |= GCR_VSPOL; - if (vm.flags & DISPLAY_FLAGS_DE_HIGH) + if (vm.flags & DISPLAY_FLAGS_DE_LOW) val |= GCR_DEPOL; if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) @@ -779,7 +784,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, /* Configures the color frame buffer pitch in bytes & line length */ pitch_in_bytes = fb->pitches[0]; - line_length = drm_format_plane_cpp(fb->format->format, 0) * + line_length = fb->format->cpp[0] * (x1 - x0 + 1) + (ldev->caps.bus_width >> 3) - 1; val = ((pitch_in_bytes << 16) | line_length); reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, @@ -822,11 +827,11 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, mutex_lock(&ldev->err_lock); if (ldev->error_status & ISR_FUIF) { - DRM_DEBUG_DRIVER("Fifo underrun\n"); + DRM_WARN("ltdc fifo underrun: please verify display mode\n"); ldev->error_status &= ~ISR_FUIF; } if (ldev->error_status & ISR_TERRIF) { - DRM_DEBUG_DRIVER("Transfer error\n"); + DRM_WARN("ltdc transfer error\n"); ldev->error_status &= ~ISR_TERRIF; } mutex_unlock(&ldev->err_lock); @@ -864,6 +869,16 @@ static void ltdc_plane_atomic_print_state(struct drm_printer *p, fpsi->counter = 0; } +static bool ltdc_plane_format_mod_supported(struct drm_plane *plane, + u32 format, + u64 modifier) +{ + if (modifier == DRM_FORMAT_MOD_LINEAR) + return true; + + return false; +} + static const struct drm_plane_funcs ltdc_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, @@ -872,6 +887,7 @@ static const struct drm_plane_funcs ltdc_plane_funcs = { .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, .atomic_print_state = ltdc_plane_atomic_print_state, + .format_mod_supported = ltdc_plane_format_mod_supported, }; static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = { @@ -890,6 +906,7 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, unsigned int i, nb_fmt = 0; u32 formats[NB_PF * 2]; u32 drm_fmt, drm_fmt_no_alpha; + const u64 *modifiers = ltdc_format_modifiers; int ret; /* Get supported pixel formats */ @@ -918,7 +935,7 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, ret = drm_universal_plane_init(ddev, plane, possible_crtcs, <dc_plane_funcs, formats, nb_fmt, - NULL, type, NULL); + modifiers, type, NULL); if (ret < 0) return NULL; @@ -1021,10 +1038,13 @@ static int ltdc_get_caps(struct drm_device *ddev) struct ltdc_device *ldev = ddev->dev_private; u32 bus_width_log2, lcr, gc2r; - /* at least 1 layer must be managed */ + /* + * at least 1 layer must be managed & the number of layers + * must not exceed LTDC_MAX_LAYER + */ lcr = reg_read(ldev->regs, LTDC_LCR); - ldev->caps.nb_layers = max_t(int, lcr, 1); + ldev->caps.nb_layers = clamp((int)lcr, 1, LTDC_MAX_LAYER); /* set data bus width */ gc2r = reg_read(ldev->regs, LTDC_GC2R); @@ -1125,8 +1145,9 @@ int ltdc_load(struct drm_device *ddev) ldev->pixel_clk = devm_clk_get(dev, "lcd"); if (IS_ERR(ldev->pixel_clk)) { - DRM_ERROR("Unable to get lcd clock\n"); - return -ENODEV; + if (PTR_ERR(ldev->pixel_clk) != -EPROBE_DEFER) + DRM_ERROR("Unable to get lcd clock\n"); + return PTR_ERR(ldev->pixel_clk); } if (clk_prepare_enable(ldev->pixel_clk)) { @@ -1134,6 +1155,12 @@ int ltdc_load(struct drm_device *ddev) return -ENODEV; } + if (!IS_ERR(rstc)) { + reset_control_assert(rstc); + usleep_range(10, 20); + reset_control_deassert(rstc); + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ldev->regs = devm_ioremap_resource(dev, res); if (IS_ERR(ldev->regs)) { @@ -1142,8 +1169,15 @@ int ltdc_load(struct drm_device *ddev) goto err; } + /* Disable interrupts */ + reg_clear(ldev->regs, LTDC_IER, + IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE); + for (i = 0; i < MAX_IRQ; i++) { irq = platform_get_irq(pdev, i); + if (irq == -EPROBE_DEFER) + goto err; + if (irq < 0) continue; @@ -1156,15 +1190,6 @@ int ltdc_load(struct drm_device *ddev) } } - if (!IS_ERR(rstc)) { - reset_control_assert(rstc); - usleep_range(10, 20); - reset_control_deassert(rstc); - } - - /* Disable interrupts */ - reg_clear(ldev->regs, LTDC_IER, - IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE); ret = ltdc_get_caps(ddev); if (ret) { @@ -1203,6 +1228,8 @@ int ltdc_load(struct drm_device *ddev) goto err; } + ddev->mode_config.allow_fb_modifiers = true; + ret = ltdc_crtc_init(ddev, crtc); if (ret) { DRM_ERROR("Failed to init crtc\n"); |