Merge tag 'for-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power...
[linux-2.6-microblaze.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 i;
199
200         if (!fb)
201                 return;
202
203         format = fb->format->format;
204
205         src_x = src->x1 >> 16;
206         src_y = src->y1 >> 16;
207         src_w = drm_rect_width(src) >> 16;
208         src_h = drm_rect_height(src) >> 16;
209
210         dst_x = dst->x1;
211         dst_y = dst->y1;
212         dst_w = drm_rect_width(dst);
213         dst_h = drm_rect_height(dst);
214
215         /* Set up data address registers for Y, Cb and Cr planes */
216         paddr_reg = layer + VL_Y;
217         for (i = 0; i < fb->format->num_planes; i++) {
218                 cma_obj = drm_fb_cma_get_gem_obj(fb, i);
219                 paddr = cma_obj->paddr + fb->offsets[i];
220                 paddr += src_y * fb->pitches[i];
221                 paddr += src_x * fb->format->cpp[i];
222                 zx_writel(paddr_reg, paddr);
223                 paddr_reg += 4;
224         }
225
226         /* Set up source height/width register */
227         zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
228
229         /* Set up start position register */
230         zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
231
232         /* Set up end position register */
233         zx_writel(layer + VL_POS_END,
234                   GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
235
236         /* Strides of Cb and Cr planes should be identical */
237         zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) |
238                   CHROMA_STRIDE(fb->pitches[1]));
239
240         /* Set up video layer data format */
241         fmt = zx_vl_get_fmt(format);
242         if (fmt >= 0)
243                 zx_writel(layer + VL_CTRL1, fmt);
244
245         /* Always use scaler since it exists (set for not bypass) */
246         zx_writel_mask(layer + VL_CTRL2, VL_SCALER_BYPASS_MODE,
247                        VL_SCALER_BYPASS_MODE);
248
249         zx_vl_rsz_setup(zplane, format, src_w, src_h, dst_w, dst_h);
250
251         /* Enable HBSC block */
252         zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
253
254         zx_vou_layer_enable(plane);
255
256         zx_vl_set_update(zplane);
257 }
258
259 static void zx_plane_atomic_disable(struct drm_plane *plane,
260                                     struct drm_plane_state *old_state)
261 {
262         struct zx_plane *zplane = to_zx_plane(plane);
263         void __iomem *hbsc = zplane->hbsc;
264
265         zx_vou_layer_disable(plane, old_state);
266
267         /* Disable HBSC block */
268         zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
269 }
270
271 static const struct drm_plane_helper_funcs zx_vl_plane_helper_funcs = {
272         .atomic_check = zx_vl_plane_atomic_check,
273         .atomic_update = zx_vl_plane_atomic_update,
274         .atomic_disable = zx_plane_atomic_disable,
275 };
276
277 static int zx_gl_plane_atomic_check(struct drm_plane *plane,
278                                     struct drm_plane_state *plane_state)
279 {
280         struct drm_framebuffer *fb = plane_state->fb;
281         struct drm_crtc *crtc = plane_state->crtc;
282         struct drm_crtc_state *crtc_state;
283
284         if (!crtc || !fb)
285                 return 0;
286
287         crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
288                                                         crtc);
289         if (WARN_ON(!crtc_state))
290                 return -EINVAL;
291
292         /* nothing to check when disabling or disabled */
293         if (!crtc_state->enable)
294                 return 0;
295
296         /* plane must be enabled */
297         if (!plane_state->crtc)
298                 return -EINVAL;
299
300         return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
301                                                    DRM_PLANE_HELPER_NO_SCALING,
302                                                    DRM_PLANE_HELPER_NO_SCALING,
303                                                    false, true);
304 }
305
306 static int zx_gl_get_fmt(uint32_t format)
307 {
308         switch (format) {
309         case DRM_FORMAT_ARGB8888:
310         case DRM_FORMAT_XRGB8888:
311                 return GL_FMT_ARGB8888;
312         case DRM_FORMAT_RGB888:
313                 return GL_FMT_RGB888;
314         case DRM_FORMAT_RGB565:
315                 return GL_FMT_RGB565;
316         case DRM_FORMAT_ARGB1555:
317                 return GL_FMT_ARGB1555;
318         case DRM_FORMAT_ARGB4444:
319                 return GL_FMT_ARGB4444;
320         default:
321                 WARN_ONCE(1, "invalid pixel format %d\n", format);
322                 return -EINVAL;
323         }
324 }
325
326 static inline void zx_gl_set_update(struct zx_plane *zplane)
327 {
328         void __iomem *layer = zplane->layer;
329
330         zx_writel_mask(layer + GL_CTRL0, GL_UPDATE, GL_UPDATE);
331 }
332
333 static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
334 {
335         zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
336 }
337
338 static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
339                             u32 dst_w, u32 dst_h)
340 {
341         void __iomem *rsz = zplane->rsz;
342
343         zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
344         zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
345
346         zx_gl_rsz_set_update(zplane);
347 }
348
349 static void zx_gl_plane_atomic_update(struct drm_plane *plane,
350                                       struct drm_plane_state *old_state)
351 {
352         struct zx_plane *zplane = to_zx_plane(plane);
353         struct drm_framebuffer *fb = plane->state->fb;
354         struct drm_gem_cma_object *cma_obj;
355         void __iomem *layer = zplane->layer;
356         void __iomem *csc = zplane->csc;
357         void __iomem *hbsc = zplane->hbsc;
358         u32 src_x, src_y, src_w, src_h;
359         u32 dst_x, dst_y, dst_w, dst_h;
360         unsigned int bpp;
361         uint32_t format;
362         dma_addr_t paddr;
363         u32 stride;
364         int fmt;
365
366         if (!fb)
367                 return;
368
369         format = fb->format->format;
370         stride = fb->pitches[0];
371
372         src_x = plane->state->src_x >> 16;
373         src_y = plane->state->src_y >> 16;
374         src_w = plane->state->src_w >> 16;
375         src_h = plane->state->src_h >> 16;
376
377         dst_x = plane->state->crtc_x;
378         dst_y = plane->state->crtc_y;
379         dst_w = plane->state->crtc_w;
380         dst_h = plane->state->crtc_h;
381
382         bpp = fb->format->cpp[0];
383
384         cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
385         paddr = cma_obj->paddr + fb->offsets[0];
386         paddr += src_y * stride + src_x * bpp / 8;
387         zx_writel(layer + GL_ADDR, paddr);
388
389         /* Set up source height/width register */
390         zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
391
392         /* Set up start position register */
393         zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
394
395         /* Set up end position register */
396         zx_writel(layer + GL_POS_END,
397                   GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
398
399         /* Set up stride register */
400         zx_writel(layer + GL_STRIDE, stride & 0xffff);
401
402         /* Set up graphic layer data format */
403         fmt = zx_gl_get_fmt(format);
404         if (fmt >= 0)
405                 zx_writel_mask(layer + GL_CTRL1, GL_DATA_FMT_MASK,
406                                fmt << GL_DATA_FMT_SHIFT);
407
408         /* Initialize global alpha with a sane value */
409         zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK,
410                        0xff << GL_GLOBAL_ALPHA_SHIFT);
411
412         /* Setup CSC for the GL */
413         if (dst_h > 720)
414                 zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
415                                CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
416         else
417                 zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
418                                CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
419         zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, CSC_WORK_ENABLE);
420
421         /* Always use scaler since it exists (set for not bypass) */
422         zx_writel_mask(layer + GL_CTRL3, GL_SCALER_BYPASS_MODE,
423                        GL_SCALER_BYPASS_MODE);
424
425         zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
426
427         /* Enable HBSC block */
428         zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
429
430         zx_vou_layer_enable(plane);
431
432         zx_gl_set_update(zplane);
433 }
434
435 static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
436         .atomic_check = zx_gl_plane_atomic_check,
437         .atomic_update = zx_gl_plane_atomic_update,
438         .atomic_disable = zx_plane_atomic_disable,
439 };
440
441 static void zx_plane_destroy(struct drm_plane *plane)
442 {
443         drm_plane_cleanup(plane);
444 }
445
446 static const struct drm_plane_funcs zx_plane_funcs = {
447         .update_plane = drm_atomic_helper_update_plane,
448         .disable_plane = drm_atomic_helper_disable_plane,
449         .destroy = zx_plane_destroy,
450         .reset = drm_atomic_helper_plane_reset,
451         .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
452         .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
453 };
454
455 void zx_plane_set_update(struct drm_plane *plane)
456 {
457         struct zx_plane *zplane = to_zx_plane(plane);
458
459         /* Do nothing if the plane is not enabled */
460         if (!plane->state->crtc)
461                 return;
462
463         switch (plane->type) {
464         case DRM_PLANE_TYPE_PRIMARY:
465                 zx_gl_rsz_set_update(zplane);
466                 zx_gl_set_update(zplane);
467                 break;
468         case DRM_PLANE_TYPE_OVERLAY:
469                 zx_vl_rsz_set_update(zplane);
470                 zx_vl_set_update(zplane);
471                 break;
472         default:
473                 WARN_ONCE(1, "unsupported plane type %d\n", plane->type);
474         }
475 }
476
477 static void zx_plane_hbsc_init(struct zx_plane *zplane)
478 {
479         void __iomem *hbsc = zplane->hbsc;
480
481         /*
482          *  Initialize HBSC block with a sane configuration per recommedation
483          *  from ZTE BSP code.
484          */
485         zx_writel(hbsc + HBSC_SATURATION, 0x200);
486         zx_writel(hbsc + HBSC_HUE, 0x0);
487         zx_writel(hbsc + HBSC_BRIGHT, 0x0);
488         zx_writel(hbsc + HBSC_CONTRAST, 0x200);
489
490         zx_writel(hbsc + HBSC_THRESHOLD_COL1, (0x3ac << 16) | 0x40);
491         zx_writel(hbsc + HBSC_THRESHOLD_COL2, (0x3c0 << 16) | 0x40);
492         zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40);
493 }
494
495 int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane,
496                   enum drm_plane_type type)
497 {
498         const struct drm_plane_helper_funcs *helper;
499         struct drm_plane *plane = &zplane->plane;
500         struct device *dev = zplane->dev;
501         const uint32_t *formats;
502         unsigned int format_count;
503         int ret;
504
505         zx_plane_hbsc_init(zplane);
506
507         switch (type) {
508         case DRM_PLANE_TYPE_PRIMARY:
509                 helper = &zx_gl_plane_helper_funcs;
510                 formats = gl_formats;
511                 format_count = ARRAY_SIZE(gl_formats);
512                 break;
513         case DRM_PLANE_TYPE_OVERLAY:
514                 helper = &zx_vl_plane_helper_funcs;
515                 formats = vl_formats;
516                 format_count = ARRAY_SIZE(vl_formats);
517                 break;
518         default:
519                 return -ENODEV;
520         }
521
522         ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
523                                        &zx_plane_funcs, formats, format_count,
524                                        NULL, type, NULL);
525         if (ret) {
526                 DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
527                 return ret;
528         }
529
530         drm_plane_helper_add(plane, helper);
531
532         return 0;
533 }