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_atomic_state * state)48 static int zx_vl_plane_atomic_check(struct drm_plane *plane,
49 				    struct drm_atomic_state *state)
50 {
51 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
52 									     plane);
53 	struct drm_framebuffer *fb = plane_state->fb;
54 	struct drm_crtc *crtc = plane_state->crtc;
55 	struct drm_crtc_state *crtc_state;
56 	int min_scale = FRAC_16_16(1, 8);
57 	int max_scale = FRAC_16_16(8, 1);
58 
59 	if (!crtc || WARN_ON(!fb))
60 		return 0;
61 
62 	crtc_state = drm_atomic_get_existing_crtc_state(state,
63 							crtc);
64 	if (WARN_ON(!crtc_state))
65 		return -EINVAL;
66 
67 	/* nothing to check when disabling or disabled */
68 	if (!crtc_state->enable)
69 		return 0;
70 
71 	/* plane must be enabled */
72 	if (!plane_state->crtc)
73 		return -EINVAL;
74 
75 	return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
76 						   min_scale, max_scale,
77 						   true, true);
78 }
79 
zx_vl_get_fmt(uint32_t format)80 static int zx_vl_get_fmt(uint32_t format)
81 {
82 	switch (format) {
83 	case DRM_FORMAT_NV12:
84 		return VL_FMT_YUV420;
85 	case DRM_FORMAT_YUV420:
86 		return VL_YUV420_PLANAR | VL_FMT_YUV420;
87 	case DRM_FORMAT_YUYV:
88 		return VL_YUV422_YUYV | VL_FMT_YUV422;
89 	case DRM_FORMAT_YVYU:
90 		return VL_YUV422_YVYU | VL_FMT_YUV422;
91 	case DRM_FORMAT_UYVY:
92 		return VL_YUV422_UYVY | VL_FMT_YUV422;
93 	case DRM_FORMAT_VYUY:
94 		return VL_YUV422_VYUY | VL_FMT_YUV422;
95 	case DRM_FORMAT_YUV444:
96 		return VL_FMT_YUV444_8BIT;
97 	default:
98 		WARN_ONCE(1, "invalid pixel format %d\n", format);
99 		return -EINVAL;
100 	}
101 }
102 
zx_vl_set_update(struct zx_plane * zplane)103 static inline void zx_vl_set_update(struct zx_plane *zplane)
104 {
105 	void __iomem *layer = zplane->layer;
106 
107 	zx_writel_mask(layer + VL_CTRL0, VL_UPDATE, VL_UPDATE);
108 }
109 
zx_vl_rsz_set_update(struct zx_plane * zplane)110 static inline void zx_vl_rsz_set_update(struct zx_plane *zplane)
111 {
112 	zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1);
113 }
114 
zx_vl_rsz_get_fmt(uint32_t format)115 static int zx_vl_rsz_get_fmt(uint32_t format)
116 {
117 	switch (format) {
118 	case DRM_FORMAT_NV12:
119 	case DRM_FORMAT_YUV420:
120 		return RSZ_VL_FMT_YCBCR420;
121 	case DRM_FORMAT_YUYV:
122 	case DRM_FORMAT_YVYU:
123 	case DRM_FORMAT_UYVY:
124 	case DRM_FORMAT_VYUY:
125 		return RSZ_VL_FMT_YCBCR422;
126 	case DRM_FORMAT_YUV444:
127 		return RSZ_VL_FMT_YCBCR444;
128 	default:
129 		WARN_ONCE(1, "invalid pixel format %d\n", format);
130 		return -EINVAL;
131 	}
132 }
133 
rsz_step_value(u32 src,u32 dst)134 static inline u32 rsz_step_value(u32 src, u32 dst)
135 {
136 	u32 val = 0;
137 
138 	if (src == dst)
139 		val = 0;
140 	else if (src < dst)
141 		val = RSZ_PARA_STEP((src << 16) / dst);
142 	else if (src > dst)
143 		val = RSZ_DATA_STEP(src / dst) |
144 		      RSZ_PARA_STEP(((src << 16) / dst) & 0xffff);
145 
146 	return val;
147 }
148 
zx_vl_rsz_setup(struct zx_plane * zplane,uint32_t format,u32 src_w,u32 src_h,u32 dst_w,u32 dst_h)149 static void zx_vl_rsz_setup(struct zx_plane *zplane, uint32_t format,
150 			    u32 src_w, u32 src_h, u32 dst_w, u32 dst_h)
151 {
152 	void __iomem *rsz = zplane->rsz;
153 	u32 src_chroma_w = src_w;
154 	u32 src_chroma_h = src_h;
155 	int fmt;
156 
157 	/* Set up source and destination resolution */
158 	zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
159 	zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
160 
161 	/* Configure data format for VL RSZ */
162 	fmt = zx_vl_rsz_get_fmt(format);
163 	if (fmt >= 0)
164 		zx_writel_mask(rsz + RSZ_VL_CTRL_CFG, RSZ_VL_FMT_MASK, fmt);
165 
166 	/* Calculate Chroma height and width */
167 	if (fmt == RSZ_VL_FMT_YCBCR420) {
168 		src_chroma_w = src_w >> 1;
169 		src_chroma_h = src_h >> 1;
170 	} else if (fmt == RSZ_VL_FMT_YCBCR422) {
171 		src_chroma_w = src_w >> 1;
172 	}
173 
174 	/* Set up Luma and Chroma step registers */
175 	zx_writel(rsz + RSZ_VL_LUMA_HOR, rsz_step_value(src_w, dst_w));
176 	zx_writel(rsz + RSZ_VL_LUMA_VER, rsz_step_value(src_h, dst_h));
177 	zx_writel(rsz + RSZ_VL_CHROMA_HOR, rsz_step_value(src_chroma_w, dst_w));
178 	zx_writel(rsz + RSZ_VL_CHROMA_VER, rsz_step_value(src_chroma_h, dst_h));
179 
180 	zx_vl_rsz_set_update(zplane);
181 }
182 
zx_vl_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)183 static void zx_vl_plane_atomic_update(struct drm_plane *plane,
184 				      struct drm_atomic_state *state)
185 {
186 	struct zx_plane *zplane = to_zx_plane(plane);
187 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
188 									   plane);
189 	struct drm_framebuffer *fb = new_state->fb;
190 	struct drm_rect *src = &new_state->src;
191 	struct drm_rect *dst = &new_state->dst;
192 	struct drm_gem_cma_object *cma_obj;
193 	void __iomem *layer = zplane->layer;
194 	void __iomem *hbsc = zplane->hbsc;
195 	void __iomem *paddr_reg;
196 	dma_addr_t paddr;
197 	u32 src_x, src_y, src_w, src_h;
198 	u32 dst_x, dst_y, dst_w, dst_h;
199 	uint32_t format;
200 	int fmt;
201 	int i;
202 
203 	if (!fb)
204 		return;
205 
206 	format = fb->format->format;
207 
208 	src_x = src->x1 >> 16;
209 	src_y = src->y1 >> 16;
210 	src_w = drm_rect_width(src) >> 16;
211 	src_h = drm_rect_height(src) >> 16;
212 
213 	dst_x = dst->x1;
214 	dst_y = dst->y1;
215 	dst_w = drm_rect_width(dst);
216 	dst_h = drm_rect_height(dst);
217 
218 	/* Set up data address registers for Y, Cb and Cr planes */
219 	paddr_reg = layer + VL_Y;
220 	for (i = 0; i < fb->format->num_planes; i++) {
221 		cma_obj = drm_fb_cma_get_gem_obj(fb, i);
222 		paddr = cma_obj->paddr + fb->offsets[i];
223 		paddr += src_y * fb->pitches[i];
224 		paddr += src_x * fb->format->cpp[i];
225 		zx_writel(paddr_reg, paddr);
226 		paddr_reg += 4;
227 	}
228 
229 	/* Set up source height/width register */
230 	zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
231 
232 	/* Set up start position register */
233 	zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
234 
235 	/* Set up end position register */
236 	zx_writel(layer + VL_POS_END,
237 		  GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
238 
239 	/* Strides of Cb and Cr planes should be identical */
240 	zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) |
241 		  CHROMA_STRIDE(fb->pitches[1]));
242 
243 	/* Set up video layer data format */
244 	fmt = zx_vl_get_fmt(format);
245 	if (fmt >= 0)
246 		zx_writel(layer + VL_CTRL1, fmt);
247 
248 	/* Always use scaler since it exists (set for not bypass) */
249 	zx_writel_mask(layer + VL_CTRL2, VL_SCALER_BYPASS_MODE,
250 		       VL_SCALER_BYPASS_MODE);
251 
252 	zx_vl_rsz_setup(zplane, format, src_w, src_h, dst_w, dst_h);
253 
254 	/* Enable HBSC block */
255 	zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
256 
257 	zx_vou_layer_enable(plane);
258 
259 	zx_vl_set_update(zplane);
260 }
261 
zx_plane_atomic_disable(struct drm_plane * plane,struct drm_atomic_state * state)262 static void zx_plane_atomic_disable(struct drm_plane *plane,
263 				    struct drm_atomic_state *state)
264 {
265 	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
266 									   plane);
267 	struct zx_plane *zplane = to_zx_plane(plane);
268 	void __iomem *hbsc = zplane->hbsc;
269 
270 	zx_vou_layer_disable(plane, old_state);
271 
272 	/* Disable HBSC block */
273 	zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
274 }
275 
276 static const struct drm_plane_helper_funcs zx_vl_plane_helper_funcs = {
277 	.atomic_check = zx_vl_plane_atomic_check,
278 	.atomic_update = zx_vl_plane_atomic_update,
279 	.atomic_disable = zx_plane_atomic_disable,
280 };
281 
zx_gl_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)282 static int zx_gl_plane_atomic_check(struct drm_plane *plane,
283 				    struct drm_atomic_state *state)
284 {
285 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
286 									     plane);
287 	struct drm_framebuffer *fb = plane_state->fb;
288 	struct drm_crtc *crtc = plane_state->crtc;
289 	struct drm_crtc_state *crtc_state;
290 
291 	if (!crtc || WARN_ON(!fb))
292 		return 0;
293 
294 	crtc_state = drm_atomic_get_existing_crtc_state(state,
295 							crtc);
296 	if (WARN_ON(!crtc_state))
297 		return -EINVAL;
298 
299 	/* nothing to check when disabling or disabled */
300 	if (!crtc_state->enable)
301 		return 0;
302 
303 	/* plane must be enabled */
304 	if (!plane_state->crtc)
305 		return -EINVAL;
306 
307 	return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
308 						   DRM_PLANE_HELPER_NO_SCALING,
309 						   DRM_PLANE_HELPER_NO_SCALING,
310 						   false, true);
311 }
312 
zx_gl_get_fmt(uint32_t format)313 static int zx_gl_get_fmt(uint32_t format)
314 {
315 	switch (format) {
316 	case DRM_FORMAT_ARGB8888:
317 	case DRM_FORMAT_XRGB8888:
318 		return GL_FMT_ARGB8888;
319 	case DRM_FORMAT_RGB888:
320 		return GL_FMT_RGB888;
321 	case DRM_FORMAT_RGB565:
322 		return GL_FMT_RGB565;
323 	case DRM_FORMAT_ARGB1555:
324 		return GL_FMT_ARGB1555;
325 	case DRM_FORMAT_ARGB4444:
326 		return GL_FMT_ARGB4444;
327 	default:
328 		WARN_ONCE(1, "invalid pixel format %d\n", format);
329 		return -EINVAL;
330 	}
331 }
332 
zx_gl_set_update(struct zx_plane * zplane)333 static inline void zx_gl_set_update(struct zx_plane *zplane)
334 {
335 	void __iomem *layer = zplane->layer;
336 
337 	zx_writel_mask(layer + GL_CTRL0, GL_UPDATE, GL_UPDATE);
338 }
339 
zx_gl_rsz_set_update(struct zx_plane * zplane)340 static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
341 {
342 	zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
343 }
344 
zx_gl_rsz_setup(struct zx_plane * zplane,u32 src_w,u32 src_h,u32 dst_w,u32 dst_h)345 static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
346 			    u32 dst_w, u32 dst_h)
347 {
348 	void __iomem *rsz = zplane->rsz;
349 
350 	zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
351 	zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
352 
353 	zx_gl_rsz_set_update(zplane);
354 }
355 
zx_gl_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)356 static void zx_gl_plane_atomic_update(struct drm_plane *plane,
357 				      struct drm_atomic_state *state)
358 {
359 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
360 									   plane);
361 	struct zx_plane *zplane = to_zx_plane(plane);
362 	struct drm_framebuffer *fb = new_state->fb;
363 	struct drm_gem_cma_object *cma_obj;
364 	void __iomem *layer = zplane->layer;
365 	void __iomem *csc = zplane->csc;
366 	void __iomem *hbsc = zplane->hbsc;
367 	u32 src_x, src_y, src_w, src_h;
368 	u32 dst_x, dst_y, dst_w, dst_h;
369 	unsigned int bpp;
370 	uint32_t format;
371 	dma_addr_t paddr;
372 	u32 stride;
373 	int fmt;
374 
375 	if (!fb)
376 		return;
377 
378 	format = fb->format->format;
379 	stride = fb->pitches[0];
380 
381 	src_x = new_state->src_x >> 16;
382 	src_y = new_state->src_y >> 16;
383 	src_w = new_state->src_w >> 16;
384 	src_h = new_state->src_h >> 16;
385 
386 	dst_x = new_state->crtc_x;
387 	dst_y = new_state->crtc_y;
388 	dst_w = new_state->crtc_w;
389 	dst_h = new_state->crtc_h;
390 
391 	bpp = fb->format->cpp[0];
392 
393 	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
394 	paddr = cma_obj->paddr + fb->offsets[0];
395 	paddr += src_y * stride + src_x * bpp / 8;
396 	zx_writel(layer + GL_ADDR, paddr);
397 
398 	/* Set up source height/width register */
399 	zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
400 
401 	/* Set up start position register */
402 	zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
403 
404 	/* Set up end position register */
405 	zx_writel(layer + GL_POS_END,
406 		  GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
407 
408 	/* Set up stride register */
409 	zx_writel(layer + GL_STRIDE, stride & 0xffff);
410 
411 	/* Set up graphic layer data format */
412 	fmt = zx_gl_get_fmt(format);
413 	if (fmt >= 0)
414 		zx_writel_mask(layer + GL_CTRL1, GL_DATA_FMT_MASK,
415 			       fmt << GL_DATA_FMT_SHIFT);
416 
417 	/* Initialize global alpha with a sane value */
418 	zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK,
419 		       0xff << GL_GLOBAL_ALPHA_SHIFT);
420 
421 	/* Setup CSC for the GL */
422 	if (dst_h > 720)
423 		zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
424 			       CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
425 	else
426 		zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
427 			       CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
428 	zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, CSC_WORK_ENABLE);
429 
430 	/* Always use scaler since it exists (set for not bypass) */
431 	zx_writel_mask(layer + GL_CTRL3, GL_SCALER_BYPASS_MODE,
432 		       GL_SCALER_BYPASS_MODE);
433 
434 	zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
435 
436 	/* Enable HBSC block */
437 	zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
438 
439 	zx_vou_layer_enable(plane);
440 
441 	zx_gl_set_update(zplane);
442 }
443 
444 static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
445 	.atomic_check = zx_gl_plane_atomic_check,
446 	.atomic_update = zx_gl_plane_atomic_update,
447 	.atomic_disable = zx_plane_atomic_disable,
448 };
449 
450 static const struct drm_plane_funcs zx_plane_funcs = {
451 	.update_plane = drm_atomic_helper_update_plane,
452 	.disable_plane = drm_atomic_helper_disable_plane,
453 	.destroy = drm_plane_cleanup,
454 	.reset = drm_atomic_helper_plane_reset,
455 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
456 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
457 };
458 
zx_plane_set_update(struct drm_plane * plane)459 void zx_plane_set_update(struct drm_plane *plane)
460 {
461 	struct zx_plane *zplane = to_zx_plane(plane);
462 
463 	/* Do nothing if the plane is not enabled */
464 	if (!plane->state->crtc)
465 		return;
466 
467 	switch (plane->type) {
468 	case DRM_PLANE_TYPE_PRIMARY:
469 		zx_gl_rsz_set_update(zplane);
470 		zx_gl_set_update(zplane);
471 		break;
472 	case DRM_PLANE_TYPE_OVERLAY:
473 		zx_vl_rsz_set_update(zplane);
474 		zx_vl_set_update(zplane);
475 		break;
476 	default:
477 		WARN_ONCE(1, "unsupported plane type %d\n", plane->type);
478 	}
479 }
480 
zx_plane_hbsc_init(struct zx_plane * zplane)481 static void zx_plane_hbsc_init(struct zx_plane *zplane)
482 {
483 	void __iomem *hbsc = zplane->hbsc;
484 
485 	/*
486 	 *  Initialize HBSC block with a sane configuration per recommedation
487 	 *  from ZTE BSP code.
488 	 */
489 	zx_writel(hbsc + HBSC_SATURATION, 0x200);
490 	zx_writel(hbsc + HBSC_HUE, 0x0);
491 	zx_writel(hbsc + HBSC_BRIGHT, 0x0);
492 	zx_writel(hbsc + HBSC_CONTRAST, 0x200);
493 
494 	zx_writel(hbsc + HBSC_THRESHOLD_COL1, (0x3ac << 16) | 0x40);
495 	zx_writel(hbsc + HBSC_THRESHOLD_COL2, (0x3c0 << 16) | 0x40);
496 	zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40);
497 }
498 
zx_plane_init(struct drm_device * drm,struct zx_plane * zplane,enum drm_plane_type type)499 int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane,
500 		  enum drm_plane_type type)
501 {
502 	const struct drm_plane_helper_funcs *helper;
503 	struct drm_plane *plane = &zplane->plane;
504 	struct device *dev = zplane->dev;
505 	const uint32_t *formats;
506 	unsigned int format_count;
507 	int ret;
508 
509 	zx_plane_hbsc_init(zplane);
510 
511 	switch (type) {
512 	case DRM_PLANE_TYPE_PRIMARY:
513 		helper = &zx_gl_plane_helper_funcs;
514 		formats = gl_formats;
515 		format_count = ARRAY_SIZE(gl_formats);
516 		break;
517 	case DRM_PLANE_TYPE_OVERLAY:
518 		helper = &zx_vl_plane_helper_funcs;
519 		formats = vl_formats;
520 		format_count = ARRAY_SIZE(vl_formats);
521 		break;
522 	default:
523 		return -ENODEV;
524 	}
525 
526 	ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
527 				       &zx_plane_funcs, formats, format_count,
528 				       NULL, type, NULL);
529 	if (ret) {
530 		DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
531 		return ret;
532 	}
533 
534 	drm_plane_helper_add(plane, helper);
535 
536 	return 0;
537 }
538