Skip to content

Commit 94dfec4

Browse files
srepH5
authored andcommitted
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 <[email protected]> Signed-off-by: Sebastian Reichel <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Philipp Zabel <[email protected]>
1 parent f4b34fa commit 94dfec4

File tree

6 files changed

+60
-6
lines changed

6 files changed

+60
-6
lines changed

drivers/gpu/drm/imx/imx-drm-core.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,26 @@ static const struct drm_ioctl_desc imx_drm_ioctls[] = {
147147
/* none so far */
148148
};
149149

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+
150167
static const struct drm_driver imx_drm_driver = {
151168
.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),
153170
.ioctls = imx_drm_ioctls,
154171
.num_ioctls = ARRAY_SIZE(imx_drm_ioctls),
155172
.fops = &imx_drm_driver_fops,

drivers/gpu/drm/imx/imx-ldb.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,11 @@ imx_ldb_encoder_atomic_mode_set(struct drm_encoder *encoder,
274274
"%s: mode exceeds 85 MHz pixel clock\n", __func__);
275275
}
276276

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+
277282
if (dual) {
278283
serial_clk = 3500UL * mode->clock;
279284
imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);

drivers/gpu/drm/imx/ipuv3-crtc.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,19 @@ static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc)
305305
sig_cfg.vsync_pin = imx_crtc_state->di_vsync_pin;
306306

307307
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+
}
308317

309318
ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di,
310319
mode->flags & DRM_MODE_FLAG_INTERLACE,
311-
imx_crtc_state->bus_format, mode->hdisplay);
320+
imx_crtc_state->bus_format, sig_cfg.mode.hactive);
312321
ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg);
313322
}
314323

drivers/gpu/drm/imx/ipuv3-plane.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ to_ipu_plane_state(struct drm_plane_state *p)
3030
return container_of(p, struct ipu_plane_state, base);
3131
}
3232

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+
3338
static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p)
3439
{
3540
return container_of(p, struct ipu_plane, base);
@@ -440,6 +445,12 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
440445
if (old_fb && fb->pitches[0] != old_fb->pitches[0])
441446
crtc_state->mode_changed = true;
442447

448+
if (ALIGN(fb->width, 8) * fb->format->cpp[0] >
449+
fb->pitches[0] + fb->offsets[0]) {
450+
dev_warn(dev, "pitch is not big enough for 8 pixels alignment");
451+
return -EINVAL;
452+
}
453+
443454
switch (fb->format->format) {
444455
case DRM_FORMAT_YUV420:
445456
case DRM_FORMAT_YVU420:
@@ -615,7 +626,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
615626
if (ipu_state->use_pre) {
616627
axi_id = ipu_chan_assign_axi_id(ipu_plane->dma);
617628
ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id,
618-
drm_rect_width(&new_state->src) >> 16,
629+
ipu_src_rect_width(new_state),
619630
drm_rect_height(&new_state->src) >> 16,
620631
fb->pitches[0], fb->format->format,
621632
fb->modifier, &eba);
@@ -648,9 +659,9 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
648659
break;
649660
}
650661

651-
ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst));
662+
ipu_dmfc_config_wait4eot(ipu_plane->dmfc, ALIGN(drm_rect_width(dst), 8));
652663

653-
width = drm_rect_width(&new_state->src) >> 16;
664+
width = ipu_src_rect_width(new_state);
654665
height = drm_rect_height(&new_state->src) >> 16;
655666
info = drm_format_info(fb->format->format);
656667
ipu_calculate_bursts(width, info->cpp[0], fb->pitches[0],
@@ -715,7 +726,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
715726

716727
ipu_cpmem_zero(ipu_plane->alpha_ch);
717728
ipu_cpmem_set_resolution(ipu_plane->alpha_ch,
718-
drm_rect_width(&new_state->src) >> 16,
729+
ipu_src_rect_width(new_state),
719730
drm_rect_height(&new_state->src) >> 16);
720731
ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8);
721732
ipu_cpmem_set_high_priority(ipu_plane->alpha_ch);

drivers/gpu/ipu-v3/ipu-dc.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
167167

168168
dc->di = ipu_di_get_num(di);
169169

170+
if (!IS_ALIGNED(width, 8)) {
171+
dev_warn(priv->dev,
172+
"%s: hactive does not align to 8 byte\n", __func__);
173+
}
174+
170175
map = ipu_bus_format_to_map(bus_format);
171176

172177
/*

drivers/gpu/ipu-v3/ipu-di.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,13 @@ int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
506506
{
507507
u32 diff;
508508

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+
509516
if (mode->vfront_porch >= 2)
510517
return 0;
511518

0 commit comments

Comments
 (0)