2 * Copyright 2016 Linaro Ltd.
3 * Copyright 2016 ZTE Corporation.
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.
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>
19 #include "zx_common_regs.h"
20 #include "zx_drm_drv.h"
22 #include "zx_plane_regs.h"
25 static const uint32_t gl_formats
[] = {
34 static const uint32_t vl_formats
[] = {
35 DRM_FORMAT_NV12
, /* Semi-planar YUV420 */
36 DRM_FORMAT_YUV420
, /* Planar YUV420 */
37 DRM_FORMAT_YUYV
, /* Packed YUV422 */
41 DRM_FORMAT_YUV444
, /* YUV444 8bit */
43 * TODO: add formats below that HW supports:
50 #define FRAC_16_16(mult, div) (((mult) << 16) / (div))
52 static int zx_vl_plane_atomic_check(struct drm_plane
*plane
,
53 struct drm_plane_state
*plane_state
)
55 struct drm_framebuffer
*fb
= plane_state
->fb
;
56 struct drm_crtc
*crtc
= plane_state
->crtc
;
57 struct drm_crtc_state
*crtc_state
;
59 int min_scale
= FRAC_16_16(1, 8);
60 int max_scale
= FRAC_16_16(8, 1);
65 crtc_state
= drm_atomic_get_existing_crtc_state(plane_state
->state
,
67 if (WARN_ON(!crtc_state
))
70 /* nothing to check when disabling or disabled */
71 if (!crtc_state
->enable
)
74 /* plane must be enabled */
75 if (!plane_state
->crtc
)
80 clip
.x2
= crtc_state
->adjusted_mode
.hdisplay
;
81 clip
.y2
= crtc_state
->adjusted_mode
.vdisplay
;
83 return drm_plane_helper_check_state(plane_state
, &clip
,
88 static int zx_vl_get_fmt(uint32_t format
)
93 case DRM_FORMAT_YUV420
:
94 return VL_YUV420_PLANAR
| VL_FMT_YUV420
;
96 return VL_YUV422_YUYV
| VL_FMT_YUV422
;
98 return VL_YUV422_YVYU
| VL_FMT_YUV422
;
100 return VL_YUV422_UYVY
| VL_FMT_YUV422
;
101 case DRM_FORMAT_VYUY
:
102 return VL_YUV422_VYUY
| VL_FMT_YUV422
;
103 case DRM_FORMAT_YUV444
:
104 return VL_FMT_YUV444_8BIT
;
106 WARN_ONCE(1, "invalid pixel format %d\n", format
);
111 static inline void zx_vl_set_update(struct zx_plane
*zplane
)
113 void __iomem
*layer
= zplane
->layer
;
115 zx_writel_mask(layer
+ VL_CTRL0
, VL_UPDATE
, VL_UPDATE
);
118 static inline void zx_vl_rsz_set_update(struct zx_plane
*zplane
)
120 zx_writel(zplane
->rsz
+ RSZ_VL_ENABLE_CFG
, 1);
123 static int zx_vl_rsz_get_fmt(uint32_t format
)
126 case DRM_FORMAT_NV12
:
127 case DRM_FORMAT_YUV420
:
128 return RSZ_VL_FMT_YCBCR420
;
129 case DRM_FORMAT_YUYV
:
130 case DRM_FORMAT_YVYU
:
131 case DRM_FORMAT_UYVY
:
132 case DRM_FORMAT_VYUY
:
133 return RSZ_VL_FMT_YCBCR422
;
134 case DRM_FORMAT_YUV444
:
135 return RSZ_VL_FMT_YCBCR444
;
137 WARN_ONCE(1, "invalid pixel format %d\n", format
);
142 static inline u32
rsz_step_value(u32 src
, u32 dst
)
149 val
= RSZ_PARA_STEP((src
<< 16) / dst
);
151 val
= RSZ_DATA_STEP(src
/ dst
) |
152 RSZ_PARA_STEP(((src
<< 16) / dst
) & 0xffff);
157 static void zx_vl_rsz_setup(struct zx_plane
*zplane
, uint32_t format
,
158 u32 src_w
, u32 src_h
, u32 dst_w
, u32 dst_h
)
160 void __iomem
*rsz
= zplane
->rsz
;
161 u32 src_chroma_w
= src_w
;
162 u32 src_chroma_h
= src_h
;
165 /* Set up source and destination resolution */
166 zx_writel(rsz
+ RSZ_SRC_CFG
, RSZ_VER(src_h
- 1) | RSZ_HOR(src_w
- 1));
167 zx_writel(rsz
+ RSZ_DEST_CFG
, RSZ_VER(dst_h
- 1) | RSZ_HOR(dst_w
- 1));
169 /* Configure data format for VL RSZ */
170 fmt
= zx_vl_rsz_get_fmt(format
);
172 zx_writel_mask(rsz
+ RSZ_VL_CTRL_CFG
, RSZ_VL_FMT_MASK
, fmt
);
174 /* Calculate Chroma height and width */
175 if (fmt
== RSZ_VL_FMT_YCBCR420
) {
176 src_chroma_w
= src_w
>> 1;
177 src_chroma_h
= src_h
>> 1;
178 } else if (fmt
== RSZ_VL_FMT_YCBCR422
) {
179 src_chroma_w
= src_w
>> 1;
182 /* Set up Luma and Chroma step registers */
183 zx_writel(rsz
+ RSZ_VL_LUMA_HOR
, rsz_step_value(src_w
, dst_w
));
184 zx_writel(rsz
+ RSZ_VL_LUMA_VER
, rsz_step_value(src_h
, dst_h
));
185 zx_writel(rsz
+ RSZ_VL_CHROMA_HOR
, rsz_step_value(src_chroma_w
, dst_w
));
186 zx_writel(rsz
+ RSZ_VL_CHROMA_VER
, rsz_step_value(src_chroma_h
, dst_h
));
188 zx_vl_rsz_set_update(zplane
);
191 static void zx_vl_plane_atomic_update(struct drm_plane
*plane
,
192 struct drm_plane_state
*old_state
)
194 struct zx_plane
*zplane
= to_zx_plane(plane
);
195 struct drm_plane_state
*state
= plane
->state
;
196 struct drm_framebuffer
*fb
= state
->fb
;
197 struct drm_rect
*src
= &state
->src
;
198 struct drm_rect
*dst
= &state
->dst
;
199 struct drm_gem_cma_object
*cma_obj
;
200 void __iomem
*layer
= zplane
->layer
;
201 void __iomem
*hbsc
= zplane
->hbsc
;
202 void __iomem
*paddr_reg
;
204 u32 src_x
, src_y
, src_w
, src_h
;
205 u32 dst_x
, dst_y
, dst_w
, dst_h
;
214 format
= fb
->format
->format
;
216 src_x
= src
->x1
>> 16;
217 src_y
= src
->y1
>> 16;
218 src_w
= drm_rect_width(src
) >> 16;
219 src_h
= drm_rect_height(src
) >> 16;
223 dst_w
= drm_rect_width(dst
);
224 dst_h
= drm_rect_height(dst
);
226 /* Set up data address registers for Y, Cb and Cr planes */
227 num_planes
= drm_format_num_planes(format
);
228 paddr_reg
= layer
+ VL_Y
;
229 for (i
= 0; i
< num_planes
; i
++) {
230 cma_obj
= drm_fb_cma_get_gem_obj(fb
, i
);
231 paddr
= cma_obj
->paddr
+ fb
->offsets
[i
];
232 paddr
+= src_y
* fb
->pitches
[i
];
233 paddr
+= src_x
* drm_format_plane_cpp(format
, i
);
234 zx_writel(paddr_reg
, paddr
);
238 /* Set up source height/width register */
239 zx_writel(layer
+ VL_SRC_SIZE
, GL_SRC_W(src_w
) | GL_SRC_H(src_h
));
241 /* Set up start position register */
242 zx_writel(layer
+ VL_POS_START
, GL_POS_X(dst_x
) | GL_POS_Y(dst_y
));
244 /* Set up end position register */
245 zx_writel(layer
+ VL_POS_END
,
246 GL_POS_X(dst_x
+ dst_w
) | GL_POS_Y(dst_y
+ dst_h
));
248 /* Strides of Cb and Cr planes should be identical */
249 zx_writel(layer
+ VL_STRIDE
, LUMA_STRIDE(fb
->pitches
[0]) |
250 CHROMA_STRIDE(fb
->pitches
[1]));
252 /* Set up video layer data format */
253 fmt
= zx_vl_get_fmt(format
);
255 zx_writel(layer
+ VL_CTRL1
, fmt
);
257 /* Always use scaler since it exists (set for not bypass) */
258 zx_writel_mask(layer
+ VL_CTRL2
, VL_SCALER_BYPASS_MODE
,
259 VL_SCALER_BYPASS_MODE
);
261 zx_vl_rsz_setup(zplane
, format
, src_w
, src_h
, dst_w
, dst_h
);
263 /* Enable HBSC block */
264 zx_writel_mask(hbsc
+ HBSC_CTRL0
, HBSC_CTRL_EN
, HBSC_CTRL_EN
);
266 zx_vou_layer_enable(plane
);
268 zx_vl_set_update(zplane
);
271 static void zx_plane_atomic_disable(struct drm_plane
*plane
,
272 struct drm_plane_state
*old_state
)
274 struct zx_plane
*zplane
= to_zx_plane(plane
);
275 void __iomem
*hbsc
= zplane
->hbsc
;
277 zx_vou_layer_disable(plane
);
279 /* Disable HBSC block */
280 zx_writel_mask(hbsc
+ HBSC_CTRL0
, HBSC_CTRL_EN
, 0);
283 static const struct drm_plane_helper_funcs zx_vl_plane_helper_funcs
= {
284 .atomic_check
= zx_vl_plane_atomic_check
,
285 .atomic_update
= zx_vl_plane_atomic_update
,
286 .atomic_disable
= zx_plane_atomic_disable
,
289 static int zx_gl_plane_atomic_check(struct drm_plane
*plane
,
290 struct drm_plane_state
*plane_state
)
292 struct drm_framebuffer
*fb
= plane_state
->fb
;
293 struct drm_crtc
*crtc
= plane_state
->crtc
;
294 struct drm_crtc_state
*crtc_state
;
295 struct drm_rect clip
;
300 crtc_state
= drm_atomic_get_existing_crtc_state(plane_state
->state
,
302 if (WARN_ON(!crtc_state
))
305 /* nothing to check when disabling or disabled */
306 if (!crtc_state
->enable
)
309 /* plane must be enabled */
310 if (!plane_state
->crtc
)
315 clip
.x2
= crtc_state
->adjusted_mode
.hdisplay
;
316 clip
.y2
= crtc_state
->adjusted_mode
.vdisplay
;
318 return drm_plane_helper_check_state(plane_state
, &clip
,
319 DRM_PLANE_HELPER_NO_SCALING
,
320 DRM_PLANE_HELPER_NO_SCALING
,
324 static int zx_gl_get_fmt(uint32_t format
)
327 case DRM_FORMAT_ARGB8888
:
328 case DRM_FORMAT_XRGB8888
:
329 return GL_FMT_ARGB8888
;
330 case DRM_FORMAT_RGB888
:
331 return GL_FMT_RGB888
;
332 case DRM_FORMAT_RGB565
:
333 return GL_FMT_RGB565
;
334 case DRM_FORMAT_ARGB1555
:
335 return GL_FMT_ARGB1555
;
336 case DRM_FORMAT_ARGB4444
:
337 return GL_FMT_ARGB4444
;
339 WARN_ONCE(1, "invalid pixel format %d\n", format
);
344 static inline void zx_gl_set_update(struct zx_plane
*zplane
)
346 void __iomem
*layer
= zplane
->layer
;
348 zx_writel_mask(layer
+ GL_CTRL0
, GL_UPDATE
, GL_UPDATE
);
351 static inline void zx_gl_rsz_set_update(struct zx_plane
*zplane
)
353 zx_writel(zplane
->rsz
+ RSZ_ENABLE_CFG
, 1);
356 static void zx_gl_rsz_setup(struct zx_plane
*zplane
, u32 src_w
, u32 src_h
,
357 u32 dst_w
, u32 dst_h
)
359 void __iomem
*rsz
= zplane
->rsz
;
361 zx_writel(rsz
+ RSZ_SRC_CFG
, RSZ_VER(src_h
- 1) | RSZ_HOR(src_w
- 1));
362 zx_writel(rsz
+ RSZ_DEST_CFG
, RSZ_VER(dst_h
- 1) | RSZ_HOR(dst_w
- 1));
364 zx_gl_rsz_set_update(zplane
);
367 static void zx_gl_plane_atomic_update(struct drm_plane
*plane
,
368 struct drm_plane_state
*old_state
)
370 struct zx_plane
*zplane
= to_zx_plane(plane
);
371 struct drm_framebuffer
*fb
= plane
->state
->fb
;
372 struct drm_gem_cma_object
*cma_obj
;
373 void __iomem
*layer
= zplane
->layer
;
374 void __iomem
*csc
= zplane
->csc
;
375 void __iomem
*hbsc
= zplane
->hbsc
;
376 u32 src_x
, src_y
, src_w
, src_h
;
377 u32 dst_x
, dst_y
, dst_w
, dst_h
;
387 format
= fb
->format
->format
;
388 stride
= fb
->pitches
[0];
390 src_x
= plane
->state
->src_x
>> 16;
391 src_y
= plane
->state
->src_y
>> 16;
392 src_w
= plane
->state
->src_w
>> 16;
393 src_h
= plane
->state
->src_h
>> 16;
395 dst_x
= plane
->state
->crtc_x
;
396 dst_y
= plane
->state
->crtc_y
;
397 dst_w
= plane
->state
->crtc_w
;
398 dst_h
= plane
->state
->crtc_h
;
400 bpp
= fb
->format
->cpp
[0];
402 cma_obj
= drm_fb_cma_get_gem_obj(fb
, 0);
403 paddr
= cma_obj
->paddr
+ fb
->offsets
[0];
404 paddr
+= src_y
* stride
+ src_x
* bpp
/ 8;
405 zx_writel(layer
+ GL_ADDR
, paddr
);
407 /* Set up source height/width register */
408 zx_writel(layer
+ GL_SRC_SIZE
, GL_SRC_W(src_w
) | GL_SRC_H(src_h
));
410 /* Set up start position register */
411 zx_writel(layer
+ GL_POS_START
, GL_POS_X(dst_x
) | GL_POS_Y(dst_y
));
413 /* Set up end position register */
414 zx_writel(layer
+ GL_POS_END
,
415 GL_POS_X(dst_x
+ dst_w
) | GL_POS_Y(dst_y
+ dst_h
));
417 /* Set up stride register */
418 zx_writel(layer
+ GL_STRIDE
, stride
& 0xffff);
420 /* Set up graphic layer data format */
421 fmt
= zx_gl_get_fmt(format
);
423 zx_writel_mask(layer
+ GL_CTRL1
, GL_DATA_FMT_MASK
,
424 fmt
<< GL_DATA_FMT_SHIFT
);
426 /* Initialize global alpha with a sane value */
427 zx_writel_mask(layer
+ GL_CTRL2
, GL_GLOBAL_ALPHA_MASK
,
428 0xff << GL_GLOBAL_ALPHA_SHIFT
);
430 /* Setup CSC for the GL */
432 zx_writel_mask(csc
+ CSC_CTRL0
, CSC_COV_MODE_MASK
,
433 CSC_BT709_IMAGE_RGB2YCBCR
<< CSC_COV_MODE_SHIFT
);
435 zx_writel_mask(csc
+ CSC_CTRL0
, CSC_COV_MODE_MASK
,
436 CSC_BT601_IMAGE_RGB2YCBCR
<< CSC_COV_MODE_SHIFT
);
437 zx_writel_mask(csc
+ CSC_CTRL0
, CSC_WORK_ENABLE
, CSC_WORK_ENABLE
);
439 /* Always use scaler since it exists (set for not bypass) */
440 zx_writel_mask(layer
+ GL_CTRL3
, GL_SCALER_BYPASS_MODE
,
441 GL_SCALER_BYPASS_MODE
);
443 zx_gl_rsz_setup(zplane
, src_w
, src_h
, dst_w
, dst_h
);
445 /* Enable HBSC block */
446 zx_writel_mask(hbsc
+ HBSC_CTRL0
, HBSC_CTRL_EN
, HBSC_CTRL_EN
);
448 zx_vou_layer_enable(plane
);
450 zx_gl_set_update(zplane
);
453 static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs
= {
454 .atomic_check
= zx_gl_plane_atomic_check
,
455 .atomic_update
= zx_gl_plane_atomic_update
,
456 .atomic_disable
= zx_plane_atomic_disable
,
459 static void zx_plane_destroy(struct drm_plane
*plane
)
461 drm_plane_helper_disable(plane
);
462 drm_plane_cleanup(plane
);
465 static const struct drm_plane_funcs zx_plane_funcs
= {
466 .update_plane
= drm_atomic_helper_update_plane
,
467 .disable_plane
= drm_atomic_helper_disable_plane
,
468 .destroy
= zx_plane_destroy
,
469 .reset
= drm_atomic_helper_plane_reset
,
470 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
471 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
474 void zx_plane_set_update(struct drm_plane
*plane
)
476 struct zx_plane
*zplane
= to_zx_plane(plane
);
478 /* Do nothing if the plane is not enabled */
479 if (!plane
->state
->crtc
)
482 switch (plane
->type
) {
483 case DRM_PLANE_TYPE_PRIMARY
:
484 zx_gl_rsz_set_update(zplane
);
485 zx_gl_set_update(zplane
);
487 case DRM_PLANE_TYPE_OVERLAY
:
488 zx_vl_rsz_set_update(zplane
);
489 zx_vl_set_update(zplane
);
492 WARN_ONCE(1, "unsupported plane type %d\n", plane
->type
);
496 static void zx_plane_hbsc_init(struct zx_plane
*zplane
)
498 void __iomem
*hbsc
= zplane
->hbsc
;
501 * Initialize HBSC block with a sane configuration per recommedation
504 zx_writel(hbsc
+ HBSC_SATURATION
, 0x200);
505 zx_writel(hbsc
+ HBSC_HUE
, 0x0);
506 zx_writel(hbsc
+ HBSC_BRIGHT
, 0x0);
507 zx_writel(hbsc
+ HBSC_CONTRAST
, 0x200);
509 zx_writel(hbsc
+ HBSC_THRESHOLD_COL1
, (0x3ac << 16) | 0x40);
510 zx_writel(hbsc
+ HBSC_THRESHOLD_COL2
, (0x3c0 << 16) | 0x40);
511 zx_writel(hbsc
+ HBSC_THRESHOLD_COL3
, (0x3c0 << 16) | 0x40);
514 int zx_plane_init(struct drm_device
*drm
, struct zx_plane
*zplane
,
515 enum drm_plane_type type
)
517 const struct drm_plane_helper_funcs
*helper
;
518 struct drm_plane
*plane
= &zplane
->plane
;
519 struct device
*dev
= zplane
->dev
;
520 const uint32_t *formats
;
521 unsigned int format_count
;
524 zx_plane_hbsc_init(zplane
);
527 case DRM_PLANE_TYPE_PRIMARY
:
528 helper
= &zx_gl_plane_helper_funcs
;
529 formats
= gl_formats
;
530 format_count
= ARRAY_SIZE(gl_formats
);
532 case DRM_PLANE_TYPE_OVERLAY
:
533 helper
= &zx_vl_plane_helper_funcs
;
534 formats
= vl_formats
;
535 format_count
= ARRAY_SIZE(vl_formats
);
541 ret
= drm_universal_plane_init(drm
, plane
, VOU_CRTC_MASK
,
542 &zx_plane_funcs
, formats
, format_count
,
545 DRM_DEV_ERROR(dev
, "failed to init universal plane: %d\n", ret
);
549 drm_plane_helper_add(plane
, helper
);