• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright 2016 Linaro Ltd.
4  * Copyright 2016 ZTE Corporation.
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 
21 static 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 
30 static const uint32_t vl_formats[] = {
31 	DRM_FORMAT_NV12,	/* Semi-planar YUV420 */
32 	DRM_FORMAT_YUV420,	/* Planar YUV420 */
33 	DRM_FORMAT_YUYV,	/* Packed YUV422 */
34 	DRM_FORMAT_YVYU,
35 	DRM_FORMAT_UYVY,
36 	DRM_FORMAT_VYUY,
37 	DRM_FORMAT_YUV444,	/* YUV444 8bit */
38 	/*
39 	 * TODO: add formats below that HW supports:
40 	 *  - YUV420 P010
41 	 *  - YUV420 Hantro
42 	 *  - YUV444 10bit
43 	 */
44 };
45 
46 #define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
47 
zx_vl_plane_atomic_check(struct drm_plane * plane,struct drm_plane_state * plane_state)48 static 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 	/* nothing to check when disabling or disabled */
66 	if (!crtc_state->enable)
67 		return 0;
68 
69 	/* plane must be enabled */
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 
zx_vl_get_fmt(uint32_t format)78 static 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 
zx_vl_set_update(struct zx_plane * zplane)101 static 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 
zx_vl_rsz_set_update(struct zx_plane * zplane)108 static inline void zx_vl_rsz_set_update(struct zx_plane *zplane)
109 {
110 	zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1);
111 }
112 
zx_vl_rsz_get_fmt(uint32_t format)113 static 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 
rsz_step_value(u32 src,u32 dst)132 static 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 
zx_vl_rsz_setup(struct zx_plane * zplane,uint32_t format,u32 src_w,u32 src_h,u32 dst_w,u32 dst_h)147 static 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 	/* Set up source and destination resolution */
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 	/* Configure data format for VL RSZ */
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 	/* Calculate Chroma height and width */
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 	/* Set up Luma and Chroma step registers */
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 
zx_vl_plane_atomic_update(struct drm_plane * plane,struct drm_plane_state * old_state)181 static 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 	/* Set up data address registers for Y, Cb and Cr planes */
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 	/* Set up source height/width register */
227 	zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
228 
229 	/* Set up start position register */
230 	zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
231 
232 	/* Set up end position register */
233 	zx_writel(layer + VL_POS_END,
234 		  GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
235 
236 	/* Strides of Cb and Cr planes should be identical */
237 	zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) |
238 		  CHROMA_STRIDE(fb->pitches[1]));
239 
240 	/* Set up video layer data format */
241 	fmt = zx_vl_get_fmt(format);
242 	if (fmt >= 0)
243 		zx_writel(layer + VL_CTRL1, fmt);
244 
245 	/* Always use scaler since it exists (set for not bypass) */
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 	/* Enable HBSC block */
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 
zx_plane_atomic_disable(struct drm_plane * plane,struct drm_plane_state * old_state)259 static 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 	/* Disable HBSC block */
268 	zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
269 }
270 
271 static 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 
zx_gl_plane_atomic_check(struct drm_plane * plane,struct drm_plane_state * plane_state)277 static 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 	/* nothing to check when disabling or disabled */
293 	if (!crtc_state->enable)
294 		return 0;
295 
296 	/* plane must be enabled */
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 
zx_gl_get_fmt(uint32_t format)306 static 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 
zx_gl_set_update(struct zx_plane * zplane)326 static 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 
zx_gl_rsz_set_update(struct zx_plane * zplane)333 static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
334 {
335 	zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
336 }
337 
zx_gl_rsz_setup(struct zx_plane * zplane,u32 src_w,u32 src_h,u32 dst_w,u32 dst_h)338 static 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 
zx_gl_plane_atomic_update(struct drm_plane * plane,struct drm_plane_state * old_state)349 static 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 	/* Set up source height/width register */
390 	zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
391 
392 	/* Set up start position register */
393 	zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
394 
395 	/* Set up end position register */
396 	zx_writel(layer + GL_POS_END,
397 		  GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
398 
399 	/* Set up stride register */
400 	zx_writel(layer + GL_STRIDE, stride & 0xffff);
401 
402 	/* Set up graphic layer data format */
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 	/* Initialize global alpha with a sane value */
409 	zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK,
410 		       0xff << GL_GLOBAL_ALPHA_SHIFT);
411 
412 	/* Setup CSC for the GL */
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 	/* Always use scaler since it exists (set for not bypass) */
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 	/* Enable HBSC block */
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 
435 static 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 
zx_plane_destroy(struct drm_plane * plane)441 static void zx_plane_destroy(struct drm_plane *plane)
442 {
443 	drm_plane_cleanup(plane);
444 }
445 
446 static 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 
zx_plane_set_update(struct drm_plane * plane)455 void zx_plane_set_update(struct drm_plane *plane)
456 {
457 	struct zx_plane *zplane = to_zx_plane(plane);
458 
459 	/* Do nothing if the plane is not enabled */
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 
zx_plane_hbsc_init(struct zx_plane * zplane)477 static void zx_plane_hbsc_init(struct zx_plane *zplane)
478 {
479 	void __iomem *hbsc = zplane->hbsc;
480 
481 	/*
482 	 *  Initialize HBSC block with a sane configuration per recommedation
483 	 *  from ZTE BSP code.
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 
zx_plane_init(struct drm_device * drm,struct zx_plane * zplane,enum drm_plane_type type)495 int 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