Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Feb 10-13, 2025
Register
Loading...
Note: File does not exist in v6.13.7.
  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
 21static 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
 30static 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
 48static 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
 80static 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
103static 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
110static inline void zx_vl_rsz_set_update(struct zx_plane *zplane)
111{
112	zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1);
113}
114
115static 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
134static 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
149static 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
183static 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
262static 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
276static 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
282static 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
313static 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
333static 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
340static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
341{
342	zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
343}
344
345static 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
356static 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
444static 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
450static 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
459void 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
481static 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
499int 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}