diff options
-rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 173 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hub.c | 45 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hub.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/plane.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/sor.c | 2 |
5 files changed, 116 insertions, 107 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index eb005dce392a..edae21197fc6 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -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; diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index cccd44711d68..63541dbd864d 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -49,39 +49,37 @@ static const u32 tegra_shared_plane_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)); } @@ -155,7 +153,7 @@ void tegra_display_hub_cleanup(struct tegra_display_hub *hub) } } -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; @@ -175,7 +173,7 @@ static void tegra_shared_plane_update(struct tegra_shared_plane *plane) } } -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; @@ -196,8 +194,7 @@ static void tegra_shared_plane_activate(struct tegra_shared_plane *plane) } 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); @@ -206,7 +203,7 @@ tegra_shared_plane_get_owner(struct tegra_shared_plane *plane, } 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; @@ -215,20 +212,20 @@ static bool tegra_dc_owns_shared_plane(struct tegra_dc *dc, 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); @@ -246,7 +243,7 @@ static int tegra_shared_plane_set_owner(struct tegra_shared_plane *plane, */ 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; @@ -263,7 +260,7 @@ static int tegra_shared_plane_set_owner(struct tegra_shared_plane *plane, } static void tegra_dc_assign_shared_plane(struct tegra_dc *dc, - struct tegra_shared_plane *plane) + struct tegra_plane *plane) { u32 value; int err; @@ -312,7 +309,7 @@ static void tegra_dc_assign_shared_plane(struct tegra_dc *dc, } 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); } @@ -370,8 +367,8 @@ static int tegra_shared_plane_atomic_check(struct drm_plane *plane, 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 */ @@ -401,9 +398,9 @@ static void tegra_shared_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_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; @@ -434,7 +431,7 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane, 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 */ diff --git a/drivers/gpu/drm/tegra/hub.h b/drivers/gpu/drm/tegra/hub.h index 965c333736b0..890a47cd05c3 100644 --- a/drivers/gpu/drm/tegra/hub.h +++ b/drivers/gpu/drm/tegra/hub.h @@ -28,7 +28,6 @@ struct tegra_windowgroup { struct tegra_shared_plane { struct tegra_plane base; struct tegra_windowgroup *wgrp; - struct tegra_dc *dc; }; static inline struct tegra_shared_plane * diff --git a/drivers/gpu/drm/tegra/plane.h b/drivers/gpu/drm/tegra/plane.h index fc7566f630fa..13b900d777e8 100644 --- a/drivers/gpu/drm/tegra/plane.h +++ b/drivers/gpu/drm/tegra/plane.h @@ -12,9 +12,11 @@ #include <drm/drm_plane.h> struct tegra_bo; +struct tegra_dc; struct tegra_plane { struct drm_plane base; + struct tegra_dc *dc; unsigned int offset; unsigned int index; unsigned int depth; diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index f6313c4d612e..4be9edf9c6fe 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -3047,6 +3047,8 @@ static int tegra_sor_probe(struct platform_device *pdev) name, err); goto remove; } + } else { + sor->clk_out = sor->clk; } sor->clk_parent = devm_clk_get(&pdev->dev, "parent"); |