]> Git Repo - linux.git/blob - drivers/gpu/drm/loongson/lsdc_plane.c
Merge tag 'input-for-v6.7-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor...
[linux.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 #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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
This page took 0.08058 seconds and 4 git commands to generate.