Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/imx: Add 8 pixel alignment fix

Some standard resolutions like 1366x768 do not work properly with
i.MX6 SoCs, since the horizontal resolution needs to be aligned
to 8 pixels (so 1360x768 or 1368x768 would work).

This patch allocates framebuffers allocated to 8 pixels. The extra
time required to send the extra pixels are removed from the blank
time. In order to expose the correct display size to userspace,
the stride is increased without increasing the width.

Without this patch systems with this display resolution hang
indefinitely during boot up.

Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Link: https://lore.kernel.org/r/20210428222953.235280-3-sebastian.reichel@collabora.com
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>

authored by

Sebastian Reichel and committed by
Philipp Zabel
94dfec48 f4b34faa

+60 -6
+18 -1
drivers/gpu/drm/imx/imx-drm-core.c
··· 147 147 /* none so far */ 148 148 }; 149 149 150 + static int imx_drm_dumb_create(struct drm_file *file_priv, 151 + struct drm_device *drm, 152 + struct drm_mode_create_dumb *args) 153 + { 154 + u32 width = args->width; 155 + int ret; 156 + 157 + args->width = ALIGN(width, 8); 158 + 159 + ret = drm_gem_cma_dumb_create(file_priv, drm, args); 160 + if (ret) 161 + return ret; 162 + 163 + args->width = width; 164 + return ret; 165 + } 166 + 150 167 static const struct drm_driver imx_drm_driver = { 151 168 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, 152 - DRM_GEM_CMA_DRIVER_OPS, 169 + DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(imx_drm_dumb_create), 153 170 .ioctls = imx_drm_ioctls, 154 171 .num_ioctls = ARRAY_SIZE(imx_drm_ioctls), 155 172 .fops = &imx_drm_driver_fops,
+5
drivers/gpu/drm/imx/imx-ldb.c
··· 274 274 "%s: mode exceeds 85 MHz pixel clock\n", __func__); 275 275 } 276 276 277 + if (!IS_ALIGNED(mode->hdisplay, 8)) { 278 + dev_warn(ldb->dev, 279 + "%s: hdisplay does not align to 8 byte\n", __func__); 280 + } 281 + 277 282 if (dual) { 278 283 serial_clk = 3500UL * mode->clock; 279 284 imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
+10 -1
drivers/gpu/drm/imx/ipuv3-crtc.c
··· 305 305 sig_cfg.vsync_pin = imx_crtc_state->di_vsync_pin; 306 306 307 307 drm_display_mode_to_videomode(mode, &sig_cfg.mode); 308 + if (!IS_ALIGNED(sig_cfg.mode.hactive, 8)) { 309 + unsigned int new_hactive = ALIGN(sig_cfg.mode.hactive, 8); 310 + 311 + dev_warn(ipu_crtc->dev, "8-pixel align hactive %d -> %d\n", 312 + sig_cfg.mode.hactive, new_hactive); 313 + 314 + sig_cfg.mode.hfront_porch = new_hactive - sig_cfg.mode.hactive; 315 + sig_cfg.mode.hactive = new_hactive; 316 + } 308 317 309 318 ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, 310 319 mode->flags & DRM_MODE_FLAG_INTERLACE, 311 - imx_crtc_state->bus_format, mode->hdisplay); 320 + imx_crtc_state->bus_format, sig_cfg.mode.hactive); 312 321 ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg); 313 322 } 314 323
+15 -4
drivers/gpu/drm/imx/ipuv3-plane.c
··· 30 30 return container_of(p, struct ipu_plane_state, base); 31 31 } 32 32 33 + static unsigned int ipu_src_rect_width(const struct drm_plane_state *state) 34 + { 35 + return ALIGN(drm_rect_width(&state->src) >> 16, 8); 36 + } 37 + 33 38 static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p) 34 39 { 35 40 return container_of(p, struct ipu_plane, base); ··· 445 440 if (old_fb && fb->pitches[0] != old_fb->pitches[0]) 446 441 crtc_state->mode_changed = true; 447 442 443 + if (ALIGN(fb->width, 8) * fb->format->cpp[0] > 444 + fb->pitches[0] + fb->offsets[0]) { 445 + dev_warn(dev, "pitch is not big enough for 8 pixels alignment"); 446 + return -EINVAL; 447 + } 448 + 448 449 switch (fb->format->format) { 449 450 case DRM_FORMAT_YUV420: 450 451 case DRM_FORMAT_YVU420: ··· 626 615 if (ipu_state->use_pre) { 627 616 axi_id = ipu_chan_assign_axi_id(ipu_plane->dma); 628 617 ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id, 629 - drm_rect_width(&new_state->src) >> 16, 618 + ipu_src_rect_width(new_state), 630 619 drm_rect_height(&new_state->src) >> 16, 631 620 fb->pitches[0], fb->format->format, 632 621 fb->modifier, &eba); ··· 659 648 break; 660 649 } 661 650 662 - ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst)); 651 + ipu_dmfc_config_wait4eot(ipu_plane->dmfc, ALIGN(drm_rect_width(dst), 8)); 663 652 664 - width = drm_rect_width(&new_state->src) >> 16; 653 + width = ipu_src_rect_width(new_state); 665 654 height = drm_rect_height(&new_state->src) >> 16; 666 655 info = drm_format_info(fb->format->format); 667 656 ipu_calculate_bursts(width, info->cpp[0], fb->pitches[0], ··· 726 715 727 716 ipu_cpmem_zero(ipu_plane->alpha_ch); 728 717 ipu_cpmem_set_resolution(ipu_plane->alpha_ch, 729 - drm_rect_width(&new_state->src) >> 16, 718 + ipu_src_rect_width(new_state), 730 719 drm_rect_height(&new_state->src) >> 16); 731 720 ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8); 732 721 ipu_cpmem_set_high_priority(ipu_plane->alpha_ch);
+5
drivers/gpu/ipu-v3/ipu-dc.c
··· 167 167 168 168 dc->di = ipu_di_get_num(di); 169 169 170 + if (!IS_ALIGNED(width, 8)) { 171 + dev_warn(priv->dev, 172 + "%s: hactive does not align to 8 byte\n", __func__); 173 + } 174 + 170 175 map = ipu_bus_format_to_map(bus_format); 171 176 172 177 /*
+7
drivers/gpu/ipu-v3/ipu-di.c
··· 506 506 { 507 507 u32 diff; 508 508 509 + if (!IS_ALIGNED(mode->hactive, 8) && 510 + mode->hfront_porch < ALIGN(mode->hactive, 8) - mode->hactive) { 511 + dev_err(di->ipu->dev, "hactive %d is not aligned to 8 and front porch is too small to compensate\n", 512 + mode->hactive); 513 + return -EINVAL; 514 + } 515 + 509 516 if (mode->vfront_porch >= 2) 510 517 return 0; 511 518