1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2 /*
3 * Copyright (c) 2022 Rockchip Electronics Co., Ltd.
4 * Author: Sandy Huang <hjc@rock-chips.com>
5 */
6
7 #include "rockchip_drm_display_pattern.h"
8
9 #define MAKE_RGB_INFO(rl, ro, gl, go, bl, bo, al, ao) \
10 .rgb = { { (rl), (ro) }, { (gl), (go) }, { (bl), (bo) }, { (al), (ao) } }
11
12 #define MAKE_YUV_INFO(order, xsub, ysub, chroma_stride) \
13 .yuv = { (order), (xsub), (ysub), (chroma_stride) }
14
15 struct color_rgb24 {
16 unsigned int value : 24;
17 } __attribute__((__packed__));
18
19 struct color_yuv {
20 unsigned char y;
21 unsigned char u;
22 unsigned char v;
23 };
24
25 #define MAKE_YUV_601_Y(r, g, b) \
26 (((66 * (r) + 129 * (g) + 25 * (b) + 128) >> 8) + 16)
27 #define MAKE_YUV_601_U(r, g, b) \
28 (((-38 * (r) - 74 * (g) + 112 * (b) + 128) >> 8) + 128)
29 #define MAKE_YUV_601_V(r, g, b) \
30 (((112 * (r) - 94 * (g) - 18 * (b) + 128) >> 8) + 128)
31
32 #define MAKE_YUV_601(r, g, b) \
33 { .y = MAKE_YUV_601_Y(r, g, b), \
34 .u = MAKE_YUV_601_U(r, g, b), \
35 .v = MAKE_YUV_601_V(r, g, b) }
36
37 #define MAKE_RGBA(rgb, r, g, b, a) \
38 ((((r) >> (8 - (rgb)->red.length)) << (rgb)->red.offset) | \
39 (((g) >> (8 - (rgb)->green.length)) << (rgb)->green.offset) | \
40 (((b) >> (8 - (rgb)->blue.length)) << (rgb)->blue.offset) | \
41 (((a) >> (8 - (rgb)->alpha.length)) << (rgb)->alpha.offset))
42
43 #define MAKE_RGB24(rgb, r, g, b) { .value = MAKE_RGBA(rgb, r, g, b, 0) }
44
45 static const struct util_format_info format_info[] = {
46 /* YUV semi-planar */
47 { DRM_FORMAT_NV12, "NV12", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 2) },
48 { DRM_FORMAT_NV21, "NV21", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 2) },
49 { DRM_FORMAT_NV16, "NV16", MAKE_YUV_INFO(YUV_YCbCr, 2, 1, 2) },
50 { DRM_FORMAT_NV61, "NV61", MAKE_YUV_INFO(YUV_YCrCb, 2, 1, 2) },
51 /* RGB565 */
52 { DRM_FORMAT_RGB565, "RG16", MAKE_RGB_INFO(5, 11, 6, 5, 5, 0, 0, 0) },
53 { DRM_FORMAT_BGR565, "BG16", MAKE_RGB_INFO(5, 0, 6, 5, 5, 11, 0, 0) },
54 /* RGB888 */
55 { DRM_FORMAT_BGR888, "BG24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) },
56 { DRM_FORMAT_RGB888, "RG24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) },
57 /* ARGB8888 */
58 { DRM_FORMAT_ARGB8888, "AR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) },
59 { DRM_FORMAT_XRGB8888, "XR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) },
60 { DRM_FORMAT_ABGR8888, "AB24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 8, 24) },
61 { DRM_FORMAT_XBGR8888, "XB24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) },
62 { DRM_FORMAT_RGBA8888, "RA24", MAKE_RGB_INFO(8, 24, 8, 16, 8, 8, 8, 0) },
63 { DRM_FORMAT_RGBX8888, "RX24", MAKE_RGB_INFO(8, 24, 8, 16, 8, 8, 0, 0) },
64 { DRM_FORMAT_BGRA8888, "BA24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) },
65 { DRM_FORMAT_BGRX8888, "BX24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 0, 0) },
66 };
67
util_format_info_find(uint32_t format)68 static const struct util_format_info *util_format_info_find(uint32_t format)
69 {
70 unsigned int i;
71
72 for (i = 0; i < ARRAY_SIZE(format_info); i++)
73 if (format_info[i].format == format)
74 return &format_info[i];
75
76 return NULL;
77 }
78 #define MAKE_RGB24(rgb, r, g, b) \
79 { .value = MAKE_RGBA(rgb, r, g, b, 0) }
80
fill_smpte_yuv_planar(const struct util_yuv_info * yuv,unsigned char * y_mem,unsigned char * u_mem,unsigned char * v_mem,unsigned int width,unsigned int height,unsigned int stride)81 static void fill_smpte_yuv_planar(const struct util_yuv_info *yuv,
82 unsigned char *y_mem, unsigned char *u_mem,
83 unsigned char *v_mem, unsigned int width,
84 unsigned int height, unsigned int stride)
85 {
86 const struct color_yuv colors_top[] = {
87 MAKE_YUV_601(191, 192, 192), /* grey */
88 MAKE_YUV_601(192, 192, 0), /* yellow */
89 MAKE_YUV_601(0, 192, 192), /* cyan */
90 MAKE_YUV_601(0, 192, 0), /* green */
91 MAKE_YUV_601(192, 0, 192), /* magenta */
92 MAKE_YUV_601(192, 0, 0), /* red */
93 MAKE_YUV_601(0, 0, 192), /* blue */
94 };
95 const struct color_yuv colors_middle[] = {
96 MAKE_YUV_601(0, 0, 192), /* blue */
97 MAKE_YUV_601(19, 19, 19), /* black */
98 MAKE_YUV_601(192, 0, 192), /* magenta */
99 MAKE_YUV_601(19, 19, 19), /* black */
100 MAKE_YUV_601(0, 192, 192), /* cyan */
101 MAKE_YUV_601(19, 19, 19), /* black */
102 MAKE_YUV_601(192, 192, 192), /* grey */
103 };
104 const struct color_yuv colors_bottom[] = {
105 MAKE_YUV_601(0, 33, 76), /* in-phase */
106 MAKE_YUV_601(255, 255, 255), /* super white */
107 MAKE_YUV_601(50, 0, 106), /* quadrature */
108 MAKE_YUV_601(19, 19, 19), /* black */
109 MAKE_YUV_601(9, 9, 9), /* 3.5% */
110 MAKE_YUV_601(19, 19, 19), /* 7.5% */
111 MAKE_YUV_601(29, 29, 29), /* 11.5% */
112 MAKE_YUV_601(19, 19, 19), /* black */
113 };
114 unsigned int cs = yuv->chroma_stride;
115 unsigned int xsub = yuv->xsub;
116 unsigned int ysub = yuv->ysub;
117 unsigned int x;
118 unsigned int y;
119
120 /* Luma */
121 for (y = 0; y < height * 6 / 9; ++y) {
122 for (x = 0; x < width; ++x)
123 y_mem[x] = colors_top[x * 7 / width].y;
124 y_mem += stride;
125 }
126
127 for (; y < height * 7 / 9; ++y) {
128 for (x = 0; x < width; ++x)
129 y_mem[x] = colors_middle[x * 7 / width].y;
130 y_mem += stride;
131 }
132
133 for (; y < height; ++y) {
134 for (x = 0; x < width * 5 / 7; ++x)
135 y_mem[x] = colors_bottom[x * 4 / (width * 5 / 7)].y;
136 for (; x < width * 6 / 7; ++x)
137 y_mem[x] = colors_bottom[(x - width * 5 / 7) * 3 / (width / 7) + 4].y;
138 for (; x < width; ++x)
139 y_mem[x] = colors_bottom[7].y;
140 y_mem += stride;
141 }
142
143 /* Chroma */
144 for (y = 0; y < height / ysub * 6 / 9; ++y) {
145 for (x = 0; x < width; x += xsub) {
146 u_mem[x * cs / xsub] = colors_top[x * 7 / width].u;
147 v_mem[x * cs / xsub] = colors_top[x * 7 / width].v;
148 }
149 u_mem += stride * cs / xsub;
150 v_mem += stride * cs / xsub;
151 }
152
153 for (; y < height / ysub * 7 / 9; ++y) {
154 for (x = 0; x < width; x += xsub) {
155 u_mem[x * cs / xsub] = colors_middle[x * 7 / width].u;
156 v_mem[x * cs / xsub] = colors_middle[x * 7 / width].v;
157 }
158 u_mem += stride * cs / xsub;
159 v_mem += stride * cs / xsub;
160 }
161
162 for (; y < height / ysub; ++y) {
163 for (x = 0; x < width * 5 / 7; x += xsub) {
164 u_mem[x * cs / xsub] =
165 colors_bottom[x * 4 / (width * 5 / 7)].u;
166 v_mem[x * cs / xsub] =
167 colors_bottom[x * 4 / (width * 5 / 7)].v;
168 }
169 for (; x < width * 6 / 7; x += xsub) {
170 u_mem[x * cs / xsub] = colors_bottom[(x - width * 5 / 7) * 3 / (width / 7) + 4].u;
171 v_mem[x * cs / xsub] = colors_bottom[(x - width * 5 / 7) * 3 / (width / 7) + 4].v;
172 }
173 for (; x < width; x += xsub) {
174 u_mem[x * cs / xsub] = colors_bottom[7].u;
175 v_mem[x * cs / xsub] = colors_bottom[7].v;
176 }
177 u_mem += stride * cs / xsub;
178 v_mem += stride * cs / xsub;
179 }
180 }
181
fill_smpte_rgb16(const struct util_rgb_info * rgb,void * mem,unsigned int width,unsigned int height,unsigned int stride)182 static void fill_smpte_rgb16(const struct util_rgb_info *rgb, void *mem,
183 unsigned int width, unsigned int height,
184 unsigned int stride)
185 {
186 unsigned int x;
187 unsigned int y;
188
189 const uint16_t colors_top[] = {
190 MAKE_RGBA(rgb, 192, 192, 192, 255), /* grey */
191 MAKE_RGBA(rgb, 192, 192, 0, 255), /* yellow */
192 MAKE_RGBA(rgb, 0, 192, 192, 255), /* cyan */
193 MAKE_RGBA(rgb, 0, 192, 0, 255), /* green */
194 MAKE_RGBA(rgb, 192, 0, 192, 255), /* magenta */
195 MAKE_RGBA(rgb, 192, 0, 0, 255), /* red */
196 MAKE_RGBA(rgb, 0, 0, 192, 255), /* blue */
197 };
198 const uint16_t colors_middle[] = {
199 MAKE_RGBA(rgb, 0, 0, 192, 127), /* blue */
200 MAKE_RGBA(rgb, 19, 19, 19, 127), /* black */
201 MAKE_RGBA(rgb, 192, 0, 192, 127), /* magenta */
202 MAKE_RGBA(rgb, 19, 19, 19, 127), /* black */
203 MAKE_RGBA(rgb, 0, 192, 192, 127), /* cyan */
204 MAKE_RGBA(rgb, 19, 19, 19, 127), /* black */
205 MAKE_RGBA(rgb, 192, 192, 192, 127), /* grey */
206 };
207 const uint16_t colors_bottom[] = {
208 MAKE_RGBA(rgb, 0, 33, 76, 255), /* in-phase */
209 MAKE_RGBA(rgb, 255, 255, 255, 255), /* super white */
210 MAKE_RGBA(rgb, 50, 0, 106, 255), /* quadrature */
211 MAKE_RGBA(rgb, 19, 19, 19, 255), /* black */
212 MAKE_RGBA(rgb, 9, 9, 9, 255), /* 3.5% */
213 MAKE_RGBA(rgb, 19, 19, 19, 255), /* 7.5% */
214 MAKE_RGBA(rgb, 29, 29, 29, 255), /* 11.5% */
215 MAKE_RGBA(rgb, 19, 19, 19, 255), /* black */
216 };
217
218 for (y = 0; y < height * 6 / 9; ++y) {
219 for (x = 0; x < width; ++x)
220 ((uint16_t *)mem)[x] = colors_top[x * 7 / width];
221 mem += stride;
222 }
223
224 for (; y < height * 7 / 9; ++y) {
225 for (x = 0; x < width; ++x)
226 ((uint16_t *)mem)[x] = colors_middle[x * 7 / width];
227 mem += stride;
228 }
229
230 for (; y < height; ++y) {
231 for (x = 0; x < width * 5 / 7; ++x)
232 ((uint16_t *)mem)[x] =
233 colors_bottom[x * 4 / (width * 5 / 7)];
234 for (; x < width * 6 / 7; ++x)
235 ((uint16_t *)mem)[x] =
236 colors_bottom[(x - width * 5 / 7) * 3 / (width / 7) + 4];
237 for (; x < width; ++x)
238 ((uint16_t *)mem)[x] = colors_bottom[7];
239 mem += stride;
240 }
241 }
242
fill_smpte_rgb24(const struct util_rgb_info * rgb,void * mem,unsigned int width,unsigned int height,unsigned int stride)243 static void fill_smpte_rgb24(const struct util_rgb_info *rgb, void *mem,
244 unsigned int width, unsigned int height,
245 unsigned int stride)
246 {
247 unsigned int x;
248 unsigned int y;
249
250 const struct color_rgb24 colors_top[] = {
251 MAKE_RGB24(rgb, 192, 192, 192), /* grey */
252 MAKE_RGB24(rgb, 192, 192, 0), /* yellow */
253 MAKE_RGB24(rgb, 0, 192, 192), /* cyan */
254 MAKE_RGB24(rgb, 0, 192, 0), /* green */
255 MAKE_RGB24(rgb, 192, 0, 192), /* magenta */
256 MAKE_RGB24(rgb, 192, 0, 0), /* red */
257 MAKE_RGB24(rgb, 0, 0, 192), /* blue */
258 };
259 const struct color_rgb24 colors_middle[] = {
260 MAKE_RGB24(rgb, 0, 0, 192), /* blue */
261 MAKE_RGB24(rgb, 19, 19, 19), /* black */
262 MAKE_RGB24(rgb, 192, 0, 192), /* magenta */
263 MAKE_RGB24(rgb, 19, 19, 19), /* black */
264 MAKE_RGB24(rgb, 0, 192, 192), /* cyan */
265 MAKE_RGB24(rgb, 19, 19, 19), /* black */
266 MAKE_RGB24(rgb, 192, 192, 192), /* grey */
267 };
268 const struct color_rgb24 colors_bottom[] = {
269 MAKE_RGB24(rgb, 0, 33, 76), /* in-phase */
270 MAKE_RGB24(rgb, 255, 255, 255), /* super white */
271 MAKE_RGB24(rgb, 50, 0, 106), /* quadrature */
272 MAKE_RGB24(rgb, 19, 19, 19), /* black */
273 MAKE_RGB24(rgb, 9, 9, 9), /* 3.5% */
274 MAKE_RGB24(rgb, 19, 19, 19), /* 7.5% */
275 MAKE_RGB24(rgb, 29, 29, 29), /* 11.5% */
276 MAKE_RGB24(rgb, 19, 19, 19), /* black */
277 };
278
279 for (y = 0; y < height * 6 / 9; ++y) {
280 for (x = 0; x < width; ++x)
281 ((struct color_rgb24 *)mem)[x] = colors_top[x * 7 / width];
282 mem += stride;
283 }
284
285 for (; y < height * 7 / 9; ++y) {
286 for (x = 0; x < width; ++x)
287 ((struct color_rgb24 *)mem)[x] = colors_middle[x * 7 / width];
288 mem += stride;
289 }
290
291 for (; y < height; ++y) {
292 for (x = 0; x < width * 5 / 7; ++x)
293 ((struct color_rgb24 *)mem)[x] =
294 colors_bottom[x * 4 / (width * 5 / 7)];
295 for (; x < width * 6 / 7; ++x)
296 ((struct color_rgb24 *)mem)[x] =
297 colors_bottom[(x - width * 5 / 7) * 3 / (width / 7) + 4];
298 for (; x < width; ++x)
299 ((struct color_rgb24 *)mem)[x] = colors_bottom[7];
300 mem += stride;
301 }
302 }
303
fill_smpte_rgb32(const struct util_rgb_info * rgb,void * mem,unsigned int width,unsigned int height,unsigned int stride)304 static void fill_smpte_rgb32(const struct util_rgb_info *rgb, void *mem,
305 unsigned int width, unsigned int height,
306 unsigned int stride)
307 {
308 unsigned int x;
309 unsigned int y;
310
311 const uint32_t colors_top[] = {
312 MAKE_RGBA(rgb, 192, 192, 192, 255), /* grey */
313 MAKE_RGBA(rgb, 192, 192, 0, 255), /* yellow */
314 MAKE_RGBA(rgb, 0, 192, 192, 255), /* cyan */
315 MAKE_RGBA(rgb, 0, 255, 0, 255), /* green */
316 MAKE_RGBA(rgb, 192, 0, 192, 255), /* magenta */
317 MAKE_RGBA(rgb, 255, 0, 0, 255), /* red */
318 MAKE_RGBA(rgb, 0, 0, 255, 255), /* blue */
319 };
320 const uint32_t colors_middle[] = {
321 MAKE_RGBA(rgb, 0, 0, 192, 127), /* blue */
322 MAKE_RGBA(rgb, 19, 19, 19, 127), /* black */
323 MAKE_RGBA(rgb, 192, 0, 192, 127), /* magenta */
324 MAKE_RGBA(rgb, 19, 19, 19, 127), /* black */
325 MAKE_RGBA(rgb, 0, 192, 192, 127), /* cyan */
326 MAKE_RGBA(rgb, 19, 19, 19, 127), /* black */
327 MAKE_RGBA(rgb, 192, 192, 192, 127), /* grey */
328 };
329 const uint32_t colors_bottom[] = {
330 MAKE_RGBA(rgb, 0, 33, 76, 255), /* in-phase */
331 MAKE_RGBA(rgb, 255, 255, 255, 255), /* super white */
332 MAKE_RGBA(rgb, 50, 0, 106, 255), /* quadrature */
333 MAKE_RGBA(rgb, 19, 19, 19, 255), /* black */
334 MAKE_RGBA(rgb, 9, 9, 9, 255), /* 3.5% */
335 MAKE_RGBA(rgb, 19, 19, 19, 255), /* 7.5% */
336 MAKE_RGBA(rgb, 29, 29, 29, 255), /* 11.5% */
337 MAKE_RGBA(rgb, 19, 19, 19, 255), /* black */
338 };
339
340 for (y = 0; y < height * 6 / 9; ++y) {
341 for (x = 0; x < width; ++x)
342 ((uint32_t *)mem)[x] = colors_top[x * 7 / width];
343 mem += stride;
344 }
345
346 for (; y < height * 7 / 9; ++y) {
347 for (x = 0; x < width; ++x)
348 ((uint32_t *)mem)[x] = colors_middle[x * 7 / width];
349 mem += stride;
350 }
351
352 for (; y < height; ++y) {
353 for (x = 0; x < width * 5 / 7; ++x)
354 ((uint32_t *)mem)[x] = colors_bottom[x * 4 / (width * 5 / 7)];
355 for (; x < width * 6 / 7; ++x)
356 ((uint32_t *)mem)[x] = colors_bottom[(x - width * 5 / 7) * 3 / (width / 7) + 4];
357 for (; x < width; ++x)
358 ((uint32_t *)mem)[x] = colors_bottom[7];
359 mem += stride;
360 }
361 }
362
fill_smpte(const struct util_format_info * info,void * planes[3],unsigned int width,unsigned int height,unsigned int stride)363 static void fill_smpte(const struct util_format_info *info, void *planes[3],
364 unsigned int width, unsigned int height, unsigned int stride)
365 {
366 unsigned char *u, *v;
367
368 if (width < 7)
369 width = 7;
370 switch (info->format) {
371 case DRM_FORMAT_NV12:
372 case DRM_FORMAT_NV21:
373 case DRM_FORMAT_NV16:
374 case DRM_FORMAT_NV61:
375 u = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1;
376 v = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1;
377 return fill_smpte_yuv_planar(&info->yuv, planes[0], u, v,
378 width, height, stride);
379 case DRM_FORMAT_RGB565:
380 case DRM_FORMAT_BGR565:
381 return fill_smpte_rgb16(&info->rgb, planes[0], width, height, stride);
382 case DRM_FORMAT_BGR888:
383 case DRM_FORMAT_RGB888:
384 return fill_smpte_rgb24(&info->rgb, planes[0], width, height, stride);
385 case DRM_FORMAT_ARGB8888:
386 case DRM_FORMAT_XRGB8888:
387 case DRM_FORMAT_ABGR8888:
388 case DRM_FORMAT_XBGR8888:
389 case DRM_FORMAT_RGBA8888:
390 case DRM_FORMAT_RGBX8888:
391 case DRM_FORMAT_BGRA8888:
392 case DRM_FORMAT_BGRX8888:
393 return fill_smpte_rgb32(&info->rgb, planes[0], width, height, stride);
394 }
395 }
396
397 /*
398 * util_fill_pattern - Fill a buffer with a test pattern
399 * @format: Pixel format
400 * @pattern: Test pattern
401 * @planes: Array of buffers
402 * @width: Width in pixels
403 * @height: Height in pixels
404 * @stride: Line stride (pitch) in bytes
405 *
406 * Fill the buffers with the test pattern specified by the pattern parameter.
407 * Supported formats vary depending on the selected pattern.
408 */
rockchip_drm_fill_color_bar(uint32_t format,void * planes[3],unsigned int width,unsigned int height,unsigned int stride)409 void rockchip_drm_fill_color_bar(uint32_t format,
410 void *planes[3], unsigned int width,
411 unsigned int height, unsigned int stride)
412 {
413 const struct util_format_info *info;
414
415 info = util_format_info_find(format);
416 if (info == NULL)
417 return;
418 return fill_smpte(info, planes, width, height, stride);
419 }
420