diff options
author | Thomas Zimmermann <tzimmermann@suse.de> | 2021-02-09 14:46:27 +0100 |
---|---|---|
committer | Thomas Zimmermann <tzimmermann@suse.de> | 2021-02-17 12:40:05 +0100 |
commit | 718c22865fc0a9c821e21eacba46829516901374 (patch) | |
tree | cb92465d7a231163c1ae21aa1646b303613c7ebc /drivers/gpu/drm/ast/ast_mode.c | |
parent | 22b6591f7ccb36142dcc0659746649eb9b4856d9 (diff) |
drm/ast: Inline ast cursor-update functions into modesetting code
The logic for cursor updates is now located in the cursor plane's
modesetting code. A number of helper functions remain to modify the
rsp registers and image.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210209134632.12157-6-tzimmermann@suse.de
Diffstat (limited to 'drivers/gpu/drm/ast/ast_mode.c')
-rw-r--r-- | drivers/gpu/drm/ast/ast_mode.c | 191 |
1 files changed, 180 insertions, 11 deletions
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 99b6f7c5cb2f..968ee0c69ec3 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -645,6 +645,110 @@ static int ast_primary_plane_init(struct ast_private *ast) * Cursor plane */ +static void ast_update_cursor_image(u8 __iomem *dst, const u8 *src, int width, int height) +{ + union { + u32 ul; + u8 b[4]; + } srcdata32[2], data32; + union { + u16 us; + u8 b[2]; + } data16; + u32 csum = 0; + s32 alpha_dst_delta, last_alpha_dst_delta; + u8 __iomem *dstxor; + const u8 *srcxor; + int i, j; + u32 per_pixel_copy, two_pixel_copy; + + alpha_dst_delta = AST_MAX_HWC_WIDTH << 1; + last_alpha_dst_delta = alpha_dst_delta - (width << 1); + + srcxor = src; + dstxor = (u8 *)dst + last_alpha_dst_delta + (AST_MAX_HWC_HEIGHT - height) * alpha_dst_delta; + per_pixel_copy = width & 1; + two_pixel_copy = width >> 1; + + for (j = 0; j < height; j++) { + for (i = 0; i < two_pixel_copy; i++) { + srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0; + srcdata32[1].ul = *((u32 *)(srcxor + 4)) & 0xf0f0f0f0; + data32.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4); + data32.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4); + data32.b[2] = srcdata32[1].b[1] | (srcdata32[1].b[0] >> 4); + data32.b[3] = srcdata32[1].b[3] | (srcdata32[1].b[2] >> 4); + + writel(data32.ul, dstxor); + csum += data32.ul; + + dstxor += 4; + srcxor += 8; + + } + + for (i = 0; i < per_pixel_copy; i++) { + srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0; + data16.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4); + data16.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4); + writew(data16.us, dstxor); + csum += (u32)data16.us; + + dstxor += 2; + srcxor += 4; + } + dstxor += last_alpha_dst_delta; + } + + /* write checksum + signature */ + dst += AST_HWC_SIZE; + writel(csum, dst); + writel(width, dst + AST_HWC_SIGNATURE_SizeX); + writel(height, dst + AST_HWC_SIGNATURE_SizeY); + writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTX); + writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTY); +} + +static void ast_set_cursor_base(struct ast_private *ast, u64 address) +{ + u8 addr0 = (address >> 3) & 0xff; + u8 addr1 = (address >> 11) & 0xff; + u8 addr2 = (address >> 19) & 0xff; + + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc8, addr0); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc9, addr1); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xca, addr2); +} + +static void ast_set_cursor_location(struct ast_private *ast, u16 x, u16 y, + u8 x_offset, u8 y_offset) +{ + u8 x0 = (x & 0x00ff); + u8 x1 = (x & 0x0f00) >> 8; + u8 y0 = (y & 0x00ff); + u8 y1 = (y & 0x0700) >> 8; + + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc2, x_offset); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc3, y_offset); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc4, x0); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc5, x1); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc6, y0); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc7, y1); +} + +static void ast_set_cursor_enabled(struct ast_private *ast, bool enabled) +{ + static const u8 mask = (u8)~(AST_IO_VGACRCB_HWC_16BPP | + AST_IO_VGACRCB_HWC_ENABLED); + + u8 vgacrcb = AST_IO_VGACRCB_HWC_16BPP; + + if (enabled) + vgacrcb |= AST_IO_VGACRCB_HWC_ENABLED; + + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, mask, vgacrcb); +} + static const uint32_t ast_cursor_plane_formats[] = { DRM_FORMAT_ARGB8888, }; @@ -654,20 +758,40 @@ ast_cursor_plane_helper_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state) { struct drm_framebuffer *fb = new_state->fb; - struct drm_crtc *crtc = new_state->crtc; - struct ast_private *ast; + struct ast_private *ast = to_ast_private(plane->dev); + struct drm_gem_vram_object *dst_gbo = ast->cursor.gbo[ast->cursor.next_index]; + struct drm_gem_vram_object *src_gbo; + struct dma_buf_map src_map, dst_map; + void __iomem *dst; + void *src; int ret; - if (!crtc || !fb) + if (!fb) return 0; - ast = to_ast_private(plane->dev); + src_gbo = drm_gem_vram_of_gem(fb->obj[0]); - ret = ast_cursor_blit(ast, fb); + ret = drm_gem_vram_vmap(src_gbo, &src_map); if (ret) return ret; + src = src_map.vaddr; /* TODO: Use mapping abstraction properly */ + + ret = drm_gem_vram_vmap(dst_gbo, &dst_map); + if (ret) + goto err_drm_gem_vram_vunmap; + dst = dst_map.vaddr_iomem; /* TODO: Use mapping abstraction properly */ + + /* do data transfer to cursor BO */ + ast_update_cursor_image(dst, src, fb->width, fb->height); + + drm_gem_vram_vunmap(dst_gbo, &dst_map); + drm_gem_vram_vunmap(src_gbo, &src_map); return 0; + +err_drm_gem_vram_vunmap: + drm_gem_vram_vunmap(src_gbo, &src_map); + return ret; } static int ast_cursor_plane_helper_atomic_check(struct drm_plane *plane, @@ -705,18 +829,63 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, struct drm_plane_state *state = plane->state; struct drm_framebuffer *fb = state->fb; struct ast_private *ast = to_ast_private(plane->dev); + struct drm_device *dev = &ast->base; + struct drm_gem_vram_object *gbo = ast->cursor.gbo[ast->cursor.next_index]; unsigned int offset_x, offset_y; + s64 off; + struct dma_buf_map map; + u16 x, y; + u8 x_offset, y_offset; + u8 __iomem *dst; + u8 __iomem *sig; + int ret; - offset_x = AST_MAX_HWC_WIDTH - fb->width; - offset_y = AST_MAX_HWC_HEIGHT - fb->height; + gbo = ast->cursor.gbo[ast->cursor.next_index]; if (state->fb != old_state->fb) { /* A new cursor image was installed. */ - ast_cursor_page_flip(ast); + off = drm_gem_vram_offset(gbo); + if (drm_WARN_ON_ONCE(dev, off < 0)) + return; /* Bug: we didn't pin the cursor HW BO to VRAM. */ + ast_set_cursor_base(ast, off); + + ++ast->cursor.next_index; + ast->cursor.next_index %= ARRAY_SIZE(ast->cursor.gbo); + } + + ret = drm_gem_vram_vmap(gbo, &map); + if (drm_WARN_ONCE(dev, ret, "drm_gem_vram_vmap() failed, ret=%d\n", ret)) + return; + dst = map.vaddr_iomem; /* TODO: Use mapping abstraction properly */ + + sig = dst + AST_HWC_SIZE; + writel(state->crtc_x, sig + AST_HWC_SIGNATURE_X); + writel(state->crtc_y, sig + AST_HWC_SIGNATURE_Y); + + drm_gem_vram_vunmap(gbo, &map); + + offset_x = AST_MAX_HWC_WIDTH - fb->width; + offset_y = AST_MAX_HWC_HEIGHT - fb->height; + + if (state->crtc_x < 0) { + x_offset = (-state->crtc_x) + offset_x; + x = 0; + } else { + x_offset = offset_x; + x = state->crtc_x; } + if (state->crtc_y < 0) { + y_offset = (-state->crtc_y) + offset_y; + y = 0; + } else { + y_offset = offset_y; + y = state->crtc_y; + } + + ast_set_cursor_location(ast, x, y, x_offset, y_offset); - ast_cursor_show(ast, state->crtc_x, state->crtc_y, - offset_x, offset_y); + /* dummy write to fire HWC */ + ast_set_cursor_enabled(ast, true); } static void @@ -725,7 +894,7 @@ ast_cursor_plane_helper_atomic_disable(struct drm_plane *plane, { struct ast_private *ast = to_ast_private(plane->dev); - ast_cursor_hide(ast); + ast_set_cursor_enabled(ast, false); } static const struct drm_plane_helper_funcs ast_cursor_plane_helper_funcs = { |