1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2023 Loongson Technology Corporation Limited
4 */
5
6 #include <linux/delay.h>
7
8 #include <drm/drm_atomic.h>
9 #include <drm/drm_atomic_helper.h>
10 #include <drm/drm_framebuffer.h>
11 #include <drm/drm_gem_atomic_helper.h>
12
13 #include "lsdc_drv.h"
14 #include "lsdc_regs.h"
15 #include "lsdc_ttm.h"
16
17 static const u32 lsdc_primary_formats[] = {
18 DRM_FORMAT_XRGB8888,
19 };
20
21 static const u32 lsdc_cursor_formats[] = {
22 DRM_FORMAT_ARGB8888,
23 };
24
25 static const u64 lsdc_fb_format_modifiers[] = {
26 DRM_FORMAT_MOD_LINEAR,
27 DRM_FORMAT_MOD_INVALID
28 };
29
lsdc_get_fb_offset(struct drm_framebuffer * fb,struct drm_plane_state * state)30 static unsigned int lsdc_get_fb_offset(struct drm_framebuffer *fb,
31 struct drm_plane_state *state)
32 {
33 unsigned int offset = fb->offsets[0];
34
35 offset += fb->format->cpp[0] * (state->src_x >> 16);
36 offset += fb->pitches[0] * (state->src_y >> 16);
37
38 return offset;
39 }
40
lsdc_fb_base_addr(struct drm_framebuffer * fb)41 static u64 lsdc_fb_base_addr(struct drm_framebuffer *fb)
42 {
43 struct lsdc_device *ldev = to_lsdc(fb->dev);
44 struct lsdc_bo *lbo = gem_to_lsdc_bo(fb->obj[0]);
45
46 return lsdc_bo_gpu_offset(lbo) + ldev->vram_base;
47 }
48
lsdc_primary_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)49 static int lsdc_primary_atomic_check(struct drm_plane *plane,
50 struct drm_atomic_state *state)
51 {
52 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
53 struct drm_crtc *crtc = new_plane_state->crtc;
54 struct drm_crtc_state *new_crtc_state;
55
56 if (!crtc)
57 return 0;
58
59 new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
60
61 return drm_atomic_helper_check_plane_state(new_plane_state,
62 new_crtc_state,
63 DRM_PLANE_NO_SCALING,
64 DRM_PLANE_NO_SCALING,
65 false, true);
66 }
67
lsdc_primary_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)68 static void lsdc_primary_atomic_update(struct drm_plane *plane,
69 struct drm_atomic_state *state)
70 {
71 struct lsdc_primary *primary = to_lsdc_primary(plane);
72 const struct lsdc_primary_plane_ops *ops = primary->ops;
73 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
74 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
75 struct drm_framebuffer *new_fb = new_plane_state->fb;
76 struct drm_framebuffer *old_fb = old_plane_state->fb;
77 u64 fb_addr = lsdc_fb_base_addr(new_fb);
78
79 fb_addr += lsdc_get_fb_offset(new_fb, new_plane_state);
80
81 ops->update_fb_addr(primary, fb_addr);
82 ops->update_fb_stride(primary, new_fb->pitches[0]);
83
84 if (!old_fb || old_fb->format != new_fb->format)
85 ops->update_fb_format(primary, new_fb->format);
86 }
87
lsdc_primary_atomic_disable(struct drm_plane * plane,struct drm_atomic_state * state)88 static void lsdc_primary_atomic_disable(struct drm_plane *plane,
89 struct drm_atomic_state *state)
90 {
91 /*
92 * Do nothing, just prevent call into atomic_update().
93 * Writing the format as LSDC_PF_NONE can disable the primary,
94 * But it seems not necessary...
95 */
96 drm_dbg(plane->dev, "%s disabled\n", plane->name);
97 }
98
lsdc_plane_prepare_fb(struct drm_plane * plane,struct drm_plane_state * new_state)99 static int lsdc_plane_prepare_fb(struct drm_plane *plane,
100 struct drm_plane_state *new_state)
101 {
102 struct drm_framebuffer *fb = new_state->fb;
103 struct lsdc_bo *lbo;
104 u64 gpu_vaddr;
105 int ret;
106
107 if (!fb)
108 return 0;
109
110 lbo = gem_to_lsdc_bo(fb->obj[0]);
111
112 ret = lsdc_bo_reserve(lbo);
113 if (unlikely(ret)) {
114 drm_err(plane->dev, "bo %p reserve failed\n", lbo);
115 return ret;
116 }
117
118 ret = lsdc_bo_pin(lbo, LSDC_GEM_DOMAIN_VRAM, &gpu_vaddr);
119
120 lsdc_bo_unreserve(lbo);
121
122 if (unlikely(ret)) {
123 drm_err(plane->dev, "bo %p pin failed\n", lbo);
124 return ret;
125 }
126
127 lsdc_bo_ref(lbo);
128
129 if (plane->type != DRM_PLANE_TYPE_CURSOR)
130 drm_dbg(plane->dev,
131 "%s[%p] pin at 0x%llx, bo size: %zu\n",
132 plane->name, lbo, gpu_vaddr, lsdc_bo_size(lbo));
133
134 return drm_gem_plane_helper_prepare_fb(plane, new_state);
135 }
136
lsdc_plane_cleanup_fb(struct drm_plane * plane,struct drm_plane_state * old_state)137 static void lsdc_plane_cleanup_fb(struct drm_plane *plane,
138 struct drm_plane_state *old_state)
139 {
140 struct drm_framebuffer *fb = old_state->fb;
141 struct lsdc_bo *lbo;
142 int ret;
143
144 if (!fb)
145 return;
146
147 lbo = gem_to_lsdc_bo(fb->obj[0]);
148
149 ret = lsdc_bo_reserve(lbo);
150 if (unlikely(ret)) {
151 drm_err(plane->dev, "%p reserve failed\n", lbo);
152 return;
153 }
154
155 lsdc_bo_unpin(lbo);
156
157 lsdc_bo_unreserve(lbo);
158
159 lsdc_bo_unref(lbo);
160
161 if (plane->type != DRM_PLANE_TYPE_CURSOR)
162 drm_dbg(plane->dev, "%s unpin\n", plane->name);
163 }
164
165 static const struct drm_plane_helper_funcs lsdc_primary_helper_funcs = {
166 .prepare_fb = lsdc_plane_prepare_fb,
167 .cleanup_fb = lsdc_plane_cleanup_fb,
168 .atomic_check = lsdc_primary_atomic_check,
169 .atomic_update = lsdc_primary_atomic_update,
170 .atomic_disable = lsdc_primary_atomic_disable,
171 };
172
lsdc_cursor_plane_atomic_async_check(struct drm_plane * plane,struct drm_atomic_state * state)173 static int lsdc_cursor_plane_atomic_async_check(struct drm_plane *plane,
174 struct drm_atomic_state *state)
175 {
176 struct drm_plane_state *new_state;
177 struct drm_crtc_state *crtc_state;
178
179 new_state = drm_atomic_get_new_plane_state(state, plane);
180
181 if (!plane->state || !plane->state->fb) {
182 drm_dbg(plane->dev, "%s: state is NULL\n", plane->name);
183 return -EINVAL;
184 }
185
186 if (new_state->crtc_w != new_state->crtc_h) {
187 drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
188 new_state->crtc_w, new_state->crtc_h);
189 return -EINVAL;
190 }
191
192 if (new_state->crtc_w != 64 && new_state->crtc_w != 32) {
193 drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
194 new_state->crtc_w, new_state->crtc_h);
195 return -EINVAL;
196 }
197
198 crtc_state = drm_atomic_get_existing_crtc_state(state, new_state->crtc);
199 if (!crtc_state->active)
200 return -EINVAL;
201
202 if (plane->state->crtc != new_state->crtc ||
203 plane->state->src_w != new_state->src_w ||
204 plane->state->src_h != new_state->src_h ||
205 plane->state->crtc_w != new_state->crtc_w ||
206 plane->state->crtc_h != new_state->crtc_h)
207 return -EINVAL;
208
209 if (new_state->visible != plane->state->visible)
210 return -EINVAL;
211
212 return drm_atomic_helper_check_plane_state(plane->state,
213 crtc_state,
214 DRM_PLANE_NO_SCALING,
215 DRM_PLANE_NO_SCALING,
216 true, true);
217 }
218
lsdc_cursor_plane_atomic_async_update(struct drm_plane * plane,struct drm_atomic_state * state)219 static void lsdc_cursor_plane_atomic_async_update(struct drm_plane *plane,
220 struct drm_atomic_state *state)
221 {
222 struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
223 const struct lsdc_cursor_plane_ops *ops = cursor->ops;
224 struct drm_framebuffer *old_fb = plane->state->fb;
225 struct drm_framebuffer *new_fb;
226 struct drm_plane_state *new_state;
227
228 new_state = drm_atomic_get_new_plane_state(state, plane);
229
230 new_fb = plane->state->fb;
231
232 plane->state->crtc_x = new_state->crtc_x;
233 plane->state->crtc_y = new_state->crtc_y;
234 plane->state->crtc_h = new_state->crtc_h;
235 plane->state->crtc_w = new_state->crtc_w;
236 plane->state->src_x = new_state->src_x;
237 plane->state->src_y = new_state->src_y;
238 plane->state->src_h = new_state->src_h;
239 plane->state->src_w = new_state->src_w;
240 swap(plane->state->fb, new_state->fb);
241
242 if (new_state->visible) {
243 enum lsdc_cursor_size cursor_size;
244
245 switch (new_state->crtc_w) {
246 case 64:
247 cursor_size = CURSOR_SIZE_64X64;
248 break;
249 case 32:
250 cursor_size = CURSOR_SIZE_32X32;
251 break;
252 default:
253 cursor_size = CURSOR_SIZE_32X32;
254 break;
255 }
256
257 ops->update_position(cursor, new_state->crtc_x, new_state->crtc_y);
258
259 ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888);
260
261 if (!old_fb || old_fb != new_fb)
262 ops->update_bo_addr(cursor, lsdc_fb_base_addr(new_fb));
263 }
264 }
265
266 /* ls7a1000 cursor plane helpers */
267
ls7a1000_cursor_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)268 static int ls7a1000_cursor_plane_atomic_check(struct drm_plane *plane,
269 struct drm_atomic_state *state)
270 {
271 struct drm_plane_state *new_plane_state;
272 struct drm_crtc_state *new_crtc_state;
273 struct drm_crtc *crtc;
274
275 new_plane_state = drm_atomic_get_new_plane_state(state, plane);
276
277 crtc = new_plane_state->crtc;
278 if (!crtc) {
279 drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name);
280 return 0;
281 }
282
283 if (new_plane_state->crtc_w != 32 || new_plane_state->crtc_h != 32) {
284 drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
285 new_plane_state->crtc_w, new_plane_state->crtc_h);
286 return -EINVAL;
287 }
288
289 new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
290
291 return drm_atomic_helper_check_plane_state(new_plane_state,
292 new_crtc_state,
293 DRM_PLANE_NO_SCALING,
294 DRM_PLANE_NO_SCALING,
295 true, true);
296 }
297
ls7a1000_cursor_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)298 static void ls7a1000_cursor_plane_atomic_update(struct drm_plane *plane,
299 struct drm_atomic_state *state)
300 {
301 struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
302 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
303 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
304 struct drm_framebuffer *new_fb = new_plane_state->fb;
305 struct drm_framebuffer *old_fb = old_plane_state->fb;
306 const struct lsdc_cursor_plane_ops *ops = cursor->ops;
307 u64 addr = lsdc_fb_base_addr(new_fb);
308
309 if (!new_plane_state->visible)
310 return;
311
312 ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y);
313
314 if (!old_fb || old_fb != new_fb)
315 ops->update_bo_addr(cursor, addr);
316
317 ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_ARGB8888);
318 }
319
ls7a1000_cursor_plane_atomic_disable(struct drm_plane * plane,struct drm_atomic_state * state)320 static void ls7a1000_cursor_plane_atomic_disable(struct drm_plane *plane,
321 struct drm_atomic_state *state)
322 {
323 struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
324 const struct lsdc_cursor_plane_ops *ops = cursor->ops;
325
326 ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_DISABLE);
327 }
328
329 static const struct drm_plane_helper_funcs ls7a1000_cursor_plane_helper_funcs = {
330 .prepare_fb = lsdc_plane_prepare_fb,
331 .cleanup_fb = lsdc_plane_cleanup_fb,
332 .atomic_check = ls7a1000_cursor_plane_atomic_check,
333 .atomic_update = ls7a1000_cursor_plane_atomic_update,
334 .atomic_disable = ls7a1000_cursor_plane_atomic_disable,
335 .atomic_async_check = lsdc_cursor_plane_atomic_async_check,
336 .atomic_async_update = lsdc_cursor_plane_atomic_async_update,
337 };
338
339 /* ls7a2000 cursor plane helpers */
340
ls7a2000_cursor_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)341 static int ls7a2000_cursor_plane_atomic_check(struct drm_plane *plane,
342 struct drm_atomic_state *state)
343 {
344 struct drm_plane_state *new_plane_state;
345 struct drm_crtc_state *new_crtc_state;
346 struct drm_crtc *crtc;
347
348 new_plane_state = drm_atomic_get_new_plane_state(state, plane);
349
350 crtc = new_plane_state->crtc;
351 if (!crtc) {
352 drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name);
353 return 0;
354 }
355
356 if (new_plane_state->crtc_w != new_plane_state->crtc_h) {
357 drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
358 new_plane_state->crtc_w, new_plane_state->crtc_h);
359 return -EINVAL;
360 }
361
362 if (new_plane_state->crtc_w != 64 && new_plane_state->crtc_w != 32) {
363 drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
364 new_plane_state->crtc_w, new_plane_state->crtc_h);
365 return -EINVAL;
366 }
367
368 new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
369
370 return drm_atomic_helper_check_plane_state(new_plane_state,
371 new_crtc_state,
372 DRM_PLANE_NO_SCALING,
373 DRM_PLANE_NO_SCALING,
374 true, true);
375 }
376
377 /* Update the format, size and location of the cursor */
378
ls7a2000_cursor_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)379 static void ls7a2000_cursor_plane_atomic_update(struct drm_plane *plane,
380 struct drm_atomic_state *state)
381 {
382 struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
383 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
384 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
385 struct drm_framebuffer *new_fb = new_plane_state->fb;
386 struct drm_framebuffer *old_fb = old_plane_state->fb;
387 const struct lsdc_cursor_plane_ops *ops = cursor->ops;
388 enum lsdc_cursor_size cursor_size;
389
390 if (!new_plane_state->visible)
391 return;
392
393 ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y);
394
395 if (!old_fb || new_fb != old_fb) {
396 u64 addr = lsdc_fb_base_addr(new_fb);
397
398 ops->update_bo_addr(cursor, addr);
399 }
400
401 switch (new_plane_state->crtc_w) {
402 case 64:
403 cursor_size = CURSOR_SIZE_64X64;
404 break;
405 case 32:
406 cursor_size = CURSOR_SIZE_32X32;
407 break;
408 default:
409 cursor_size = CURSOR_SIZE_64X64;
410 break;
411 }
412
413 ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888);
414 }
415
ls7a2000_cursor_plane_atomic_disable(struct drm_plane * plane,struct drm_atomic_state * state)416 static void ls7a2000_cursor_plane_atomic_disable(struct drm_plane *plane,
417 struct drm_atomic_state *state)
418 {
419 struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
420 const struct lsdc_cursor_plane_ops *hw_ops = cursor->ops;
421
422 hw_ops->update_cfg(cursor, CURSOR_SIZE_64X64, CURSOR_FORMAT_DISABLE);
423 }
424
425 static const struct drm_plane_helper_funcs ls7a2000_cursor_plane_helper_funcs = {
426 .prepare_fb = lsdc_plane_prepare_fb,
427 .cleanup_fb = lsdc_plane_cleanup_fb,
428 .atomic_check = ls7a2000_cursor_plane_atomic_check,
429 .atomic_update = ls7a2000_cursor_plane_atomic_update,
430 .atomic_disable = ls7a2000_cursor_plane_atomic_disable,
431 .atomic_async_check = lsdc_cursor_plane_atomic_async_check,
432 .atomic_async_update = lsdc_cursor_plane_atomic_async_update,
433 };
434
lsdc_plane_atomic_print_state(struct drm_printer * p,const struct drm_plane_state * state)435 static void lsdc_plane_atomic_print_state(struct drm_printer *p,
436 const struct drm_plane_state *state)
437 {
438 struct drm_framebuffer *fb = state->fb;
439 u64 addr;
440
441 if (!fb)
442 return;
443
444 addr = lsdc_fb_base_addr(fb);
445
446 drm_printf(p, "\tdma addr=%llx\n", addr);
447 }
448
449 static const struct drm_plane_funcs lsdc_plane_funcs = {
450 .update_plane = drm_atomic_helper_update_plane,
451 .disable_plane = drm_atomic_helper_disable_plane,
452 .destroy = drm_plane_cleanup,
453 .reset = drm_atomic_helper_plane_reset,
454 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
455 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
456 .atomic_print_state = lsdc_plane_atomic_print_state,
457 };
458
459 /* Primary plane 0 hardware related ops */
460
lsdc_primary0_update_fb_addr(struct lsdc_primary * primary,u64 addr)461 static void lsdc_primary0_update_fb_addr(struct lsdc_primary *primary, u64 addr)
462 {
463 struct lsdc_device *ldev = primary->ldev;
464 u32 status;
465 u32 lo, hi;
466
467 /* 40-bit width physical address bus */
468 lo = addr & 0xFFFFFFFF;
469 hi = (addr >> 32) & 0xFF;
470
471 status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
472 if (status & FB_REG_IN_USING) {
473 lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_LO_REG, lo);
474 lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_HI_REG, hi);
475 } else {
476 lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_LO_REG, lo);
477 lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_HI_REG, hi);
478 }
479 }
480
lsdc_primary0_update_fb_stride(struct lsdc_primary * primary,u32 stride)481 static void lsdc_primary0_update_fb_stride(struct lsdc_primary *primary, u32 stride)
482 {
483 struct lsdc_device *ldev = primary->ldev;
484
485 lsdc_wreg32(ldev, LSDC_CRTC0_STRIDE_REG, stride);
486 }
487
lsdc_primary0_update_fb_format(struct lsdc_primary * primary,const struct drm_format_info * format)488 static void lsdc_primary0_update_fb_format(struct lsdc_primary *primary,
489 const struct drm_format_info *format)
490 {
491 struct lsdc_device *ldev = primary->ldev;
492 u32 status;
493
494 status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
495
496 /*
497 * TODO: add RGB565 support, only support XRBG8888 at present
498 */
499 status &= ~CFG_PIX_FMT_MASK;
500 status |= LSDC_PF_XRGB8888;
501
502 lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, status);
503 }
504
505 /* Primary plane 1 hardware related ops */
506
lsdc_primary1_update_fb_addr(struct lsdc_primary * primary,u64 addr)507 static void lsdc_primary1_update_fb_addr(struct lsdc_primary *primary, u64 addr)
508 {
509 struct lsdc_device *ldev = primary->ldev;
510 u32 status;
511 u32 lo, hi;
512
513 /* 40-bit width physical address bus */
514 lo = addr & 0xFFFFFFFF;
515 hi = (addr >> 32) & 0xFF;
516
517 status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
518 if (status & FB_REG_IN_USING) {
519 lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_LO_REG, lo);
520 lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_HI_REG, hi);
521 } else {
522 lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_LO_REG, lo);
523 lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_HI_REG, hi);
524 }
525 }
526
lsdc_primary1_update_fb_stride(struct lsdc_primary * primary,u32 stride)527 static void lsdc_primary1_update_fb_stride(struct lsdc_primary *primary, u32 stride)
528 {
529 struct lsdc_device *ldev = primary->ldev;
530
531 lsdc_wreg32(ldev, LSDC_CRTC1_STRIDE_REG, stride);
532 }
533
lsdc_primary1_update_fb_format(struct lsdc_primary * primary,const struct drm_format_info * format)534 static void lsdc_primary1_update_fb_format(struct lsdc_primary *primary,
535 const struct drm_format_info *format)
536 {
537 struct lsdc_device *ldev = primary->ldev;
538 u32 status;
539
540 status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
541
542 /*
543 * TODO: add RGB565 support, only support XRBG8888 at present
544 */
545 status &= ~CFG_PIX_FMT_MASK;
546 status |= LSDC_PF_XRGB8888;
547
548 lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, status);
549 }
550
551 static const struct lsdc_primary_plane_ops lsdc_primary_plane_hw_ops[2] = {
552 {
553 .update_fb_addr = lsdc_primary0_update_fb_addr,
554 .update_fb_stride = lsdc_primary0_update_fb_stride,
555 .update_fb_format = lsdc_primary0_update_fb_format,
556 },
557 {
558 .update_fb_addr = lsdc_primary1_update_fb_addr,
559 .update_fb_stride = lsdc_primary1_update_fb_stride,
560 .update_fb_format = lsdc_primary1_update_fb_format,
561 },
562 };
563
564 /*
565 * Update location, format, enable and disable state of the cursor,
566 * For those who have two hardware cursor, let cursor 0 is attach to CRTC-0,
567 * cursor 1 is attach to CRTC-1. Compositing the primary plane and cursor
568 * plane is automatically done by hardware, the cursor is alway on the top of
569 * the primary plane. In other word, z-order is fixed in hardware and cannot
570 * be changed. For those old DC who has only one hardware cursor, we made it
571 * shared by the two screen, this works on extend screen mode.
572 */
573
574 /* cursor plane 0 (for pipe 0) related hardware ops */
575
lsdc_cursor0_update_bo_addr(struct lsdc_cursor * cursor,u64 addr)576 static void lsdc_cursor0_update_bo_addr(struct lsdc_cursor *cursor, u64 addr)
577 {
578 struct lsdc_device *ldev = cursor->ldev;
579
580 /* 40-bit width physical address bus */
581 lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF);
582 lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr);
583 }
584
lsdc_cursor0_update_position(struct lsdc_cursor * cursor,int x,int y)585 static void lsdc_cursor0_update_position(struct lsdc_cursor *cursor, int x, int y)
586 {
587 struct lsdc_device *ldev = cursor->ldev;
588
589 if (x < 0)
590 x = 0;
591
592 if (y < 0)
593 y = 0;
594
595 lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x);
596 }
597
lsdc_cursor0_update_cfg(struct lsdc_cursor * cursor,enum lsdc_cursor_size cursor_size,enum lsdc_cursor_format fmt)598 static void lsdc_cursor0_update_cfg(struct lsdc_cursor *cursor,
599 enum lsdc_cursor_size cursor_size,
600 enum lsdc_cursor_format fmt)
601 {
602 struct lsdc_device *ldev = cursor->ldev;
603 u32 cfg;
604
605 cfg = CURSOR_ON_CRTC0 << CURSOR_LOCATION_SHIFT |
606 cursor_size << CURSOR_SIZE_SHIFT |
607 fmt << CURSOR_FORMAT_SHIFT;
608
609 lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg);
610 }
611
612 /* cursor plane 1 (for pipe 1) related hardware ops */
613
lsdc_cursor1_update_bo_addr(struct lsdc_cursor * cursor,u64 addr)614 static void lsdc_cursor1_update_bo_addr(struct lsdc_cursor *cursor, u64 addr)
615 {
616 struct lsdc_device *ldev = cursor->ldev;
617
618 /* 40-bit width physical address bus */
619 lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_HI_REG, (addr >> 32) & 0xFF);
620 lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_LO_REG, addr);
621 }
622
lsdc_cursor1_update_position(struct lsdc_cursor * cursor,int x,int y)623 static void lsdc_cursor1_update_position(struct lsdc_cursor *cursor, int x, int y)
624 {
625 struct lsdc_device *ldev = cursor->ldev;
626
627 if (x < 0)
628 x = 0;
629
630 if (y < 0)
631 y = 0;
632
633 lsdc_wreg32(ldev, LSDC_CURSOR1_POSITION_REG, (y << 16) | x);
634 }
635
lsdc_cursor1_update_cfg(struct lsdc_cursor * cursor,enum lsdc_cursor_size cursor_size,enum lsdc_cursor_format fmt)636 static void lsdc_cursor1_update_cfg(struct lsdc_cursor *cursor,
637 enum lsdc_cursor_size cursor_size,
638 enum lsdc_cursor_format fmt)
639 {
640 struct lsdc_device *ldev = cursor->ldev;
641 u32 cfg;
642
643 cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT |
644 cursor_size << CURSOR_SIZE_SHIFT |
645 fmt << CURSOR_FORMAT_SHIFT;
646
647 lsdc_wreg32(ldev, LSDC_CURSOR1_CFG_REG, cfg);
648 }
649
650 /* The hardware cursors become normal since ls7a2000/ls2k2000 */
651
652 static const struct lsdc_cursor_plane_ops ls7a2000_cursor_hw_ops[2] = {
653 {
654 .update_bo_addr = lsdc_cursor0_update_bo_addr,
655 .update_cfg = lsdc_cursor0_update_cfg,
656 .update_position = lsdc_cursor0_update_position,
657 },
658 {
659 .update_bo_addr = lsdc_cursor1_update_bo_addr,
660 .update_cfg = lsdc_cursor1_update_cfg,
661 .update_position = lsdc_cursor1_update_position,
662 },
663 };
664
665 /* Quirks for cursor 1, only for old loongson display controller */
666
lsdc_cursor1_update_bo_addr_quirk(struct lsdc_cursor * cursor,u64 addr)667 static void lsdc_cursor1_update_bo_addr_quirk(struct lsdc_cursor *cursor, u64 addr)
668 {
669 struct lsdc_device *ldev = cursor->ldev;
670
671 /* 40-bit width physical address bus */
672 lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF);
673 lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr);
674 }
675
lsdc_cursor1_update_position_quirk(struct lsdc_cursor * cursor,int x,int y)676 static void lsdc_cursor1_update_position_quirk(struct lsdc_cursor *cursor, int x, int y)
677 {
678 struct lsdc_device *ldev = cursor->ldev;
679
680 if (x < 0)
681 x = 0;
682
683 if (y < 0)
684 y = 0;
685
686 lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x);
687 }
688
lsdc_cursor1_update_cfg_quirk(struct lsdc_cursor * cursor,enum lsdc_cursor_size cursor_size,enum lsdc_cursor_format fmt)689 static void lsdc_cursor1_update_cfg_quirk(struct lsdc_cursor *cursor,
690 enum lsdc_cursor_size cursor_size,
691 enum lsdc_cursor_format fmt)
692 {
693 struct lsdc_device *ldev = cursor->ldev;
694 u32 cfg;
695
696 cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT |
697 cursor_size << CURSOR_SIZE_SHIFT |
698 fmt << CURSOR_FORMAT_SHIFT;
699
700 lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg);
701 }
702
703 /*
704 * The unforgiving LS7A1000/LS2K1000 has only one hardware cursors plane
705 */
706 static const struct lsdc_cursor_plane_ops ls7a1000_cursor_hw_ops[2] = {
707 {
708 .update_bo_addr = lsdc_cursor0_update_bo_addr,
709 .update_cfg = lsdc_cursor0_update_cfg,
710 .update_position = lsdc_cursor0_update_position,
711 },
712 {
713 .update_bo_addr = lsdc_cursor1_update_bo_addr_quirk,
714 .update_cfg = lsdc_cursor1_update_cfg_quirk,
715 .update_position = lsdc_cursor1_update_position_quirk,
716 },
717 };
718
lsdc_primary_plane_init(struct drm_device * ddev,struct drm_plane * plane,unsigned int index)719 int lsdc_primary_plane_init(struct drm_device *ddev,
720 struct drm_plane *plane,
721 unsigned int index)
722 {
723 struct lsdc_primary *primary = to_lsdc_primary(plane);
724 int ret;
725
726 ret = drm_universal_plane_init(ddev, plane, 1 << index,
727 &lsdc_plane_funcs,
728 lsdc_primary_formats,
729 ARRAY_SIZE(lsdc_primary_formats),
730 lsdc_fb_format_modifiers,
731 DRM_PLANE_TYPE_PRIMARY,
732 "ls-primary-plane-%u", index);
733 if (ret)
734 return ret;
735
736 drm_plane_helper_add(plane, &lsdc_primary_helper_funcs);
737
738 primary->ldev = to_lsdc(ddev);
739 primary->ops = &lsdc_primary_plane_hw_ops[index];
740
741 return 0;
742 }
743
ls7a1000_cursor_plane_init(struct drm_device * ddev,struct drm_plane * plane,unsigned int index)744 int ls7a1000_cursor_plane_init(struct drm_device *ddev,
745 struct drm_plane *plane,
746 unsigned int index)
747 {
748 struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
749 int ret;
750
751 ret = drm_universal_plane_init(ddev, plane, 1 << index,
752 &lsdc_plane_funcs,
753 lsdc_cursor_formats,
754 ARRAY_SIZE(lsdc_cursor_formats),
755 lsdc_fb_format_modifiers,
756 DRM_PLANE_TYPE_CURSOR,
757 "ls-cursor-plane-%u", index);
758 if (ret)
759 return ret;
760
761 cursor->ldev = to_lsdc(ddev);
762 cursor->ops = &ls7a1000_cursor_hw_ops[index];
763
764 drm_plane_helper_add(plane, &ls7a1000_cursor_plane_helper_funcs);
765
766 return 0;
767 }
768
ls7a2000_cursor_plane_init(struct drm_device * ddev,struct drm_plane * plane,unsigned int index)769 int ls7a2000_cursor_plane_init(struct drm_device *ddev,
770 struct drm_plane *plane,
771 unsigned int index)
772 {
773 struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
774 int ret;
775
776 ret = drm_universal_plane_init(ddev, plane, 1 << index,
777 &lsdc_plane_funcs,
778 lsdc_cursor_formats,
779 ARRAY_SIZE(lsdc_cursor_formats),
780 lsdc_fb_format_modifiers,
781 DRM_PLANE_TYPE_CURSOR,
782 "ls-cursor-plane-%u", index);
783 if (ret)
784 return ret;
785
786 cursor->ldev = to_lsdc(ddev);
787 cursor->ops = &ls7a2000_cursor_hw_ops[index];
788
789 drm_plane_helper_add(plane, &ls7a2000_cursor_plane_helper_funcs);
790
791 return 0;
792 }
793