2 * Copyright 2016 Linaro Ltd.
3 * Copyright 2016 ZTE Corporation.
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.
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>
19 #include "zx_drm_drv.h"
21 #include "zx_plane_regs.h"
25 struct drm_plane plane;
32 #define to_zx_plane(plane) container_of(plane, struct zx_plane, plane)
34 static const uint32_t gl_formats[] = {
43 static int zx_gl_plane_atomic_check(struct drm_plane *plane,
44 struct drm_plane_state *plane_state)
46 struct drm_framebuffer *fb = plane_state->fb;
47 struct drm_crtc *crtc = plane_state->crtc;
48 struct drm_crtc_state *crtc_state;
54 crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
56 if (WARN_ON(!crtc_state))
59 /* nothing to check when disabling or disabled */
60 if (!crtc_state->enable)
63 /* plane must be enabled */
64 if (!plane_state->crtc)
69 clip.x2 = crtc_state->adjusted_mode.hdisplay;
70 clip.y2 = crtc_state->adjusted_mode.vdisplay;
72 return drm_plane_helper_check_state(plane_state, &clip,
73 DRM_PLANE_HELPER_NO_SCALING,
74 DRM_PLANE_HELPER_NO_SCALING,
78 static int zx_gl_get_fmt(uint32_t format)
81 case DRM_FORMAT_ARGB8888:
82 case DRM_FORMAT_XRGB8888:
83 return GL_FMT_ARGB8888;
84 case DRM_FORMAT_RGB888:
86 case DRM_FORMAT_RGB565:
88 case DRM_FORMAT_ARGB1555:
89 return GL_FMT_ARGB1555;
90 case DRM_FORMAT_ARGB4444:
91 return GL_FMT_ARGB4444;
93 WARN_ONCE(1, "invalid pixel format %d\n", format);
98 static inline void zx_gl_set_update(struct zx_plane *zplane)
100 void __iomem *layer = zplane->layer;
102 zx_writel_mask(layer + GL_CTRL0, GL_UPDATE, GL_UPDATE);
105 static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
107 zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
110 void zx_plane_set_update(struct drm_plane *plane)
112 struct zx_plane *zplane = to_zx_plane(plane);
114 zx_gl_rsz_set_update(zplane);
115 zx_gl_set_update(zplane);
118 static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
119 u32 dst_w, u32 dst_h)
121 void __iomem *rsz = zplane->rsz;
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));
126 zx_gl_rsz_set_update(zplane);
129 static void zx_gl_plane_atomic_update(struct drm_plane *plane,
130 struct drm_plane_state *old_state)
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;
149 format = fb->pixel_format;
150 stride = fb->pitches[0];
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;
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;
162 bpp = drm_format_plane_cpp(format, 0);
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);
169 /* Set up source height/width register */
170 zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
172 /* Set up start position register */
173 zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
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));
179 /* Set up stride register */
180 zx_writel(layer + GL_STRIDE, stride & 0xffff);
182 /* Set up graphic layer data format */
183 fmt = zx_gl_get_fmt(format);
185 zx_writel_mask(layer + GL_CTRL1, GL_DATA_FMT_MASK,
186 fmt << GL_DATA_FMT_SHIFT);
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);
192 /* Setup CSC for the GL */
194 zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
195 CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
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);
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);
205 zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
207 /* Enable HBSC block */
208 zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
210 zx_gl_set_update(zplane);
213 static 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,
218 static void zx_plane_destroy(struct drm_plane *plane)
220 drm_plane_helper_disable(plane);
221 drm_plane_cleanup(plane);
224 static 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,
233 static void zx_plane_hbsc_init(struct zx_plane *zplane)
235 void __iomem *hbsc = zplane->hbsc;
238 * Initialize HBSC block with a sane configuration per recommedation
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);
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);
251 struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
252 struct zx_layer_data *data,
253 enum drm_plane_type type)
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;
262 zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
264 return ERR_PTR(-ENOMEM);
266 plane = &zplane->plane;
268 zplane->layer = data->layer;
269 zplane->hbsc = data->hbsc;
270 zplane->csc = data->csc;
271 zplane->rsz = data->rsz;
273 zx_plane_hbsc_init(zplane);
276 case DRM_PLANE_TYPE_PRIMARY:
277 helper = &zx_gl_plane_helper_funcs;
278 formats = gl_formats;
279 format_count = ARRAY_SIZE(gl_formats);
281 case DRM_PLANE_TYPE_OVERLAY:
282 /* TODO: add video layer (vl) support */
285 return ERR_PTR(-ENODEV);
288 ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
289 &zx_plane_funcs, formats, format_count,
292 DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
296 drm_plane_helper_add(plane, helper);