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 		C1_B_Cb, C0_G_Y, C2_R_Cr, 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 		C2_R_Cr, C0_G_Y, C1_B_Cb, 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 	/* ARGB8888 and ABGR8888 purposely have the same color
493 	 * ordering.  The hardware only supports ABGR8888 UBWC
494 	 * natively.
495 	 */
496 	INTERLEAVED_RGB_FMT_TILED(ARGB8888,
497 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
498 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
499 		true, 4, DPU_FORMAT_FLAG_COMPRESSED,
500 		DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC),
501 
502 	INTERLEAVED_RGB_FMT_TILED(XBGR8888,
503 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
504 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
505 		false, 4, DPU_FORMAT_FLAG_COMPRESSED,
506 		DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC),
507 
508 	INTERLEAVED_RGB_FMT_TILED(XRGB8888,
509 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
510 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
511 		false, 4, DPU_FORMAT_FLAG_COMPRESSED,
512 		DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC),
513 
514 	INTERLEAVED_RGB_FMT_TILED(ABGR2101010,
515 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
516 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
517 		true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED,
518 		DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC),
519 
520 	INTERLEAVED_RGB_FMT_TILED(XBGR2101010,
521 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
522 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
523 		true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED,
524 		DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC),
525 
526 	PSEUDO_YUV_FMT_TILED(NV12,
527 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
528 		C1_B_Cb, C2_R_Cr,
529 		DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV |
530 				DPU_FORMAT_FLAG_COMPRESSED,
531 		DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_NV12),
532 };
533 
534 /* _dpu_get_v_h_subsample_rate - Get subsample rates for all formats we support
535  *   Note: Not using the drm_format_*_subsampling since we have formats
536  */
_dpu_get_v_h_subsample_rate(enum dpu_chroma_samp_type chroma_sample,uint32_t * v_sample,uint32_t * h_sample)537 static void _dpu_get_v_h_subsample_rate(
538 	enum dpu_chroma_samp_type chroma_sample,
539 	uint32_t *v_sample,
540 	uint32_t *h_sample)
541 {
542 	if (!v_sample || !h_sample)
543 		return;
544 
545 	switch (chroma_sample) {
546 	case DPU_CHROMA_H2V1:
547 		*v_sample = 1;
548 		*h_sample = 2;
549 		break;
550 	case DPU_CHROMA_H1V2:
551 		*v_sample = 2;
552 		*h_sample = 1;
553 		break;
554 	case DPU_CHROMA_420:
555 		*v_sample = 2;
556 		*h_sample = 2;
557 		break;
558 	default:
559 		*v_sample = 1;
560 		*h_sample = 1;
561 		break;
562 	}
563 }
564 
_dpu_format_get_media_color_ubwc(const struct dpu_format * fmt)565 static int _dpu_format_get_media_color_ubwc(const struct dpu_format *fmt)
566 {
567 	static const struct dpu_media_color_map dpu_media_ubwc_map[] = {
568 		{DRM_FORMAT_ABGR8888, COLOR_FMT_RGBA8888_UBWC},
569 		{DRM_FORMAT_ARGB8888, COLOR_FMT_RGBA8888_UBWC},
570 		{DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC},
571 		{DRM_FORMAT_XRGB8888, COLOR_FMT_RGBA8888_UBWC},
572 		{DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC},
573 		{DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC},
574 		{DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC},
575 	};
576 	int color_fmt = -1;
577 	int i;
578 
579 	if (fmt->base.pixel_format == DRM_FORMAT_NV12) {
580 		if (DPU_FORMAT_IS_DX(fmt)) {
581 			if (fmt->unpack_tight)
582 				color_fmt = COLOR_FMT_NV12_BPP10_UBWC;
583 			else
584 				color_fmt = COLOR_FMT_P010_UBWC;
585 		} else
586 			color_fmt = COLOR_FMT_NV12_UBWC;
587 		return color_fmt;
588 	}
589 
590 	for (i = 0; i < ARRAY_SIZE(dpu_media_ubwc_map); ++i)
591 		if (fmt->base.pixel_format == dpu_media_ubwc_map[i].format) {
592 			color_fmt = dpu_media_ubwc_map[i].color;
593 			break;
594 		}
595 	return color_fmt;
596 }
597 
_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)598 static int _dpu_format_get_plane_sizes_ubwc(
599 		const struct dpu_format *fmt,
600 		const uint32_t width,
601 		const uint32_t height,
602 		struct dpu_hw_fmt_layout *layout)
603 {
604 	int i;
605 	int color;
606 	bool meta = DPU_FORMAT_IS_UBWC(fmt);
607 
608 	memset(layout, 0, sizeof(struct dpu_hw_fmt_layout));
609 	layout->format = fmt;
610 	layout->width = width;
611 	layout->height = height;
612 	layout->num_planes = fmt->num_planes;
613 
614 	color = _dpu_format_get_media_color_ubwc(fmt);
615 	if (color < 0) {
616 		DRM_ERROR("UBWC format not supported for fmt: %4.4s\n",
617 			(char *)&fmt->base.pixel_format);
618 		return -EINVAL;
619 	}
620 
621 	if (DPU_FORMAT_IS_YUV(layout->format)) {
622 		uint32_t y_sclines, uv_sclines;
623 		uint32_t y_meta_scanlines = 0;
624 		uint32_t uv_meta_scanlines = 0;
625 
626 		layout->num_planes = 2;
627 		layout->plane_pitch[0] = VENUS_Y_STRIDE(color, width);
628 		y_sclines = VENUS_Y_SCANLINES(color, height);
629 		layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] *
630 			y_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
631 
632 		layout->plane_pitch[1] = VENUS_UV_STRIDE(color, width);
633 		uv_sclines = VENUS_UV_SCANLINES(color, height);
634 		layout->plane_size[1] = MSM_MEDIA_ALIGN(layout->plane_pitch[1] *
635 			uv_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
636 
637 		if (!meta)
638 			goto done;
639 
640 		layout->num_planes += 2;
641 		layout->plane_pitch[2] = VENUS_Y_META_STRIDE(color, width);
642 		y_meta_scanlines = VENUS_Y_META_SCANLINES(color, height);
643 		layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] *
644 			y_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
645 
646 		layout->plane_pitch[3] = VENUS_UV_META_STRIDE(color, width);
647 		uv_meta_scanlines = VENUS_UV_META_SCANLINES(color, height);
648 		layout->plane_size[3] = MSM_MEDIA_ALIGN(layout->plane_pitch[3] *
649 			uv_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
650 
651 	} else {
652 		uint32_t rgb_scanlines, rgb_meta_scanlines;
653 
654 		layout->num_planes = 1;
655 
656 		layout->plane_pitch[0] = VENUS_RGB_STRIDE(color, width);
657 		rgb_scanlines = VENUS_RGB_SCANLINES(color, height);
658 		layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] *
659 			rgb_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
660 
661 		if (!meta)
662 			goto done;
663 		layout->num_planes += 2;
664 		layout->plane_pitch[2] = VENUS_RGB_META_STRIDE(color, width);
665 		rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color, height);
666 		layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] *
667 			rgb_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
668 	}
669 
670 done:
671 	for (i = 0; i < DPU_MAX_PLANES; i++)
672 		layout->total_size += layout->plane_size[i];
673 
674 	return 0;
675 }
676 
_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)677 static int _dpu_format_get_plane_sizes_linear(
678 		const struct dpu_format *fmt,
679 		const uint32_t width,
680 		const uint32_t height,
681 		struct dpu_hw_fmt_layout *layout,
682 		const uint32_t *pitches)
683 {
684 	int i;
685 
686 	memset(layout, 0, sizeof(struct dpu_hw_fmt_layout));
687 	layout->format = fmt;
688 	layout->width = width;
689 	layout->height = height;
690 	layout->num_planes = fmt->num_planes;
691 
692 	/* Due to memset above, only need to set planes of interest */
693 	if (fmt->fetch_planes == DPU_PLANE_INTERLEAVED) {
694 		layout->num_planes = 1;
695 		layout->plane_size[0] = width * height * layout->format->bpp;
696 		layout->plane_pitch[0] = width * layout->format->bpp;
697 	} else {
698 		uint32_t v_subsample, h_subsample;
699 		uint32_t chroma_samp;
700 		uint32_t bpp = 1;
701 
702 		chroma_samp = fmt->chroma_sample;
703 		_dpu_get_v_h_subsample_rate(chroma_samp, &v_subsample,
704 				&h_subsample);
705 
706 		if (width % h_subsample || height % v_subsample) {
707 			DRM_ERROR("mismatch in subsample vs dimensions\n");
708 			return -EINVAL;
709 		}
710 
711 		if ((fmt->base.pixel_format == DRM_FORMAT_NV12) &&
712 			(DPU_FORMAT_IS_DX(fmt)))
713 			bpp = 2;
714 		layout->plane_pitch[0] = width * bpp;
715 		layout->plane_pitch[1] = layout->plane_pitch[0] / h_subsample;
716 		layout->plane_size[0] = layout->plane_pitch[0] * height;
717 		layout->plane_size[1] = layout->plane_pitch[1] *
718 				(height / v_subsample);
719 
720 		if (fmt->fetch_planes == DPU_PLANE_PSEUDO_PLANAR) {
721 			layout->num_planes = 2;
722 			layout->plane_size[1] *= 2;
723 			layout->plane_pitch[1] *= 2;
724 		} else {
725 			/* planar */
726 			layout->num_planes = 3;
727 			layout->plane_size[2] = layout->plane_size[1];
728 			layout->plane_pitch[2] = layout->plane_pitch[1];
729 		}
730 	}
731 
732 	/*
733 	 * linear format: allow user allocated pitches if they are greater than
734 	 * the requirement.
735 	 * ubwc format: pitch values are computed uniformly across
736 	 * all the components based on ubwc specifications.
737 	 */
738 	for (i = 0; i < layout->num_planes && i < DPU_MAX_PLANES; ++i) {
739 		if (pitches && layout->plane_pitch[i] < pitches[i])
740 			layout->plane_pitch[i] = pitches[i];
741 	}
742 
743 	for (i = 0; i < DPU_MAX_PLANES; i++)
744 		layout->total_size += layout->plane_size[i];
745 
746 	return 0;
747 }
748 
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)749 static int dpu_format_get_plane_sizes(
750 		const struct dpu_format *fmt,
751 		const uint32_t w,
752 		const uint32_t h,
753 		struct dpu_hw_fmt_layout *layout,
754 		const uint32_t *pitches)
755 {
756 	if (!layout || !fmt) {
757 		DRM_ERROR("invalid pointer\n");
758 		return -EINVAL;
759 	}
760 
761 	if ((w > DPU_MAX_IMG_WIDTH) || (h > DPU_MAX_IMG_HEIGHT)) {
762 		DRM_ERROR("image dimensions outside max range\n");
763 		return -ERANGE;
764 	}
765 
766 	if (DPU_FORMAT_IS_UBWC(fmt) || DPU_FORMAT_IS_TILE(fmt))
767 		return _dpu_format_get_plane_sizes_ubwc(fmt, w, h, layout);
768 
769 	return _dpu_format_get_plane_sizes_linear(fmt, w, h, layout, pitches);
770 }
771 
_dpu_format_populate_addrs_ubwc(struct msm_gem_address_space * aspace,struct drm_framebuffer * fb,struct dpu_hw_fmt_layout * layout)772 static int _dpu_format_populate_addrs_ubwc(
773 		struct msm_gem_address_space *aspace,
774 		struct drm_framebuffer *fb,
775 		struct dpu_hw_fmt_layout *layout)
776 {
777 	uint32_t base_addr = 0;
778 	bool meta;
779 
780 	if (!fb || !layout) {
781 		DRM_ERROR("invalid pointers\n");
782 		return -EINVAL;
783 	}
784 
785 	if (aspace)
786 		base_addr = msm_framebuffer_iova(fb, aspace, 0);
787 	if (!base_addr) {
788 		DRM_ERROR("failed to retrieve base addr\n");
789 		return -EFAULT;
790 	}
791 
792 	meta = DPU_FORMAT_IS_UBWC(layout->format);
793 
794 	/* Per-format logic for verifying active planes */
795 	if (DPU_FORMAT_IS_YUV(layout->format)) {
796 		/************************************************/
797 		/*      UBWC            **                      */
798 		/*      buffer          **      DPU PLANE       */
799 		/*      format          **                      */
800 		/************************************************/
801 		/* -------------------  ** -------------------- */
802 		/* |      Y meta     |  ** |    Y bitstream   | */
803 		/* |       data      |  ** |       plane      | */
804 		/* -------------------  ** -------------------- */
805 		/* |    Y bitstream  |  ** |  CbCr bitstream  | */
806 		/* |       data      |  ** |       plane      | */
807 		/* -------------------  ** -------------------- */
808 		/* |   Cbcr metadata |  ** |       Y meta     | */
809 		/* |       data      |  ** |       plane      | */
810 		/* -------------------  ** -------------------- */
811 		/* |  CbCr bitstream |  ** |     CbCr meta    | */
812 		/* |       data      |  ** |       plane      | */
813 		/* -------------------  ** -------------------- */
814 		/************************************************/
815 
816 		/* configure Y bitstream plane */
817 		layout->plane_addr[0] = base_addr + layout->plane_size[2];
818 
819 		/* configure CbCr bitstream plane */
820 		layout->plane_addr[1] = base_addr + layout->plane_size[0]
821 			+ layout->plane_size[2] + layout->plane_size[3];
822 
823 		if (!meta)
824 			return 0;
825 
826 		/* configure Y metadata plane */
827 		layout->plane_addr[2] = base_addr;
828 
829 		/* configure CbCr metadata plane */
830 		layout->plane_addr[3] = base_addr + layout->plane_size[0]
831 			+ layout->plane_size[2];
832 
833 	} else {
834 		/************************************************/
835 		/*      UBWC            **                      */
836 		/*      buffer          **      DPU PLANE       */
837 		/*      format          **                      */
838 		/************************************************/
839 		/* -------------------  ** -------------------- */
840 		/* |      RGB meta   |  ** |   RGB bitstream  | */
841 		/* |       data      |  ** |       plane      | */
842 		/* -------------------  ** -------------------- */
843 		/* |  RGB bitstream  |  ** |       NONE       | */
844 		/* |       data      |  ** |                  | */
845 		/* -------------------  ** -------------------- */
846 		/*                      ** |     RGB meta     | */
847 		/*                      ** |       plane      | */
848 		/*                      ** -------------------- */
849 		/************************************************/
850 
851 		layout->plane_addr[0] = base_addr + layout->plane_size[2];
852 		layout->plane_addr[1] = 0;
853 
854 		if (!meta)
855 			return 0;
856 
857 		layout->plane_addr[2] = base_addr;
858 		layout->plane_addr[3] = 0;
859 	}
860 	return 0;
861 }
862 
_dpu_format_populate_addrs_linear(struct msm_gem_address_space * aspace,struct drm_framebuffer * fb,struct dpu_hw_fmt_layout * layout)863 static int _dpu_format_populate_addrs_linear(
864 		struct msm_gem_address_space *aspace,
865 		struct drm_framebuffer *fb,
866 		struct dpu_hw_fmt_layout *layout)
867 {
868 	unsigned int i;
869 
870 	/* Can now check the pitches given vs pitches expected */
871 	for (i = 0; i < layout->num_planes; ++i) {
872 		if (layout->plane_pitch[i] > fb->pitches[i]) {
873 			DRM_ERROR("plane %u expected pitch %u, fb %u\n",
874 				i, layout->plane_pitch[i], fb->pitches[i]);
875 			return -EINVAL;
876 		}
877 	}
878 
879 	/* Populate addresses for simple formats here */
880 	for (i = 0; i < layout->num_planes; ++i) {
881 		if (aspace)
882 			layout->plane_addr[i] =
883 				msm_framebuffer_iova(fb, aspace, i);
884 		if (!layout->plane_addr[i]) {
885 			DRM_ERROR("failed to retrieve base addr\n");
886 			return -EFAULT;
887 		}
888 	}
889 
890 	return 0;
891 }
892 
dpu_format_populate_layout(struct msm_gem_address_space * aspace,struct drm_framebuffer * fb,struct dpu_hw_fmt_layout * layout)893 int dpu_format_populate_layout(
894 		struct msm_gem_address_space *aspace,
895 		struct drm_framebuffer *fb,
896 		struct dpu_hw_fmt_layout *layout)
897 {
898 	uint32_t plane_addr[DPU_MAX_PLANES];
899 	int i, ret;
900 
901 	if (!fb || !layout) {
902 		DRM_ERROR("invalid arguments\n");
903 		return -EINVAL;
904 	}
905 
906 	if ((fb->width > DPU_MAX_IMG_WIDTH) ||
907 			(fb->height > DPU_MAX_IMG_HEIGHT)) {
908 		DRM_ERROR("image dimensions outside max range\n");
909 		return -ERANGE;
910 	}
911 
912 	layout->format = to_dpu_format(msm_framebuffer_format(fb));
913 
914 	/* Populate the plane sizes etc via get_format */
915 	ret = dpu_format_get_plane_sizes(layout->format, fb->width, fb->height,
916 			layout, fb->pitches);
917 	if (ret)
918 		return ret;
919 
920 	for (i = 0; i < DPU_MAX_PLANES; ++i)
921 		plane_addr[i] = layout->plane_addr[i];
922 
923 	/* Populate the addresses given the fb */
924 	if (DPU_FORMAT_IS_UBWC(layout->format) ||
925 			DPU_FORMAT_IS_TILE(layout->format))
926 		ret = _dpu_format_populate_addrs_ubwc(aspace, fb, layout);
927 	else
928 		ret = _dpu_format_populate_addrs_linear(aspace, fb, layout);
929 
930 	/* check if anything changed */
931 	if (!ret && !memcmp(plane_addr, layout->plane_addr, sizeof(plane_addr)))
932 		ret = -EAGAIN;
933 
934 	return ret;
935 }
936 
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)937 int dpu_format_check_modified_format(
938 		const struct msm_kms *kms,
939 		const struct msm_format *msm_fmt,
940 		const struct drm_mode_fb_cmd2 *cmd,
941 		struct drm_gem_object **bos)
942 {
943 	const struct drm_format_info *info;
944 	const struct dpu_format *fmt;
945 	struct dpu_hw_fmt_layout layout;
946 	uint32_t bos_total_size = 0;
947 	int ret, i;
948 
949 	if (!msm_fmt || !cmd || !bos) {
950 		DRM_ERROR("invalid arguments\n");
951 		return -EINVAL;
952 	}
953 
954 	fmt = to_dpu_format(msm_fmt);
955 	info = drm_format_info(fmt->base.pixel_format);
956 	if (!info)
957 		return -EINVAL;
958 
959 	ret = dpu_format_get_plane_sizes(fmt, cmd->width, cmd->height,
960 			&layout, cmd->pitches);
961 	if (ret)
962 		return ret;
963 
964 	for (i = 0; i < info->num_planes; i++) {
965 		if (!bos[i]) {
966 			DRM_ERROR("invalid handle for plane %d\n", i);
967 			return -EINVAL;
968 		}
969 		if ((i == 0) || (bos[i] != bos[0]))
970 			bos_total_size += bos[i]->size;
971 	}
972 
973 	if (bos_total_size < layout.total_size) {
974 		DRM_ERROR("buffers total size too small %u expected %u\n",
975 				bos_total_size, layout.total_size);
976 		return -EINVAL;
977 	}
978 
979 	return 0;
980 }
981 
dpu_get_dpu_format_ext(const uint32_t format,const uint64_t modifier)982 const struct dpu_format *dpu_get_dpu_format_ext(
983 		const uint32_t format,
984 		const uint64_t modifier)
985 {
986 	uint32_t i = 0;
987 	const struct dpu_format *fmt = NULL;
988 	const struct dpu_format *map = NULL;
989 	ssize_t map_size = 0;
990 
991 	/*
992 	 * Currently only support exactly zero or one modifier.
993 	 * All planes use the same modifier.
994 	 */
995 	DRM_DEBUG_ATOMIC("plane format modifier 0x%llX\n", modifier);
996 
997 	switch (modifier) {
998 	case 0:
999 		map = dpu_format_map;
1000 		map_size = ARRAY_SIZE(dpu_format_map);
1001 		break;
1002 	case DRM_FORMAT_MOD_QCOM_COMPRESSED:
1003 		map = dpu_format_map_ubwc;
1004 		map_size = ARRAY_SIZE(dpu_format_map_ubwc);
1005 		DRM_DEBUG_ATOMIC("found fmt: %4.4s  DRM_FORMAT_MOD_QCOM_COMPRESSED\n",
1006 				(char *)&format);
1007 		break;
1008 	default:
1009 		DPU_ERROR("unsupported format modifier %llX\n", modifier);
1010 		return NULL;
1011 	}
1012 
1013 	for (i = 0; i < map_size; i++) {
1014 		if (format == map[i].base.pixel_format) {
1015 			fmt = &map[i];
1016 			break;
1017 		}
1018 	}
1019 
1020 	if (fmt == NULL)
1021 		DPU_ERROR("unsupported fmt: %4.4s modifier 0x%llX\n",
1022 			(char *)&format, modifier);
1023 	else
1024 		DRM_DEBUG_ATOMIC("fmt %4.4s mod 0x%llX ubwc %d yuv %d\n",
1025 				(char *)&format, modifier,
1026 				DPU_FORMAT_IS_UBWC(fmt),
1027 				DPU_FORMAT_IS_YUV(fmt));
1028 
1029 	return fmt;
1030 }
1031 
dpu_get_msm_format(struct msm_kms * kms,const uint32_t format,const uint64_t modifiers)1032 const struct msm_format *dpu_get_msm_format(
1033 		struct msm_kms *kms,
1034 		const uint32_t format,
1035 		const uint64_t modifiers)
1036 {
1037 	const struct dpu_format *fmt = dpu_get_dpu_format_ext(format,
1038 			modifiers);
1039 	if (fmt)
1040 		return &fmt->base;
1041 	return NULL;
1042 }
1043