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