1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
3 */
4
5 #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
6
7 #include <uapi/drm/drm_fourcc.h>
8
9 #include "msm_media_info.h"
10 #include "dpu_kms.h"
11 #include "dpu_formats.h"
12
13 #define DPU_UBWC_META_MACRO_W_H 16
14 #define DPU_UBWC_META_BLOCK_SIZE 256
15 #define DPU_UBWC_PLANE_SIZE_ALIGNMENT 4096
16
17 #define DPU_TILE_HEIGHT_DEFAULT 1
18 #define DPU_TILE_HEIGHT_TILED 4
19 #define DPU_TILE_HEIGHT_UBWC 4
20 #define DPU_TILE_HEIGHT_NV12 8
21
22 #define DPU_MAX_IMG_WIDTH 0x3FFF
23 #define DPU_MAX_IMG_HEIGHT 0x3FFF
24
25 /**
26 * DPU supported format packing, bpp, and other format
27 * information.
28 * DPU currently only supports interleaved RGB formats
29 * UBWC support for a pixel format is indicated by the flag,
30 * there is additional meta data plane for such formats
31 */
32
33 #define INTERLEAVED_RGB_FMT(fmt, a, r, g, b, e0, e1, e2, e3, uc, alpha, \
34 bp, flg, fm, np) \
35 { \
36 .base.pixel_format = DRM_FORMAT_ ## fmt, \
37 .fetch_planes = DPU_PLANE_INTERLEAVED, \
38 .alpha_enable = alpha, \
39 .element = { (e0), (e1), (e2), (e3) }, \
40 .bits = { g, b, r, a }, \
41 .chroma_sample = DPU_CHROMA_RGB, \
42 .unpack_align_msb = 0, \
43 .unpack_tight = 1, \
44 .unpack_count = uc, \
45 .bpp = bp, \
46 .fetch_mode = fm, \
47 .flag = {(flg)}, \
48 .num_planes = np, \
49 .tile_height = DPU_TILE_HEIGHT_DEFAULT \
50 }
51
52 #define INTERLEAVED_RGB_FMT_TILED(fmt, a, r, g, b, e0, e1, e2, e3, uc, \
53 alpha, bp, flg, fm, np, th) \
54 { \
55 .base.pixel_format = DRM_FORMAT_ ## fmt, \
56 .fetch_planes = DPU_PLANE_INTERLEAVED, \
57 .alpha_enable = alpha, \
58 .element = { (e0), (e1), (e2), (e3) }, \
59 .bits = { g, b, r, a }, \
60 .chroma_sample = DPU_CHROMA_RGB, \
61 .unpack_align_msb = 0, \
62 .unpack_tight = 1, \
63 .unpack_count = uc, \
64 .bpp = bp, \
65 .fetch_mode = fm, \
66 .flag = {(flg)}, \
67 .num_planes = np, \
68 .tile_height = th \
69 }
70
71
72 #define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3, \
73 alpha, chroma, count, bp, flg, fm, np) \
74 { \
75 .base.pixel_format = DRM_FORMAT_ ## fmt, \
76 .fetch_planes = DPU_PLANE_INTERLEAVED, \
77 .alpha_enable = alpha, \
78 .element = { (e0), (e1), (e2), (e3)}, \
79 .bits = { g, b, r, a }, \
80 .chroma_sample = chroma, \
81 .unpack_align_msb = 0, \
82 .unpack_tight = 1, \
83 .unpack_count = count, \
84 .bpp = bp, \
85 .fetch_mode = fm, \
86 .flag = {(flg)}, \
87 .num_planes = np, \
88 .tile_height = DPU_TILE_HEIGHT_DEFAULT \
89 }
90
91 #define PSEUDO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np) \
92 { \
93 .base.pixel_format = DRM_FORMAT_ ## fmt, \
94 .fetch_planes = DPU_PLANE_PSEUDO_PLANAR, \
95 .alpha_enable = false, \
96 .element = { (e0), (e1), 0, 0 }, \
97 .bits = { g, b, r, a }, \
98 .chroma_sample = chroma, \
99 .unpack_align_msb = 0, \
100 .unpack_tight = 1, \
101 .unpack_count = 2, \
102 .bpp = 2, \
103 .fetch_mode = fm, \
104 .flag = {(flg)}, \
105 .num_planes = np, \
106 .tile_height = DPU_TILE_HEIGHT_DEFAULT \
107 }
108
109 #define PSEUDO_YUV_FMT_TILED(fmt, a, r, g, b, e0, e1, chroma, \
110 flg, fm, np, th) \
111 { \
112 .base.pixel_format = DRM_FORMAT_ ## fmt, \
113 .fetch_planes = DPU_PLANE_PSEUDO_PLANAR, \
114 .alpha_enable = false, \
115 .element = { (e0), (e1), 0, 0 }, \
116 .bits = { g, b, r, a }, \
117 .chroma_sample = chroma, \
118 .unpack_align_msb = 0, \
119 .unpack_tight = 1, \
120 .unpack_count = 2, \
121 .bpp = 2, \
122 .fetch_mode = fm, \
123 .flag = {(flg)}, \
124 .num_planes = np, \
125 .tile_height = th \
126 }
127
128 #define PSEUDO_YUV_FMT_LOOSE(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np)\
129 { \
130 .base.pixel_format = DRM_FORMAT_ ## fmt, \
131 .fetch_planes = DPU_PLANE_PSEUDO_PLANAR, \
132 .alpha_enable = false, \
133 .element = { (e0), (e1), 0, 0 }, \
134 .bits = { g, b, r, a }, \
135 .chroma_sample = chroma, \
136 .unpack_align_msb = 1, \
137 .unpack_tight = 0, \
138 .unpack_count = 2, \
139 .bpp = 2, \
140 .fetch_mode = fm, \
141 .flag = {(flg)}, \
142 .num_planes = np, \
143 .tile_height = DPU_TILE_HEIGHT_DEFAULT \
144 }
145
146 #define PSEUDO_YUV_FMT_LOOSE_TILED(fmt, a, r, g, b, e0, e1, chroma, \
147 flg, fm, np, th) \
148 { \
149 .base.pixel_format = DRM_FORMAT_ ## fmt, \
150 .fetch_planes = DPU_PLANE_PSEUDO_PLANAR, \
151 .alpha_enable = false, \
152 .element = { (e0), (e1), 0, 0 }, \
153 .bits = { g, b, r, a }, \
154 .chroma_sample = chroma, \
155 .unpack_align_msb = 1, \
156 .unpack_tight = 0, \
157 .unpack_count = 2, \
158 .bpp = 2, \
159 .fetch_mode = fm, \
160 .flag = {(flg)}, \
161 .num_planes = np, \
162 .tile_height = th \
163 }
164
165
166 #define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp, \
167 flg, fm, np) \
168 { \
169 .base.pixel_format = DRM_FORMAT_ ## fmt, \
170 .fetch_planes = DPU_PLANE_PLANAR, \
171 .alpha_enable = alpha, \
172 .element = { (e0), (e1), (e2), 0 }, \
173 .bits = { g, b, r, a }, \
174 .chroma_sample = chroma, \
175 .unpack_align_msb = 0, \
176 .unpack_tight = 1, \
177 .unpack_count = 1, \
178 .bpp = bp, \
179 .fetch_mode = fm, \
180 .flag = {(flg)}, \
181 .num_planes = np, \
182 .tile_height = DPU_TILE_HEIGHT_DEFAULT \
183 }
184
185 /*
186 * struct dpu_media_color_map - maps drm format to media format
187 * @format: DRM base pixel format
188 * @color: Media API color related to DRM format
189 */
190 struct dpu_media_color_map {
191 uint32_t format;
192 uint32_t color;
193 };
194
195 static const struct dpu_format dpu_format_map[] = {
196 INTERLEAVED_RGB_FMT(ARGB8888,
197 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
198 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
199 true, 4, 0,
200 DPU_FETCH_LINEAR, 1),
201
202 INTERLEAVED_RGB_FMT(ABGR8888,
203 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
204 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
205 true, 4, 0,
206 DPU_FETCH_LINEAR, 1),
207
208 INTERLEAVED_RGB_FMT(XBGR8888,
209 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
210 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
211 false, 4, 0,
212 DPU_FETCH_LINEAR, 1),
213
214 INTERLEAVED_RGB_FMT(RGBA8888,
215 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
216 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
217 true, 4, 0,
218 DPU_FETCH_LINEAR, 1),
219
220 INTERLEAVED_RGB_FMT(BGRA8888,
221 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
222 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
223 true, 4, 0,
224 DPU_FETCH_LINEAR, 1),
225
226 INTERLEAVED_RGB_FMT(BGRX8888,
227 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
228 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
229 false, 4, 0,
230 DPU_FETCH_LINEAR, 1),
231
232 INTERLEAVED_RGB_FMT(XRGB8888,
233 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
234 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
235 false, 4, 0,
236 DPU_FETCH_LINEAR, 1),
237
238 INTERLEAVED_RGB_FMT(RGBX8888,
239 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
240 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
241 false, 4, 0,
242 DPU_FETCH_LINEAR, 1),
243
244 INTERLEAVED_RGB_FMT(RGB888,
245 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
246 C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
247 false, 3, 0,
248 DPU_FETCH_LINEAR, 1),
249
250 INTERLEAVED_RGB_FMT(BGR888,
251 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
252 C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
253 false, 3, 0,
254 DPU_FETCH_LINEAR, 1),
255
256 INTERLEAVED_RGB_FMT(RGB565,
257 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
258 C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
259 false, 2, 0,
260 DPU_FETCH_LINEAR, 1),
261
262 INTERLEAVED_RGB_FMT(BGR565,
263 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
264 C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
265 false, 2, 0,
266 DPU_FETCH_LINEAR, 1),
267
268 INTERLEAVED_RGB_FMT(ARGB1555,
269 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
270 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
271 true, 2, 0,
272 DPU_FETCH_LINEAR, 1),
273
274 INTERLEAVED_RGB_FMT(ABGR1555,
275 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
276 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
277 true, 2, 0,
278 DPU_FETCH_LINEAR, 1),
279
280 INTERLEAVED_RGB_FMT(RGBA5551,
281 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
282 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
283 true, 2, 0,
284 DPU_FETCH_LINEAR, 1),
285
286 INTERLEAVED_RGB_FMT(BGRA5551,
287 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
288 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
289 true, 2, 0,
290 DPU_FETCH_LINEAR, 1),
291
292 INTERLEAVED_RGB_FMT(XRGB1555,
293 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
294 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
295 false, 2, 0,
296 DPU_FETCH_LINEAR, 1),
297
298 INTERLEAVED_RGB_FMT(XBGR1555,
299 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
300 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
301 false, 2, 0,
302 DPU_FETCH_LINEAR, 1),
303
304 INTERLEAVED_RGB_FMT(RGBX5551,
305 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
306 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
307 false, 2, 0,
308 DPU_FETCH_LINEAR, 1),
309
310 INTERLEAVED_RGB_FMT(BGRX5551,
311 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
312 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
313 false, 2, 0,
314 DPU_FETCH_LINEAR, 1),
315
316 INTERLEAVED_RGB_FMT(ARGB4444,
317 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
318 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
319 true, 2, 0,
320 DPU_FETCH_LINEAR, 1),
321
322 INTERLEAVED_RGB_FMT(ABGR4444,
323 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
324 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
325 true, 2, 0,
326 DPU_FETCH_LINEAR, 1),
327
328 INTERLEAVED_RGB_FMT(RGBA4444,
329 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
330 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
331 true, 2, 0,
332 DPU_FETCH_LINEAR, 1),
333
334 INTERLEAVED_RGB_FMT(BGRA4444,
335 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
336 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
337 true, 2, 0,
338 DPU_FETCH_LINEAR, 1),
339
340 INTERLEAVED_RGB_FMT(XRGB4444,
341 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
342 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
343 false, 2, 0,
344 DPU_FETCH_LINEAR, 1),
345
346 INTERLEAVED_RGB_FMT(XBGR4444,
347 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
348 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
349 false, 2, 0,
350 DPU_FETCH_LINEAR, 1),
351
352 INTERLEAVED_RGB_FMT(RGBX4444,
353 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
354 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
355 false, 2, 0,
356 DPU_FETCH_LINEAR, 1),
357
358 INTERLEAVED_RGB_FMT(BGRX4444,
359 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
360 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
361 false, 2, 0,
362 DPU_FETCH_LINEAR, 1),
363
364 INTERLEAVED_RGB_FMT(BGRA1010102,
365 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
366 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
367 true, 4, DPU_FORMAT_FLAG_DX,
368 DPU_FETCH_LINEAR, 1),
369
370 INTERLEAVED_RGB_FMT(RGBA1010102,
371 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
372 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
373 true, 4, DPU_FORMAT_FLAG_DX,
374 DPU_FETCH_LINEAR, 1),
375
376 INTERLEAVED_RGB_FMT(ABGR2101010,
377 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
378 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
379 true, 4, DPU_FORMAT_FLAG_DX,
380 DPU_FETCH_LINEAR, 1),
381
382 INTERLEAVED_RGB_FMT(ARGB2101010,
383 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
384 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
385 true, 4, DPU_FORMAT_FLAG_DX,
386 DPU_FETCH_LINEAR, 1),
387
388 INTERLEAVED_RGB_FMT(XRGB2101010,
389 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
390 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
391 false, 4, DPU_FORMAT_FLAG_DX,
392 DPU_FETCH_LINEAR, 1),
393
394 INTERLEAVED_RGB_FMT(BGRX1010102,
395 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
396 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
397 false, 4, DPU_FORMAT_FLAG_DX,
398 DPU_FETCH_LINEAR, 1),
399
400 INTERLEAVED_RGB_FMT(XBGR2101010,
401 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
402 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
403 false, 4, DPU_FORMAT_FLAG_DX,
404 DPU_FETCH_LINEAR, 1),
405
406 INTERLEAVED_RGB_FMT(RGBX1010102,
407 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
408 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
409 false, 4, DPU_FORMAT_FLAG_DX,
410 DPU_FETCH_LINEAR, 1),
411
412 PSEUDO_YUV_FMT(NV12,
413 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
414 C1_B_Cb, C2_R_Cr,
415 DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV,
416 DPU_FETCH_LINEAR, 2),
417
418 PSEUDO_YUV_FMT(NV21,
419 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
420 C2_R_Cr, C1_B_Cb,
421 DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV,
422 DPU_FETCH_LINEAR, 2),
423
424 PSEUDO_YUV_FMT(NV16,
425 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
426 C1_B_Cb, C2_R_Cr,
427 DPU_CHROMA_H2V1, DPU_FORMAT_FLAG_YUV,
428 DPU_FETCH_LINEAR, 2),
429
430 PSEUDO_YUV_FMT(NV61,
431 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
432 C2_R_Cr, C1_B_Cb,
433 DPU_CHROMA_H2V1, DPU_FORMAT_FLAG_YUV,
434 DPU_FETCH_LINEAR, 2),
435
436 INTERLEAVED_YUV_FMT(VYUY,
437 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
438 C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y,
439 false, DPU_CHROMA_H2V1, 4, 2, DPU_FORMAT_FLAG_YUV,
440 DPU_FETCH_LINEAR, 2),
441
442 INTERLEAVED_YUV_FMT(UYVY,
443 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
444 C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y,
445 false, DPU_CHROMA_H2V1, 4, 2, DPU_FORMAT_FLAG_YUV,
446 DPU_FETCH_LINEAR, 2),
447
448 INTERLEAVED_YUV_FMT(YUYV,
449 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
450 C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr,
451 false, DPU_CHROMA_H2V1, 4, 2, DPU_FORMAT_FLAG_YUV,
452 DPU_FETCH_LINEAR, 2),
453
454 INTERLEAVED_YUV_FMT(YVYU,
455 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
456 C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb,
457 false, DPU_CHROMA_H2V1, 4, 2, DPU_FORMAT_FLAG_YUV,
458 DPU_FETCH_LINEAR, 2),
459
460 PLANAR_YUV_FMT(YUV420,
461 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
462 C2_R_Cr, C1_B_Cb, C0_G_Y,
463 false, DPU_CHROMA_420, 1, DPU_FORMAT_FLAG_YUV,
464 DPU_FETCH_LINEAR, 3),
465
466 PLANAR_YUV_FMT(YVU420,
467 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
468 C1_B_Cb, C2_R_Cr, C0_G_Y,
469 false, DPU_CHROMA_420, 1, DPU_FORMAT_FLAG_YUV,
470 DPU_FETCH_LINEAR, 3),
471 };
472
473 /*
474 * UBWC formats table:
475 * This table holds the UBWC formats supported.
476 * If a compression ratio needs to be used for this or any other format,
477 * the data will be passed by user-space.
478 */
479 static const struct dpu_format dpu_format_map_ubwc[] = {
480 INTERLEAVED_RGB_FMT_TILED(BGR565,
481 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
482 C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
483 false, 2, DPU_FORMAT_FLAG_COMPRESSED,
484 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC),
485
486 INTERLEAVED_RGB_FMT_TILED(ABGR8888,
487 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
488 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
489 true, 4, DPU_FORMAT_FLAG_COMPRESSED,
490 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC),
491
492 INTERLEAVED_RGB_FMT_TILED(XBGR8888,
493 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
494 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
495 false, 4, DPU_FORMAT_FLAG_COMPRESSED,
496 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC),
497
498 INTERLEAVED_RGB_FMT_TILED(ABGR2101010,
499 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
500 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
501 true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED,
502 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC),
503
504 INTERLEAVED_RGB_FMT_TILED(XBGR2101010,
505 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
506 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
507 true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED,
508 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC),
509
510 PSEUDO_YUV_FMT_TILED(NV12,
511 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
512 C1_B_Cb, C2_R_Cr,
513 DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV |
514 DPU_FORMAT_FLAG_COMPRESSED,
515 DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_NV12),
516 };
517
518 /* _dpu_get_v_h_subsample_rate - Get subsample rates for all formats we support
519 * Note: Not using the drm_format_*_subsampling since we have formats
520 */
_dpu_get_v_h_subsample_rate(enum dpu_chroma_samp_type chroma_sample,uint32_t * v_sample,uint32_t * h_sample)521 static void _dpu_get_v_h_subsample_rate(
522 enum dpu_chroma_samp_type chroma_sample,
523 uint32_t *v_sample,
524 uint32_t *h_sample)
525 {
526 if (!v_sample || !h_sample)
527 return;
528
529 switch (chroma_sample) {
530 case DPU_CHROMA_H2V1:
531 *v_sample = 1;
532 *h_sample = 2;
533 break;
534 case DPU_CHROMA_H1V2:
535 *v_sample = 2;
536 *h_sample = 1;
537 break;
538 case DPU_CHROMA_420:
539 *v_sample = 2;
540 *h_sample = 2;
541 break;
542 default:
543 *v_sample = 1;
544 *h_sample = 1;
545 break;
546 }
547 }
548
_dpu_format_get_media_color_ubwc(const struct dpu_format * fmt)549 static int _dpu_format_get_media_color_ubwc(const struct dpu_format *fmt)
550 {
551 static const struct dpu_media_color_map dpu_media_ubwc_map[] = {
552 {DRM_FORMAT_ABGR8888, COLOR_FMT_RGBA8888_UBWC},
553 {DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC},
554 {DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC},
555 {DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC},
556 {DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC},
557 };
558 int color_fmt = -1;
559 int i;
560
561 if (fmt->base.pixel_format == DRM_FORMAT_NV12) {
562 if (DPU_FORMAT_IS_DX(fmt)) {
563 if (fmt->unpack_tight)
564 color_fmt = COLOR_FMT_NV12_BPP10_UBWC;
565 else
566 color_fmt = COLOR_FMT_P010_UBWC;
567 } else
568 color_fmt = COLOR_FMT_NV12_UBWC;
569 return color_fmt;
570 }
571
572 for (i = 0; i < ARRAY_SIZE(dpu_media_ubwc_map); ++i)
573 if (fmt->base.pixel_format == dpu_media_ubwc_map[i].format) {
574 color_fmt = dpu_media_ubwc_map[i].color;
575 break;
576 }
577 return color_fmt;
578 }
579
_dpu_format_get_plane_sizes_ubwc(const struct dpu_format * fmt,const uint32_t width,const uint32_t height,struct dpu_hw_fmt_layout * layout)580 static int _dpu_format_get_plane_sizes_ubwc(
581 const struct dpu_format *fmt,
582 const uint32_t width,
583 const uint32_t height,
584 struct dpu_hw_fmt_layout *layout)
585 {
586 int i;
587 int color;
588 bool meta = DPU_FORMAT_IS_UBWC(fmt);
589
590 memset(layout, 0, sizeof(struct dpu_hw_fmt_layout));
591 layout->format = fmt;
592 layout->width = width;
593 layout->height = height;
594 layout->num_planes = fmt->num_planes;
595
596 color = _dpu_format_get_media_color_ubwc(fmt);
597 if (color < 0) {
598 DRM_ERROR("UBWC format not supported for fmt: %4.4s\n",
599 (char *)&fmt->base.pixel_format);
600 return -EINVAL;
601 }
602
603 if (DPU_FORMAT_IS_YUV(layout->format)) {
604 uint32_t y_sclines, uv_sclines;
605 uint32_t y_meta_scanlines = 0;
606 uint32_t uv_meta_scanlines = 0;
607
608 layout->num_planes = 2;
609 layout->plane_pitch[0] = VENUS_Y_STRIDE(color, width);
610 y_sclines = VENUS_Y_SCANLINES(color, height);
611 layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] *
612 y_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
613
614 layout->plane_pitch[1] = VENUS_UV_STRIDE(color, width);
615 uv_sclines = VENUS_UV_SCANLINES(color, height);
616 layout->plane_size[1] = MSM_MEDIA_ALIGN(layout->plane_pitch[1] *
617 uv_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
618
619 if (!meta)
620 goto done;
621
622 layout->num_planes += 2;
623 layout->plane_pitch[2] = VENUS_Y_META_STRIDE(color, width);
624 y_meta_scanlines = VENUS_Y_META_SCANLINES(color, height);
625 layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] *
626 y_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
627
628 layout->plane_pitch[3] = VENUS_UV_META_STRIDE(color, width);
629 uv_meta_scanlines = VENUS_UV_META_SCANLINES(color, height);
630 layout->plane_size[3] = MSM_MEDIA_ALIGN(layout->plane_pitch[3] *
631 uv_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
632
633 } else {
634 uint32_t rgb_scanlines, rgb_meta_scanlines;
635
636 layout->num_planes = 1;
637
638 layout->plane_pitch[0] = VENUS_RGB_STRIDE(color, width);
639 rgb_scanlines = VENUS_RGB_SCANLINES(color, height);
640 layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] *
641 rgb_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
642
643 if (!meta)
644 goto done;
645 layout->num_planes += 2;
646 layout->plane_pitch[2] = VENUS_RGB_META_STRIDE(color, width);
647 rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color, height);
648 layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] *
649 rgb_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
650 }
651
652 done:
653 for (i = 0; i < DPU_MAX_PLANES; i++)
654 layout->total_size += layout->plane_size[i];
655
656 return 0;
657 }
658
_dpu_format_get_plane_sizes_linear(const struct dpu_format * fmt,const uint32_t width,const uint32_t height,struct dpu_hw_fmt_layout * layout,const uint32_t * pitches)659 static int _dpu_format_get_plane_sizes_linear(
660 const struct dpu_format *fmt,
661 const uint32_t width,
662 const uint32_t height,
663 struct dpu_hw_fmt_layout *layout,
664 const uint32_t *pitches)
665 {
666 int i;
667
668 memset(layout, 0, sizeof(struct dpu_hw_fmt_layout));
669 layout->format = fmt;
670 layout->width = width;
671 layout->height = height;
672 layout->num_planes = fmt->num_planes;
673
674 /* Due to memset above, only need to set planes of interest */
675 if (fmt->fetch_planes == DPU_PLANE_INTERLEAVED) {
676 layout->num_planes = 1;
677 layout->plane_size[0] = width * height * layout->format->bpp;
678 layout->plane_pitch[0] = width * layout->format->bpp;
679 } else {
680 uint32_t v_subsample, h_subsample;
681 uint32_t chroma_samp;
682 uint32_t bpp = 1;
683
684 chroma_samp = fmt->chroma_sample;
685 _dpu_get_v_h_subsample_rate(chroma_samp, &v_subsample,
686 &h_subsample);
687
688 if (width % h_subsample || height % v_subsample) {
689 DRM_ERROR("mismatch in subsample vs dimensions\n");
690 return -EINVAL;
691 }
692
693 if ((fmt->base.pixel_format == DRM_FORMAT_NV12) &&
694 (DPU_FORMAT_IS_DX(fmt)))
695 bpp = 2;
696 layout->plane_pitch[0] = width * bpp;
697 layout->plane_pitch[1] = layout->plane_pitch[0] / h_subsample;
698 layout->plane_size[0] = layout->plane_pitch[0] * height;
699 layout->plane_size[1] = layout->plane_pitch[1] *
700 (height / v_subsample);
701
702 if (fmt->fetch_planes == DPU_PLANE_PSEUDO_PLANAR) {
703 layout->num_planes = 2;
704 layout->plane_size[1] *= 2;
705 layout->plane_pitch[1] *= 2;
706 } else {
707 /* planar */
708 layout->num_planes = 3;
709 layout->plane_size[2] = layout->plane_size[1];
710 layout->plane_pitch[2] = layout->plane_pitch[1];
711 }
712 }
713
714 /*
715 * linear format: allow user allocated pitches if they are greater than
716 * the requirement.
717 * ubwc format: pitch values are computed uniformly across
718 * all the components based on ubwc specifications.
719 */
720 for (i = 0; i < layout->num_planes && i < DPU_MAX_PLANES; ++i) {
721 if (pitches && layout->plane_pitch[i] < pitches[i])
722 layout->plane_pitch[i] = pitches[i];
723 }
724
725 for (i = 0; i < DPU_MAX_PLANES; i++)
726 layout->total_size += layout->plane_size[i];
727
728 return 0;
729 }
730
dpu_format_get_plane_sizes(const struct dpu_format * fmt,const uint32_t w,const uint32_t h,struct dpu_hw_fmt_layout * layout,const uint32_t * pitches)731 static int dpu_format_get_plane_sizes(
732 const struct dpu_format *fmt,
733 const uint32_t w,
734 const uint32_t h,
735 struct dpu_hw_fmt_layout *layout,
736 const uint32_t *pitches)
737 {
738 if (!layout || !fmt) {
739 DRM_ERROR("invalid pointer\n");
740 return -EINVAL;
741 }
742
743 if ((w > DPU_MAX_IMG_WIDTH) || (h > DPU_MAX_IMG_HEIGHT)) {
744 DRM_ERROR("image dimensions outside max range\n");
745 return -ERANGE;
746 }
747
748 if (DPU_FORMAT_IS_UBWC(fmt) || DPU_FORMAT_IS_TILE(fmt))
749 return _dpu_format_get_plane_sizes_ubwc(fmt, w, h, layout);
750
751 return _dpu_format_get_plane_sizes_linear(fmt, w, h, layout, pitches);
752 }
753
_dpu_format_populate_addrs_ubwc(struct msm_gem_address_space * aspace,struct drm_framebuffer * fb,struct dpu_hw_fmt_layout * layout)754 static int _dpu_format_populate_addrs_ubwc(
755 struct msm_gem_address_space *aspace,
756 struct drm_framebuffer *fb,
757 struct dpu_hw_fmt_layout *layout)
758 {
759 uint32_t base_addr = 0;
760 bool meta;
761
762 if (!fb || !layout) {
763 DRM_ERROR("invalid pointers\n");
764 return -EINVAL;
765 }
766
767 if (aspace)
768 base_addr = msm_framebuffer_iova(fb, aspace, 0);
769 if (!base_addr) {
770 DRM_ERROR("failed to retrieve base addr\n");
771 return -EFAULT;
772 }
773
774 meta = DPU_FORMAT_IS_UBWC(layout->format);
775
776 /* Per-format logic for verifying active planes */
777 if (DPU_FORMAT_IS_YUV(layout->format)) {
778 /************************************************/
779 /* UBWC ** */
780 /* buffer ** DPU PLANE */
781 /* format ** */
782 /************************************************/
783 /* ------------------- ** -------------------- */
784 /* | Y meta | ** | Y bitstream | */
785 /* | data | ** | plane | */
786 /* ------------------- ** -------------------- */
787 /* | Y bitstream | ** | CbCr bitstream | */
788 /* | data | ** | plane | */
789 /* ------------------- ** -------------------- */
790 /* | Cbcr metadata | ** | Y meta | */
791 /* | data | ** | plane | */
792 /* ------------------- ** -------------------- */
793 /* | CbCr bitstream | ** | CbCr meta | */
794 /* | data | ** | plane | */
795 /* ------------------- ** -------------------- */
796 /************************************************/
797
798 /* configure Y bitstream plane */
799 layout->plane_addr[0] = base_addr + layout->plane_size[2];
800
801 /* configure CbCr bitstream plane */
802 layout->plane_addr[1] = base_addr + layout->plane_size[0]
803 + layout->plane_size[2] + layout->plane_size[3];
804
805 if (!meta)
806 return 0;
807
808 /* configure Y metadata plane */
809 layout->plane_addr[2] = base_addr;
810
811 /* configure CbCr metadata plane */
812 layout->plane_addr[3] = base_addr + layout->plane_size[0]
813 + layout->plane_size[2];
814
815 } else {
816 /************************************************/
817 /* UBWC ** */
818 /* buffer ** DPU PLANE */
819 /* format ** */
820 /************************************************/
821 /* ------------------- ** -------------------- */
822 /* | RGB meta | ** | RGB bitstream | */
823 /* | data | ** | plane | */
824 /* ------------------- ** -------------------- */
825 /* | RGB bitstream | ** | NONE | */
826 /* | data | ** | | */
827 /* ------------------- ** -------------------- */
828 /* ** | RGB meta | */
829 /* ** | plane | */
830 /* ** -------------------- */
831 /************************************************/
832
833 layout->plane_addr[0] = base_addr + layout->plane_size[2];
834 layout->plane_addr[1] = 0;
835
836 if (!meta)
837 return 0;
838
839 layout->plane_addr[2] = base_addr;
840 layout->plane_addr[3] = 0;
841 }
842 return 0;
843 }
844
_dpu_format_populate_addrs_linear(struct msm_gem_address_space * aspace,struct drm_framebuffer * fb,struct dpu_hw_fmt_layout * layout)845 static int _dpu_format_populate_addrs_linear(
846 struct msm_gem_address_space *aspace,
847 struct drm_framebuffer *fb,
848 struct dpu_hw_fmt_layout *layout)
849 {
850 unsigned int i;
851
852 /* Can now check the pitches given vs pitches expected */
853 for (i = 0; i < layout->num_planes; ++i) {
854 if (layout->plane_pitch[i] > fb->pitches[i]) {
855 DRM_ERROR("plane %u expected pitch %u, fb %u\n",
856 i, layout->plane_pitch[i], fb->pitches[i]);
857 return -EINVAL;
858 }
859 }
860
861 /* Populate addresses for simple formats here */
862 for (i = 0; i < layout->num_planes; ++i) {
863 if (aspace)
864 layout->plane_addr[i] =
865 msm_framebuffer_iova(fb, aspace, i);
866 if (!layout->plane_addr[i]) {
867 DRM_ERROR("failed to retrieve base addr\n");
868 return -EFAULT;
869 }
870 }
871
872 return 0;
873 }
874
dpu_format_populate_layout(struct msm_gem_address_space * aspace,struct drm_framebuffer * fb,struct dpu_hw_fmt_layout * layout)875 int dpu_format_populate_layout(
876 struct msm_gem_address_space *aspace,
877 struct drm_framebuffer *fb,
878 struct dpu_hw_fmt_layout *layout)
879 {
880 uint32_t plane_addr[DPU_MAX_PLANES];
881 int i, ret;
882
883 if (!fb || !layout) {
884 DRM_ERROR("invalid arguments\n");
885 return -EINVAL;
886 }
887
888 if ((fb->width > DPU_MAX_IMG_WIDTH) ||
889 (fb->height > DPU_MAX_IMG_HEIGHT)) {
890 DRM_ERROR("image dimensions outside max range\n");
891 return -ERANGE;
892 }
893
894 layout->format = to_dpu_format(msm_framebuffer_format(fb));
895
896 /* Populate the plane sizes etc via get_format */
897 ret = dpu_format_get_plane_sizes(layout->format, fb->width, fb->height,
898 layout, fb->pitches);
899 if (ret)
900 return ret;
901
902 for (i = 0; i < DPU_MAX_PLANES; ++i)
903 plane_addr[i] = layout->plane_addr[i];
904
905 /* Populate the addresses given the fb */
906 if (DPU_FORMAT_IS_UBWC(layout->format) ||
907 DPU_FORMAT_IS_TILE(layout->format))
908 ret = _dpu_format_populate_addrs_ubwc(aspace, fb, layout);
909 else
910 ret = _dpu_format_populate_addrs_linear(aspace, fb, layout);
911
912 /* check if anything changed */
913 if (!ret && !memcmp(plane_addr, layout->plane_addr, sizeof(plane_addr)))
914 ret = -EAGAIN;
915
916 return ret;
917 }
918
dpu_format_check_modified_format(const struct msm_kms * kms,const struct msm_format * msm_fmt,const struct drm_mode_fb_cmd2 * cmd,struct drm_gem_object ** bos)919 int dpu_format_check_modified_format(
920 const struct msm_kms *kms,
921 const struct msm_format *msm_fmt,
922 const struct drm_mode_fb_cmd2 *cmd,
923 struct drm_gem_object **bos)
924 {
925 const struct drm_format_info *info;
926 const struct dpu_format *fmt;
927 struct dpu_hw_fmt_layout layout;
928 uint32_t bos_total_size = 0;
929 int ret, i;
930
931 if (!msm_fmt || !cmd || !bos) {
932 DRM_ERROR("invalid arguments\n");
933 return -EINVAL;
934 }
935
936 fmt = to_dpu_format(msm_fmt);
937 info = drm_format_info(fmt->base.pixel_format);
938 if (!info)
939 return -EINVAL;
940
941 ret = dpu_format_get_plane_sizes(fmt, cmd->width, cmd->height,
942 &layout, cmd->pitches);
943 if (ret)
944 return ret;
945
946 for (i = 0; i < info->num_planes; i++) {
947 if (!bos[i]) {
948 DRM_ERROR("invalid handle for plane %d\n", i);
949 return -EINVAL;
950 }
951 if ((i == 0) || (bos[i] != bos[0]))
952 bos_total_size += bos[i]->size;
953 }
954
955 if (bos_total_size < layout.total_size) {
956 DRM_ERROR("buffers total size too small %u expected %u\n",
957 bos_total_size, layout.total_size);
958 return -EINVAL;
959 }
960
961 return 0;
962 }
963
dpu_get_dpu_format_ext(const uint32_t format,const uint64_t modifier)964 const struct dpu_format *dpu_get_dpu_format_ext(
965 const uint32_t format,
966 const uint64_t modifier)
967 {
968 uint32_t i = 0;
969 const struct dpu_format *fmt = NULL;
970 const struct dpu_format *map = NULL;
971 ssize_t map_size = 0;
972
973 /*
974 * Currently only support exactly zero or one modifier.
975 * All planes use the same modifier.
976 */
977 DPU_DEBUG("plane format modifier 0x%llX\n", modifier);
978
979 switch (modifier) {
980 case 0:
981 map = dpu_format_map;
982 map_size = ARRAY_SIZE(dpu_format_map);
983 break;
984 case DRM_FORMAT_MOD_QCOM_COMPRESSED:
985 map = dpu_format_map_ubwc;
986 map_size = ARRAY_SIZE(dpu_format_map_ubwc);
987 DPU_DEBUG("found fmt: %4.4s DRM_FORMAT_MOD_QCOM_COMPRESSED\n",
988 (char *)&format);
989 break;
990 default:
991 DPU_ERROR("unsupported format modifier %llX\n", modifier);
992 return NULL;
993 }
994
995 for (i = 0; i < map_size; i++) {
996 if (format == map[i].base.pixel_format) {
997 fmt = &map[i];
998 break;
999 }
1000 }
1001
1002 if (fmt == NULL)
1003 DPU_ERROR("unsupported fmt: %4.4s modifier 0x%llX\n",
1004 (char *)&format, modifier);
1005 else
1006 DPU_DEBUG("fmt %4.4s mod 0x%llX ubwc %d yuv %d\n",
1007 (char *)&format, modifier,
1008 DPU_FORMAT_IS_UBWC(fmt),
1009 DPU_FORMAT_IS_YUV(fmt));
1010
1011 return fmt;
1012 }
1013
dpu_get_msm_format(struct msm_kms * kms,const uint32_t format,const uint64_t modifiers)1014 const struct msm_format *dpu_get_msm_format(
1015 struct msm_kms *kms,
1016 const uint32_t format,
1017 const uint64_t modifiers)
1018 {
1019 const struct dpu_format *fmt = dpu_get_dpu_format_ext(format,
1020 modifiers);
1021 if (fmt)
1022 return &fmt->base;
1023 return NULL;
1024 }
1025