2 * Copyright 2012 Red Hat Inc.
3 * Parts based on xf86-video-ast
4 * Copyright (c) 2005 ASPEED Technology Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
30 #include <drm/drm_gem_vram_helper.h>
31 #include <drm/drm_managed.h>
35 static void ast_cursor_fini(struct ast_private *ast)
38 struct drm_gem_vram_object *gbo;
40 for (i = 0; i < ARRAY_SIZE(ast->cursor.gbo); ++i) {
41 gbo = ast->cursor.gbo[i];
42 drm_gem_vram_vunmap(gbo, &ast->cursor.map[i]);
43 drm_gem_vram_unpin(gbo);
44 drm_gem_vram_put(gbo);
48 static void ast_cursor_release(struct drm_device *dev, void *ptr)
50 struct ast_private *ast = to_ast_private(dev);
56 * Allocate cursor BOs and pins them at the end of VRAM.
58 int ast_cursor_init(struct ast_private *ast)
60 struct drm_device *dev = &ast->base;
62 struct drm_gem_vram_object *gbo;
63 struct dma_buf_map map;
66 size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE);
68 for (i = 0; i < ARRAY_SIZE(ast->cursor.gbo); ++i) {
69 gbo = drm_gem_vram_create(dev, size, 0);
72 goto err_drm_gem_vram_put;
74 ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM |
75 DRM_GEM_VRAM_PL_FLAG_TOPDOWN);
77 drm_gem_vram_put(gbo);
78 goto err_drm_gem_vram_put;
80 ret = drm_gem_vram_vmap(gbo, &map);
82 drm_gem_vram_unpin(gbo);
83 drm_gem_vram_put(gbo);
84 goto err_drm_gem_vram_put;
87 ast->cursor.gbo[i] = gbo;
88 ast->cursor.map[i] = map;
91 return drmm_add_action_or_reset(dev, ast_cursor_release, NULL);
96 gbo = ast->cursor.gbo[i];
97 drm_gem_vram_vunmap(gbo, &ast->cursor.map[i]);
98 drm_gem_vram_unpin(gbo);
99 drm_gem_vram_put(gbo);
104 static void update_cursor_image(u8 __iomem *dst, const u8 *src, int width, int height)
109 } srcdata32[2], data32;
115 s32 alpha_dst_delta, last_alpha_dst_delta;
119 u32 per_pixel_copy, two_pixel_copy;
121 alpha_dst_delta = AST_MAX_HWC_WIDTH << 1;
122 last_alpha_dst_delta = alpha_dst_delta - (width << 1);
125 dstxor = (u8 *)dst + last_alpha_dst_delta + (AST_MAX_HWC_HEIGHT - height) * alpha_dst_delta;
126 per_pixel_copy = width & 1;
127 two_pixel_copy = width >> 1;
129 for (j = 0; j < height; j++) {
130 for (i = 0; i < two_pixel_copy; i++) {
131 srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0;
132 srcdata32[1].ul = *((u32 *)(srcxor + 4)) & 0xf0f0f0f0;
133 data32.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4);
134 data32.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4);
135 data32.b[2] = srcdata32[1].b[1] | (srcdata32[1].b[0] >> 4);
136 data32.b[3] = srcdata32[1].b[3] | (srcdata32[1].b[2] >> 4);
138 writel(data32.ul, dstxor);
146 for (i = 0; i < per_pixel_copy; i++) {
147 srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0;
148 data16.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4);
149 data16.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4);
150 writew(data16.us, dstxor);
151 csum += (u32)data16.us;
156 dstxor += last_alpha_dst_delta;
159 /* write checksum + signature */
162 writel(width, dst + AST_HWC_SIGNATURE_SizeX);
163 writel(height, dst + AST_HWC_SIGNATURE_SizeY);
164 writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTX);
165 writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTY);
168 int ast_cursor_blit(struct ast_private *ast, struct drm_framebuffer *fb)
170 struct drm_device *dev = &ast->base;
171 struct drm_gem_vram_object *gbo;
172 struct dma_buf_map map;
177 if (drm_WARN_ON_ONCE(dev, fb->width > AST_MAX_HWC_WIDTH) ||
178 drm_WARN_ON_ONCE(dev, fb->height > AST_MAX_HWC_HEIGHT))
181 gbo = drm_gem_vram_of_gem(fb->obj[0]);
183 ret = drm_gem_vram_pin(gbo, 0);
186 ret = drm_gem_vram_vmap(gbo, &map);
188 goto err_drm_gem_vram_unpin;
189 src = map.vaddr; /* TODO: Use mapping abstraction properly */
191 dst = ast->cursor.map[ast->cursor.next_index].vaddr_iomem;
193 /* do data transfer to cursor BO */
194 update_cursor_image(dst, src, fb->width, fb->height);
196 drm_gem_vram_vunmap(gbo, &map);
197 drm_gem_vram_unpin(gbo);
201 err_drm_gem_vram_unpin:
202 drm_gem_vram_unpin(gbo);
206 static void ast_cursor_set_base(struct ast_private *ast, u64 address)
208 u8 addr0 = (address >> 3) & 0xff;
209 u8 addr1 = (address >> 11) & 0xff;
210 u8 addr2 = (address >> 19) & 0xff;
212 ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc8, addr0);
213 ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc9, addr1);
214 ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xca, addr2);
217 void ast_cursor_page_flip(struct ast_private *ast)
219 struct drm_device *dev = &ast->base;
220 struct drm_gem_vram_object *gbo;
223 gbo = ast->cursor.gbo[ast->cursor.next_index];
225 off = drm_gem_vram_offset(gbo);
226 if (drm_WARN_ON_ONCE(dev, off < 0))
227 return; /* Bug: we didn't pin the cursor HW BO to VRAM. */
229 ast_cursor_set_base(ast, off);
231 ++ast->cursor.next_index;
232 ast->cursor.next_index %= ARRAY_SIZE(ast->cursor.gbo);
235 static void ast_cursor_set_location(struct ast_private *ast, u16 x, u16 y,
236 u8 x_offset, u8 y_offset)
238 u8 x0 = (x & 0x00ff);
239 u8 x1 = (x & 0x0f00) >> 8;
240 u8 y0 = (y & 0x00ff);
241 u8 y1 = (y & 0x0700) >> 8;
243 ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc2, x_offset);
244 ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc3, y_offset);
245 ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc4, x0);
246 ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc5, x1);
247 ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc6, y0);
248 ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc7, y1);
251 void ast_cursor_show(struct ast_private *ast, int x, int y,
252 unsigned int offset_x, unsigned int offset_y)
254 u8 x_offset, y_offset;
259 dst = ast->cursor.map[ast->cursor.next_index].vaddr;
261 sig = dst + AST_HWC_SIZE;
262 writel(x, sig + AST_HWC_SIGNATURE_X);
263 writel(y, sig + AST_HWC_SIGNATURE_Y);
266 x_offset = (-x) + offset_x;
272 y_offset = (-y) + offset_y;
278 ast_cursor_set_location(ast, x, y, x_offset, y_offset);
280 /* dummy write to fire HWC */
282 0x01; /* enable ARGB4444 cursor */
283 ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, jreg);
286 void ast_cursor_hide(struct ast_private *ast)
288 ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, 0x00);