Merge tag 'rpmsg-v6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc...
[linux-2.6-microblaze.git] / drivers / gpu / drm / loongson / lsdc_plane.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }