]>
Commit | Line | Data |
---|---|---|
0a886f59 SG |
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 | ||
24 | struct 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 | ||
34 | static 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 | ||
43 | static 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 | ||
78 | static 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 | ||
98 | static 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 | ||
105 | static inline void zx_gl_rsz_set_update(struct zx_plane *zplane) | |
106 | { | |
107 | zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1); | |
108 | } | |
109 | ||
110 | void 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 | ||
118 | static 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 | ||
129 | static 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 depth, 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 | drm_fb_get_bpp_depth(format, &depth, &bpp); | |
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 | ||
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, | |
216 | }; | |
217 | ||
218 | static void zx_plane_destroy(struct drm_plane *plane) | |
219 | { | |
220 | drm_plane_helper_disable(plane); | |
221 | drm_plane_cleanup(plane); | |
222 | } | |
223 | ||
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, | |
231 | }; | |
232 | ||
233 | static 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 | ||
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) | |
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 | } |