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