Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  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
 25static 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
 34static 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
 52static 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
 82static 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
105static 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
112static inline void zx_vl_rsz_set_update(struct zx_plane *zplane)
113{
114	zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1);
115}
116
117static 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
136static 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
151static 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
185static 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
265static 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);
272
273	/* Disable HBSC block */
274	zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
275}
276
277static 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
283static 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
312static 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
332static 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
339static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
340{
341	zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
342}
343
344static 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
355static 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
441static 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
447static void zx_plane_destroy(struct drm_plane *plane)
448{
449	drm_plane_helper_disable(plane);
450	drm_plane_cleanup(plane);
451}
452
453static 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
462void 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
484static 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
502int 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}