Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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_drm_drv.h"
 20#include "zx_plane.h"
 21#include "zx_plane_regs.h"
 22#include "zx_vou.h"
 23
 24struct zx_plane {
 25	struct drm_plane plane;
 26	void __iomem *layer;
 27	void __iomem *csc;
 28	void __iomem *hbsc;
 29	void __iomem *rsz;
 30};
 31
 32#define to_zx_plane(plane)	container_of(plane, struct zx_plane, plane)
 33
 34static const uint32_t gl_formats[] = {
 35	DRM_FORMAT_ARGB8888,
 36	DRM_FORMAT_XRGB8888,
 37	DRM_FORMAT_RGB888,
 38	DRM_FORMAT_RGB565,
 39	DRM_FORMAT_ARGB1555,
 40	DRM_FORMAT_ARGB4444,
 41};
 42
 43static int zx_gl_plane_atomic_check(struct drm_plane *plane,
 44				    struct drm_plane_state *plane_state)
 45{
 46	struct drm_framebuffer *fb = plane_state->fb;
 47	struct drm_crtc *crtc = plane_state->crtc;
 48	struct drm_crtc_state *crtc_state;
 49	struct drm_rect clip;
 50
 51	if (!crtc || !fb)
 52		return 0;
 53
 54	crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
 55							crtc);
 56	if (WARN_ON(!crtc_state))
 57		return -EINVAL;
 58
 59	/* nothing to check when disabling or disabled */
 60	if (!crtc_state->enable)
 61		return 0;
 62
 63	/* plane must be enabled */
 64	if (!plane_state->crtc)
 65		return -EINVAL;
 66
 67	clip.x1 = 0;
 68	clip.y1 = 0;
 69	clip.x2 = crtc_state->adjusted_mode.hdisplay;
 70	clip.y2 = crtc_state->adjusted_mode.vdisplay;
 71
 72	return drm_plane_helper_check_state(plane_state, &clip,
 73					    DRM_PLANE_HELPER_NO_SCALING,
 74					    DRM_PLANE_HELPER_NO_SCALING,
 75					    false, true);
 76}
 77
 78static int zx_gl_get_fmt(uint32_t format)
 79{
 80	switch (format) {
 81	case DRM_FORMAT_ARGB8888:
 82	case DRM_FORMAT_XRGB8888:
 83		return GL_FMT_ARGB8888;
 84	case DRM_FORMAT_RGB888:
 85		return GL_FMT_RGB888;
 86	case DRM_FORMAT_RGB565:
 87		return GL_FMT_RGB565;
 88	case DRM_FORMAT_ARGB1555:
 89		return GL_FMT_ARGB1555;
 90	case DRM_FORMAT_ARGB4444:
 91		return GL_FMT_ARGB4444;
 92	default:
 93		WARN_ONCE(1, "invalid pixel format %d\n", format);
 94		return -EINVAL;
 95	}
 96}
 97
 98static inline void zx_gl_set_update(struct zx_plane *zplane)
 99{
100	void __iomem *layer = zplane->layer;
101
102	zx_writel_mask(layer + GL_CTRL0, GL_UPDATE, GL_UPDATE);
103}
104
105static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
106{
107	zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
108}
109
110void zx_plane_set_update(struct drm_plane *plane)
111{
112	struct zx_plane *zplane = to_zx_plane(plane);
113
114	zx_gl_rsz_set_update(zplane);
115	zx_gl_set_update(zplane);
116}
117
118static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
119			    u32 dst_w, u32 dst_h)
120{
121	void __iomem *rsz = zplane->rsz;
122
123	zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
124	zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
125
126	zx_gl_rsz_set_update(zplane);
127}
128
129static void zx_gl_plane_atomic_update(struct drm_plane *plane,
130				      struct drm_plane_state *old_state)
131{
132	struct zx_plane *zplane = to_zx_plane(plane);
133	struct drm_framebuffer *fb = plane->state->fb;
134	struct drm_gem_cma_object *cma_obj;
135	void __iomem *layer = zplane->layer;
136	void __iomem *csc = zplane->csc;
137	void __iomem *hbsc = zplane->hbsc;
138	u32 src_x, src_y, src_w, src_h;
139	u32 dst_x, dst_y, dst_w, dst_h;
140	unsigned int bpp;
141	uint32_t format;
142	dma_addr_t paddr;
143	u32 stride;
144	int fmt;
145
146	if (!fb)
147		return;
148
149	format = fb->pixel_format;
150	stride = fb->pitches[0];
151
152	src_x = plane->state->src_x >> 16;
153	src_y = plane->state->src_y >> 16;
154	src_w = plane->state->src_w >> 16;
155	src_h = plane->state->src_h >> 16;
156
157	dst_x = plane->state->crtc_x;
158	dst_y = plane->state->crtc_y;
159	dst_w = plane->state->crtc_w;
160	dst_h = plane->state->crtc_h;
161
162	bpp = drm_format_plane_cpp(format, 0);
163
164	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
165	paddr = cma_obj->paddr + fb->offsets[0];
166	paddr += src_y * stride + src_x * bpp / 8;
167	zx_writel(layer + GL_ADDR, paddr);
168
169	/* Set up source height/width register */
170	zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
171
172	/* Set up start position register */
173	zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
174
175	/* Set up end position register */
176	zx_writel(layer + GL_POS_END,
177		  GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
178
179	/* Set up stride register */
180	zx_writel(layer + GL_STRIDE, stride & 0xffff);
181
182	/* Set up graphic layer data format */
183	fmt = zx_gl_get_fmt(format);
184	if (fmt >= 0)
185		zx_writel_mask(layer + GL_CTRL1, GL_DATA_FMT_MASK,
186			       fmt << GL_DATA_FMT_SHIFT);
187
188	/* Initialize global alpha with a sane value */
189	zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK,
190		       0xff << GL_GLOBAL_ALPHA_SHIFT);
191
192	/* Setup CSC for the GL */
193	if (dst_h > 720)
194		zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
195			       CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
196	else
197		zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
198			       CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
199	zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, CSC_WORK_ENABLE);
200
201	/* Always use scaler since it exists (set for not bypass) */
202	zx_writel_mask(layer + GL_CTRL3, GL_SCALER_BYPASS_MODE,
203		       GL_SCALER_BYPASS_MODE);
204
205	zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
206
207	/* Enable HBSC block */
208	zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
209
210	zx_gl_set_update(zplane);
211}
212
213static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
214	.atomic_check = zx_gl_plane_atomic_check,
215	.atomic_update = zx_gl_plane_atomic_update,
216};
217
218static void zx_plane_destroy(struct drm_plane *plane)
219{
220	drm_plane_helper_disable(plane);
221	drm_plane_cleanup(plane);
222}
223
224static const struct drm_plane_funcs zx_plane_funcs = {
225	.update_plane = drm_atomic_helper_update_plane,
226	.disable_plane = drm_atomic_helper_disable_plane,
227	.destroy = zx_plane_destroy,
228	.reset = drm_atomic_helper_plane_reset,
229	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
230	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
231};
232
233static void zx_plane_hbsc_init(struct zx_plane *zplane)
234{
235	void __iomem *hbsc = zplane->hbsc;
236
237	/*
238	 *  Initialize HBSC block with a sane configuration per recommedation
239	 *  from ZTE BSP code.
240	 */
241	zx_writel(hbsc + HBSC_SATURATION, 0x200);
242	zx_writel(hbsc + HBSC_HUE, 0x0);
243	zx_writel(hbsc + HBSC_BRIGHT, 0x0);
244	zx_writel(hbsc + HBSC_CONTRAST, 0x200);
245
246	zx_writel(hbsc + HBSC_THRESHOLD_COL1, (0x3ac << 16) | 0x40);
247	zx_writel(hbsc + HBSC_THRESHOLD_COL2, (0x3c0 << 16) | 0x40);
248	zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40);
249}
250
251struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
252				struct zx_layer_data *data,
253				enum drm_plane_type type)
254{
255	const struct drm_plane_helper_funcs *helper;
256	struct zx_plane *zplane;
257	struct drm_plane *plane;
258	const uint32_t *formats;
259	unsigned int format_count;
260	int ret;
261
262	zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
263	if (!zplane)
264		return ERR_PTR(-ENOMEM);
265
266	plane = &zplane->plane;
267
268	zplane->layer = data->layer;
269	zplane->hbsc = data->hbsc;
270	zplane->csc = data->csc;
271	zplane->rsz = data->rsz;
272
273	zx_plane_hbsc_init(zplane);
274
275	switch (type) {
276	case DRM_PLANE_TYPE_PRIMARY:
277		helper = &zx_gl_plane_helper_funcs;
278		formats = gl_formats;
279		format_count = ARRAY_SIZE(gl_formats);
280		break;
281	case DRM_PLANE_TYPE_OVERLAY:
282		/* TODO: add video layer (vl) support */
283		break;
284	default:
285		return ERR_PTR(-ENODEV);
286	}
287
288	ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
289				       &zx_plane_funcs, formats, format_count,
290				       type, NULL);
291	if (ret) {
292		DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
293		return ERR_PTR(ret);
294	}
295
296	drm_plane_helper_add(plane, helper);
297
298	return plane;
299}