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;
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
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;
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
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;
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:
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) {
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[] = {
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;
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 = {
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,
* 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;
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;
DRM_FORMAT_YUV422,
};
-static inline unsigned int tegra_plane_offset(struct tegra_shared_plane *plane,
+static inline unsigned int tegra_plane_offset(struct tegra_plane *plane,
unsigned int offset)
{
- struct tegra_plane *p = &plane->base;
-
if (offset >= 0x500 && offset <= 0x581) {
offset = 0x000 + (offset - 0x500);
- return p->offset + offset;
+ return plane->offset + offset;
}
if (offset >= 0x700 && offset <= 0x73c) {
offset = 0x180 + (offset - 0x700);
- return p->offset + offset;
+ return plane->offset + offset;
}
if (offset >= 0x800 && offset <= 0x83e) {
offset = 0x1c0 + (offset - 0x800);
- return p->offset + offset;
+ return plane->offset + offset;
}
dev_WARN(plane->dc->dev, "invalid offset: %x\n", offset);
- return p->offset + offset;
+ return plane->offset + offset;
}
-static inline u32 tegra_plane_readl(struct tegra_shared_plane *plane,
+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_shared_plane *plane,
- u32 value, unsigned int 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));
}
}
}
-static void tegra_shared_plane_update(struct tegra_shared_plane *plane)
+static void tegra_shared_plane_update(struct tegra_plane *plane)
{
struct tegra_dc *dc = plane->dc;
unsigned long timeout;
}
}
-static void tegra_shared_plane_activate(struct tegra_shared_plane *plane)
+static void tegra_shared_plane_activate(struct tegra_plane *plane)
{
struct tegra_dc *dc = plane->dc;
unsigned long timeout;
}
static unsigned int
-tegra_shared_plane_get_owner(struct tegra_shared_plane *plane,
- struct tegra_dc *dc)
+tegra_shared_plane_get_owner(struct tegra_plane *plane, struct tegra_dc *dc)
{
unsigned int offset =
tegra_plane_offset(plane, DC_WIN_CORE_WINDOWGROUP_SET_CONTROL);
}
static bool tegra_dc_owns_shared_plane(struct tegra_dc *dc,
- struct tegra_shared_plane *plane)
+ struct tegra_plane *plane)
{
struct device *dev = dc->dev;
return true;
dev_WARN(dev, "head %u owns window %u but is not attached\n",
- dc->pipe, plane->base.index);
+ dc->pipe, plane->index);
}
return false;
}
-static int tegra_shared_plane_set_owner(struct tegra_shared_plane *plane,
+static int tegra_shared_plane_set_owner(struct tegra_plane *plane,
struct tegra_dc *new)
{
unsigned int offset =
tegra_plane_offset(plane, DC_WIN_CORE_WINDOWGROUP_SET_CONTROL);
struct tegra_dc *old = plane->dc, *dc = new ? new : old;
struct device *dev = new ? new->dev : old->dev;
- unsigned int owner, index = plane->base.index;
+ unsigned int owner, index = plane->index;
u32 value;
value = tegra_dc_readl(dc, offset);
*/
if (old && owner == OWNER_MASK)
dev_dbg(dev, "window %u not owned by head %u but %u\n", index,
- old->pipe, owner);
+ old->pipe, owner);
value &= ~OWNER_MASK;
}
static void tegra_dc_assign_shared_plane(struct tegra_dc *dc,
- struct tegra_shared_plane *plane)
+ struct tegra_plane *plane)
{
u32 value;
int err;
}
static void tegra_dc_remove_shared_plane(struct tegra_dc *dc,
- struct tegra_shared_plane *plane)
+ struct tegra_plane *plane)
{
tegra_shared_plane_set_owner(plane, NULL);
}
static void tegra_shared_plane_atomic_disable(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
- struct tegra_shared_plane *p = to_tegra_shared_plane(plane);
struct tegra_dc *dc = to_tegra_dc(old_state->crtc);
+ struct tegra_plane *p = to_tegra_plane(plane);
u32 value;
/* rien ne va plus */
struct drm_plane_state *old_state)
{
struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
- struct tegra_shared_plane *p = to_tegra_shared_plane(plane);
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_bo *bo;
dma_addr_t base;
u32 value;
BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC;
tegra_plane_writel(p, value, DC_WIN_BLEND_NOMATCH_SELECT);
- value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(p->base.depth);
+ value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(p->depth);
tegra_plane_writel(p, value, DC_WIN_BLEND_LAYER_CONTROL);
/* bypass scaling */