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_drm_drv.h"
21 #include "zx_plane_regs.h"
24 static const uint32_t gl_formats
[] = {
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 */
40 DRM_FORMAT_YUV444
, /* YUV444 8bit */
42 * TODO: add formats below that HW supports:
49 #define FRAC_16_16(mult, div) (((mult) << 16) / (div))
51 static int zx_vl_plane_atomic_check(struct drm_plane
*plane
,
52 struct drm_plane_state
*plane_state
)
54 struct drm_framebuffer
*fb
= plane_state
->fb
;
55 struct drm_crtc
*crtc
= plane_state
->crtc
;
56 struct drm_crtc_state
*crtc_state
;
58 int min_scale
= FRAC_16_16(1, 8);
59 int max_scale
= FRAC_16_16(8, 1);
64 crtc_state
= drm_atomic_get_existing_crtc_state(plane_state
->state
,
66 if (WARN_ON(!crtc_state
))
69 /* nothing to check when disabling or disabled */
70 if (!crtc_state
->enable
)
73 /* plane must be enabled */
74 if (!plane_state
->crtc
)
79 clip
.x2
= crtc_state
->adjusted_mode
.hdisplay
;
80 clip
.y2
= crtc_state
->adjusted_mode
.vdisplay
;
82 return drm_plane_helper_check_state(plane_state
, &clip
,
87 static int zx_vl_get_fmt(uint32_t format
)
92 case DRM_FORMAT_YUV420
:
93 return VL_YUV420_PLANAR
| VL_FMT_YUV420
;
95 return VL_YUV422_YUYV
| VL_FMT_YUV422
;
97 return VL_YUV422_YVYU
| VL_FMT_YUV422
;
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
;
105 WARN_ONCE(1, "invalid pixel format %d\n", format
);
110 static inline void zx_vl_set_update(struct zx_plane
*zplane
)
112 void __iomem
*layer
= zplane
->layer
;
114 zx_writel_mask(layer
+ VL_CTRL0
, VL_UPDATE
, VL_UPDATE
);
117 static inline void zx_vl_rsz_set_update(struct zx_plane
*zplane
)
119 zx_writel(zplane
->rsz
+ RSZ_VL_ENABLE_CFG
, 1);
122 static int zx_vl_rsz_get_fmt(uint32_t 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
;
136 WARN_ONCE(1, "invalid pixel format %d\n", format
);
141 static inline u32
rsz_step_value(u32 src
, u32 dst
)
148 val
= RSZ_PARA_STEP((src
<< 16) / dst
);
150 val
= RSZ_DATA_STEP(src
/ dst
) |
151 RSZ_PARA_STEP(((src
<< 16) / dst
) & 0xffff);
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
)
159 void __iomem
*rsz
= zplane
->rsz
;
160 u32 src_chroma_w
= src_w
;
161 u32 src_chroma_h
= src_h
;
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));
168 /* Configure data format for VL RSZ */
169 fmt
= zx_vl_rsz_get_fmt(format
);
171 zx_writel_mask(rsz
+ RSZ_VL_CTRL_CFG
, RSZ_VL_FMT_MASK
, fmt
);
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;
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
));
187 zx_vl_rsz_set_update(zplane
);
190 static void zx_vl_plane_atomic_update(struct drm_plane
*plane
,
191 struct drm_plane_state
*old_state
)
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
;
203 u32 src_x
, src_y
, src_w
, src_h
;
204 u32 dst_x
, dst_y
, dst_w
, dst_h
;
213 format
= fb
->format
->format
;
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;
222 dst_w
= drm_rect_width(dst
);
223 dst_h
= drm_rect_height(dst
);
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
);
237 /* Set up source height/width register */
238 zx_writel(layer
+ VL_SRC_SIZE
, GL_SRC_W(src_w
) | GL_SRC_H(src_h
));
240 /* Set up start position register */
241 zx_writel(layer
+ VL_POS_START
, GL_POS_X(dst_x
) | GL_POS_Y(dst_y
));
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
));
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]));
251 /* Set up video layer data format */
252 fmt
= zx_vl_get_fmt(format
);
254 zx_writel(layer
+ VL_CTRL1
, fmt
);
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
);
260 zx_vl_rsz_setup(zplane
, format
, src_w
, src_h
, dst_w
, dst_h
);
262 /* Enable HBSC block */
263 zx_writel_mask(hbsc
+ HBSC_CTRL0
, HBSC_CTRL_EN
, HBSC_CTRL_EN
);
265 zx_vou_layer_enable(plane
);
267 zx_vl_set_update(zplane
);
270 static void zx_plane_atomic_disable(struct drm_plane
*plane
,
271 struct drm_plane_state
*old_state
)
273 struct zx_plane
*zplane
= to_zx_plane(plane
);
274 void __iomem
*hbsc
= zplane
->hbsc
;
276 zx_vou_layer_disable(plane
);
278 /* Disable HBSC block */
279 zx_writel_mask(hbsc
+ HBSC_CTRL0
, HBSC_CTRL_EN
, 0);
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
,
288 static int zx_gl_plane_atomic_check(struct drm_plane
*plane
,
289 struct drm_plane_state
*plane_state
)
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
;
299 crtc_state
= drm_atomic_get_existing_crtc_state(plane_state
->state
,
301 if (WARN_ON(!crtc_state
))
304 /* nothing to check when disabling or disabled */
305 if (!crtc_state
->enable
)
308 /* plane must be enabled */
309 if (!plane_state
->crtc
)
314 clip
.x2
= crtc_state
->adjusted_mode
.hdisplay
;
315 clip
.y2
= crtc_state
->adjusted_mode
.vdisplay
;
317 return drm_plane_helper_check_state(plane_state
, &clip
,
318 DRM_PLANE_HELPER_NO_SCALING
,
319 DRM_PLANE_HELPER_NO_SCALING
,
323 static int zx_gl_get_fmt(uint32_t 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
;
338 WARN_ONCE(1, "invalid pixel format %d\n", format
);
343 static inline void zx_gl_set_update(struct zx_plane
*zplane
)
345 void __iomem
*layer
= zplane
->layer
;
347 zx_writel_mask(layer
+ GL_CTRL0
, GL_UPDATE
, GL_UPDATE
);
350 static inline void zx_gl_rsz_set_update(struct zx_plane
*zplane
)
352 zx_writel(zplane
->rsz
+ RSZ_ENABLE_CFG
, 1);
355 static void zx_gl_rsz_setup(struct zx_plane
*zplane
, u32 src_w
, u32 src_h
,
356 u32 dst_w
, u32 dst_h
)
358 void __iomem
*rsz
= zplane
->rsz
;
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));
363 zx_gl_rsz_set_update(zplane
);
366 static void zx_gl_plane_atomic_update(struct drm_plane
*plane
,
367 struct drm_plane_state
*old_state
)
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
;
386 format
= fb
->format
->format
;
387 stride
= fb
->pitches
[0];
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;
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
;
399 bpp
= fb
->format
->cpp
[0];
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
);
406 /* Set up source height/width register */
407 zx_writel(layer
+ GL_SRC_SIZE
, GL_SRC_W(src_w
) | GL_SRC_H(src_h
));
409 /* Set up start position register */
410 zx_writel(layer
+ GL_POS_START
, GL_POS_X(dst_x
) | GL_POS_Y(dst_y
));
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
));
416 /* Set up stride register */
417 zx_writel(layer
+ GL_STRIDE
, stride
& 0xffff);
419 /* Set up graphic layer data format */
420 fmt
= zx_gl_get_fmt(format
);
422 zx_writel_mask(layer
+ GL_CTRL1
, GL_DATA_FMT_MASK
,
423 fmt
<< GL_DATA_FMT_SHIFT
);
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
);
429 /* Setup CSC for the GL */
431 zx_writel_mask(csc
+ CSC_CTRL0
, CSC_COV_MODE_MASK
,
432 CSC_BT709_IMAGE_RGB2YCBCR
<< CSC_COV_MODE_SHIFT
);
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
);
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
);
442 zx_gl_rsz_setup(zplane
, src_w
, src_h
, dst_w
, dst_h
);
444 /* Enable HBSC block */
445 zx_writel_mask(hbsc
+ HBSC_CTRL0
, HBSC_CTRL_EN
, HBSC_CTRL_EN
);
447 zx_vou_layer_enable(plane
);
449 zx_gl_set_update(zplane
);
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
,
458 static void zx_plane_destroy(struct drm_plane
*plane
)
460 drm_plane_helper_disable(plane
);
461 drm_plane_cleanup(plane
);
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
,
473 void zx_plane_set_update(struct drm_plane
*plane
)
475 struct zx_plane
*zplane
= to_zx_plane(plane
);
477 /* Do nothing if the plane is not enabled */
478 if (!plane
->state
->crtc
)
481 switch (plane
->type
) {
482 case DRM_PLANE_TYPE_PRIMARY
:
483 zx_gl_rsz_set_update(zplane
);
484 zx_gl_set_update(zplane
);
486 case DRM_PLANE_TYPE_OVERLAY
:
487 zx_vl_rsz_set_update(zplane
);
488 zx_vl_set_update(zplane
);
491 WARN_ONCE(1, "unsupported plane type %d\n", plane
->type
);
495 static void zx_plane_hbsc_init(struct zx_plane
*zplane
)
497 void __iomem
*hbsc
= zplane
->hbsc
;
500 * Initialize HBSC block with a sane configuration per recommedation
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);
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);
513 int zx_plane_init(struct drm_device
*drm
, struct zx_plane
*zplane
,
514 enum drm_plane_type type
)
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
;
523 zx_plane_hbsc_init(zplane
);
526 case DRM_PLANE_TYPE_PRIMARY
:
527 helper
= &zx_gl_plane_helper_funcs
;
528 formats
= gl_formats
;
529 format_count
= ARRAY_SIZE(gl_formats
);
531 case DRM_PLANE_TYPE_OVERLAY
:
532 helper
= &zx_vl_plane_helper_funcs
;
533 formats
= vl_formats
;
534 format_count
= ARRAY_SIZE(vl_formats
);
540 ret
= drm_universal_plane_init(drm
, plane
, VOU_CRTC_MASK
,
541 &zx_plane_funcs
, formats
, format_count
,
544 DRM_DEV_ERROR(dev
, "failed to init universal plane: %d\n", ret
);
548 drm_plane_helper_add(plane
, helper
);