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