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