Revert "sync: fix dEQP-EGL*get_frame_timestamps* "
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_mali-driver.git] / t83x / kernel / drivers / gpu / drm / pl111 / pl111_drm_cursor.c
1 /*
2 *
3 * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
4 *
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
8 * of such GNU licence.
9 *
10 * A copy of the licence is included with the program, and can also be obtained
11 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
12 * Boston, MA 02110-1301, USA.
13 *
14 */
15
16
17
18 /**
19 * pl111_drm_cursor.c
20 * Implementation of cursor functions for PL111 DRM
21 */
22 #include <linux/amba/bus.h>
23 #include <linux/amba/clcd.h>
24 #include <linux/version.h>
25 #include <linux/shmem_fs.h>
26 #include <linux/dma-buf.h>
27 #include <linux/module.h>
28
29 #include <drm/drmP.h>
30 #include <drm/drm_crtc_helper.h>
31 #include "pl111_clcd_ext.h"
32 #include "pl111_drm.h"
33
34 #define PL111_MAX_CURSOR_WIDTH (64)
35 #define PL111_MAX_CURSOR_HEIGHT (64)
36
37 #define ARGB_2_LBBP_BINARY_THRESHOLD (1 << 7)
38 #define ARGB_ALPHA_SHIFT 24
39 #define ARGB_ALPHA_MASK (0xff << ARGB_ALPHA_SHIFT)
40 #define ARGB_RED_SHIFT 16
41 #define ARGB_RED_MASK (0xff << ARGB_RED_SHIFT)
42 #define ARGB_GREEN_SHIFT 8
43 #define ARGB_GREEN_MASK (0xff << ARGB_GREEN_SHIFT)
44 #define ARGB_BLUE_SHIFT 0
45 #define ARGB_BLUE_MASK (0xff << ARGB_BLUE_SHIFT)
46
47
48 void pl111_set_cursor_size(enum pl111_cursor_size size)
49 {
50 u32 reg_data = readl(priv.regs + CLCD_CRSR_CONFIG);
51
52 if (size == CURSOR_64X64)
53 reg_data |= CRSR_CONFIG_CRSR_SIZE;
54 else
55 reg_data &= ~CRSR_CONFIG_CRSR_SIZE;
56
57 writel(reg_data, priv.regs + CLCD_CRSR_CONFIG);
58 }
59
60 void pl111_set_cursor_sync(enum pl111_cursor_sync sync)
61 {
62 u32 reg_data = readl(priv.regs + CLCD_CRSR_CONFIG);
63
64 if (sync == CURSOR_SYNC_VSYNC)
65 reg_data |= CRSR_CONFIG_CRSR_FRAME_SYNC;
66 else
67 reg_data &= ~CRSR_CONFIG_CRSR_FRAME_SYNC;
68
69 writel(reg_data, priv.regs + CLCD_CRSR_CONFIG);
70 }
71
72 void pl111_set_cursor(u32 cursor)
73 {
74 u32 reg_data = readl(priv.regs + CLCD_CRSR_CTRL);
75
76 reg_data &= ~(CRSR_CTRL_CRSR_MAX << CRSR_CTRL_CRSR_NUM_SHIFT);
77 reg_data |= (cursor & CRSR_CTRL_CRSR_MAX) << CRSR_CTRL_CRSR_NUM_SHIFT;
78
79 writel(reg_data, priv.regs + CLCD_CRSR_CTRL);
80 }
81
82 void pl111_set_cursor_enable(bool enable)
83 {
84 u32 reg_data = readl(priv.regs + CLCD_CRSR_CTRL);
85
86 if (enable)
87 reg_data |= CRSR_CTRL_CRSR_ON;
88 else
89 reg_data &= ~CRSR_CTRL_CRSR_ON;
90
91 writel(reg_data, priv.regs + CLCD_CRSR_CTRL);
92 }
93
94 void pl111_set_cursor_position(u32 x, u32 y)
95 {
96 u32 reg_data = (x & CRSR_XY_MASK) |
97 ((y & CRSR_XY_MASK) << CRSR_XY_Y_SHIFT);
98
99 writel(reg_data, priv.regs + CLCD_CRSR_XY);
100 }
101
102 void pl111_set_cursor_clipping(u32 x, u32 y)
103 {
104 u32 reg_data;
105
106 /*
107 * Do not allow setting clipping values larger than
108 * the cursor size since the cursor is already fully hidden
109 * when x,y = PL111_MAX_CURSOR_WIDTH.
110 */
111 if (x > PL111_MAX_CURSOR_WIDTH)
112 x = PL111_MAX_CURSOR_WIDTH;
113 if (y > PL111_MAX_CURSOR_WIDTH)
114 y = PL111_MAX_CURSOR_WIDTH;
115
116 reg_data = (x & CRSR_CLIP_MASK) |
117 ((y & CRSR_CLIP_MASK) << CRSR_CLIP_Y_SHIFT);
118
119 writel(reg_data, priv.regs + CLCD_CRSR_CLIP);
120 }
121
122 void pl111_set_cursor_palette(u32 color0, u32 color1)
123 {
124 writel(color0 & CRSR_PALETTE_MASK, priv.regs + CLCD_CRSR_PALETTE_0);
125 writel(color1 & CRSR_PALETTE_MASK, priv.regs + CLCD_CRSR_PALETTE_1);
126 }
127
128 void pl111_cursor_enable(void)
129 {
130 pl111_set_cursor_sync(CURSOR_SYNC_VSYNC);
131 pl111_set_cursor_size(CURSOR_64X64);
132 pl111_set_cursor_palette(0x0, 0x00ffffff);
133 pl111_set_cursor_enable(true);
134 }
135
136 void pl111_cursor_disable(void)
137 {
138 pl111_set_cursor_enable(false);
139 }
140
141 /* shift required to locate pixel into the correct position in
142 * a cursor LBBP word, indexed by x mod 16.
143 */
144 static const unsigned char
145 x_mod_16_to_value_shift[CLCD_CRSR_IMAGE_PIXELS_PER_WORD] = {
146 6, 4, 2, 0, 14, 12, 10, 8, 22, 20, 18, 16, 30, 28, 26, 24
147 };
148
149 /* Pack the pixel value into its correct position in the buffer as specified
150 * for LBBP */
151 static inline void
152 set_lbbp_pixel(uint32_t *buffer, unsigned int x, unsigned int y,
153 uint32_t value)
154 {
155 u32 *cursor_ram = priv.regs + CLCD_CRSR_IMAGE;
156 uint32_t shift;
157 uint32_t data;
158
159 shift = x_mod_16_to_value_shift[x % CLCD_CRSR_IMAGE_PIXELS_PER_WORD];
160
161 /* Get the word containing this pixel */
162 cursor_ram = cursor_ram + (x >> CLCD_CRSR_IMAGE_WORDS_PER_LINE) + (y << 2);
163
164 /* Update pixel in cursor RAM */
165 data = readl(cursor_ram);
166 data &= ~(CLCD_CRSR_LBBP_COLOR_MASK << shift);
167 data |= value << shift;
168 writel(data, cursor_ram);
169 }
170
171 static u32 pl111_argb_to_lbbp(u32 argb_pix)
172 {
173 u32 lbbp_pix = CLCD_CRSR_LBBP_TRANSPARENT;
174 u32 alpha = (argb_pix & ARGB_ALPHA_MASK) >> ARGB_ALPHA_SHIFT;
175 u32 red = (argb_pix & ARGB_RED_MASK) >> ARGB_RED_SHIFT;
176 u32 green = (argb_pix & ARGB_GREEN_MASK) >> ARGB_GREEN_SHIFT;
177 u32 blue = (argb_pix & ARGB_BLUE_MASK) >> ARGB_BLUE_SHIFT;
178
179 /*
180 * Converting from 8 pixel transparency to binary transparency
181 * it's the best we can achieve.
182 */
183 if (alpha & ARGB_2_LBBP_BINARY_THRESHOLD) {
184 u32 gray, max, min;
185
186 /*
187 * Convert to gray using the lightness method:
188 * gray = [max(R,G,B) + min(R,G,B)]/2
189 */
190 min = min(red, green);
191 min = min(min, blue);
192 max = max(red, green);
193 max = max(max, blue);
194 gray = (min + max) >> 1; /* divide by 2 */
195 /* Apply binary threshold to the gray value calculated */
196 if (gray & ARGB_2_LBBP_BINARY_THRESHOLD)
197 lbbp_pix = CLCD_CRSR_LBBP_FOREGROUND;
198 else
199 lbbp_pix = CLCD_CRSR_LBBP_BACKGROUND;
200 }
201
202 return lbbp_pix;
203 }
204
205 /*
206 * The PL111 hardware cursor supports only LBBP which is a 2bpp format but
207 * the cursor format from userspace is ARGB8888 so we need to convert
208 * to LBBP here.
209 */
210 static void pl111_set_cursor_image(u32 *data)
211 {
212 #ifdef ARGB_LBBP_CONVERSION_DEBUG
213 /* Add 1 on width to insert trailing NULL */
214 char string_cursor[PL111_MAX_CURSOR_WIDTH + 1];
215 #endif /* ARGB_LBBP_CONVERSION_DEBUG */
216 unsigned int x;
217 unsigned int y;
218
219 for (y = 0; y < PL111_MAX_CURSOR_HEIGHT; y++) {
220 for (x = 0; x < PL111_MAX_CURSOR_WIDTH; x++) {
221 u32 value = pl111_argb_to_lbbp(*data);
222
223 #ifdef ARGB_LBBP_CONVERSION_DEBUG
224 if (value == CLCD_CRSR_LBBP_TRANSPARENT)
225 string_cursor[x] = 'T';
226 else if (value == CLCD_CRSR_LBBP_FOREGROUND)
227 string_cursor[x] = 'F';
228 else if (value == CLCD_CRSR_LBBP_INVERSE)
229 string_cursor[x] = 'I';
230 else
231 string_cursor[x] = 'B';
232
233 #endif /* ARGB_LBBP_CONVERSION_DEBUG */
234 set_lbbp_pixel(data, x, y, value);
235 ++data;
236 }
237 #ifdef ARGB_LBBP_CONVERSION_DEBUG
238 string_cursor[PL111_MAX_CURSOR_WIDTH] = '\0';
239 DRM_INFO("%s\n", string_cursor);
240 #endif /* ARGB_LBBP_CONVERSION_DEBUG */
241 }
242 }
243
244 int pl111_crtc_cursor_set(struct drm_crtc *crtc,
245 struct drm_file *file_priv,
246 uint32_t handle,
247 uint32_t width,
248 uint32_t height)
249 {
250 struct drm_gem_object *obj;
251 struct pl111_gem_bo *bo;
252
253 DRM_DEBUG_KMS("handle = %u, width = %u, height = %u\n",
254 handle, width, height);
255
256 if (!handle) {
257 pl111_cursor_disable();
258 return 0;
259 }
260
261 if ((width != PL111_MAX_CURSOR_WIDTH) ||
262 (height != PL111_MAX_CURSOR_HEIGHT))
263 return -EINVAL;
264
265 obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
266 if (!obj) {
267 DRM_ERROR("Cannot find cursor object for handle = %d\n",
268 handle);
269 return -ENOENT;
270 }
271
272 /*
273 * We expect a PL111_MAX_CURSOR_WIDTH x PL111_MAX_CURSOR_HEIGHT
274 * ARGB888 buffer object in the input.
275 *
276 */
277 if (obj->size < (PL111_MAX_CURSOR_WIDTH * PL111_MAX_CURSOR_HEIGHT * 4)) {
278 DRM_ERROR("Cannot set cursor with an obj size = %d\n",
279 obj->size);
280 drm_gem_object_unreference_unlocked(obj);
281 return -EINVAL;
282 }
283
284 bo = PL111_BO_FROM_GEM(obj);
285 if (!(bo->type & PL111_BOT_DMA)) {
286 DRM_ERROR("Tried to set cursor with non DMA backed obj = %p\n",
287 obj);
288 drm_gem_object_unreference_unlocked(obj);
289 return -EINVAL;
290 }
291
292 pl111_set_cursor_image(bo->backing_data.dma.fb_cpu_addr);
293
294 /*
295 * Since we copy the contents of the buffer to the HW cursor internal
296 * memory this GEM object is not needed anymore.
297 */
298 drm_gem_object_unreference_unlocked(obj);
299
300 pl111_cursor_enable();
301
302 return 0;
303 }
304
305 int pl111_crtc_cursor_move(struct drm_crtc *crtc,
306 int x, int y)
307 {
308 int x_clip = 0;
309 int y_clip = 0;
310
311 DRM_DEBUG("x %d y %d\n", x, y);
312
313 /*
314 * The cursor image is clipped automatically at the screen limits when
315 * it extends beyond the screen image to the right or bottom but
316 * we must clip it using pl111 HW features for negative values.
317 */
318 if (x < 0) {
319 x_clip = -x;
320 x = 0;
321 }
322 if (y < 0) {
323 y_clip = -y;
324 y = 0;
325 }
326
327 pl111_set_cursor_clipping(x_clip, y_clip);
328 pl111_set_cursor_position(x, y);
329
330 return 0;
331 }