drm/tegra: dc: Select root window for event dispatch
In finish pageflip, the driver was not selecting the root window when dispatching events. This exposed a race where a plane update would change the window selection and cause tegra_dc_finish_page_flip to check the wrong base address. This patch also protects access to the window selection register as well as the registers affected by it. Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Thierry Reding <treding@nvidia.com>
This commit is contained in:
parent
73c42c7976
commit
93396d0f9c
|
@ -168,7 +168,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
|
|||
const struct tegra_dc_window *window)
|
||||
{
|
||||
unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
|
||||
unsigned long value;
|
||||
unsigned long value, flags;
|
||||
bool yuv, planar;
|
||||
|
||||
/*
|
||||
|
@ -181,6 +181,8 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
|
|||
else
|
||||
bpp = planar ? 1 : 2;
|
||||
|
||||
spin_lock_irqsave(&dc->lock, flags);
|
||||
|
||||
value = WINDOW_A_SELECT << index;
|
||||
tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
|
||||
|
||||
|
@ -273,6 +275,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
|
|||
|
||||
case TEGRA_BO_TILING_MODE_BLOCK:
|
||||
DRM_ERROR("hardware doesn't support block linear mode\n");
|
||||
spin_unlock_irqrestore(&dc->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -331,6 +334,8 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
|
|||
|
||||
tegra_dc_window_commit(dc, index);
|
||||
|
||||
spin_unlock_irqrestore(&dc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -338,11 +343,14 @@ static int tegra_window_plane_disable(struct drm_plane *plane)
|
|||
{
|
||||
struct tegra_dc *dc = to_tegra_dc(plane->crtc);
|
||||
struct tegra_plane *p = to_tegra_plane(plane);
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
|
||||
if (!plane->crtc)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&dc->lock, flags);
|
||||
|
||||
value = WINDOW_A_SELECT << p->index;
|
||||
tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
|
||||
|
||||
|
@ -352,6 +360,8 @@ static int tegra_window_plane_disable(struct drm_plane *plane)
|
|||
|
||||
tegra_dc_window_commit(dc, p->index);
|
||||
|
||||
spin_unlock_irqrestore(&dc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -699,14 +709,16 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
|
|||
struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
|
||||
unsigned int h_offset = 0, v_offset = 0;
|
||||
struct tegra_bo_tiling tiling;
|
||||
unsigned long value, flags;
|
||||
unsigned int format, swap;
|
||||
unsigned long value;
|
||||
int err;
|
||||
|
||||
err = tegra_fb_get_tiling(fb, &tiling);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
spin_lock_irqsave(&dc->lock, flags);
|
||||
|
||||
tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
|
||||
|
||||
value = fb->offsets[0] + y * fb->pitches[0] +
|
||||
|
@ -752,6 +764,7 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
|
|||
|
||||
case TEGRA_BO_TILING_MODE_BLOCK:
|
||||
DRM_ERROR("hardware doesn't support block linear mode\n");
|
||||
spin_unlock_irqrestore(&dc->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -778,6 +791,8 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
|
|||
tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
|
||||
tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
|
||||
|
||||
spin_unlock_irqrestore(&dc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -823,11 +838,16 @@ static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
|
|||
|
||||
bo = tegra_fb_get_plane(crtc->primary->fb, 0);
|
||||
|
||||
spin_lock_irqsave(&dc->lock, flags);
|
||||
|
||||
/* check if new start address has been latched */
|
||||
tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
|
||||
tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
|
||||
base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR);
|
||||
tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
|
||||
|
||||
spin_unlock_irqrestore(&dc->lock, flags);
|
||||
|
||||
if (base == bo->paddr + crtc->primary->fb->offsets[0]) {
|
||||
drm_crtc_send_vblank_event(crtc, dc->event);
|
||||
drm_crtc_vblank_put(crtc);
|
||||
|
|
Loading…
Reference in New Issue