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