|
@@ -34,26 +34,53 @@ static void tegra_dc_stats_reset(struct tegra_dc_stats *stats)
|
|
|
stats->overflow = 0;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Reads the active copy of a register. This takes the dc->lock spinlock to
|
|
|
- * prevent races with the VBLANK processing which also needs access to the
|
|
|
- * active copy of some registers.
|
|
|
- */
|
|
|
+/* Reads the active copy of a register. */
|
|
|
static u32 tegra_dc_readl_active(struct tegra_dc *dc, unsigned long offset)
|
|
|
{
|
|
|
- unsigned long flags;
|
|
|
u32 value;
|
|
|
|
|
|
- spin_lock_irqsave(&dc->lock, flags);
|
|
|
-
|
|
|
tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
|
|
|
value = tegra_dc_readl(dc, offset);
|
|
|
tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
|
|
|
|
|
|
- spin_unlock_irqrestore(&dc->lock, flags);
|
|
|
return value;
|
|
|
}
|
|
|
|
|
|
+static inline unsigned int tegra_plane_offset(struct tegra_plane *plane,
|
|
|
+ unsigned int offset)
|
|
|
+{
|
|
|
+ if (offset >= 0x500 && offset <= 0x638) {
|
|
|
+ offset = 0x000 + (offset - 0x500);
|
|
|
+ return plane->offset + offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (offset >= 0x700 && offset <= 0x719) {
|
|
|
+ offset = 0x180 + (offset - 0x700);
|
|
|
+ return plane->offset + offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (offset >= 0x800 && offset <= 0x839) {
|
|
|
+ offset = 0x1c0 + (offset - 0x800);
|
|
|
+ return plane->offset + offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ dev_WARN(plane->dc->dev, "invalid offset: %x\n", offset);
|
|
|
+
|
|
|
+ return plane->offset + offset;
|
|
|
+}
|
|
|
+
|
|
|
+static inline u32 tegra_plane_readl(struct tegra_plane *plane,
|
|
|
+ unsigned int offset)
|
|
|
+{
|
|
|
+ return tegra_dc_readl(plane->dc, tegra_plane_offset(plane, offset));
|
|
|
+}
|
|
|
+
|
|
|
+static inline void tegra_plane_writel(struct tegra_plane *plane, u32 value,
|
|
|
+ unsigned int offset)
|
|
|
+{
|
|
|
+ tegra_dc_writel(plane->dc, value, tegra_plane_offset(plane, offset));
|
|
|
+}
|
|
|
+
|
|
|
bool tegra_dc_has_output(struct tegra_dc *dc, struct device *dev)
|
|
|
{
|
|
|
struct device_node *np = dc->dev->of_node;
|
|
@@ -125,12 +152,13 @@ static inline u32 compute_initial_dda(unsigned int in)
|
|
|
return dfixed_frac(inf);
|
|
|
}
|
|
|
|
|
|
-static void tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
|
|
|
+static void tegra_dc_setup_window(struct tegra_plane *plane,
|
|
|
const struct tegra_dc_window *window)
|
|
|
{
|
|
|
unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
|
|
|
- unsigned long value, flags;
|
|
|
+ struct tegra_dc *dc = plane->dc;
|
|
|
bool yuv, planar;
|
|
|
+ u32 value;
|
|
|
|
|
|
/*
|
|
|
* For YUV planar modes, the number of bytes per pixel takes into
|
|
@@ -142,19 +170,14 @@ static void 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);
|
|
|
-
|
|
|
- tegra_dc_writel(dc, window->format, DC_WIN_COLOR_DEPTH);
|
|
|
- tegra_dc_writel(dc, window->swap, DC_WIN_BYTE_SWAP);
|
|
|
+ tegra_plane_writel(plane, window->format, DC_WIN_COLOR_DEPTH);
|
|
|
+ tegra_plane_writel(plane, window->swap, DC_WIN_BYTE_SWAP);
|
|
|
|
|
|
value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x);
|
|
|
- tegra_dc_writel(dc, value, DC_WIN_POSITION);
|
|
|
+ tegra_plane_writel(plane, value, DC_WIN_POSITION);
|
|
|
|
|
|
value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w);
|
|
|
- tegra_dc_writel(dc, value, DC_WIN_SIZE);
|
|
|
+ tegra_plane_writel(plane, value, DC_WIN_SIZE);
|
|
|
|
|
|
h_offset = window->src.x * bpp;
|
|
|
v_offset = window->src.y;
|
|
@@ -162,7 +185,7 @@ static void tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
|
|
|
v_size = window->src.h;
|
|
|
|
|
|
value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size);
|
|
|
- tegra_dc_writel(dc, value, DC_WIN_PRESCALED_SIZE);
|
|
|
+ tegra_plane_writel(plane, value, DC_WIN_PRESCALED_SIZE);
|
|
|
|
|
|
/*
|
|
|
* For DDA computations the number of bytes per pixel for YUV planar
|
|
@@ -175,33 +198,33 @@ static void tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
|
|
|
v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp);
|
|
|
|
|
|
value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda);
|
|
|
- tegra_dc_writel(dc, value, DC_WIN_DDA_INC);
|
|
|
+ tegra_plane_writel(plane, value, DC_WIN_DDA_INC);
|
|
|
|
|
|
h_dda = compute_initial_dda(window->src.x);
|
|
|
v_dda = compute_initial_dda(window->src.y);
|
|
|
|
|
|
- tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
|
|
|
- tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
|
|
|
+ tegra_plane_writel(plane, h_dda, DC_WIN_H_INITIAL_DDA);
|
|
|
+ tegra_plane_writel(plane, v_dda, DC_WIN_V_INITIAL_DDA);
|
|
|
|
|
|
- tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
|
|
|
- tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
|
|
|
+ tegra_plane_writel(plane, 0, DC_WIN_UV_BUF_STRIDE);
|
|
|
+ tegra_plane_writel(plane, 0, DC_WIN_BUF_STRIDE);
|
|
|
|
|
|
- tegra_dc_writel(dc, window->base[0], DC_WINBUF_START_ADDR);
|
|
|
+ tegra_plane_writel(plane, window->base[0], DC_WINBUF_START_ADDR);
|
|
|
|
|
|
if (yuv && planar) {
|
|
|
- tegra_dc_writel(dc, window->base[1], DC_WINBUF_START_ADDR_U);
|
|
|
- tegra_dc_writel(dc, window->base[2], DC_WINBUF_START_ADDR_V);
|
|
|
+ tegra_plane_writel(plane, window->base[1], DC_WINBUF_START_ADDR_U);
|
|
|
+ tegra_plane_writel(plane, window->base[2], DC_WINBUF_START_ADDR_V);
|
|
|
value = window->stride[1] << 16 | window->stride[0];
|
|
|
- tegra_dc_writel(dc, value, DC_WIN_LINE_STRIDE);
|
|
|
+ tegra_plane_writel(plane, value, DC_WIN_LINE_STRIDE);
|
|
|
} else {
|
|
|
- tegra_dc_writel(dc, window->stride[0], DC_WIN_LINE_STRIDE);
|
|
|
+ tegra_plane_writel(plane, window->stride[0], DC_WIN_LINE_STRIDE);
|
|
|
}
|
|
|
|
|
|
if (window->bottom_up)
|
|
|
v_offset += window->src.h - 1;
|
|
|
|
|
|
- tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
|
|
|
- tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
|
|
|
+ tegra_plane_writel(plane, h_offset, DC_WINBUF_ADDR_H_OFFSET);
|
|
|
+ tegra_plane_writel(plane, v_offset, DC_WINBUF_ADDR_V_OFFSET);
|
|
|
|
|
|
if (dc->soc->supports_block_linear) {
|
|
|
unsigned long height = window->tiling.value;
|
|
@@ -221,7 +244,7 @@ static void tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND);
|
|
|
+ tegra_plane_writel(plane, value, DC_WINBUF_SURFACE_KIND);
|
|
|
} else {
|
|
|
switch (window->tiling.mode) {
|
|
|
case TEGRA_BO_TILING_MODE_PITCH:
|
|
@@ -242,21 +265,21 @@ static void tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
|
|
|
+ tegra_plane_writel(plane, value, DC_WIN_BUFFER_ADDR_MODE);
|
|
|
}
|
|
|
|
|
|
value = WIN_ENABLE;
|
|
|
|
|
|
if (yuv) {
|
|
|
/* setup default colorspace conversion coefficients */
|
|
|
- tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF);
|
|
|
- tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB);
|
|
|
- tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR);
|
|
|
- tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR);
|
|
|
- tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG);
|
|
|
- tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG);
|
|
|
- tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB);
|
|
|
- tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB);
|
|
|
+ tegra_plane_writel(plane, 0x00f0, DC_WIN_CSC_YOF);
|
|
|
+ tegra_plane_writel(plane, 0x012a, DC_WIN_CSC_KYRGB);
|
|
|
+ tegra_plane_writel(plane, 0x0000, DC_WIN_CSC_KUR);
|
|
|
+ tegra_plane_writel(plane, 0x0198, DC_WIN_CSC_KVR);
|
|
|
+ tegra_plane_writel(plane, 0x039b, DC_WIN_CSC_KUG);
|
|
|
+ tegra_plane_writel(plane, 0x032f, DC_WIN_CSC_KVG);
|
|
|
+ tegra_plane_writel(plane, 0x0204, DC_WIN_CSC_KUB);
|
|
|
+ tegra_plane_writel(plane, 0x0000, DC_WIN_CSC_KVB);
|
|
|
|
|
|
value |= CSC_ENABLE;
|
|
|
} else if (window->bits_per_pixel < 24) {
|
|
@@ -266,36 +289,34 @@ static void tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
|
|
|
if (window->bottom_up)
|
|
|
value |= V_DIRECTION;
|
|
|
|
|
|
- tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
|
|
|
+ tegra_plane_writel(plane, value, DC_WIN_WIN_OPTIONS);
|
|
|
|
|
|
/*
|
|
|
* Disable blending and assume Window A is the bottom-most window,
|
|
|
* Window C is the top-most window and Window B is in the middle.
|
|
|
*/
|
|
|
- tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_NOKEY);
|
|
|
- tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_1WIN);
|
|
|
+ tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_NOKEY);
|
|
|
+ tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_1WIN);
|
|
|
|
|
|
- switch (index) {
|
|
|
+ switch (plane->index) {
|
|
|
case 0:
|
|
|
- tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_X);
|
|
|
- tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y);
|
|
|
- tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY);
|
|
|
+ tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_X);
|
|
|
+ tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y);
|
|
|
+ tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY);
|
|
|
break;
|
|
|
|
|
|
case 1:
|
|
|
- tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X);
|
|
|
- tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y);
|
|
|
- tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY);
|
|
|
+ tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X);
|
|
|
+ tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y);
|
|
|
+ tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY);
|
|
|
break;
|
|
|
|
|
|
case 2:
|
|
|
- tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X);
|
|
|
- tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_Y);
|
|
|
- tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_3WIN_XY);
|
|
|
+ tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X);
|
|
|
+ tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_Y);
|
|
|
+ tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_3WIN_XY);
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
- spin_unlock_irqrestore(&dc->lock, flags);
|
|
|
}
|
|
|
|
|
|
static const u32 tegra20_primary_formats[] = {
|
|
@@ -405,32 +426,22 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
|
|
|
static void tegra_plane_atomic_disable(struct drm_plane *plane,
|
|
|
struct drm_plane_state *old_state)
|
|
|
{
|
|
|
- struct tegra_dc *dc = to_tegra_dc(old_state->crtc);
|
|
|
struct tegra_plane *p = to_tegra_plane(plane);
|
|
|
- unsigned long flags;
|
|
|
u32 value;
|
|
|
|
|
|
/* rien ne va plus */
|
|
|
if (!old_state || !old_state->crtc)
|
|
|
return;
|
|
|
|
|
|
- spin_lock_irqsave(&dc->lock, flags);
|
|
|
-
|
|
|
- value = WINDOW_A_SELECT << p->index;
|
|
|
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
|
|
|
-
|
|
|
- value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
|
|
|
+ value = tegra_plane_readl(p, DC_WIN_WIN_OPTIONS);
|
|
|
value &= ~WIN_ENABLE;
|
|
|
- tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
|
|
|
-
|
|
|
- spin_unlock_irqrestore(&dc->lock, flags);
|
|
|
+ tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS);
|
|
|
}
|
|
|
|
|
|
static void tegra_plane_atomic_update(struct drm_plane *plane,
|
|
|
struct drm_plane_state *old_state)
|
|
|
{
|
|
|
struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
|
|
|
- struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
|
|
|
struct drm_framebuffer *fb = plane->state->fb;
|
|
|
struct tegra_plane *p = to_tegra_plane(plane);
|
|
|
struct tegra_dc_window window;
|
|
@@ -474,7 +485,7 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
|
|
|
window.stride[i] = fb->pitches[i];
|
|
|
}
|
|
|
|
|
|
- tegra_dc_setup_window(dc, p->index, &window);
|
|
|
+ tegra_dc_setup_window(p, &window);
|
|
|
}
|
|
|
|
|
|
static const struct drm_plane_helper_funcs tegra_plane_helper_funcs = {
|
|
@@ -509,17 +520,14 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm,
|
|
|
if (!plane)
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
- num_formats = dc->soc->num_primary_formats;
|
|
|
- formats = dc->soc->primary_formats;
|
|
|
-
|
|
|
- /*
|
|
|
- * XXX compute offset so that we can directly access windows.
|
|
|
- *
|
|
|
- * Always use window A as primary window.
|
|
|
- */
|
|
|
- plane->offset = 0;
|
|
|
+ /* Always use window A as primary window */
|
|
|
+ plane->offset = 0xa00;
|
|
|
plane->index = 0;
|
|
|
plane->depth = 255;
|
|
|
+ plane->dc = dc;
|
|
|
+
|
|
|
+ num_formats = dc->soc->num_primary_formats;
|
|
|
+ formats = dc->soc->primary_formats;
|
|
|
|
|
|
err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
|
|
|
&tegra_plane_funcs, formats,
|
|
@@ -673,6 +681,7 @@ static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
|
|
|
* need to special-casing the cursor plane.
|
|
|
*/
|
|
|
plane->index = 6;
|
|
|
+ plane->dc = dc;
|
|
|
|
|
|
num_formats = ARRAY_SIZE(tegra_cursor_plane_formats);
|
|
|
formats = tegra_cursor_plane_formats;
|
|
@@ -775,10 +784,10 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
|
|
|
if (!plane)
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
- /* XXX compute offset so that we can directly access windows */
|
|
|
- plane->offset = 0;
|
|
|
+ plane->offset = 0xa00 + 0x200 * index;
|
|
|
plane->index = index;
|
|
|
plane->depth = 0;
|
|
|
+ plane->dc = dc;
|
|
|
|
|
|
num_formats = dc->soc->num_overlay_formats;
|
|
|
formats = dc->soc->overlay_formats;
|