1
2
3
4
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_fourcc.h>
11#include <drm/drm_gem_cma_helper.h>
12#include <drm/drm_modeset_helper_vtables.h>
13#include <drm/drm_plane_helper.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
21static 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
30static const uint32_t vl_formats[] = {
31 DRM_FORMAT_NV12,
32 DRM_FORMAT_YUV420,
33 DRM_FORMAT_YUYV,
34 DRM_FORMAT_YVYU,
35 DRM_FORMAT_UYVY,
36 DRM_FORMAT_VYUY,
37 DRM_FORMAT_YUV444,
38
39
40
41
42
43
44};
45
46#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
47
48static 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 || WARN_ON(!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
66 if (!crtc_state->enable)
67 return 0;
68
69
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
78static 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
101static 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
108static inline void zx_vl_rsz_set_update(struct zx_plane *zplane)
109{
110 zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1);
111}
112
113static 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
132static 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
147static 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
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
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
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
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
181static 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
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
227 zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
228
229
230 zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
231
232
233 zx_writel(layer + VL_POS_END,
234 GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
235
236
237 zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) |
238 CHROMA_STRIDE(fb->pitches[1]));
239
240
241 fmt = zx_vl_get_fmt(format);
242 if (fmt >= 0)
243 zx_writel(layer + VL_CTRL1, fmt);
244
245
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
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
259static 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
268 zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
269}
270
271static 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
277static 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 || WARN_ON(!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
293 if (!crtc_state->enable)
294 return 0;
295
296
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
306static 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
326static 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
333static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
334{
335 zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
336}
337
338static 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
349static 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
390 zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
391
392
393 zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
394
395
396 zx_writel(layer + GL_POS_END,
397 GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
398
399
400 zx_writel(layer + GL_STRIDE, stride & 0xffff);
401
402
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
409 zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK,
410 0xff << GL_GLOBAL_ALPHA_SHIFT);
411
412
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
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
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
435static 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
441static void zx_plane_destroy(struct drm_plane *plane)
442{
443 drm_plane_cleanup(plane);
444}
445
446static 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
455void zx_plane_set_update(struct drm_plane *plane)
456{
457 struct zx_plane *zplane = to_zx_plane(plane);
458
459
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
477static void zx_plane_hbsc_init(struct zx_plane *zplane)
478{
479 void __iomem *hbsc = zplane->hbsc;
480
481
482
483
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
495int 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}
534