1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * ZynqMP Display Controller Driver |
4 | * |
5 | * Copyright (C) 2017 - 2020 Xilinx, Inc. |
6 | * |
7 | * Authors: |
8 | * - Hyun Woo Kwon <hyun.kwon@xilinx.com> |
9 | * - Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
10 | */ |
11 | |
12 | #include <drm/drm_fb_dma_helper.h> |
13 | #include <drm/drm_fourcc.h> |
14 | #include <drm/drm_framebuffer.h> |
15 | #include <drm/drm_plane.h> |
16 | |
17 | #include <linux/clk.h> |
18 | #include <linux/dma/xilinx_dpdma.h> |
19 | #include <linux/dma-mapping.h> |
20 | #include <linux/dmaengine.h> |
21 | #include <linux/module.h> |
22 | #include <linux/of.h> |
23 | #include <linux/platform_device.h> |
24 | #include <linux/slab.h> |
25 | |
26 | #include "zynqmp_disp.h" |
27 | #include "zynqmp_disp_regs.h" |
28 | #include "zynqmp_dp.h" |
29 | #include "zynqmp_dpsub.h" |
30 | |
31 | /* |
32 | * Overview |
33 | * -------- |
34 | * |
35 | * The display controller part of ZynqMP DP subsystem, made of the Audio/Video |
36 | * Buffer Manager, the Video Rendering Pipeline (blender) and the Audio Mixer. |
37 | * |
38 | * +------------------------------------------------------------+ |
39 | * +--------+ | +----------------+ +-----------+ | |
40 | * | DPDMA | --->| | --> | Video | Video +-------------+ | |
41 | * | 4x vid | | | | | Rendering | -+--> | | | +------+ |
42 | * | 2x aud | | | Audio/Video | --> | Pipeline | | | DisplayPort |---> | PHY0 | |
43 | * +--------+ | | Buffer Manager | +-----------+ | | Source | | +------+ |
44 | * | | and STC | +-----------+ | | Controller | | +------+ |
45 | * Live Video --->| | --> | Audio | Audio | |---> | PHY1 | |
46 | * | | | | Mixer | --+-> | | | +------+ |
47 | * Live Audio --->| | --> | | || +-------------+ | |
48 | * | +----------------+ +-----------+ || | |
49 | * +---------------------------------------||-------------------+ |
50 | * vv |
51 | * Blended Video and |
52 | * Mixed Audio to PL |
53 | * |
54 | * Only non-live input from the DPDMA and output to the DisplayPort Source |
55 | * Controller are currently supported. Interface with the programmable logic |
56 | * for live streams is not implemented. |
57 | * |
58 | * The display controller code creates planes for the DPDMA video and graphics |
59 | * layers, and a CRTC for the Video Rendering Pipeline. |
60 | */ |
61 | |
62 | #define ZYNQMP_DISP_AV_BUF_NUM_VID_GFX_BUFFERS 4 |
63 | #define ZYNQMP_DISP_AV_BUF_NUM_BUFFERS 6 |
64 | |
65 | #define ZYNQMP_DISP_MAX_NUM_SUB_PLANES 3 |
66 | |
67 | /** |
68 | * struct zynqmp_disp_format - Display subsystem format information |
69 | * @drm_fmt: DRM format (4CC) |
70 | * @buf_fmt: AV buffer format |
71 | * @swap: Flag to swap R & B for RGB formats, and U & V for YUV formats |
72 | * @sf: Scaling factors for color components |
73 | */ |
74 | struct zynqmp_disp_format { |
75 | u32 drm_fmt; |
76 | u32 buf_fmt; |
77 | bool swap; |
78 | const u32 *sf; |
79 | }; |
80 | |
81 | /** |
82 | * struct zynqmp_disp_layer_dma - DMA channel for one data plane of a layer |
83 | * @chan: DMA channel |
84 | * @xt: Interleaved DMA descriptor template |
85 | * @sgl: Data chunk for dma_interleaved_template |
86 | */ |
87 | struct zynqmp_disp_layer_dma { |
88 | struct dma_chan *chan; |
89 | struct dma_interleaved_template xt; |
90 | struct data_chunk sgl; |
91 | }; |
92 | |
93 | /** |
94 | * struct zynqmp_disp_layer_info - Static layer information |
95 | * @formats: Array of supported formats |
96 | * @num_formats: Number of formats in @formats array |
97 | * @num_channels: Number of DMA channels |
98 | */ |
99 | struct zynqmp_disp_layer_info { |
100 | const struct zynqmp_disp_format *formats; |
101 | unsigned int num_formats; |
102 | unsigned int num_channels; |
103 | }; |
104 | |
105 | /** |
106 | * struct zynqmp_disp_layer - Display layer |
107 | * @id: Layer ID |
108 | * @disp: Back pointer to struct zynqmp_disp |
109 | * @info: Static layer information |
110 | * @dmas: DMA channels |
111 | * @disp_fmt: Current format information |
112 | * @drm_fmt: Current DRM format information |
113 | * @mode: Current operation mode |
114 | */ |
115 | struct zynqmp_disp_layer { |
116 | enum zynqmp_dpsub_layer_id id; |
117 | struct zynqmp_disp *disp; |
118 | const struct zynqmp_disp_layer_info *info; |
119 | |
120 | struct zynqmp_disp_layer_dma dmas[ZYNQMP_DISP_MAX_NUM_SUB_PLANES]; |
121 | |
122 | const struct zynqmp_disp_format *disp_fmt; |
123 | const struct drm_format_info *drm_fmt; |
124 | enum zynqmp_dpsub_layer_mode mode; |
125 | }; |
126 | |
127 | /** |
128 | * struct zynqmp_disp - Display controller |
129 | * @dev: Device structure |
130 | * @dpsub: Display subsystem |
131 | * @blend.base: Register I/O base address for the blender |
132 | * @avbuf.base: Register I/O base address for the audio/video buffer manager |
133 | * @audio.base: Registers I/O base address for the audio mixer |
134 | * @layers: Layers (planes) |
135 | */ |
136 | struct zynqmp_disp { |
137 | struct device *dev; |
138 | struct zynqmp_dpsub *dpsub; |
139 | |
140 | struct { |
141 | void __iomem *base; |
142 | } blend; |
143 | struct { |
144 | void __iomem *base; |
145 | } avbuf; |
146 | struct { |
147 | void __iomem *base; |
148 | } audio; |
149 | |
150 | struct zynqmp_disp_layer layers[ZYNQMP_DPSUB_NUM_LAYERS]; |
151 | }; |
152 | |
153 | /* ----------------------------------------------------------------------------- |
154 | * Audio/Video Buffer Manager |
155 | */ |
156 | |
157 | static const u32 scaling_factors_444[] = { |
158 | ZYNQMP_DISP_AV_BUF_4BIT_SF, |
159 | ZYNQMP_DISP_AV_BUF_4BIT_SF, |
160 | ZYNQMP_DISP_AV_BUF_4BIT_SF, |
161 | }; |
162 | |
163 | static const u32 scaling_factors_555[] = { |
164 | ZYNQMP_DISP_AV_BUF_5BIT_SF, |
165 | ZYNQMP_DISP_AV_BUF_5BIT_SF, |
166 | ZYNQMP_DISP_AV_BUF_5BIT_SF, |
167 | }; |
168 | |
169 | static const u32 scaling_factors_565[] = { |
170 | ZYNQMP_DISP_AV_BUF_5BIT_SF, |
171 | ZYNQMP_DISP_AV_BUF_6BIT_SF, |
172 | ZYNQMP_DISP_AV_BUF_5BIT_SF, |
173 | }; |
174 | |
175 | static const u32 scaling_factors_888[] = { |
176 | ZYNQMP_DISP_AV_BUF_8BIT_SF, |
177 | ZYNQMP_DISP_AV_BUF_8BIT_SF, |
178 | ZYNQMP_DISP_AV_BUF_8BIT_SF, |
179 | }; |
180 | |
181 | static const u32 scaling_factors_101010[] = { |
182 | ZYNQMP_DISP_AV_BUF_10BIT_SF, |
183 | ZYNQMP_DISP_AV_BUF_10BIT_SF, |
184 | ZYNQMP_DISP_AV_BUF_10BIT_SF, |
185 | }; |
186 | |
187 | /* List of video layer formats */ |
188 | static const struct zynqmp_disp_format avbuf_vid_fmts[] = { |
189 | { |
190 | .drm_fmt = DRM_FORMAT_VYUY, |
191 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_VYUY, |
192 | .swap = true, |
193 | .sf = scaling_factors_888, |
194 | }, { |
195 | .drm_fmt = DRM_FORMAT_UYVY, |
196 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_VYUY, |
197 | .swap = false, |
198 | .sf = scaling_factors_888, |
199 | }, { |
200 | .drm_fmt = DRM_FORMAT_YUYV, |
201 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUYV, |
202 | .swap = false, |
203 | .sf = scaling_factors_888, |
204 | }, { |
205 | .drm_fmt = DRM_FORMAT_YVYU, |
206 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUYV, |
207 | .swap = true, |
208 | .sf = scaling_factors_888, |
209 | }, { |
210 | .drm_fmt = DRM_FORMAT_YUV422, |
211 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16, |
212 | .swap = false, |
213 | .sf = scaling_factors_888, |
214 | }, { |
215 | .drm_fmt = DRM_FORMAT_YVU422, |
216 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16, |
217 | .swap = true, |
218 | .sf = scaling_factors_888, |
219 | }, { |
220 | .drm_fmt = DRM_FORMAT_YUV444, |
221 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24, |
222 | .swap = false, |
223 | .sf = scaling_factors_888, |
224 | }, { |
225 | .drm_fmt = DRM_FORMAT_YVU444, |
226 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24, |
227 | .swap = true, |
228 | .sf = scaling_factors_888, |
229 | }, { |
230 | .drm_fmt = DRM_FORMAT_NV16, |
231 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI, |
232 | .swap = false, |
233 | .sf = scaling_factors_888, |
234 | }, { |
235 | .drm_fmt = DRM_FORMAT_NV61, |
236 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI, |
237 | .swap = true, |
238 | .sf = scaling_factors_888, |
239 | }, { |
240 | .drm_fmt = DRM_FORMAT_BGR888, |
241 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888, |
242 | .swap = false, |
243 | .sf = scaling_factors_888, |
244 | }, { |
245 | .drm_fmt = DRM_FORMAT_RGB888, |
246 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888, |
247 | .swap = true, |
248 | .sf = scaling_factors_888, |
249 | }, { |
250 | .drm_fmt = DRM_FORMAT_XBGR8888, |
251 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGBA8880, |
252 | .swap = false, |
253 | .sf = scaling_factors_888, |
254 | }, { |
255 | .drm_fmt = DRM_FORMAT_XRGB8888, |
256 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGBA8880, |
257 | .swap = true, |
258 | .sf = scaling_factors_888, |
259 | }, { |
260 | .drm_fmt = DRM_FORMAT_XBGR2101010, |
261 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888_10, |
262 | .swap = false, |
263 | .sf = scaling_factors_101010, |
264 | }, { |
265 | .drm_fmt = DRM_FORMAT_XRGB2101010, |
266 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888_10, |
267 | .swap = true, |
268 | .sf = scaling_factors_101010, |
269 | }, { |
270 | .drm_fmt = DRM_FORMAT_YUV420, |
271 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16_420, |
272 | .swap = false, |
273 | .sf = scaling_factors_888, |
274 | }, { |
275 | .drm_fmt = DRM_FORMAT_YVU420, |
276 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16_420, |
277 | .swap = true, |
278 | .sf = scaling_factors_888, |
279 | }, { |
280 | .drm_fmt = DRM_FORMAT_NV12, |
281 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420, |
282 | .swap = false, |
283 | .sf = scaling_factors_888, |
284 | }, { |
285 | .drm_fmt = DRM_FORMAT_NV21, |
286 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420, |
287 | .swap = true, |
288 | .sf = scaling_factors_888, |
289 | }, |
290 | }; |
291 | |
292 | /* List of graphics layer formats */ |
293 | static const struct zynqmp_disp_format avbuf_gfx_fmts[] = { |
294 | { |
295 | .drm_fmt = DRM_FORMAT_ABGR8888, |
296 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA8888, |
297 | .swap = false, |
298 | .sf = scaling_factors_888, |
299 | }, { |
300 | .drm_fmt = DRM_FORMAT_ARGB8888, |
301 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA8888, |
302 | .swap = true, |
303 | .sf = scaling_factors_888, |
304 | }, { |
305 | .drm_fmt = DRM_FORMAT_RGBA8888, |
306 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_ABGR8888, |
307 | .swap = false, |
308 | .sf = scaling_factors_888, |
309 | }, { |
310 | .drm_fmt = DRM_FORMAT_BGRA8888, |
311 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_ABGR8888, |
312 | .swap = true, |
313 | .sf = scaling_factors_888, |
314 | }, { |
315 | .drm_fmt = DRM_FORMAT_BGR888, |
316 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB888, |
317 | .swap = false, |
318 | .sf = scaling_factors_888, |
319 | }, { |
320 | .drm_fmt = DRM_FORMAT_RGB888, |
321 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_BGR888, |
322 | .swap = false, |
323 | .sf = scaling_factors_888, |
324 | }, { |
325 | .drm_fmt = DRM_FORMAT_RGBA5551, |
326 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA5551, |
327 | .swap = false, |
328 | .sf = scaling_factors_555, |
329 | }, { |
330 | .drm_fmt = DRM_FORMAT_BGRA5551, |
331 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA5551, |
332 | .swap = true, |
333 | .sf = scaling_factors_555, |
334 | }, { |
335 | .drm_fmt = DRM_FORMAT_RGBA4444, |
336 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA4444, |
337 | .swap = false, |
338 | .sf = scaling_factors_444, |
339 | }, { |
340 | .drm_fmt = DRM_FORMAT_BGRA4444, |
341 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA4444, |
342 | .swap = true, |
343 | .sf = scaling_factors_444, |
344 | }, { |
345 | .drm_fmt = DRM_FORMAT_RGB565, |
346 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB565, |
347 | .swap = false, |
348 | .sf = scaling_factors_565, |
349 | }, { |
350 | .drm_fmt = DRM_FORMAT_BGR565, |
351 | .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB565, |
352 | .swap = true, |
353 | .sf = scaling_factors_565, |
354 | }, |
355 | }; |
356 | |
357 | static u32 zynqmp_disp_avbuf_read(struct zynqmp_disp *disp, int reg) |
358 | { |
359 | return readl(addr: disp->avbuf.base + reg); |
360 | } |
361 | |
362 | static void zynqmp_disp_avbuf_write(struct zynqmp_disp *disp, int reg, u32 val) |
363 | { |
364 | writel(val, addr: disp->avbuf.base + reg); |
365 | } |
366 | |
367 | static bool zynqmp_disp_layer_is_video(const struct zynqmp_disp_layer *layer) |
368 | { |
369 | return layer->id == ZYNQMP_DPSUB_LAYER_VID; |
370 | } |
371 | |
372 | /** |
373 | * zynqmp_disp_avbuf_set_format - Set the input format for a layer |
374 | * @disp: Display controller |
375 | * @layer: The layer |
376 | * @fmt: The format information |
377 | * |
378 | * Set the video buffer manager format for @layer to @fmt. |
379 | */ |
380 | static void zynqmp_disp_avbuf_set_format(struct zynqmp_disp *disp, |
381 | struct zynqmp_disp_layer *layer, |
382 | const struct zynqmp_disp_format *fmt) |
383 | { |
384 | unsigned int i; |
385 | u32 val; |
386 | |
387 | val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_FMT); |
388 | val &= zynqmp_disp_layer_is_video(layer) |
389 | ? ~ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MASK |
390 | : ~ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_MASK; |
391 | val |= fmt->buf_fmt; |
392 | zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_FMT, val); |
393 | |
394 | for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_SF; i++) { |
395 | unsigned int reg = zynqmp_disp_layer_is_video(layer) |
396 | ? ZYNQMP_DISP_AV_BUF_VID_COMP_SF(i) |
397 | : ZYNQMP_DISP_AV_BUF_GFX_COMP_SF(i); |
398 | |
399 | zynqmp_disp_avbuf_write(disp, reg, val: fmt->sf[i]); |
400 | } |
401 | } |
402 | |
403 | /** |
404 | * zynqmp_disp_avbuf_set_clocks_sources - Set the clocks sources |
405 | * @disp: Display controller |
406 | * @video_from_ps: True if the video clock originates from the PS |
407 | * @audio_from_ps: True if the audio clock originates from the PS |
408 | * @timings_internal: True if video timings are generated internally |
409 | * |
410 | * Set the source for the video and audio clocks, as well as for the video |
411 | * timings. Clocks can originate from the PS or PL, and timings can be |
412 | * generated internally or externally. |
413 | */ |
414 | static void |
415 | zynqmp_disp_avbuf_set_clocks_sources(struct zynqmp_disp *disp, |
416 | bool video_from_ps, bool audio_from_ps, |
417 | bool timings_internal) |
418 | { |
419 | u32 val = 0; |
420 | |
421 | if (video_from_ps) |
422 | val |= ZYNQMP_DISP_AV_BUF_CLK_SRC_VID_FROM_PS; |
423 | if (audio_from_ps) |
424 | val |= ZYNQMP_DISP_AV_BUF_CLK_SRC_AUD_FROM_PS; |
425 | if (timings_internal) |
426 | val |= ZYNQMP_DISP_AV_BUF_CLK_SRC_VID_INTERNAL_TIMING; |
427 | |
428 | zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CLK_SRC, val); |
429 | } |
430 | |
431 | /** |
432 | * zynqmp_disp_avbuf_enable_channels - Enable buffer channels |
433 | * @disp: Display controller |
434 | * |
435 | * Enable all (video and audio) buffer channels. |
436 | */ |
437 | static void zynqmp_disp_avbuf_enable_channels(struct zynqmp_disp *disp) |
438 | { |
439 | unsigned int i; |
440 | u32 val; |
441 | |
442 | val = ZYNQMP_DISP_AV_BUF_CHBUF_EN | |
443 | (ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_MAX << |
444 | ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_SHIFT); |
445 | |
446 | for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_VID_GFX_BUFFERS; i++) |
447 | zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i), |
448 | val); |
449 | |
450 | val = ZYNQMP_DISP_AV_BUF_CHBUF_EN | |
451 | (ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_AUD_MAX << |
452 | ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_SHIFT); |
453 | |
454 | for (; i < ZYNQMP_DISP_AV_BUF_NUM_BUFFERS; i++) |
455 | zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i), |
456 | val); |
457 | } |
458 | |
459 | /** |
460 | * zynqmp_disp_avbuf_disable_channels - Disable buffer channels |
461 | * @disp: Display controller |
462 | * |
463 | * Disable all (video and audio) buffer channels. |
464 | */ |
465 | static void zynqmp_disp_avbuf_disable_channels(struct zynqmp_disp *disp) |
466 | { |
467 | unsigned int i; |
468 | |
469 | for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_BUFFERS; i++) |
470 | zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i), |
471 | ZYNQMP_DISP_AV_BUF_CHBUF_FLUSH); |
472 | } |
473 | |
474 | /** |
475 | * zynqmp_disp_avbuf_enable_audio - Enable audio |
476 | * @disp: Display controller |
477 | * |
478 | * Enable all audio buffers with a non-live (memory) source. |
479 | */ |
480 | static void zynqmp_disp_avbuf_enable_audio(struct zynqmp_disp *disp) |
481 | { |
482 | u32 val; |
483 | |
484 | val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT); |
485 | val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MASK; |
486 | val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MEM; |
487 | val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD2_EN; |
488 | zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val); |
489 | } |
490 | |
491 | /** |
492 | * zynqmp_disp_avbuf_disable_audio - Disable audio |
493 | * @disp: Display controller |
494 | * |
495 | * Disable all audio buffers. |
496 | */ |
497 | static void zynqmp_disp_avbuf_disable_audio(struct zynqmp_disp *disp) |
498 | { |
499 | u32 val; |
500 | |
501 | val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT); |
502 | val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MASK; |
503 | val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_DISABLE; |
504 | val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD2_EN; |
505 | zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val); |
506 | } |
507 | |
508 | /** |
509 | * zynqmp_disp_avbuf_enable_video - Enable a video layer |
510 | * @disp: Display controller |
511 | * @layer: The layer |
512 | * |
513 | * Enable the video/graphics buffer for @layer. |
514 | */ |
515 | static void zynqmp_disp_avbuf_enable_video(struct zynqmp_disp *disp, |
516 | struct zynqmp_disp_layer *layer) |
517 | { |
518 | u32 val; |
519 | |
520 | val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT); |
521 | if (zynqmp_disp_layer_is_video(layer)) { |
522 | val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK; |
523 | if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) |
524 | val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MEM; |
525 | else |
526 | val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_LIVE; |
527 | } else { |
528 | val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK; |
529 | val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM; |
530 | if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) |
531 | val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM; |
532 | else |
533 | val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_LIVE; |
534 | } |
535 | zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val); |
536 | } |
537 | |
538 | /** |
539 | * zynqmp_disp_avbuf_disable_video - Disable a video layer |
540 | * @disp: Display controller |
541 | * @layer: The layer |
542 | * |
543 | * Disable the video/graphics buffer for @layer. |
544 | */ |
545 | static void zynqmp_disp_avbuf_disable_video(struct zynqmp_disp *disp, |
546 | struct zynqmp_disp_layer *layer) |
547 | { |
548 | u32 val; |
549 | |
550 | val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT); |
551 | if (zynqmp_disp_layer_is_video(layer)) { |
552 | val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK; |
553 | val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_NONE; |
554 | } else { |
555 | val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK; |
556 | val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_DISABLE; |
557 | } |
558 | zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val); |
559 | } |
560 | |
561 | /** |
562 | * zynqmp_disp_avbuf_enable - Enable the video pipe |
563 | * @disp: Display controller |
564 | * |
565 | * De-assert the video pipe reset. |
566 | */ |
567 | static void zynqmp_disp_avbuf_enable(struct zynqmp_disp *disp) |
568 | { |
569 | zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_SRST_REG, val: 0); |
570 | } |
571 | |
572 | /** |
573 | * zynqmp_disp_avbuf_disable - Disable the video pipe |
574 | * @disp: Display controller |
575 | * |
576 | * Assert the video pipe reset. |
577 | */ |
578 | static void zynqmp_disp_avbuf_disable(struct zynqmp_disp *disp) |
579 | { |
580 | zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_SRST_REG, |
581 | ZYNQMP_DISP_AV_BUF_SRST_REG_VID_RST); |
582 | } |
583 | |
584 | /* ----------------------------------------------------------------------------- |
585 | * Blender (Video Pipeline) |
586 | */ |
587 | |
588 | static void zynqmp_disp_blend_write(struct zynqmp_disp *disp, int reg, u32 val) |
589 | { |
590 | writel(val, addr: disp->blend.base + reg); |
591 | } |
592 | |
593 | /* |
594 | * Colorspace conversion matrices. |
595 | * |
596 | * Hardcode RGB <-> YUV conversion to full-range SDTV for now. |
597 | */ |
598 | static const u16 csc_zero_matrix[] = { |
599 | 0x0, 0x0, 0x0, |
600 | 0x0, 0x0, 0x0, |
601 | 0x0, 0x0, 0x0 |
602 | }; |
603 | |
604 | static const u16 csc_identity_matrix[] = { |
605 | 0x1000, 0x0, 0x0, |
606 | 0x0, 0x1000, 0x0, |
607 | 0x0, 0x0, 0x1000 |
608 | }; |
609 | |
610 | static const u32 csc_zero_offsets[] = { |
611 | 0, 0, 0 |
612 | }; |
613 | |
614 | static const u16 csc_rgb_to_sdtv_matrix[] = { |
615 | 0x4c9, 0x864, 0x1d3, |
616 | 0x7d4d, 0x7ab3, 0x800, |
617 | 0x800, 0x794d, 0x7eb3 |
618 | }; |
619 | |
620 | static const u32 csc_rgb_to_sdtv_offsets[] = { |
621 | 0x0, 0x8000000, 0x8000000 |
622 | }; |
623 | |
624 | static const u16 csc_sdtv_to_rgb_matrix[] = { |
625 | 0x1000, 0x166f, 0x0, |
626 | 0x1000, 0x7483, 0x7a7f, |
627 | 0x1000, 0x0, 0x1c5a |
628 | }; |
629 | |
630 | static const u32 csc_sdtv_to_rgb_offsets[] = { |
631 | 0x0, 0x1800, 0x1800 |
632 | }; |
633 | |
634 | /** |
635 | * zynqmp_disp_blend_set_output_format - Set the output format of the blender |
636 | * @disp: Display controller |
637 | * @format: Output format |
638 | * |
639 | * Set the output format of the blender to @format. |
640 | */ |
641 | static void zynqmp_disp_blend_set_output_format(struct zynqmp_disp *disp, |
642 | enum zynqmp_dpsub_format format) |
643 | { |
644 | static const unsigned int blend_output_fmts[] = { |
645 | [ZYNQMP_DPSUB_FORMAT_RGB] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_RGB, |
646 | [ZYNQMP_DPSUB_FORMAT_YCRCB444] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YCBCR444, |
647 | [ZYNQMP_DPSUB_FORMAT_YCRCB422] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YCBCR422 |
648 | | ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_EN_DOWNSAMPLE, |
649 | [ZYNQMP_DPSUB_FORMAT_YONLY] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YONLY, |
650 | }; |
651 | |
652 | u32 fmt = blend_output_fmts[format]; |
653 | const u16 *coeffs; |
654 | const u32 *offsets; |
655 | unsigned int i; |
656 | |
657 | zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT, val: fmt); |
658 | if (fmt == ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_RGB) { |
659 | coeffs = csc_identity_matrix; |
660 | offsets = csc_zero_offsets; |
661 | } else { |
662 | coeffs = csc_rgb_to_sdtv_matrix; |
663 | offsets = csc_rgb_to_sdtv_offsets; |
664 | } |
665 | |
666 | for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_COEFF; i++) |
667 | zynqmp_disp_blend_write(disp, |
668 | ZYNQMP_DISP_V_BLEND_RGB2YCBCR_COEFF(i), |
669 | val: coeffs[i]); |
670 | |
671 | for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_OFFSET; i++) |
672 | zynqmp_disp_blend_write(disp, |
673 | ZYNQMP_DISP_V_BLEND_OUTCSC_OFFSET(i), |
674 | val: offsets[i]); |
675 | } |
676 | |
677 | /** |
678 | * zynqmp_disp_blend_set_bg_color - Set the background color |
679 | * @disp: Display controller |
680 | * @rcr: Red/Cr color component |
681 | * @gy: Green/Y color component |
682 | * @bcb: Blue/Cb color component |
683 | * |
684 | * Set the background color to (@rcr, @gy, @bcb), corresponding to the R, G and |
685 | * B or Cr, Y and Cb components respectively depending on the selected output |
686 | * format. |
687 | */ |
688 | static void zynqmp_disp_blend_set_bg_color(struct zynqmp_disp *disp, |
689 | u32 rcr, u32 gy, u32 bcb) |
690 | { |
691 | zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_0, val: rcr); |
692 | zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_1, val: gy); |
693 | zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_2, val: bcb); |
694 | } |
695 | |
696 | /** |
697 | * zynqmp_disp_blend_set_global_alpha - Configure global alpha blending |
698 | * @disp: Display controller |
699 | * @enable: True to enable global alpha blending |
700 | * @alpha: Global alpha value (ignored if @enabled is false) |
701 | */ |
702 | void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp *disp, |
703 | bool enable, u32 alpha) |
704 | { |
705 | zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA, |
706 | ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_VALUE(alpha) | |
707 | (enable ? ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_EN : 0)); |
708 | } |
709 | |
710 | /** |
711 | * zynqmp_disp_blend_layer_set_csc - Configure colorspace conversion for layer |
712 | * @disp: Display controller |
713 | * @layer: The layer |
714 | * @coeffs: Colorspace conversion matrix |
715 | * @offsets: Colorspace conversion offsets |
716 | * |
717 | * Configure the input colorspace conversion matrix and offsets for the @layer. |
718 | * Columns of the matrix are automatically swapped based on the input format to |
719 | * handle RGB and YCrCb components permutations. |
720 | */ |
721 | static void zynqmp_disp_blend_layer_set_csc(struct zynqmp_disp *disp, |
722 | struct zynqmp_disp_layer *layer, |
723 | const u16 *coeffs, |
724 | const u32 *offsets) |
725 | { |
726 | unsigned int swap[3] = { 0, 1, 2 }; |
727 | unsigned int reg; |
728 | unsigned int i; |
729 | |
730 | if (layer->disp_fmt->swap) { |
731 | if (layer->drm_fmt->is_yuv) { |
732 | /* Swap U and V. */ |
733 | swap[1] = 2; |
734 | swap[2] = 1; |
735 | } else { |
736 | /* Swap R and B. */ |
737 | swap[0] = 2; |
738 | swap[2] = 0; |
739 | } |
740 | } |
741 | |
742 | if (zynqmp_disp_layer_is_video(layer)) |
743 | reg = ZYNQMP_DISP_V_BLEND_IN1CSC_COEFF(0); |
744 | else |
745 | reg = ZYNQMP_DISP_V_BLEND_IN2CSC_COEFF(0); |
746 | |
747 | for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_COEFF; i += 3, reg += 12) { |
748 | zynqmp_disp_blend_write(disp, reg: reg + 0, val: coeffs[i + swap[0]]); |
749 | zynqmp_disp_blend_write(disp, reg: reg + 4, val: coeffs[i + swap[1]]); |
750 | zynqmp_disp_blend_write(disp, reg: reg + 8, val: coeffs[i + swap[2]]); |
751 | } |
752 | |
753 | if (zynqmp_disp_layer_is_video(layer)) |
754 | reg = ZYNQMP_DISP_V_BLEND_IN1CSC_OFFSET(0); |
755 | else |
756 | reg = ZYNQMP_DISP_V_BLEND_IN2CSC_OFFSET(0); |
757 | |
758 | for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_OFFSET; i++) |
759 | zynqmp_disp_blend_write(disp, reg: reg + i * 4, val: offsets[i]); |
760 | } |
761 | |
762 | /** |
763 | * zynqmp_disp_blend_layer_enable - Enable a layer |
764 | * @disp: Display controller |
765 | * @layer: The layer |
766 | */ |
767 | static void zynqmp_disp_blend_layer_enable(struct zynqmp_disp *disp, |
768 | struct zynqmp_disp_layer *layer) |
769 | { |
770 | const u16 *coeffs; |
771 | const u32 *offsets; |
772 | u32 val; |
773 | |
774 | val = (layer->drm_fmt->is_yuv ? |
775 | 0 : ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_RGB) | |
776 | (layer->drm_fmt->hsub > 1 ? |
777 | ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_EN_US : 0); |
778 | |
779 | zynqmp_disp_blend_write(disp, |
780 | ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id), |
781 | val); |
782 | |
783 | if (layer->drm_fmt->is_yuv) { |
784 | coeffs = csc_sdtv_to_rgb_matrix; |
785 | offsets = csc_sdtv_to_rgb_offsets; |
786 | } else { |
787 | coeffs = csc_identity_matrix; |
788 | offsets = csc_zero_offsets; |
789 | } |
790 | |
791 | zynqmp_disp_blend_layer_set_csc(disp, layer, coeffs, offsets); |
792 | } |
793 | |
794 | /** |
795 | * zynqmp_disp_blend_layer_disable - Disable a layer |
796 | * @disp: Display controller |
797 | * @layer: The layer |
798 | */ |
799 | static void zynqmp_disp_blend_layer_disable(struct zynqmp_disp *disp, |
800 | struct zynqmp_disp_layer *layer) |
801 | { |
802 | zynqmp_disp_blend_write(disp, |
803 | ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id), |
804 | val: 0); |
805 | |
806 | zynqmp_disp_blend_layer_set_csc(disp, layer, coeffs: csc_zero_matrix, |
807 | offsets: csc_zero_offsets); |
808 | } |
809 | |
810 | /* ----------------------------------------------------------------------------- |
811 | * Audio Mixer |
812 | */ |
813 | |
814 | static void zynqmp_disp_audio_write(struct zynqmp_disp *disp, int reg, u32 val) |
815 | { |
816 | writel(val, addr: disp->audio.base + reg); |
817 | } |
818 | |
819 | /** |
820 | * zynqmp_disp_audio_enable - Enable the audio mixer |
821 | * @disp: Display controller |
822 | * |
823 | * Enable the audio mixer by de-asserting the soft reset. The audio state is set to |
824 | * default values by the reset, set the default mixer volume explicitly. |
825 | */ |
826 | static void zynqmp_disp_audio_enable(struct zynqmp_disp *disp) |
827 | { |
828 | /* Clear the audio soft reset register as it's an non-reset flop. */ |
829 | zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_SOFT_RESET, val: 0); |
830 | zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_MIXER_VOLUME, |
831 | ZYNQMP_DISP_AUD_MIXER_VOLUME_NO_SCALE); |
832 | } |
833 | |
834 | /** |
835 | * zynqmp_disp_audio_disable - Disable the audio mixer |
836 | * @disp: Display controller |
837 | * |
838 | * Disable the audio mixer by asserting its soft reset. |
839 | */ |
840 | static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp) |
841 | { |
842 | zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_SOFT_RESET, |
843 | ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST); |
844 | } |
845 | |
846 | /* ----------------------------------------------------------------------------- |
847 | * ZynqMP Display Layer & DRM Plane |
848 | */ |
849 | |
850 | /** |
851 | * zynqmp_disp_layer_find_format - Find format information for a DRM format |
852 | * @layer: The layer |
853 | * @drm_fmt: DRM format to search |
854 | * |
855 | * Search display subsystem format information corresponding to the given DRM |
856 | * format @drm_fmt for the @layer, and return a pointer to the format |
857 | * descriptor. |
858 | * |
859 | * Return: A pointer to the format descriptor if found, NULL otherwise |
860 | */ |
861 | static const struct zynqmp_disp_format * |
862 | zynqmp_disp_layer_find_format(struct zynqmp_disp_layer *layer, |
863 | u32 drm_fmt) |
864 | { |
865 | unsigned int i; |
866 | |
867 | for (i = 0; i < layer->info->num_formats; i++) { |
868 | if (layer->info->formats[i].drm_fmt == drm_fmt) |
869 | return &layer->info->formats[i]; |
870 | } |
871 | |
872 | return NULL; |
873 | } |
874 | |
875 | /** |
876 | * zynqmp_disp_layer_drm_formats - Return the DRM formats supported by the layer |
877 | * @layer: The layer |
878 | * @num_formats: Pointer to the returned number of formats |
879 | * |
880 | * Return: A newly allocated u32 array that stores all the DRM formats |
881 | * supported by the layer. The number of formats in the array is returned |
882 | * through the num_formats argument. |
883 | */ |
884 | u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer, |
885 | unsigned int *num_formats) |
886 | { |
887 | unsigned int i; |
888 | u32 *formats; |
889 | |
890 | formats = kcalloc(n: layer->info->num_formats, size: sizeof(*formats), |
891 | GFP_KERNEL); |
892 | if (!formats) |
893 | return NULL; |
894 | |
895 | for (i = 0; i < layer->info->num_formats; ++i) |
896 | formats[i] = layer->info->formats[i].drm_fmt; |
897 | |
898 | *num_formats = layer->info->num_formats; |
899 | return formats; |
900 | } |
901 | |
902 | /** |
903 | * zynqmp_disp_layer_enable - Enable a layer |
904 | * @layer: The layer |
905 | * @mode: Operating mode of layer |
906 | * |
907 | * Enable the @layer in the audio/video buffer manager and the blender. DMA |
908 | * channels are started separately by zynqmp_disp_layer_update(). |
909 | */ |
910 | void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer, |
911 | enum zynqmp_dpsub_layer_mode mode) |
912 | { |
913 | layer->mode = mode; |
914 | zynqmp_disp_avbuf_enable_video(disp: layer->disp, layer); |
915 | zynqmp_disp_blend_layer_enable(disp: layer->disp, layer); |
916 | } |
917 | |
918 | /** |
919 | * zynqmp_disp_layer_disable - Disable the layer |
920 | * @layer: The layer |
921 | * |
922 | * Disable the layer by stopping its DMA channels and disabling it in the |
923 | * audio/video buffer manager and the blender. |
924 | */ |
925 | void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer) |
926 | { |
927 | unsigned int i; |
928 | |
929 | if (layer->disp->dpsub->dma_enabled) { |
930 | for (i = 0; i < layer->drm_fmt->num_planes; i++) |
931 | dmaengine_terminate_sync(chan: layer->dmas[i].chan); |
932 | } |
933 | |
934 | zynqmp_disp_avbuf_disable_video(disp: layer->disp, layer); |
935 | zynqmp_disp_blend_layer_disable(disp: layer->disp, layer); |
936 | } |
937 | |
938 | /** |
939 | * zynqmp_disp_layer_set_format - Set the layer format |
940 | * @layer: The layer |
941 | * @info: The format info |
942 | * |
943 | * Set the format for @layer to @info. The layer must be disabled. |
944 | */ |
945 | void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer, |
946 | const struct drm_format_info *info) |
947 | { |
948 | unsigned int i; |
949 | |
950 | layer->disp_fmt = zynqmp_disp_layer_find_format(layer, drm_fmt: info->format); |
951 | layer->drm_fmt = info; |
952 | |
953 | zynqmp_disp_avbuf_set_format(disp: layer->disp, layer, fmt: layer->disp_fmt); |
954 | |
955 | if (!layer->disp->dpsub->dma_enabled) |
956 | return; |
957 | |
958 | /* |
959 | * Set pconfig for each DMA channel to indicate they're part of a |
960 | * video group. |
961 | */ |
962 | for (i = 0; i < info->num_planes; i++) { |
963 | struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; |
964 | struct xilinx_dpdma_peripheral_config pconfig = { |
965 | .video_group = true, |
966 | }; |
967 | struct dma_slave_config config = { |
968 | .direction = DMA_MEM_TO_DEV, |
969 | .peripheral_config = &pconfig, |
970 | .peripheral_size = sizeof(pconfig), |
971 | }; |
972 | |
973 | dmaengine_slave_config(chan: dma->chan, config: &config); |
974 | } |
975 | } |
976 | |
977 | /** |
978 | * zynqmp_disp_layer_update - Update the layer framebuffer |
979 | * @layer: The layer |
980 | * @state: The plane state |
981 | * |
982 | * Update the framebuffer for the layer by issuing a new DMA engine transaction |
983 | * for the new framebuffer. |
984 | * |
985 | * Return: 0 on success, or the DMA descriptor failure error otherwise |
986 | */ |
987 | int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer, |
988 | struct drm_plane_state *state) |
989 | { |
990 | const struct drm_format_info *info = layer->drm_fmt; |
991 | unsigned int i; |
992 | |
993 | if (!layer->disp->dpsub->dma_enabled) |
994 | return 0; |
995 | |
996 | for (i = 0; i < info->num_planes; i++) { |
997 | unsigned int width = state->crtc_w / (i ? info->hsub : 1); |
998 | unsigned int height = state->crtc_h / (i ? info->vsub : 1); |
999 | struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; |
1000 | struct dma_async_tx_descriptor *desc; |
1001 | dma_addr_t dma_addr; |
1002 | |
1003 | dma_addr = drm_fb_dma_get_gem_addr(fb: state->fb, state, plane: i); |
1004 | |
1005 | dma->xt.numf = height; |
1006 | dma->sgl.size = width * info->cpp[i]; |
1007 | dma->sgl.icg = state->fb->pitches[i] - dma->sgl.size; |
1008 | dma->xt.src_start = dma_addr; |
1009 | dma->xt.frame_size = 1; |
1010 | dma->xt.dir = DMA_MEM_TO_DEV; |
1011 | dma->xt.src_sgl = true; |
1012 | dma->xt.dst_sgl = false; |
1013 | |
1014 | desc = dmaengine_prep_interleaved_dma(chan: dma->chan, xt: &dma->xt, |
1015 | flags: DMA_CTRL_ACK | |
1016 | DMA_PREP_REPEAT | |
1017 | DMA_PREP_LOAD_EOT); |
1018 | if (!desc) { |
1019 | dev_err(layer->disp->dev, |
1020 | "failed to prepare DMA descriptor\n" ); |
1021 | return -ENOMEM; |
1022 | } |
1023 | |
1024 | dmaengine_submit(desc); |
1025 | dma_async_issue_pending(chan: dma->chan); |
1026 | } |
1027 | |
1028 | return 0; |
1029 | } |
1030 | |
1031 | /** |
1032 | * zynqmp_disp_layer_release_dma - Release DMA channels for a layer |
1033 | * @disp: Display controller |
1034 | * @layer: The layer |
1035 | * |
1036 | * Release the DMA channels associated with @layer. |
1037 | */ |
1038 | static void zynqmp_disp_layer_release_dma(struct zynqmp_disp *disp, |
1039 | struct zynqmp_disp_layer *layer) |
1040 | { |
1041 | unsigned int i; |
1042 | |
1043 | if (!layer->info || !disp->dpsub->dma_enabled) |
1044 | return; |
1045 | |
1046 | for (i = 0; i < layer->info->num_channels; i++) { |
1047 | struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; |
1048 | |
1049 | if (!dma->chan) |
1050 | continue; |
1051 | |
1052 | /* Make sure the channel is terminated before release. */ |
1053 | dmaengine_terminate_sync(chan: dma->chan); |
1054 | dma_release_channel(chan: dma->chan); |
1055 | } |
1056 | } |
1057 | |
1058 | /** |
1059 | * zynqmp_disp_destroy_layers - Destroy all layers |
1060 | * @disp: Display controller |
1061 | */ |
1062 | static void zynqmp_disp_destroy_layers(struct zynqmp_disp *disp) |
1063 | { |
1064 | unsigned int i; |
1065 | |
1066 | for (i = 0; i < ARRAY_SIZE(disp->layers); i++) |
1067 | zynqmp_disp_layer_release_dma(disp, layer: &disp->layers[i]); |
1068 | } |
1069 | |
1070 | /** |
1071 | * zynqmp_disp_layer_request_dma - Request DMA channels for a layer |
1072 | * @disp: Display controller |
1073 | * @layer: The layer |
1074 | * |
1075 | * Request all DMA engine channels needed by @layer. |
1076 | * |
1077 | * Return: 0 on success, or the DMA channel request error otherwise |
1078 | */ |
1079 | static int zynqmp_disp_layer_request_dma(struct zynqmp_disp *disp, |
1080 | struct zynqmp_disp_layer *layer) |
1081 | { |
1082 | static const char * const dma_names[] = { "vid" , "gfx" }; |
1083 | unsigned int i; |
1084 | int ret; |
1085 | |
1086 | if (!disp->dpsub->dma_enabled) |
1087 | return 0; |
1088 | |
1089 | for (i = 0; i < layer->info->num_channels; i++) { |
1090 | struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; |
1091 | char dma_channel_name[16]; |
1092 | |
1093 | snprintf(buf: dma_channel_name, size: sizeof(dma_channel_name), |
1094 | fmt: "%s%u" , dma_names[layer->id], i); |
1095 | dma->chan = dma_request_chan(dev: disp->dev, name: dma_channel_name); |
1096 | if (IS_ERR(ptr: dma->chan)) { |
1097 | ret = dev_err_probe(dev: disp->dev, err: PTR_ERR(ptr: dma->chan), |
1098 | fmt: "failed to request dma channel\n" ); |
1099 | dma->chan = NULL; |
1100 | return ret; |
1101 | } |
1102 | } |
1103 | |
1104 | return 0; |
1105 | } |
1106 | |
1107 | /** |
1108 | * zynqmp_disp_create_layers - Create and initialize all layers |
1109 | * @disp: Display controller |
1110 | * |
1111 | * Return: 0 on success, or the DMA channel request error otherwise |
1112 | */ |
1113 | static int zynqmp_disp_create_layers(struct zynqmp_disp *disp) |
1114 | { |
1115 | static const struct zynqmp_disp_layer_info layer_info[] = { |
1116 | [ZYNQMP_DPSUB_LAYER_VID] = { |
1117 | .formats = avbuf_vid_fmts, |
1118 | .num_formats = ARRAY_SIZE(avbuf_vid_fmts), |
1119 | .num_channels = 3, |
1120 | }, |
1121 | [ZYNQMP_DPSUB_LAYER_GFX] = { |
1122 | .formats = avbuf_gfx_fmts, |
1123 | .num_formats = ARRAY_SIZE(avbuf_gfx_fmts), |
1124 | .num_channels = 1, |
1125 | }, |
1126 | }; |
1127 | |
1128 | unsigned int i; |
1129 | int ret; |
1130 | |
1131 | for (i = 0; i < ARRAY_SIZE(disp->layers); i++) { |
1132 | struct zynqmp_disp_layer *layer = &disp->layers[i]; |
1133 | |
1134 | layer->id = i; |
1135 | layer->disp = disp; |
1136 | layer->info = &layer_info[i]; |
1137 | |
1138 | ret = zynqmp_disp_layer_request_dma(disp, layer); |
1139 | if (ret) |
1140 | goto err; |
1141 | |
1142 | disp->dpsub->layers[i] = layer; |
1143 | } |
1144 | |
1145 | return 0; |
1146 | |
1147 | err: |
1148 | zynqmp_disp_destroy_layers(disp); |
1149 | return ret; |
1150 | } |
1151 | |
1152 | /* ----------------------------------------------------------------------------- |
1153 | * ZynqMP Display |
1154 | */ |
1155 | |
1156 | /** |
1157 | * zynqmp_disp_enable - Enable the display controller |
1158 | * @disp: Display controller |
1159 | */ |
1160 | void zynqmp_disp_enable(struct zynqmp_disp *disp) |
1161 | { |
1162 | zynqmp_disp_blend_set_output_format(disp, format: ZYNQMP_DPSUB_FORMAT_RGB); |
1163 | zynqmp_disp_blend_set_bg_color(disp, rcr: 0, gy: 0, bcb: 0); |
1164 | |
1165 | zynqmp_disp_avbuf_enable(disp); |
1166 | /* Choose clock source based on the DT clock handle. */ |
1167 | zynqmp_disp_avbuf_set_clocks_sources(disp, video_from_ps: disp->dpsub->vid_clk_from_ps, |
1168 | audio_from_ps: disp->dpsub->aud_clk_from_ps, |
1169 | timings_internal: disp->dpsub->vid_clk_from_ps); |
1170 | zynqmp_disp_avbuf_enable_channels(disp); |
1171 | zynqmp_disp_avbuf_enable_audio(disp); |
1172 | |
1173 | zynqmp_disp_audio_enable(disp); |
1174 | } |
1175 | |
1176 | /** |
1177 | * zynqmp_disp_disable - Disable the display controller |
1178 | * @disp: Display controller |
1179 | */ |
1180 | void zynqmp_disp_disable(struct zynqmp_disp *disp) |
1181 | { |
1182 | zynqmp_disp_audio_disable(disp); |
1183 | |
1184 | zynqmp_disp_avbuf_disable_audio(disp); |
1185 | zynqmp_disp_avbuf_disable_channels(disp); |
1186 | zynqmp_disp_avbuf_disable(disp); |
1187 | } |
1188 | |
1189 | /** |
1190 | * zynqmp_disp_setup_clock - Configure the display controller pixel clock rate |
1191 | * @disp: Display controller |
1192 | * @mode_clock: The pixel clock rate, in Hz |
1193 | * |
1194 | * Return: 0 on success, or a negative error clock otherwise |
1195 | */ |
1196 | int zynqmp_disp_setup_clock(struct zynqmp_disp *disp, |
1197 | unsigned long mode_clock) |
1198 | { |
1199 | unsigned long rate; |
1200 | long diff; |
1201 | int ret; |
1202 | |
1203 | ret = clk_set_rate(clk: disp->dpsub->vid_clk, rate: mode_clock); |
1204 | if (ret) { |
1205 | dev_err(disp->dev, "failed to set the video clock\n" ); |
1206 | return ret; |
1207 | } |
1208 | |
1209 | rate = clk_get_rate(clk: disp->dpsub->vid_clk); |
1210 | diff = rate - mode_clock; |
1211 | if (abs(diff) > mode_clock / 20) |
1212 | dev_info(disp->dev, |
1213 | "requested pixel rate: %lu actual rate: %lu\n" , |
1214 | mode_clock, rate); |
1215 | else |
1216 | dev_dbg(disp->dev, |
1217 | "requested pixel rate: %lu actual rate: %lu\n" , |
1218 | mode_clock, rate); |
1219 | |
1220 | return 0; |
1221 | } |
1222 | |
1223 | /* ----------------------------------------------------------------------------- |
1224 | * Initialization & Cleanup |
1225 | */ |
1226 | |
1227 | int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub) |
1228 | { |
1229 | struct platform_device *pdev = to_platform_device(dpsub->dev); |
1230 | struct zynqmp_disp *disp; |
1231 | int ret; |
1232 | |
1233 | disp = kzalloc(size: sizeof(*disp), GFP_KERNEL); |
1234 | if (!disp) |
1235 | return -ENOMEM; |
1236 | |
1237 | disp->dev = &pdev->dev; |
1238 | disp->dpsub = dpsub; |
1239 | |
1240 | disp->blend.base = devm_platform_ioremap_resource_byname(pdev, name: "blend" ); |
1241 | if (IS_ERR(ptr: disp->blend.base)) { |
1242 | ret = PTR_ERR(ptr: disp->blend.base); |
1243 | goto error; |
1244 | } |
1245 | |
1246 | disp->avbuf.base = devm_platform_ioremap_resource_byname(pdev, name: "av_buf" ); |
1247 | if (IS_ERR(ptr: disp->avbuf.base)) { |
1248 | ret = PTR_ERR(ptr: disp->avbuf.base); |
1249 | goto error; |
1250 | } |
1251 | |
1252 | disp->audio.base = devm_platform_ioremap_resource_byname(pdev, name: "aud" ); |
1253 | if (IS_ERR(ptr: disp->audio.base)) { |
1254 | ret = PTR_ERR(ptr: disp->audio.base); |
1255 | goto error; |
1256 | } |
1257 | |
1258 | ret = zynqmp_disp_create_layers(disp); |
1259 | if (ret) |
1260 | goto error; |
1261 | |
1262 | if (disp->dpsub->dma_enabled) { |
1263 | struct zynqmp_disp_layer *layer; |
1264 | |
1265 | layer = &disp->layers[ZYNQMP_DPSUB_LAYER_VID]; |
1266 | dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align; |
1267 | } |
1268 | |
1269 | dpsub->disp = disp; |
1270 | |
1271 | return 0; |
1272 | |
1273 | error: |
1274 | kfree(objp: disp); |
1275 | return ret; |
1276 | } |
1277 | |
1278 | void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub) |
1279 | { |
1280 | struct zynqmp_disp *disp = dpsub->disp; |
1281 | |
1282 | zynqmp_disp_destroy_layers(disp); |
1283 | } |
1284 | |