1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright © 2018-2020 Intel Corporation |
4 | */ |
5 | |
6 | #include <drm/drm_atomic.h> |
7 | #include <drm/drm_atomic_helper.h> |
8 | #include <drm/drm_blend.h> |
9 | #include <drm/drm_crtc.h> |
10 | #include <drm/drm_fb_dma_helper.h> |
11 | #include <drm/drm_fourcc.h> |
12 | #include <drm/drm_framebuffer.h> |
13 | #include <drm/drm_gem_dma_helper.h> |
14 | #include <drm/drm_managed.h> |
15 | |
16 | #include "kmb_drv.h" |
17 | #include "kmb_plane.h" |
18 | #include "kmb_regs.h" |
19 | |
20 | const u32 layer_irqs[] = { |
21 | LCD_INT_VL0, |
22 | LCD_INT_VL1, |
23 | LCD_INT_GL0, |
24 | LCD_INT_GL1 |
25 | }; |
26 | |
27 | /* Conversion (yuv->rgb) matrix from myriadx */ |
28 | static const u32 csc_coef_lcd[] = { |
29 | 1024, 0, 1436, |
30 | 1024, -352, -731, |
31 | 1024, 1814, 0, |
32 | -179, 125, -226 |
33 | }; |
34 | |
35 | /* Graphics layer (layers 2 & 3) formats, only packed formats are supported */ |
36 | static const u32 kmb_formats_g[] = { |
37 | DRM_FORMAT_RGB332, |
38 | DRM_FORMAT_XRGB4444, DRM_FORMAT_XBGR4444, |
39 | DRM_FORMAT_ARGB4444, DRM_FORMAT_ABGR4444, |
40 | DRM_FORMAT_XRGB1555, DRM_FORMAT_XBGR1555, |
41 | DRM_FORMAT_ARGB1555, DRM_FORMAT_ABGR1555, |
42 | DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, |
43 | DRM_FORMAT_RGB888, DRM_FORMAT_BGR888, |
44 | DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, |
45 | DRM_FORMAT_ARGB8888, DRM_FORMAT_ABGR8888, |
46 | }; |
47 | |
48 | /* Video layer ( 0 & 1) formats, packed and planar formats are supported */ |
49 | static const u32 kmb_formats_v[] = { |
50 | /* packed formats */ |
51 | DRM_FORMAT_RGB332, |
52 | DRM_FORMAT_XRGB4444, DRM_FORMAT_XBGR4444, |
53 | DRM_FORMAT_ARGB4444, DRM_FORMAT_ABGR4444, |
54 | DRM_FORMAT_XRGB1555, DRM_FORMAT_XBGR1555, |
55 | DRM_FORMAT_ARGB1555, DRM_FORMAT_ABGR1555, |
56 | DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, |
57 | DRM_FORMAT_RGB888, DRM_FORMAT_BGR888, |
58 | DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, |
59 | DRM_FORMAT_ARGB8888, DRM_FORMAT_ABGR8888, |
60 | /*planar formats */ |
61 | DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, |
62 | DRM_FORMAT_YUV422, DRM_FORMAT_YVU422, |
63 | DRM_FORMAT_YUV444, DRM_FORMAT_YVU444, |
64 | DRM_FORMAT_NV12, DRM_FORMAT_NV21, |
65 | }; |
66 | |
67 | static unsigned int check_pixel_format(struct drm_plane *plane, u32 format) |
68 | { |
69 | struct kmb_drm_private *kmb; |
70 | struct kmb_plane *kmb_plane = to_kmb_plane(plane); |
71 | int i; |
72 | int plane_id = kmb_plane->id; |
73 | struct disp_cfg init_disp_cfg; |
74 | |
75 | kmb = to_kmb(dev: plane->dev); |
76 | init_disp_cfg = kmb->init_disp_cfg[plane_id]; |
77 | /* Due to HW limitations, changing pixel format after initial |
78 | * plane configuration is not supported. |
79 | */ |
80 | if (init_disp_cfg.format && init_disp_cfg.format != format) { |
81 | drm_dbg(&kmb->drm, "Cannot change format after initial plane configuration" ); |
82 | return -EINVAL; |
83 | } |
84 | for (i = 0; i < plane->format_count; i++) { |
85 | if (plane->format_types[i] == format) |
86 | return 0; |
87 | } |
88 | return -EINVAL; |
89 | } |
90 | |
91 | static int kmb_plane_atomic_check(struct drm_plane *plane, |
92 | struct drm_atomic_state *state) |
93 | { |
94 | struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, |
95 | plane); |
96 | struct kmb_drm_private *kmb; |
97 | struct kmb_plane *kmb_plane = to_kmb_plane(plane); |
98 | int plane_id = kmb_plane->id; |
99 | struct disp_cfg init_disp_cfg; |
100 | struct drm_framebuffer *fb; |
101 | int ret; |
102 | struct drm_crtc_state *crtc_state; |
103 | bool can_position; |
104 | |
105 | kmb = to_kmb(dev: plane->dev); |
106 | init_disp_cfg = kmb->init_disp_cfg[plane_id]; |
107 | fb = new_plane_state->fb; |
108 | if (!fb || !new_plane_state->crtc) |
109 | return 0; |
110 | |
111 | ret = check_pixel_format(plane, format: fb->format->format); |
112 | if (ret) |
113 | return ret; |
114 | |
115 | if (new_plane_state->crtc_w > KMB_FB_MAX_WIDTH || |
116 | new_plane_state->crtc_h > KMB_FB_MAX_HEIGHT || |
117 | new_plane_state->crtc_w < KMB_FB_MIN_WIDTH || |
118 | new_plane_state->crtc_h < KMB_FB_MIN_HEIGHT) |
119 | return -EINVAL; |
120 | |
121 | /* Due to HW limitations, changing plane height or width after |
122 | * initial plane configuration is not supported. |
123 | */ |
124 | if ((init_disp_cfg.width && init_disp_cfg.height) && |
125 | (init_disp_cfg.width != fb->width || |
126 | init_disp_cfg.height != fb->height)) { |
127 | drm_dbg(&kmb->drm, "Cannot change plane height or width after initial configuration" ); |
128 | return -EINVAL; |
129 | } |
130 | can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY); |
131 | crtc_state = |
132 | drm_atomic_get_existing_crtc_state(state, |
133 | crtc: new_plane_state->crtc); |
134 | return drm_atomic_helper_check_plane_state(plane_state: new_plane_state, |
135 | crtc_state, |
136 | DRM_PLANE_NO_SCALING, |
137 | DRM_PLANE_NO_SCALING, |
138 | can_position, can_update_disabled: true); |
139 | } |
140 | |
141 | static void kmb_plane_atomic_disable(struct drm_plane *plane, |
142 | struct drm_atomic_state *state) |
143 | { |
144 | struct kmb_plane *kmb_plane = to_kmb_plane(plane); |
145 | int plane_id = kmb_plane->id; |
146 | struct kmb_drm_private *kmb; |
147 | |
148 | kmb = to_kmb(dev: plane->dev); |
149 | |
150 | if (WARN_ON(plane_id >= KMB_MAX_PLANES)) |
151 | return; |
152 | |
153 | switch (plane_id) { |
154 | case LAYER_0: |
155 | kmb->plane_status[plane_id].ctrl = LCD_CTRL_VL1_ENABLE; |
156 | break; |
157 | case LAYER_1: |
158 | kmb->plane_status[plane_id].ctrl = LCD_CTRL_VL2_ENABLE; |
159 | break; |
160 | } |
161 | |
162 | kmb->plane_status[plane_id].disable = true; |
163 | } |
164 | |
165 | static unsigned int get_pixel_format(u32 format) |
166 | { |
167 | unsigned int val = 0; |
168 | |
169 | switch (format) { |
170 | /* planar formats */ |
171 | case DRM_FORMAT_YUV444: |
172 | val = LCD_LAYER_FORMAT_YCBCR444PLAN | LCD_LAYER_PLANAR_STORAGE; |
173 | break; |
174 | case DRM_FORMAT_YVU444: |
175 | val = LCD_LAYER_FORMAT_YCBCR444PLAN | LCD_LAYER_PLANAR_STORAGE |
176 | | LCD_LAYER_CRCB_ORDER; |
177 | break; |
178 | case DRM_FORMAT_YUV422: |
179 | val = LCD_LAYER_FORMAT_YCBCR422PLAN | LCD_LAYER_PLANAR_STORAGE; |
180 | break; |
181 | case DRM_FORMAT_YVU422: |
182 | val = LCD_LAYER_FORMAT_YCBCR422PLAN | LCD_LAYER_PLANAR_STORAGE |
183 | | LCD_LAYER_CRCB_ORDER; |
184 | break; |
185 | case DRM_FORMAT_YUV420: |
186 | val = LCD_LAYER_FORMAT_YCBCR420PLAN | LCD_LAYER_PLANAR_STORAGE; |
187 | break; |
188 | case DRM_FORMAT_YVU420: |
189 | val = LCD_LAYER_FORMAT_YCBCR420PLAN | LCD_LAYER_PLANAR_STORAGE |
190 | | LCD_LAYER_CRCB_ORDER; |
191 | break; |
192 | case DRM_FORMAT_NV12: |
193 | val = LCD_LAYER_FORMAT_NV12 | LCD_LAYER_PLANAR_STORAGE; |
194 | break; |
195 | case DRM_FORMAT_NV21: |
196 | val = LCD_LAYER_FORMAT_NV12 | LCD_LAYER_PLANAR_STORAGE |
197 | | LCD_LAYER_CRCB_ORDER; |
198 | break; |
199 | /* packed formats */ |
200 | /* looks hw requires B & G to be swapped when RGB */ |
201 | case DRM_FORMAT_RGB332: |
202 | val = LCD_LAYER_FORMAT_RGB332 | LCD_LAYER_BGR_ORDER; |
203 | break; |
204 | case DRM_FORMAT_XBGR4444: |
205 | val = LCD_LAYER_FORMAT_RGBX4444; |
206 | break; |
207 | case DRM_FORMAT_ARGB4444: |
208 | val = LCD_LAYER_FORMAT_RGBA4444 | LCD_LAYER_BGR_ORDER; |
209 | break; |
210 | case DRM_FORMAT_ABGR4444: |
211 | val = LCD_LAYER_FORMAT_RGBA4444; |
212 | break; |
213 | case DRM_FORMAT_XRGB1555: |
214 | val = LCD_LAYER_FORMAT_XRGB1555 | LCD_LAYER_BGR_ORDER; |
215 | break; |
216 | case DRM_FORMAT_XBGR1555: |
217 | val = LCD_LAYER_FORMAT_XRGB1555; |
218 | break; |
219 | case DRM_FORMAT_ARGB1555: |
220 | val = LCD_LAYER_FORMAT_RGBA1555 | LCD_LAYER_BGR_ORDER; |
221 | break; |
222 | case DRM_FORMAT_ABGR1555: |
223 | val = LCD_LAYER_FORMAT_RGBA1555; |
224 | break; |
225 | case DRM_FORMAT_RGB565: |
226 | val = LCD_LAYER_FORMAT_RGB565 | LCD_LAYER_BGR_ORDER; |
227 | break; |
228 | case DRM_FORMAT_BGR565: |
229 | val = LCD_LAYER_FORMAT_RGB565; |
230 | break; |
231 | case DRM_FORMAT_RGB888: |
232 | val = LCD_LAYER_FORMAT_RGB888 | LCD_LAYER_BGR_ORDER; |
233 | break; |
234 | case DRM_FORMAT_BGR888: |
235 | val = LCD_LAYER_FORMAT_RGB888; |
236 | break; |
237 | case DRM_FORMAT_XRGB8888: |
238 | val = LCD_LAYER_FORMAT_RGBX8888 | LCD_LAYER_BGR_ORDER; |
239 | break; |
240 | case DRM_FORMAT_XBGR8888: |
241 | val = LCD_LAYER_FORMAT_RGBX8888; |
242 | break; |
243 | case DRM_FORMAT_ARGB8888: |
244 | val = LCD_LAYER_FORMAT_RGBA8888 | LCD_LAYER_BGR_ORDER; |
245 | break; |
246 | case DRM_FORMAT_ABGR8888: |
247 | val = LCD_LAYER_FORMAT_RGBA8888; |
248 | break; |
249 | } |
250 | DRM_INFO_ONCE("%s : %d format=0x%x val=0x%x\n" , |
251 | __func__, __LINE__, format, val); |
252 | return val; |
253 | } |
254 | |
255 | static unsigned int get_bits_per_pixel(const struct drm_format_info *format) |
256 | { |
257 | u32 bpp = 0; |
258 | unsigned int val = 0; |
259 | |
260 | if (format->num_planes > 1) { |
261 | val = LCD_LAYER_8BPP; |
262 | return val; |
263 | } |
264 | |
265 | bpp += 8 * format->cpp[0]; |
266 | |
267 | switch (bpp) { |
268 | case 8: |
269 | val = LCD_LAYER_8BPP; |
270 | break; |
271 | case 16: |
272 | val = LCD_LAYER_16BPP; |
273 | break; |
274 | case 24: |
275 | val = LCD_LAYER_24BPP; |
276 | break; |
277 | case 32: |
278 | val = LCD_LAYER_32BPP; |
279 | break; |
280 | } |
281 | |
282 | DRM_DEBUG("bpp=%d val=0x%x\n" , bpp, val); |
283 | return val; |
284 | } |
285 | |
286 | static void config_csc(struct kmb_drm_private *kmb, int plane_id) |
287 | { |
288 | /* YUV to RGB conversion using the fixed matrix csc_coef_lcd */ |
289 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_CSC_COEFF11(plane_id), value: csc_coef_lcd[0]); |
290 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_CSC_COEFF12(plane_id), value: csc_coef_lcd[1]); |
291 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_CSC_COEFF13(plane_id), value: csc_coef_lcd[2]); |
292 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_CSC_COEFF21(plane_id), value: csc_coef_lcd[3]); |
293 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_CSC_COEFF22(plane_id), value: csc_coef_lcd[4]); |
294 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_CSC_COEFF23(plane_id), value: csc_coef_lcd[5]); |
295 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_CSC_COEFF31(plane_id), value: csc_coef_lcd[6]); |
296 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_CSC_COEFF32(plane_id), value: csc_coef_lcd[7]); |
297 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_CSC_COEFF33(plane_id), value: csc_coef_lcd[8]); |
298 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_CSC_OFF1(plane_id), value: csc_coef_lcd[9]); |
299 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_CSC_OFF2(plane_id), value: csc_coef_lcd[10]); |
300 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_CSC_OFF3(plane_id), value: csc_coef_lcd[11]); |
301 | } |
302 | |
303 | static void kmb_plane_set_alpha(struct kmb_drm_private *kmb, |
304 | const struct drm_plane_state *state, |
305 | unsigned char plane_id, |
306 | unsigned int *val) |
307 | { |
308 | u16 plane_alpha = state->alpha; |
309 | u16 pixel_blend_mode = state->pixel_blend_mode; |
310 | int has_alpha = state->fb->format->has_alpha; |
311 | |
312 | if (plane_alpha != DRM_BLEND_ALPHA_OPAQUE) |
313 | *val |= LCD_LAYER_ALPHA_STATIC; |
314 | |
315 | if (has_alpha) { |
316 | switch (pixel_blend_mode) { |
317 | case DRM_MODE_BLEND_PIXEL_NONE: |
318 | break; |
319 | case DRM_MODE_BLEND_PREMULTI: |
320 | *val |= LCD_LAYER_ALPHA_EMBED | LCD_LAYER_ALPHA_PREMULT; |
321 | break; |
322 | case DRM_MODE_BLEND_COVERAGE: |
323 | *val |= LCD_LAYER_ALPHA_EMBED; |
324 | break; |
325 | default: |
326 | DRM_DEBUG("Missing pixel blend mode case (%s == %ld)\n" , |
327 | __stringify(pixel_blend_mode), |
328 | (long)pixel_blend_mode); |
329 | break; |
330 | } |
331 | } |
332 | |
333 | if (plane_alpha == DRM_BLEND_ALPHA_OPAQUE && !has_alpha) { |
334 | *val &= LCD_LAYER_ALPHA_DISABLED; |
335 | return; |
336 | } |
337 | |
338 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_ALPHA(plane_id), value: plane_alpha); |
339 | } |
340 | |
341 | static void kmb_plane_atomic_update(struct drm_plane *plane, |
342 | struct drm_atomic_state *state) |
343 | { |
344 | struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, |
345 | plane); |
346 | struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, |
347 | plane); |
348 | struct drm_framebuffer *fb; |
349 | struct kmb_drm_private *kmb; |
350 | unsigned int width; |
351 | unsigned int height; |
352 | unsigned int dma_len; |
353 | struct kmb_plane *kmb_plane; |
354 | unsigned int dma_cfg; |
355 | unsigned int ctrl = 0, val = 0, out_format = 0; |
356 | unsigned int src_w, src_h, crtc_x, crtc_y; |
357 | unsigned char plane_id; |
358 | int num_planes; |
359 | static dma_addr_t addr[MAX_SUB_PLANES]; |
360 | struct disp_cfg *init_disp_cfg; |
361 | |
362 | if (!plane || !new_plane_state || !old_plane_state) |
363 | return; |
364 | |
365 | fb = new_plane_state->fb; |
366 | if (!fb) |
367 | return; |
368 | |
369 | num_planes = fb->format->num_planes; |
370 | kmb_plane = to_kmb_plane(plane); |
371 | |
372 | kmb = to_kmb(dev: plane->dev); |
373 | plane_id = kmb_plane->id; |
374 | |
375 | spin_lock_irq(lock: &kmb->irq_lock); |
376 | if (kmb->kmb_under_flow || kmb->kmb_flush_done) { |
377 | spin_unlock_irq(lock: &kmb->irq_lock); |
378 | drm_dbg(&kmb->drm, "plane_update:underflow!!!! returning" ); |
379 | return; |
380 | } |
381 | spin_unlock_irq(lock: &kmb->irq_lock); |
382 | |
383 | init_disp_cfg = &kmb->init_disp_cfg[plane_id]; |
384 | src_w = new_plane_state->src_w >> 16; |
385 | src_h = new_plane_state->src_h >> 16; |
386 | crtc_x = new_plane_state->crtc_x; |
387 | crtc_y = new_plane_state->crtc_y; |
388 | |
389 | drm_dbg(&kmb->drm, |
390 | "src_w=%d src_h=%d, fb->format->format=0x%x fb->flags=0x%x\n" , |
391 | src_w, src_h, fb->format->format, fb->flags); |
392 | |
393 | width = fb->width; |
394 | height = fb->height; |
395 | dma_len = (width * height * fb->format->cpp[0]); |
396 | drm_dbg(&kmb->drm, "dma_len=%d " , dma_len); |
397 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_DMA_LEN(plane_id), value: dma_len); |
398 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_DMA_LEN_SHADOW(plane_id), value: dma_len); |
399 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_DMA_LINE_VSTRIDE(plane_id), |
400 | value: fb->pitches[0]); |
401 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_DMA_LINE_WIDTH(plane_id), |
402 | value: (width * fb->format->cpp[0])); |
403 | |
404 | addr[Y_PLANE] = drm_fb_dma_get_gem_addr(fb, state: new_plane_state, plane: 0); |
405 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_DMA_START_ADDR(plane_id), |
406 | value: addr[Y_PLANE] + fb->offsets[0]); |
407 | val = get_pixel_format(format: fb->format->format); |
408 | val |= get_bits_per_pixel(format: fb->format); |
409 | /* Program Cb/Cr for planar formats */ |
410 | if (num_planes > 1) { |
411 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_DMA_CB_LINE_VSTRIDE(plane_id), |
412 | value: width * fb->format->cpp[0]); |
413 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_DMA_CB_LINE_WIDTH(plane_id), |
414 | value: (width * fb->format->cpp[0])); |
415 | |
416 | addr[U_PLANE] = drm_fb_dma_get_gem_addr(fb, state: new_plane_state, |
417 | plane: U_PLANE); |
418 | /* check if Cb/Cr is swapped*/ |
419 | if (num_planes == 3 && (val & LCD_LAYER_CRCB_ORDER)) |
420 | kmb_write_lcd(dev_p: kmb, |
421 | LCD_LAYERn_DMA_START_CR_ADR(plane_id), |
422 | value: addr[U_PLANE]); |
423 | else |
424 | kmb_write_lcd(dev_p: kmb, |
425 | LCD_LAYERn_DMA_START_CB_ADR(plane_id), |
426 | value: addr[U_PLANE]); |
427 | |
428 | if (num_planes == 3) { |
429 | kmb_write_lcd(dev_p: kmb, |
430 | LCD_LAYERn_DMA_CR_LINE_VSTRIDE(plane_id), |
431 | value: ((width) * fb->format->cpp[0])); |
432 | |
433 | kmb_write_lcd(dev_p: kmb, |
434 | LCD_LAYERn_DMA_CR_LINE_WIDTH(plane_id), |
435 | value: ((width) * fb->format->cpp[0])); |
436 | |
437 | addr[V_PLANE] = drm_fb_dma_get_gem_addr(fb, |
438 | state: new_plane_state, |
439 | plane: V_PLANE); |
440 | |
441 | /* check if Cb/Cr is swapped*/ |
442 | if (val & LCD_LAYER_CRCB_ORDER) |
443 | kmb_write_lcd(dev_p: kmb, |
444 | LCD_LAYERn_DMA_START_CB_ADR(plane_id), |
445 | value: addr[V_PLANE]); |
446 | else |
447 | kmb_write_lcd(dev_p: kmb, |
448 | LCD_LAYERn_DMA_START_CR_ADR(plane_id), |
449 | value: addr[V_PLANE]); |
450 | } |
451 | } |
452 | |
453 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_WIDTH(plane_id), value: src_w - 1); |
454 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_HEIGHT(plane_id), value: src_h - 1); |
455 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_COL_START(plane_id), value: crtc_x); |
456 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_ROW_START(plane_id), value: crtc_y); |
457 | |
458 | val |= LCD_LAYER_FIFO_100; |
459 | |
460 | if (val & LCD_LAYER_PLANAR_STORAGE) { |
461 | val |= LCD_LAYER_CSC_EN; |
462 | |
463 | /* Enable CSC if input is planar and output is RGB */ |
464 | config_csc(kmb, plane_id); |
465 | } |
466 | |
467 | kmb_plane_set_alpha(kmb, state: plane->state, plane_id, val: &val); |
468 | |
469 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_CFG(plane_id), value: val); |
470 | |
471 | /* Configure LCD_CONTROL */ |
472 | ctrl = kmb_read_lcd(dev_p: kmb, LCD_CONTROL); |
473 | |
474 | /* Set layer blending config */ |
475 | ctrl &= ~LCD_CTRL_ALPHA_ALL; |
476 | ctrl |= LCD_CTRL_ALPHA_BOTTOM_VL1 | |
477 | LCD_CTRL_ALPHA_BLEND_VL2; |
478 | |
479 | ctrl &= ~LCD_CTRL_ALPHA_BLEND_BKGND_DISABLE; |
480 | |
481 | switch (plane_id) { |
482 | case LAYER_0: |
483 | ctrl |= LCD_CTRL_VL1_ENABLE; |
484 | break; |
485 | case LAYER_1: |
486 | ctrl |= LCD_CTRL_VL2_ENABLE; |
487 | break; |
488 | case LAYER_2: |
489 | ctrl |= LCD_CTRL_GL1_ENABLE; |
490 | break; |
491 | case LAYER_3: |
492 | ctrl |= LCD_CTRL_GL2_ENABLE; |
493 | break; |
494 | } |
495 | |
496 | ctrl |= LCD_CTRL_PROGRESSIVE | LCD_CTRL_TIM_GEN_ENABLE |
497 | | LCD_CTRL_CONTINUOUS | LCD_CTRL_OUTPUT_ENABLED; |
498 | |
499 | /* LCD is connected to MIPI on kmb |
500 | * Therefore this bit is required for DSI Tx |
501 | */ |
502 | ctrl |= LCD_CTRL_VHSYNC_IDLE_LVL; |
503 | |
504 | kmb_write_lcd(dev_p: kmb, LCD_CONTROL, value: ctrl); |
505 | |
506 | /* Enable pipeline AXI read transactions for the DMA |
507 | * after setting graphics layers. This must be done |
508 | * in a separate write cycle. |
509 | */ |
510 | kmb_set_bitmask_lcd(dev_p: kmb, LCD_CONTROL, LCD_CTRL_PIPELINE_DMA); |
511 | |
512 | /* FIXME no doc on how to set output format, these values are taken |
513 | * from the Myriadx tests |
514 | */ |
515 | out_format |= LCD_OUTF_FORMAT_RGB888; |
516 | |
517 | /* Leave RGB order,conversion mode and clip mode to default */ |
518 | /* do not interleave RGB channels for mipi Tx compatibility */ |
519 | out_format |= LCD_OUTF_MIPI_RGB_MODE; |
520 | kmb_write_lcd(dev_p: kmb, LCD_OUT_FORMAT_CFG, value: out_format); |
521 | |
522 | dma_cfg = LCD_DMA_LAYER_ENABLE | LCD_DMA_LAYER_VSTRIDE_EN | |
523 | LCD_DMA_LAYER_CONT_UPDATE | LCD_DMA_LAYER_AXI_BURST_16; |
524 | |
525 | /* Enable DMA */ |
526 | kmb_write_lcd(dev_p: kmb, LCD_LAYERn_DMA_CFG(plane_id), value: dma_cfg); |
527 | |
528 | /* Save initial display config */ |
529 | if (!init_disp_cfg->width || |
530 | !init_disp_cfg->height || |
531 | !init_disp_cfg->format) { |
532 | init_disp_cfg->width = width; |
533 | init_disp_cfg->height = height; |
534 | init_disp_cfg->format = fb->format->format; |
535 | } |
536 | |
537 | drm_dbg(&kmb->drm, "dma_cfg=0x%x LCD_DMA_CFG=0x%x\n" , dma_cfg, |
538 | kmb_read_lcd(kmb, LCD_LAYERn_DMA_CFG(plane_id))); |
539 | |
540 | kmb_set_bitmask_lcd(dev_p: kmb, LCD_INT_CLEAR, LCD_INT_EOF | |
541 | LCD_INT_DMA_ERR); |
542 | kmb_set_bitmask_lcd(dev_p: kmb, LCD_INT_ENABLE, LCD_INT_EOF | |
543 | LCD_INT_DMA_ERR); |
544 | } |
545 | |
546 | static const struct drm_plane_helper_funcs kmb_plane_helper_funcs = { |
547 | .atomic_check = kmb_plane_atomic_check, |
548 | .atomic_update = kmb_plane_atomic_update, |
549 | .atomic_disable = kmb_plane_atomic_disable |
550 | }; |
551 | |
552 | void kmb_plane_destroy(struct drm_plane *plane) |
553 | { |
554 | struct kmb_plane *kmb_plane = to_kmb_plane(plane); |
555 | |
556 | drm_plane_cleanup(plane); |
557 | kfree(objp: kmb_plane); |
558 | } |
559 | |
560 | static const struct drm_plane_funcs kmb_plane_funcs = { |
561 | .update_plane = drm_atomic_helper_update_plane, |
562 | .disable_plane = drm_atomic_helper_disable_plane, |
563 | .destroy = kmb_plane_destroy, |
564 | .reset = drm_atomic_helper_plane_reset, |
565 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, |
566 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, |
567 | }; |
568 | |
569 | struct kmb_plane *kmb_plane_init(struct drm_device *drm) |
570 | { |
571 | struct kmb_drm_private *kmb = to_kmb(dev: drm); |
572 | struct kmb_plane *plane = NULL; |
573 | struct kmb_plane *primary = NULL; |
574 | int i = 0; |
575 | int ret = 0; |
576 | enum drm_plane_type plane_type; |
577 | const u32 *plane_formats; |
578 | int num_plane_formats; |
579 | unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) | |
580 | BIT(DRM_MODE_BLEND_PREMULTI) | |
581 | BIT(DRM_MODE_BLEND_COVERAGE); |
582 | |
583 | for (i = 0; i < KMB_MAX_PLANES; i++) { |
584 | plane = drmm_kzalloc(dev: drm, size: sizeof(*plane), GFP_KERNEL); |
585 | |
586 | if (!plane) { |
587 | drm_err(drm, "Failed to allocate plane\n" ); |
588 | return ERR_PTR(error: -ENOMEM); |
589 | } |
590 | |
591 | plane_type = (i == 0) ? DRM_PLANE_TYPE_PRIMARY : |
592 | DRM_PLANE_TYPE_OVERLAY; |
593 | if (i < 2) { |
594 | plane_formats = kmb_formats_v; |
595 | num_plane_formats = ARRAY_SIZE(kmb_formats_v); |
596 | } else { |
597 | plane_formats = kmb_formats_g; |
598 | num_plane_formats = ARRAY_SIZE(kmb_formats_g); |
599 | } |
600 | |
601 | ret = drm_universal_plane_init(dev: drm, plane: &plane->base_plane, |
602 | POSSIBLE_CRTCS, funcs: &kmb_plane_funcs, |
603 | formats: plane_formats, format_count: num_plane_formats, |
604 | NULL, type: plane_type, name: "plane %d" , i); |
605 | if (ret < 0) { |
606 | drm_err(drm, "drm_universal_plane_init failed (ret=%d)" , |
607 | ret); |
608 | goto cleanup; |
609 | } |
610 | drm_dbg(drm, "%s : %d i=%d type=%d" , |
611 | __func__, __LINE__, |
612 | i, plane_type); |
613 | drm_plane_create_alpha_property(plane: &plane->base_plane); |
614 | |
615 | drm_plane_create_blend_mode_property(plane: &plane->base_plane, |
616 | supported_modes: blend_caps); |
617 | |
618 | drm_plane_create_zpos_immutable_property(plane: &plane->base_plane, zpos: i); |
619 | |
620 | drm_plane_helper_add(plane: &plane->base_plane, |
621 | funcs: &kmb_plane_helper_funcs); |
622 | |
623 | if (plane_type == DRM_PLANE_TYPE_PRIMARY) { |
624 | primary = plane; |
625 | kmb->plane = plane; |
626 | } |
627 | drm_dbg(drm, "%s : %d primary=%p\n" , __func__, __LINE__, |
628 | &primary->base_plane); |
629 | plane->id = i; |
630 | } |
631 | |
632 | /* Disable pipeline AXI read transactions for the DMA |
633 | * prior to setting graphics layers |
634 | */ |
635 | kmb_clr_bitmask_lcd(dev_p: kmb, LCD_CONTROL, LCD_CTRL_PIPELINE_DMA); |
636 | |
637 | return primary; |
638 | cleanup: |
639 | drmm_kfree(dev: drm, data: plane); |
640 | return ERR_PTR(error: ret); |
641 | } |
642 | |