treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 500
[sfrench/cifs-2.6.git] / drivers / gpu / drm / zte / zx_plane.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright 2016 Linaro Ltd.
4  * Copyright 2016 ZTE Corporation.
5  */
6
7 #include <drm/drm_atomic.h>
8 #include <drm/drm_atomic_helper.h>
9 #include <drm/drm_fb_cma_helper.h>
10 #include <drm/drm_gem_cma_helper.h>
11 #include <drm/drm_modeset_helper_vtables.h>
12 #include <drm/drm_plane_helper.h>
13 #include <drm/drmP.h>
14
15 #include "zx_common_regs.h"
16 #include "zx_drm_drv.h"
17 #include "zx_plane.h"
18 #include "zx_plane_regs.h"
19 #include "zx_vou.h"
20
21 static const uint32_t gl_formats[] = {
22         DRM_FORMAT_ARGB8888,
23         DRM_FORMAT_XRGB8888,
24         DRM_FORMAT_RGB888,
25         DRM_FORMAT_RGB565,
26         DRM_FORMAT_ARGB1555,
27         DRM_FORMAT_ARGB4444,
28 };
29
30 static const uint32_t vl_formats[] = {
31         DRM_FORMAT_NV12,        /* Semi-planar YUV420 */
32         DRM_FORMAT_YUV420,      /* Planar YUV420 */
33         DRM_FORMAT_YUYV,        /* Packed YUV422 */
34         DRM_FORMAT_YVYU,
35         DRM_FORMAT_UYVY,
36         DRM_FORMAT_VYUY,
37         DRM_FORMAT_YUV444,      /* YUV444 8bit */
38         /*
39          * TODO: add formats below that HW supports:
40          *  - YUV420 P010
41          *  - YUV420 Hantro
42          *  - YUV444 10bit
43          */
44 };
45
46 #define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
47
48 static int zx_vl_plane_atomic_check(struct drm_plane *plane,
49                                     struct drm_plane_state *plane_state)
50 {
51         struct drm_framebuffer *fb = plane_state->fb;
52         struct drm_crtc *crtc = plane_state->crtc;
53         struct drm_crtc_state *crtc_state;
54         int min_scale = FRAC_16_16(1, 8);
55         int max_scale = FRAC_16_16(8, 1);
56
57         if (!crtc || !fb)
58                 return 0;
59
60         crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
61                                                         crtc);
62         if (WARN_ON(!crtc_state))
63                 return -EINVAL;
64
65         /* nothing to check when disabling or disabled */
66         if (!crtc_state->enable)
67                 return 0;
68
69         /* plane must be enabled */
70         if (!plane_state->crtc)
71                 return -EINVAL;
72
73         return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
74                                                    min_scale, max_scale,
75                                                    true, true);
76 }
77
78 static int zx_vl_get_fmt(uint32_t format)
79 {
80         switch (format) {
81         case DRM_FORMAT_NV12:
82                 return VL_FMT_YUV420;
83         case DRM_FORMAT_YUV420:
84                 return VL_YUV420_PLANAR | VL_FMT_YUV420;
85         case DRM_FORMAT_YUYV:
86                 return VL_YUV422_YUYV | VL_FMT_YUV422;
87         case DRM_FORMAT_YVYU:
88                 return VL_YUV422_YVYU | VL_FMT_YUV422;
89         case DRM_FORMAT_UYVY:
90                 return VL_YUV422_UYVY | VL_FMT_YUV422;
91         case DRM_FORMAT_VYUY:
92                 return VL_YUV422_VYUY | VL_FMT_YUV422;
93         case DRM_FORMAT_YUV444:
94                 return VL_FMT_YUV444_8BIT;
95         default:
96                 WARN_ONCE(1, "invalid pixel format %d\n", format);
97                 return -EINVAL;
98         }
99 }
100
101 static inline void zx_vl_set_update(struct zx_plane *zplane)
102 {
103         void __iomem *layer = zplane->layer;
104
105         zx_writel_mask(layer + VL_CTRL0, VL_UPDATE, VL_UPDATE);
106 }
107
108 static inline void zx_vl_rsz_set_update(struct zx_plane *zplane)
109 {
110         zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1);
111 }
112
113 static int zx_vl_rsz_get_fmt(uint32_t format)
114 {
115         switch (format) {
116         case DRM_FORMAT_NV12:
117         case DRM_FORMAT_YUV420:
118                 return RSZ_VL_FMT_YCBCR420;
119         case DRM_FORMAT_YUYV:
120         case DRM_FORMAT_YVYU:
121         case DRM_FORMAT_UYVY:
122         case DRM_FORMAT_VYUY:
123                 return RSZ_VL_FMT_YCBCR422;
124         case DRM_FORMAT_YUV444:
125                 return RSZ_VL_FMT_YCBCR444;
126         default:
127                 WARN_ONCE(1, "invalid pixel format %d\n", format);
128                 return -EINVAL;
129         }
130 }
131
132 static inline u32 rsz_step_value(u32 src, u32 dst)
133 {
134         u32 val = 0;
135
136         if (src == dst)
137                 val = 0;
138         else if (src < dst)
139                 val = RSZ_PARA_STEP((src << 16) / dst);
140         else if (src > dst)
141                 val = RSZ_DATA_STEP(src / dst) |
142                       RSZ_PARA_STEP(((src << 16) / dst) & 0xffff);
143
144         return val;
145 }
146
147 static void zx_vl_rsz_setup(struct zx_plane *zplane, uint32_t format,
148                             u32 src_w, u32 src_h, u32 dst_w, u32 dst_h)
149 {
150         void __iomem *rsz = zplane->rsz;
151         u32 src_chroma_w = src_w;
152         u32 src_chroma_h = src_h;
153         int fmt;
154
155         /* Set up source and destination resolution */
156         zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
157         zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
158
159         /* Configure data format for VL RSZ */
160         fmt = zx_vl_rsz_get_fmt(format);
161         if (fmt >= 0)
162                 zx_writel_mask(rsz + RSZ_VL_CTRL_CFG, RSZ_VL_FMT_MASK, fmt);
163
164         /* Calculate Chroma height and width */
165         if (fmt == RSZ_VL_FMT_YCBCR420) {
166                 src_chroma_w = src_w >> 1;
167                 src_chroma_h = src_h >> 1;
168         } else if (fmt == RSZ_VL_FMT_YCBCR422) {
169                 src_chroma_w = src_w >> 1;
170         }
171
172         /* Set up Luma and Chroma step registers */
173         zx_writel(rsz + RSZ_VL_LUMA_HOR, rsz_step_value(src_w, dst_w));
174         zx_writel(rsz + RSZ_VL_LUMA_VER, rsz_step_value(src_h, dst_h));
175         zx_writel(rsz + RSZ_VL_CHROMA_HOR, rsz_step_value(src_chroma_w, dst_w));
176         zx_writel(rsz + RSZ_VL_CHROMA_VER, rsz_step_value(src_chroma_h, dst_h));
177
178         zx_vl_rsz_set_update(zplane);
179 }
180
181 static void zx_vl_plane_atomic_update(struct drm_plane *plane,
182                                       struct drm_plane_state *old_state)
183 {
184         struct zx_plane *zplane = to_zx_plane(plane);
185         struct drm_plane_state *state = plane->state;
186         struct drm_framebuffer *fb = state->fb;
187         struct drm_rect *src = &state->src;
188         struct drm_rect *dst = &state->dst;
189         struct drm_gem_cma_object *cma_obj;
190         void __iomem *layer = zplane->layer;
191         void __iomem *hbsc = zplane->hbsc;
192         void __iomem *paddr_reg;
193         dma_addr_t paddr;
194         u32 src_x, src_y, src_w, src_h;
195         u32 dst_x, dst_y, dst_w, dst_h;
196         uint32_t format;
197         int fmt;
198         int num_planes;
199         int i;
200
201         if (!fb)
202                 return;
203
204         format = fb->format->format;
205
206         src_x = src->x1 >> 16;
207         src_y = src->y1 >> 16;
208         src_w = drm_rect_width(src) >> 16;
209         src_h = drm_rect_height(src) >> 16;
210
211         dst_x = dst->x1;
212         dst_y = dst->y1;
213         dst_w = drm_rect_width(dst);
214         dst_h = drm_rect_height(dst);
215
216         /* Set up data address registers for Y, Cb and Cr planes */
217         num_planes = drm_format_num_planes(format);
218         paddr_reg = layer + VL_Y;
219         for (i = 0; i < num_planes; i++) {
220                 cma_obj = drm_fb_cma_get_gem_obj(fb, i);
221                 paddr = cma_obj->paddr + fb->offsets[i];
222                 paddr += src_y * fb->pitches[i];
223                 paddr += src_x * drm_format_plane_cpp(format, i);
224                 zx_writel(paddr_reg, paddr);
225                 paddr_reg += 4;
226         }
227
228         /* Set up source height/width register */
229         zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
230
231         /* Set up start position register */
232         zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
233
234         /* Set up end position register */
235         zx_writel(layer + VL_POS_END,
236                   GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
237
238         /* Strides of Cb and Cr planes should be identical */
239         zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) |
240                   CHROMA_STRIDE(fb->pitches[1]));
241
242         /* Set up video layer data format */
243         fmt = zx_vl_get_fmt(format);
244         if (fmt >= 0)
245                 zx_writel(layer + VL_CTRL1, fmt);
246
247         /* Always use scaler since it exists (set for not bypass) */
248         zx_writel_mask(layer + VL_CTRL2, VL_SCALER_BYPASS_MODE,
249                        VL_SCALER_BYPASS_MODE);
250
251         zx_vl_rsz_setup(zplane, format, src_w, src_h, dst_w, dst_h);
252
253         /* Enable HBSC block */
254         zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
255
256         zx_vou_layer_enable(plane);
257
258         zx_vl_set_update(zplane);
259 }
260
261 static void zx_plane_atomic_disable(struct drm_plane *plane,
262                                     struct drm_plane_state *old_state)
263 {
264         struct zx_plane *zplane = to_zx_plane(plane);
265         void __iomem *hbsc = zplane->hbsc;
266
267         zx_vou_layer_disable(plane, old_state);
268
269         /* Disable HBSC block */
270         zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
271 }
272
273 static const struct drm_plane_helper_funcs zx_vl_plane_helper_funcs = {
274         .atomic_check = zx_vl_plane_atomic_check,
275         .atomic_update = zx_vl_plane_atomic_update,
276         .atomic_disable = zx_plane_atomic_disable,
277 };
278
279 static int zx_gl_plane_atomic_check(struct drm_plane *plane,
280                                     struct drm_plane_state *plane_state)
281 {
282         struct drm_framebuffer *fb = plane_state->fb;
283         struct drm_crtc *crtc = plane_state->crtc;
284         struct drm_crtc_state *crtc_state;
285
286         if (!crtc || !fb)
287                 return 0;
288
289         crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
290                                                         crtc);
291         if (WARN_ON(!crtc_state))
292                 return -EINVAL;
293
294         /* nothing to check when disabling or disabled */
295         if (!crtc_state->enable)
296                 return 0;
297
298         /* plane must be enabled */
299         if (!plane_state->crtc)
300                 return -EINVAL;
301
302         return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
303                                                    DRM_PLANE_HELPER_NO_SCALING,
304                                                    DRM_PLANE_HELPER_NO_SCALING,
305                                                    false, true);
306 }
307
308 static int zx_gl_get_fmt(uint32_t format)
309 {
310         switch (format) {
311         case DRM_FORMAT_ARGB8888:
312         case DRM_FORMAT_XRGB8888:
313                 return GL_FMT_ARGB8888;
314         case DRM_FORMAT_RGB888:
315                 return GL_FMT_RGB888;
316         case DRM_FORMAT_RGB565:
317                 return GL_FMT_RGB565;
318         case DRM_FORMAT_ARGB1555:
319                 return GL_FMT_ARGB1555;
320         case DRM_FORMAT_ARGB4444:
321                 return GL_FMT_ARGB4444;
322         default:
323                 WARN_ONCE(1, "invalid pixel format %d\n", format);
324                 return -EINVAL;
325         }
326 }
327
328 static inline void zx_gl_set_update(struct zx_plane *zplane)
329 {
330         void __iomem *layer = zplane->layer;
331
332         zx_writel_mask(layer + GL_CTRL0, GL_UPDATE, GL_UPDATE);
333 }
334
335 static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
336 {
337         zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
338 }
339
340 static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
341                             u32 dst_w, u32 dst_h)
342 {
343         void __iomem *rsz = zplane->rsz;
344
345         zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
346         zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
347
348         zx_gl_rsz_set_update(zplane);
349 }
350
351 static void zx_gl_plane_atomic_update(struct drm_plane *plane,
352                                       struct drm_plane_state *old_state)
353 {
354         struct zx_plane *zplane = to_zx_plane(plane);
355         struct drm_framebuffer *fb = plane->state->fb;
356         struct drm_gem_cma_object *cma_obj;
357         void __iomem *layer = zplane->layer;
358         void __iomem *csc = zplane->csc;
359         void __iomem *hbsc = zplane->hbsc;
360         u32 src_x, src_y, src_w, src_h;
361         u32 dst_x, dst_y, dst_w, dst_h;
362         unsigned int bpp;
363         uint32_t format;
364         dma_addr_t paddr;
365         u32 stride;
366         int fmt;
367
368         if (!fb)
369                 return;
370
371         format = fb->format->format;
372         stride = fb->pitches[0];
373
374         src_x = plane->state->src_x >> 16;
375         src_y = plane->state->src_y >> 16;
376         src_w = plane->state->src_w >> 16;
377         src_h = plane->state->src_h >> 16;
378
379         dst_x = plane->state->crtc_x;
380         dst_y = plane->state->crtc_y;
381         dst_w = plane->state->crtc_w;
382         dst_h = plane->state->crtc_h;
383
384         bpp = fb->format->cpp[0];
385
386         cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
387         paddr = cma_obj->paddr + fb->offsets[0];
388         paddr += src_y * stride + src_x * bpp / 8;
389         zx_writel(layer + GL_ADDR, paddr);
390
391         /* Set up source height/width register */
392         zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
393
394         /* Set up start position register */
395         zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
396
397         /* Set up end position register */
398         zx_writel(layer + GL_POS_END,
399                   GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
400
401         /* Set up stride register */
402         zx_writel(layer + GL_STRIDE, stride & 0xffff);
403
404         /* Set up graphic layer data format */
405         fmt = zx_gl_get_fmt(format);
406         if (fmt >= 0)
407                 zx_writel_mask(layer + GL_CTRL1, GL_DATA_FMT_MASK,
408                                fmt << GL_DATA_FMT_SHIFT);
409
410         /* Initialize global alpha with a sane value */
411         zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK,
412                        0xff << GL_GLOBAL_ALPHA_SHIFT);
413
414         /* Setup CSC for the GL */
415         if (dst_h > 720)
416                 zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
417                                CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
418         else
419                 zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
420                                CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
421         zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, CSC_WORK_ENABLE);
422
423         /* Always use scaler since it exists (set for not bypass) */
424         zx_writel_mask(layer + GL_CTRL3, GL_SCALER_BYPASS_MODE,
425                        GL_SCALER_BYPASS_MODE);
426
427         zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
428
429         /* Enable HBSC block */
430         zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
431
432         zx_vou_layer_enable(plane);
433
434         zx_gl_set_update(zplane);
435 }
436
437 static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
438         .atomic_check = zx_gl_plane_atomic_check,
439         .atomic_update = zx_gl_plane_atomic_update,
440         .atomic_disable = zx_plane_atomic_disable,
441 };
442
443 static void zx_plane_destroy(struct drm_plane *plane)
444 {
445         drm_plane_cleanup(plane);
446 }
447
448 static const struct drm_plane_funcs zx_plane_funcs = {
449         .update_plane = drm_atomic_helper_update_plane,
450         .disable_plane = drm_atomic_helper_disable_plane,
451         .destroy = zx_plane_destroy,
452         .reset = drm_atomic_helper_plane_reset,
453         .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
454         .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
455 };
456
457 void zx_plane_set_update(struct drm_plane *plane)
458 {
459         struct zx_plane *zplane = to_zx_plane(plane);
460
461         /* Do nothing if the plane is not enabled */
462         if (!plane->state->crtc)
463                 return;
464
465         switch (plane->type) {
466         case DRM_PLANE_TYPE_PRIMARY:
467                 zx_gl_rsz_set_update(zplane);
468                 zx_gl_set_update(zplane);
469                 break;
470         case DRM_PLANE_TYPE_OVERLAY:
471                 zx_vl_rsz_set_update(zplane);
472                 zx_vl_set_update(zplane);
473                 break;
474         default:
475                 WARN_ONCE(1, "unsupported plane type %d\n", plane->type);
476         }
477 }
478
479 static void zx_plane_hbsc_init(struct zx_plane *zplane)
480 {
481         void __iomem *hbsc = zplane->hbsc;
482
483         /*
484          *  Initialize HBSC block with a sane configuration per recommedation
485          *  from ZTE BSP code.
486          */
487         zx_writel(hbsc + HBSC_SATURATION, 0x200);
488         zx_writel(hbsc + HBSC_HUE, 0x0);
489         zx_writel(hbsc + HBSC_BRIGHT, 0x0);
490         zx_writel(hbsc + HBSC_CONTRAST, 0x200);
491
492         zx_writel(hbsc + HBSC_THRESHOLD_COL1, (0x3ac << 16) | 0x40);
493         zx_writel(hbsc + HBSC_THRESHOLD_COL2, (0x3c0 << 16) | 0x40);
494         zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40);
495 }
496
497 int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane,
498                   enum drm_plane_type type)
499 {
500         const struct drm_plane_helper_funcs *helper;
501         struct drm_plane *plane = &zplane->plane;
502         struct device *dev = zplane->dev;
503         const uint32_t *formats;
504         unsigned int format_count;
505         int ret;
506
507         zx_plane_hbsc_init(zplane);
508
509         switch (type) {
510         case DRM_PLANE_TYPE_PRIMARY:
511                 helper = &zx_gl_plane_helper_funcs;
512                 formats = gl_formats;
513                 format_count = ARRAY_SIZE(gl_formats);
514                 break;
515         case DRM_PLANE_TYPE_OVERLAY:
516                 helper = &zx_vl_plane_helper_funcs;
517                 formats = vl_formats;
518                 format_count = ARRAY_SIZE(vl_formats);
519                 break;
520         default:
521                 return -ENODEV;
522         }
523
524         ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
525                                        &zx_plane_funcs, formats, format_count,
526                                        NULL, type, NULL);
527         if (ret) {
528                 DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
529                 return ret;
530         }
531
532         drm_plane_helper_add(plane, helper);
533
534         return 0;
535 }