• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Linaro Ltd.
3  * Copyright 2016 ZTE Corporation.
4  *
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.
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 
25 static 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 
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 */
38 	DRM_FORMAT_YVYU,
39 	DRM_FORMAT_UYVY,
40 	DRM_FORMAT_VYUY,
41 	DRM_FORMAT_YUV444,	/* YUV444 8bit */
42 	/*
43 	 * TODO: add formats below that HW supports:
44 	 *  - YUV420 P010
45 	 *  - YUV420 Hantro
46 	 *  - YUV444 10bit
47 	 */
48 };
49 
50 #define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
51 
zx_vl_plane_atomic_check(struct drm_plane * plane,struct drm_plane_state * plane_state)52 static 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 	/* nothing to check when disabling or disabled */
70 	if (!crtc_state->enable)
71 		return 0;
72 
73 	/* plane must be enabled */
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 
zx_vl_get_fmt(uint32_t format)82 static 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 
zx_vl_set_update(struct zx_plane * zplane)105 static 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 
zx_vl_rsz_set_update(struct zx_plane * zplane)112 static inline void zx_vl_rsz_set_update(struct zx_plane *zplane)
113 {
114 	zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1);
115 }
116 
zx_vl_rsz_get_fmt(uint32_t format)117 static 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 
rsz_step_value(u32 src,u32 dst)136 static 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 
zx_vl_rsz_setup(struct zx_plane * zplane,uint32_t format,u32 src_w,u32 src_h,u32 dst_w,u32 dst_h)151 static 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 	/* Set up source and destination resolution */
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 	/* Configure data format for VL RSZ */
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 	/* Calculate Chroma height and width */
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 	/* Set up Luma and Chroma step registers */
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 
zx_vl_plane_atomic_update(struct drm_plane * plane,struct drm_plane_state * old_state)185 static 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 	/* Set up data address registers for Y, Cb and Cr planes */
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 	/* Set up source height/width register */
233 	zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
234 
235 	/* Set up start position register */
236 	zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
237 
238 	/* Set up end position register */
239 	zx_writel(layer + VL_POS_END,
240 		  GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
241 
242 	/* Strides of Cb and Cr planes should be identical */
243 	zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) |
244 		  CHROMA_STRIDE(fb->pitches[1]));
245 
246 	/* Set up video layer data format */
247 	fmt = zx_vl_get_fmt(format);
248 	if (fmt >= 0)
249 		zx_writel(layer + VL_CTRL1, fmt);
250 
251 	/* Always use scaler since it exists (set for not bypass) */
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 	/* Enable HBSC block */
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 
zx_plane_atomic_disable(struct drm_plane * plane,struct drm_plane_state * old_state)265 static 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 	/* Disable HBSC block */
274 	zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
275 }
276 
277 static 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 
zx_gl_plane_atomic_check(struct drm_plane * plane,struct drm_plane_state * plane_state)283 static 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 	/* nothing to check when disabling or disabled */
299 	if (!crtc_state->enable)
300 		return 0;
301 
302 	/* plane must be enabled */
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 
zx_gl_get_fmt(uint32_t format)312 static 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 
zx_gl_set_update(struct zx_plane * zplane)332 static 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 
zx_gl_rsz_set_update(struct zx_plane * zplane)339 static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
340 {
341 	zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
342 }
343 
zx_gl_rsz_setup(struct zx_plane * zplane,u32 src_w,u32 src_h,u32 dst_w,u32 dst_h)344 static 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 
zx_gl_plane_atomic_update(struct drm_plane * plane,struct drm_plane_state * old_state)355 static 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 	/* Set up source height/width register */
396 	zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
397 
398 	/* Set up start position register */
399 	zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
400 
401 	/* Set up end position register */
402 	zx_writel(layer + GL_POS_END,
403 		  GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
404 
405 	/* Set up stride register */
406 	zx_writel(layer + GL_STRIDE, stride & 0xffff);
407 
408 	/* Set up graphic layer data format */
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 	/* Initialize global alpha with a sane value */
415 	zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK,
416 		       0xff << GL_GLOBAL_ALPHA_SHIFT);
417 
418 	/* Setup CSC for the GL */
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 	/* Always use scaler since it exists (set for not bypass) */
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 	/* Enable HBSC block */
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 
441 static 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 
zx_plane_destroy(struct drm_plane * plane)447 static void zx_plane_destroy(struct drm_plane *plane)
448 {
449 	drm_plane_helper_disable(plane, NULL);
450 	drm_plane_cleanup(plane);
451 }
452 
453 static 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 
zx_plane_set_update(struct drm_plane * plane)462 void zx_plane_set_update(struct drm_plane *plane)
463 {
464 	struct zx_plane *zplane = to_zx_plane(plane);
465 
466 	/* Do nothing if the plane is not enabled */
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 
zx_plane_hbsc_init(struct zx_plane * zplane)484 static void zx_plane_hbsc_init(struct zx_plane *zplane)
485 {
486 	void __iomem *hbsc = zplane->hbsc;
487 
488 	/*
489 	 *  Initialize HBSC block with a sane configuration per recommedation
490 	 *  from ZTE BSP code.
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 
zx_plane_init(struct drm_device * drm,struct zx_plane * zplane,enum drm_plane_type type)502 int 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