1 // SPDX-License-Identifier: GPL-2.0 or MIT 2 /* 3 * Copyright (C) 2016 Noralf Trønnes 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 */ 10 11 #include <linux/io.h> 12 #include <linux/iosys-map.h> 13 #include <linux/module.h> 14 #include <linux/slab.h> 15 16 #include <drm/drm_device.h> 17 #include <drm/drm_format_helper.h> 18 #include <drm/drm_framebuffer.h> 19 #include <drm/drm_fourcc.h> 20 #include <drm/drm_print.h> 21 #include <drm/drm_rect.h> 22 23 static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp) 24 { 25 return clip->y1 * pitch + clip->x1 * cpp; 26 } 27 28 /** 29 * drm_fb_clip_offset - Returns the clipping rectangles byte-offset in a framebuffer 30 * @pitch: Framebuffer line pitch in byte 31 * @format: Framebuffer format 32 * @clip: Clip rectangle 33 * 34 * Returns: 35 * The byte offset of the clip rectangle's top-left corner within the framebuffer. 36 */ 37 unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format, 38 const struct drm_rect *clip) 39 { 40 return clip_offset(clip, pitch, format->cpp[0]); 41 } 42 EXPORT_SYMBOL(drm_fb_clip_offset); 43 44 /* TODO: Make this function work with multi-plane formats. */ 45 static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize, 46 const void *vaddr, const struct drm_framebuffer *fb, 47 const struct drm_rect *clip, bool vaddr_cached_hint, 48 void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) 49 { 50 unsigned long linepixels = drm_rect_width(clip); 51 unsigned long lines = drm_rect_height(clip); 52 size_t sbuf_len = linepixels * fb->format->cpp[0]; 53 void *stmp = NULL; 54 unsigned long i; 55 const void *sbuf; 56 57 /* 58 * Some source buffers, such as DMA memory, use write-combine 59 * caching, so reads are uncached. Speed up access by fetching 60 * one line at a time. 61 */ 62 if (!vaddr_cached_hint) { 63 stmp = kmalloc(sbuf_len, GFP_KERNEL); 64 if (!stmp) 65 return -ENOMEM; 66 } 67 68 if (!dst_pitch) 69 dst_pitch = drm_rect_width(clip) * dst_pixsize; 70 vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]); 71 72 for (i = 0; i < lines; ++i) { 73 if (stmp) 74 sbuf = memcpy(stmp, vaddr, sbuf_len); 75 else 76 sbuf = vaddr; 77 xfrm_line(dst, sbuf, linepixels); 78 vaddr += fb->pitches[0]; 79 dst += dst_pitch; 80 } 81 82 kfree(stmp); 83 84 return 0; 85 } 86 87 /* TODO: Make this function work with multi-plane formats. */ 88 static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize, 89 const void *vaddr, const struct drm_framebuffer *fb, 90 const struct drm_rect *clip, bool vaddr_cached_hint, 91 void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) 92 { 93 unsigned long linepixels = drm_rect_width(clip); 94 unsigned long lines = drm_rect_height(clip); 95 size_t dbuf_len = linepixels * dst_pixsize; 96 size_t stmp_off = round_up(dbuf_len, ARCH_KMALLOC_MINALIGN); /* for sbuf alignment */ 97 size_t sbuf_len = linepixels * fb->format->cpp[0]; 98 void *stmp = NULL; 99 unsigned long i; 100 const void *sbuf; 101 void *dbuf; 102 103 if (vaddr_cached_hint) { 104 dbuf = kmalloc(dbuf_len, GFP_KERNEL); 105 } else { 106 dbuf = kmalloc(stmp_off + sbuf_len, GFP_KERNEL); 107 stmp = dbuf + stmp_off; 108 } 109 if (!dbuf) 110 return -ENOMEM; 111 112 if (!dst_pitch) 113 dst_pitch = linepixels * dst_pixsize; 114 vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]); 115 116 for (i = 0; i < lines; ++i) { 117 if (stmp) 118 sbuf = memcpy(stmp, vaddr, sbuf_len); 119 else 120 sbuf = vaddr; 121 xfrm_line(dbuf, sbuf, linepixels); 122 memcpy_toio(dst, dbuf, dbuf_len); 123 vaddr += fb->pitches[0]; 124 dst += dst_pitch; 125 } 126 127 kfree(dbuf); 128 129 return 0; 130 } 131 132 /* TODO: Make this function work with multi-plane formats. */ 133 static int drm_fb_xfrm(struct iosys_map *dst, 134 const unsigned int *dst_pitch, const u8 *dst_pixsize, 135 const struct iosys_map *src, const struct drm_framebuffer *fb, 136 const struct drm_rect *clip, bool vaddr_cached_hint, 137 void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) 138 { 139 static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { 140 0, 0, 0, 0 141 }; 142 143 if (!dst_pitch) 144 dst_pitch = default_dst_pitch; 145 146 /* TODO: handle src in I/O memory here */ 147 if (dst[0].is_iomem) 148 return __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0], 149 src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line); 150 else 151 return __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0], 152 src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line); 153 } 154 155 /** 156 * drm_fb_memcpy - Copy clip buffer 157 * @dst: Array of destination buffers 158 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines 159 * within @dst; can be NULL if scanlines are stored next to each other. 160 * @src: Array of source buffers 161 * @fb: DRM framebuffer 162 * @clip: Clip rectangle area to copy 163 * 164 * This function copies parts of a framebuffer to display memory. Destination and 165 * framebuffer formats must match. No conversion takes place. The parameters @dst, 166 * @dst_pitch and @src refer to arrays. Each array must have at least as many entries 167 * as there are planes in @fb's format. Each entry stores the value for the format's 168 * respective color plane at the same index. 169 * 170 * This function does not apply clipping on @dst (i.e. the destination is at the 171 * top-left corner). 172 */ 173 void drm_fb_memcpy(struct iosys_map *dst, const unsigned int *dst_pitch, 174 const struct iosys_map *src, const struct drm_framebuffer *fb, 175 const struct drm_rect *clip) 176 { 177 static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { 178 0, 0, 0, 0 179 }; 180 181 const struct drm_format_info *format = fb->format; 182 unsigned int i, y, lines = drm_rect_height(clip); 183 184 if (!dst_pitch) 185 dst_pitch = default_dst_pitch; 186 187 for (i = 0; i < format->num_planes; ++i) { 188 unsigned int bpp_i = drm_format_info_bpp(format, i); 189 unsigned int cpp_i = DIV_ROUND_UP(bpp_i, 8); 190 size_t len_i = DIV_ROUND_UP(drm_rect_width(clip) * bpp_i, 8); 191 unsigned int dst_pitch_i = dst_pitch[i]; 192 struct iosys_map dst_i = dst[i]; 193 struct iosys_map src_i = src[i]; 194 195 if (!dst_pitch_i) 196 dst_pitch_i = len_i; 197 198 iosys_map_incr(&src_i, clip_offset(clip, fb->pitches[i], cpp_i)); 199 for (y = 0; y < lines; y++) { 200 /* TODO: handle src_i in I/O memory here */ 201 iosys_map_memcpy_to(&dst_i, 0, src_i.vaddr, len_i); 202 iosys_map_incr(&src_i, fb->pitches[i]); 203 iosys_map_incr(&dst_i, dst_pitch_i); 204 } 205 } 206 } 207 EXPORT_SYMBOL(drm_fb_memcpy); 208 209 static void drm_fb_swab16_line(void *dbuf, const void *sbuf, unsigned int pixels) 210 { 211 u16 *dbuf16 = dbuf; 212 const u16 *sbuf16 = sbuf; 213 const u16 *send16 = sbuf16 + pixels; 214 215 while (sbuf16 < send16) 216 *dbuf16++ = swab16(*sbuf16++); 217 } 218 219 static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels) 220 { 221 u32 *dbuf32 = dbuf; 222 const u32 *sbuf32 = sbuf; 223 const u32 *send32 = sbuf32 + pixels; 224 225 while (sbuf32 < send32) 226 *dbuf32++ = swab32(*sbuf32++); 227 } 228 229 /** 230 * drm_fb_swab - Swap bytes into clip buffer 231 * @dst: Array of destination buffers 232 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines 233 * within @dst; can be NULL if scanlines are stored next to each other. 234 * @src: Array of source buffers 235 * @fb: DRM framebuffer 236 * @clip: Clip rectangle area to copy 237 * @cached: Source buffer is mapped cached (eg. not write-combined) 238 * 239 * This function copies parts of a framebuffer to display memory and swaps per-pixel 240 * bytes during the process. Destination and framebuffer formats must match. The 241 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at 242 * least as many entries as there are planes in @fb's format. Each entry stores the 243 * value for the format's respective color plane at the same index. If @cached is 244 * false a temporary buffer is used to cache one pixel line at a time to speed up 245 * slow uncached reads. 246 * 247 * This function does not apply clipping on @dst (i.e. the destination is at the 248 * top-left corner). 249 */ 250 void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch, 251 const struct iosys_map *src, const struct drm_framebuffer *fb, 252 const struct drm_rect *clip, bool cached) 253 { 254 const struct drm_format_info *format = fb->format; 255 u8 cpp = DIV_ROUND_UP(drm_format_info_bpp(format, 0), 8); 256 void (*swab_line)(void *dbuf, const void *sbuf, unsigned int npixels); 257 258 switch (cpp) { 259 case 4: 260 swab_line = drm_fb_swab32_line; 261 break; 262 case 2: 263 swab_line = drm_fb_swab16_line; 264 break; 265 default: 266 drm_warn_once(fb->dev, "Format %p4cc has unsupported pixel size.\n", 267 &format->format); 268 return; 269 } 270 271 drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, swab_line); 272 } 273 EXPORT_SYMBOL(drm_fb_swab); 274 275 static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels) 276 { 277 u8 *dbuf8 = dbuf; 278 const __le32 *sbuf32 = sbuf; 279 unsigned int x; 280 u32 pix; 281 282 for (x = 0; x < pixels; x++) { 283 pix = le32_to_cpu(sbuf32[x]); 284 dbuf8[x] = ((pix & 0x00e00000) >> 16) | 285 ((pix & 0x0000e000) >> 11) | 286 ((pix & 0x000000c0) >> 6); 287 } 288 } 289 290 /** 291 * drm_fb_xrgb8888_to_rgb332 - Convert XRGB8888 to RGB332 clip buffer 292 * @dst: Array of RGB332 destination buffers 293 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines 294 * within @dst; can be NULL if scanlines are stored next to each other. 295 * @src: Array of XRGB8888 source buffers 296 * @fb: DRM framebuffer 297 * @clip: Clip rectangle area to copy 298 * 299 * This function copies parts of a framebuffer to display memory and converts the 300 * color format during the process. Destination and framebuffer formats must match. The 301 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at 302 * least as many entries as there are planes in @fb's format. Each entry stores the 303 * value for the format's respective color plane at the same index. 304 * 305 * This function does not apply clipping on @dst (i.e. the destination is at the 306 * top-left corner). 307 * 308 * Drivers can use this function for RGB332 devices that don't support XRGB8888 natively. 309 */ 310 void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch, 311 const struct iosys_map *src, const struct drm_framebuffer *fb, 312 const struct drm_rect *clip) 313 { 314 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 315 1, 316 }; 317 318 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, 319 drm_fb_xrgb8888_to_rgb332_line); 320 } 321 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332); 322 323 static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels) 324 { 325 u16 *dbuf16 = dbuf; 326 const __le32 *sbuf32 = sbuf; 327 unsigned int x; 328 u16 val16; 329 u32 pix; 330 331 for (x = 0; x < pixels; x++) { 332 pix = le32_to_cpu(sbuf32[x]); 333 val16 = ((pix & 0x00F80000) >> 8) | 334 ((pix & 0x0000FC00) >> 5) | 335 ((pix & 0x000000F8) >> 3); 336 dbuf16[x] = val16; 337 } 338 } 339 340 static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf, 341 unsigned int pixels) 342 { 343 u16 *dbuf16 = dbuf; 344 const __le32 *sbuf32 = sbuf; 345 unsigned int x; 346 u16 val16; 347 u32 pix; 348 349 for (x = 0; x < pixels; x++) { 350 pix = le32_to_cpu(sbuf32[x]); 351 val16 = ((pix & 0x00F80000) >> 8) | 352 ((pix & 0x0000FC00) >> 5) | 353 ((pix & 0x000000F8) >> 3); 354 dbuf16[x] = swab16(val16); 355 } 356 } 357 358 /** 359 * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer 360 * @dst: Array of RGB565 destination buffers 361 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines 362 * within @dst; can be NULL if scanlines are stored next to each other. 363 * @src: Array of XRGB8888 source buffer 364 * @fb: DRM framebuffer 365 * @clip: Clip rectangle area to copy 366 * @swab: Swap bytes 367 * 368 * This function copies parts of a framebuffer to display memory and converts the 369 * color format during the process. Destination and framebuffer formats must match. The 370 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at 371 * least as many entries as there are planes in @fb's format. Each entry stores the 372 * value for the format's respective color plane at the same index. 373 * 374 * This function does not apply clipping on @dst (i.e. the destination is at the 375 * top-left corner). 376 * 377 * Drivers can use this function for RGB565 devices that don't support XRGB8888 natively. 378 */ 379 void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch, 380 const struct iosys_map *src, const struct drm_framebuffer *fb, 381 const struct drm_rect *clip, bool swab) 382 { 383 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 384 2, 385 }; 386 387 void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels); 388 389 if (swab) 390 xfrm_line = drm_fb_xrgb8888_to_rgb565_swab_line; 391 else 392 xfrm_line = drm_fb_xrgb8888_to_rgb565_line; 393 394 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm_line); 395 } 396 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); 397 398 static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels) 399 { 400 u8 *dbuf8 = dbuf; 401 const __le32 *sbuf32 = sbuf; 402 unsigned int x; 403 u32 pix; 404 405 for (x = 0; x < pixels; x++) { 406 pix = le32_to_cpu(sbuf32[x]); 407 *dbuf8++ = (pix & 0x000000FF) >> 0; 408 *dbuf8++ = (pix & 0x0000FF00) >> 8; 409 *dbuf8++ = (pix & 0x00FF0000) >> 16; 410 } 411 } 412 413 /** 414 * drm_fb_xrgb8888_to_rgb888 - Convert XRGB8888 to RGB888 clip buffer 415 * @dst: Array of RGB888 destination buffers 416 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines 417 * within @dst; can be NULL if scanlines are stored next to each other. 418 * @src: Array of XRGB8888 source buffers 419 * @fb: DRM framebuffer 420 * @clip: Clip rectangle area to copy 421 * 422 * This function copies parts of a framebuffer to display memory and converts the 423 * color format during the process. Destination and framebuffer formats must match. The 424 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at 425 * least as many entries as there are planes in @fb's format. Each entry stores the 426 * value for the format's respective color plane at the same index. 427 * 428 * This function does not apply clipping on @dst (i.e. the destination is at the 429 * top-left corner). 430 * 431 * Drivers can use this function for RGB888 devices that don't natively 432 * support XRGB8888. 433 */ 434 void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch, 435 const struct iosys_map *src, const struct drm_framebuffer *fb, 436 const struct drm_rect *clip) 437 { 438 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 439 3, 440 }; 441 442 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, 443 drm_fb_xrgb8888_to_rgb888_line); 444 } 445 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888); 446 447 static void drm_fb_rgb565_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels) 448 { 449 __le32 *dbuf32 = dbuf; 450 const __le16 *sbuf16 = sbuf; 451 unsigned int x; 452 453 for (x = 0; x < pixels; x++) { 454 u16 val16 = le16_to_cpu(sbuf16[x]); 455 u32 val32 = ((val16 & 0xf800) << 8) | 456 ((val16 & 0x07e0) << 5) | 457 ((val16 & 0x001f) << 3); 458 val32 = 0xff000000 | val32 | 459 ((val32 >> 3) & 0x00070007) | 460 ((val32 >> 2) & 0x00000300); 461 dbuf32[x] = cpu_to_le32(val32); 462 } 463 } 464 465 static void drm_fb_rgb565_to_xrgb8888(struct iosys_map *dst, const unsigned int *dst_pitch, 466 const struct iosys_map *src, 467 const struct drm_framebuffer *fb, 468 const struct drm_rect *clip) 469 { 470 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 471 4, 472 }; 473 474 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, 475 drm_fb_rgb565_to_xrgb8888_line); 476 } 477 478 static void drm_fb_rgb888_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels) 479 { 480 __le32 *dbuf32 = dbuf; 481 const u8 *sbuf8 = sbuf; 482 unsigned int x; 483 484 for (x = 0; x < pixels; x++) { 485 u8 r = *sbuf8++; 486 u8 g = *sbuf8++; 487 u8 b = *sbuf8++; 488 u32 pix = 0xff000000 | (r << 16) | (g << 8) | b; 489 dbuf32[x] = cpu_to_le32(pix); 490 } 491 } 492 493 static void drm_fb_rgb888_to_xrgb8888(struct iosys_map *dst, const unsigned int *dst_pitch, 494 const struct iosys_map *src, 495 const struct drm_framebuffer *fb, 496 const struct drm_rect *clip) 497 { 498 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 499 4, 500 }; 501 502 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, 503 drm_fb_rgb888_to_xrgb8888_line); 504 } 505 506 static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels) 507 { 508 __le32 *dbuf32 = dbuf; 509 const __le32 *sbuf32 = sbuf; 510 unsigned int x; 511 u32 val32; 512 u32 pix; 513 514 for (x = 0; x < pixels; x++) { 515 pix = le32_to_cpu(sbuf32[x]); 516 val32 = ((pix & 0x000000FF) << 2) | 517 ((pix & 0x0000FF00) << 4) | 518 ((pix & 0x00FF0000) << 6); 519 pix = val32 | ((val32 >> 8) & 0x00300C03); 520 *dbuf32++ = cpu_to_le32(pix); 521 } 522 } 523 524 /** 525 * drm_fb_xrgb8888_to_xrgb2101010 - Convert XRGB8888 to XRGB2101010 clip buffer 526 * @dst: Array of XRGB2101010 destination buffers 527 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines 528 * within @dst; can be NULL if scanlines are stored next to each other. 529 * @src: Array of XRGB8888 source buffers 530 * @fb: DRM framebuffer 531 * @clip: Clip rectangle area to copy 532 * 533 * This function copies parts of a framebuffer to display memory and converts the 534 * color format during the process. Destination and framebuffer formats must match. The 535 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at 536 * least as many entries as there are planes in @fb's format. Each entry stores the 537 * value for the format's respective color plane at the same index. 538 * 539 * This function does not apply clipping on @dst (i.e. the destination is at the 540 * top-left corner). 541 * 542 * Drivers can use this function for XRGB2101010 devices that don't support XRGB8888 543 * natively. 544 */ 545 void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch, 546 const struct iosys_map *src, const struct drm_framebuffer *fb, 547 const struct drm_rect *clip) 548 { 549 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 550 4, 551 }; 552 553 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, 554 drm_fb_xrgb8888_to_xrgb2101010_line); 555 } 556 EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010); 557 558 static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels) 559 { 560 u8 *dbuf8 = dbuf; 561 const __le32 *sbuf32 = sbuf; 562 unsigned int x; 563 564 for (x = 0; x < pixels; x++) { 565 u32 pix = le32_to_cpu(sbuf32[x]); 566 u8 r = (pix & 0x00ff0000) >> 16; 567 u8 g = (pix & 0x0000ff00) >> 8; 568 u8 b = pix & 0x000000ff; 569 570 /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */ 571 *dbuf8++ = (3 * r + 6 * g + b) / 10; 572 } 573 } 574 575 /** 576 * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale 577 * @dst: Array of 8-bit grayscale destination buffers 578 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines 579 * within @dst; can be NULL if scanlines are stored next to each other. 580 * @src: Array of XRGB8888 source buffers 581 * @fb: DRM framebuffer 582 * @clip: Clip rectangle area to copy 583 * 584 * This function copies parts of a framebuffer to display memory and converts the 585 * color format during the process. Destination and framebuffer formats must match. The 586 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at 587 * least as many entries as there are planes in @fb's format. Each entry stores the 588 * value for the format's respective color plane at the same index. 589 * 590 * This function does not apply clipping on @dst (i.e. the destination is at the 591 * top-left corner). 592 * 593 * DRM doesn't have native monochrome or grayscale support. Drivers can use this 594 * function for grayscale devices that don't support XRGB8888 natively.Such 595 * drivers can announce the commonly supported XR24 format to userspace and use 596 * this function to convert to the native format. Monochrome drivers will use the 597 * most significant bit, where 1 means foreground color and 0 background color. 598 * ITU BT.601 is being used for the RGB -> luma (brightness) conversion. 599 */ 600 void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch, 601 const struct iosys_map *src, const struct drm_framebuffer *fb, 602 const struct drm_rect *clip) 603 { 604 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 605 1, 606 }; 607 608 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, 609 drm_fb_xrgb8888_to_gray8_line); 610 } 611 EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); 612 613 /** 614 * drm_fb_blit - Copy parts of a framebuffer to display memory 615 * @dst: Array of display-memory addresses to copy to 616 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines 617 * within @dst; can be NULL if scanlines are stored next to each other. 618 * @dst_format: FOURCC code of the display's color format 619 * @src: The framebuffer memory to copy from 620 * @fb: The framebuffer to copy from 621 * @clip: Clip rectangle area to copy 622 * 623 * This function copies parts of a framebuffer to display memory. If the 624 * formats of the display and the framebuffer mismatch, the blit function 625 * will attempt to convert between them during the process. The parameters @dst, 626 * @dst_pitch and @src refer to arrays. Each array must have at least as many 627 * entries as there are planes in @dst_format's format. Each entry stores the 628 * value for the format's respective color plane at the same index. 629 * 630 * This function does not apply clipping on @dst (i.e. the destination is at the 631 * top-left corner). 632 * 633 * Returns: 634 * 0 on success, or 635 * -EINVAL if the color-format conversion failed, or 636 * a negative error code otherwise. 637 */ 638 int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t dst_format, 639 const struct iosys_map *src, const struct drm_framebuffer *fb, 640 const struct drm_rect *clip) 641 { 642 uint32_t fb_format = fb->format->format; 643 644 /* treat alpha channel like filler bits */ 645 if (fb_format == DRM_FORMAT_ARGB8888) 646 fb_format = DRM_FORMAT_XRGB8888; 647 if (dst_format == DRM_FORMAT_ARGB8888) 648 dst_format = DRM_FORMAT_XRGB8888; 649 if (fb_format == DRM_FORMAT_ARGB2101010) 650 fb_format = DRM_FORMAT_XRGB2101010; 651 if (dst_format == DRM_FORMAT_ARGB2101010) 652 dst_format = DRM_FORMAT_XRGB2101010; 653 654 if (dst_format == fb_format) { 655 drm_fb_memcpy(dst, dst_pitch, src, fb, clip); 656 return 0; 657 658 } else if (dst_format == DRM_FORMAT_RGB565) { 659 if (fb_format == DRM_FORMAT_XRGB8888) { 660 drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, false); 661 return 0; 662 } 663 } else if (dst_format == DRM_FORMAT_RGB888) { 664 if (fb_format == DRM_FORMAT_XRGB8888) { 665 drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip); 666 return 0; 667 } 668 } else if (dst_format == DRM_FORMAT_XRGB8888) { 669 if (fb_format == DRM_FORMAT_RGB888) { 670 drm_fb_rgb888_to_xrgb8888(dst, dst_pitch, src, fb, clip); 671 return 0; 672 } else if (fb_format == DRM_FORMAT_RGB565) { 673 drm_fb_rgb565_to_xrgb8888(dst, dst_pitch, src, fb, clip); 674 return 0; 675 } 676 } else if (dst_format == DRM_FORMAT_XRGB2101010) { 677 if (fb_format == DRM_FORMAT_XRGB8888) { 678 drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip); 679 return 0; 680 } 681 } 682 683 drm_warn_once(fb->dev, "No conversion helper from %p4cc to %p4cc found.\n", 684 &fb_format, &dst_format); 685 686 return -EINVAL; 687 } 688 EXPORT_SYMBOL(drm_fb_blit); 689 690 static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int pixels) 691 { 692 u8 *dbuf8 = dbuf; 693 const u8 *sbuf8 = sbuf; 694 695 while (pixels) { 696 unsigned int i, bits = min(pixels, 8U); 697 u8 byte = 0; 698 699 for (i = 0; i < bits; i++, pixels--) { 700 if (*sbuf8++ >= 128) 701 byte |= BIT(i); 702 } 703 *dbuf8++ = byte; 704 } 705 } 706 707 /** 708 * drm_fb_xrgb8888_to_mono - Convert XRGB8888 to monochrome 709 * @dst: Array of monochrome destination buffers (0=black, 1=white) 710 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines 711 * within @dst; can be NULL if scanlines are stored next to each other. 712 * @src: Array of XRGB8888 source buffers 713 * @fb: DRM framebuffer 714 * @clip: Clip rectangle area to copy 715 * 716 * This function copies parts of a framebuffer to display memory and converts the 717 * color format during the process. Destination and framebuffer formats must match. The 718 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at 719 * least as many entries as there are planes in @fb's format. Each entry stores the 720 * value for the format's respective color plane at the same index. 721 * 722 * This function does not apply clipping on @dst (i.e. the destination is at the 723 * top-left corner). The first pixel (upper left corner of the clip rectangle) will 724 * be converted and copied to the first bit (LSB) in the first byte of the monochrome 725 * destination buffer. If the caller requires that the first pixel in a byte must 726 * be located at an x-coordinate that is a multiple of 8, then the caller must take 727 * care itself of supplying a suitable clip rectangle. 728 * 729 * DRM doesn't have native monochrome support. Drivers can use this function for 730 * monochrome devices that don't support XRGB8888 natively. Such drivers can 731 * announce the commonly supported XR24 format to userspace and use this function 732 * to convert to the native format. 733 * 734 * This function uses drm_fb_xrgb8888_to_gray8() to convert to grayscale and 735 * then the result is converted from grayscale to monochrome. 736 */ 737 void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitch, 738 const struct iosys_map *src, const struct drm_framebuffer *fb, 739 const struct drm_rect *clip) 740 { 741 static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { 742 0, 0, 0, 0 743 }; 744 unsigned int linepixels = drm_rect_width(clip); 745 unsigned int lines = drm_rect_height(clip); 746 unsigned int cpp = fb->format->cpp[0]; 747 unsigned int len_src32 = linepixels * cpp; 748 struct drm_device *dev = fb->dev; 749 void *vaddr = src[0].vaddr; 750 unsigned int dst_pitch_0; 751 unsigned int y; 752 u8 *mono = dst[0].vaddr, *gray8; 753 u32 *src32; 754 755 if (drm_WARN_ON(dev, fb->format->format != DRM_FORMAT_XRGB8888)) 756 return; 757 758 if (!dst_pitch) 759 dst_pitch = default_dst_pitch; 760 dst_pitch_0 = dst_pitch[0]; 761 762 /* 763 * The mono destination buffer contains 1 bit per pixel 764 */ 765 if (!dst_pitch_0) 766 dst_pitch_0 = DIV_ROUND_UP(linepixels, 8); 767 768 /* 769 * The dma memory is write-combined so reads are uncached. 770 * Speed up by fetching one line at a time. 771 * 772 * Also, format conversion from XR24 to monochrome are done 773 * line-by-line but are converted to 8-bit grayscale as an 774 * intermediate step. 775 * 776 * Allocate a buffer to be used for both copying from the cma 777 * memory and to store the intermediate grayscale line pixels. 778 */ 779 src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL); 780 if (!src32) 781 return; 782 783 gray8 = (u8 *)src32 + len_src32; 784 785 vaddr += clip_offset(clip, fb->pitches[0], cpp); 786 for (y = 0; y < lines; y++) { 787 src32 = memcpy(src32, vaddr, len_src32); 788 drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels); 789 drm_fb_gray8_to_mono_line(mono, gray8, linepixels); 790 vaddr += fb->pitches[0]; 791 mono += dst_pitch_0; 792 } 793 794 kfree(src32); 795 } 796 EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono); 797 798 static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc) 799 { 800 const uint32_t *fourccs_end = fourccs + nfourccs; 801 802 while (fourccs < fourccs_end) { 803 if (*fourccs == fourcc) 804 return true; 805 ++fourccs; 806 } 807 return false; 808 } 809 810 static const uint32_t conv_from_xrgb8888[] = { 811 DRM_FORMAT_XRGB8888, 812 DRM_FORMAT_ARGB8888, 813 DRM_FORMAT_XRGB2101010, 814 DRM_FORMAT_ARGB2101010, 815 DRM_FORMAT_RGB565, 816 DRM_FORMAT_RGB888, 817 }; 818 819 static const uint32_t conv_from_rgb565_888[] = { 820 DRM_FORMAT_XRGB8888, 821 DRM_FORMAT_ARGB8888, 822 }; 823 824 static bool is_conversion_supported(uint32_t from, uint32_t to) 825 { 826 switch (from) { 827 case DRM_FORMAT_XRGB8888: 828 case DRM_FORMAT_ARGB8888: 829 return is_listed_fourcc(conv_from_xrgb8888, ARRAY_SIZE(conv_from_xrgb8888), to); 830 case DRM_FORMAT_RGB565: 831 case DRM_FORMAT_RGB888: 832 return is_listed_fourcc(conv_from_rgb565_888, ARRAY_SIZE(conv_from_rgb565_888), to); 833 case DRM_FORMAT_XRGB2101010: 834 return to == DRM_FORMAT_ARGB2101010; 835 case DRM_FORMAT_ARGB2101010: 836 return to == DRM_FORMAT_XRGB2101010; 837 default: 838 return false; 839 } 840 } 841 842 /** 843 * drm_fb_build_fourcc_list - Filters a list of supported color formats against 844 * the device's native formats 845 * @dev: DRM device 846 * @native_fourccs: 4CC codes of natively supported color formats 847 * @native_nfourccs: The number of entries in @native_fourccs 848 * @driver_fourccs: 4CC codes of all driver-supported color formats 849 * @driver_nfourccs: The number of entries in @driver_fourccs 850 * @fourccs_out: Returns 4CC codes of supported color formats 851 * @nfourccs_out: The number of available entries in @fourccs_out 852 * 853 * This function create a list of supported color format from natively 854 * supported formats and the emulated formats. 855 * At a minimum, most userspace programs expect at least support for 856 * XRGB8888 on the primary plane. Devices that have to emulate the 857 * format, and possibly others, can use drm_fb_build_fourcc_list() to 858 * create a list of supported color formats. The returned list can 859 * be handed over to drm_universal_plane_init() et al. Native formats 860 * will go before emulated formats. Other heuristics might be applied 861 * to optimize the order. Formats near the beginning of the list are 862 * usually preferred over formats near the end of the list. Formats 863 * without conversion helpers will be skipped. New drivers should only 864 * pass in XRGB8888 and avoid exposing additional emulated formats. 865 * 866 * Returns: 867 * The number of color-formats 4CC codes returned in @fourccs_out. 868 */ 869 size_t drm_fb_build_fourcc_list(struct drm_device *dev, 870 const u32 *native_fourccs, size_t native_nfourccs, 871 const u32 *driver_fourccs, size_t driver_nfourccs, 872 u32 *fourccs_out, size_t nfourccs_out) 873 { 874 u32 *fourccs = fourccs_out; 875 const u32 *fourccs_end = fourccs_out + nfourccs_out; 876 uint32_t native_format = 0; 877 size_t i; 878 879 /* 880 * The device's native formats go first. 881 */ 882 883 for (i = 0; i < native_nfourccs; ++i) { 884 u32 fourcc = native_fourccs[i]; 885 886 if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) { 887 continue; /* skip duplicate entries */ 888 } else if (fourccs == fourccs_end) { 889 drm_warn(dev, "Ignoring native format %p4cc\n", &fourcc); 890 continue; /* end of available output buffer */ 891 } 892 893 drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc); 894 895 /* 896 * There should only be one native format with the current API. 897 * This API needs to be refactored to correctly support arbitrary 898 * sets of native formats, since it needs to report which native 899 * format to use for each emulated format. 900 */ 901 if (!native_format) 902 native_format = fourcc; 903 *fourccs = fourcc; 904 ++fourccs; 905 } 906 907 /* 908 * The extra formats, emulated by the driver, go second. 909 */ 910 911 for (i = 0; (i < driver_nfourccs) && (fourccs < fourccs_end); ++i) { 912 u32 fourcc = driver_fourccs[i]; 913 914 if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) { 915 continue; /* skip duplicate and native entries */ 916 } else if (fourccs == fourccs_end) { 917 drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc); 918 continue; /* end of available output buffer */ 919 } else if (!is_conversion_supported(fourcc, native_format)) { 920 drm_dbg_kms(dev, "Unsupported emulated format %p4cc\n", &fourcc); 921 continue; /* format is not supported for conversion */ 922 } 923 924 drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc); 925 926 *fourccs = fourcc; 927 ++fourccs; 928 } 929 930 return fourccs - fourccs_out; 931 } 932 EXPORT_SYMBOL(drm_fb_build_fourcc_list); 933