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/module.h> 12 #include <linux/slab.h> 13 #include <linux/io.h> 14 15 #include <drm/drm_device.h> 16 #include <drm/drm_format_helper.h> 17 #include <drm/drm_framebuffer.h> 18 #include <drm/drm_fourcc.h> 19 #include <drm/drm_print.h> 20 #include <drm/drm_rect.h> 21 22 static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp) 23 { 24 return clip->y1 * pitch + clip->x1 * cpp; 25 } 26 27 /** 28 * drm_fb_clip_offset - Returns the clipping rectangles byte-offset in a framebuffer 29 * @pitch: Framebuffer line pitch in byte 30 * @format: Framebuffer format 31 * @clip: Clip rectangle 32 * 33 * Returns: 34 * The byte offset of the clip rectangle's top-left corner within the framebuffer. 35 */ 36 unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format, 37 const struct drm_rect *clip) 38 { 39 return clip_offset(clip, pitch, format->cpp[0]); 40 } 41 EXPORT_SYMBOL(drm_fb_clip_offset); 42 43 /* TODO: Make this functon work with multi-plane formats. */ 44 static int drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize, 45 const void *vaddr, const struct drm_framebuffer *fb, 46 const struct drm_rect *clip, bool vaddr_cached_hint, 47 void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) 48 { 49 unsigned long linepixels = drm_rect_width(clip); 50 unsigned long lines = drm_rect_height(clip); 51 size_t sbuf_len = linepixels * fb->format->cpp[0]; 52 void *stmp = NULL; 53 unsigned long i; 54 const void *sbuf; 55 56 /* 57 * Some source buffers, such as CMA memory, use write-combine 58 * caching, so reads are uncached. Speed up access by fetching 59 * one line at a time. 60 */ 61 if (!vaddr_cached_hint) { 62 stmp = kmalloc(sbuf_len, GFP_KERNEL); 63 if (!stmp) 64 return -ENOMEM; 65 } 66 67 if (!dst_pitch) 68 dst_pitch = drm_rect_width(clip) * dst_pixsize; 69 vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]); 70 71 for (i = 0; i < lines; ++i) { 72 if (stmp) 73 sbuf = memcpy(stmp, vaddr, sbuf_len); 74 else 75 sbuf = vaddr; 76 xfrm_line(dst, sbuf, linepixels); 77 vaddr += fb->pitches[0]; 78 dst += dst_pitch; 79 } 80 81 kfree(stmp); 82 83 return 0; 84 } 85 86 /* TODO: Make this functon work with multi-plane formats. */ 87 static int drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize, 88 const void *vaddr, const struct drm_framebuffer *fb, 89 const struct drm_rect *clip, bool vaddr_cached_hint, 90 void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) 91 { 92 unsigned long linepixels = drm_rect_width(clip); 93 unsigned long lines = drm_rect_height(clip); 94 size_t dbuf_len = linepixels * dst_pixsize; 95 size_t stmp_off = round_up(dbuf_len, ARCH_KMALLOC_MINALIGN); /* for sbuf alignment */ 96 size_t sbuf_len = linepixels * fb->format->cpp[0]; 97 void *stmp = NULL; 98 unsigned long i; 99 const void *sbuf; 100 void *dbuf; 101 102 if (vaddr_cached_hint) { 103 dbuf = kmalloc(dbuf_len, GFP_KERNEL); 104 } else { 105 dbuf = kmalloc(stmp_off + sbuf_len, GFP_KERNEL); 106 stmp = dbuf + stmp_off; 107 } 108 if (!dbuf) 109 return -ENOMEM; 110 111 if (!dst_pitch) 112 dst_pitch = linepixels * dst_pixsize; 113 vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]); 114 115 for (i = 0; i < lines; ++i) { 116 if (stmp) 117 sbuf = memcpy(stmp, vaddr, sbuf_len); 118 else 119 sbuf = vaddr; 120 xfrm_line(dbuf, sbuf, linepixels); 121 memcpy_toio(dst, dbuf, dbuf_len); 122 vaddr += fb->pitches[0]; 123 dst += dst_pitch; 124 } 125 126 kfree(dbuf); 127 128 return 0; 129 } 130 131 /** 132 * drm_fb_memcpy - Copy clip buffer 133 * @dst: Destination buffer 134 * @dst_pitch: Number of bytes between two consecutive scanlines within dst 135 * @vaddr: Source buffer 136 * @fb: DRM framebuffer 137 * @clip: Clip rectangle area to copy 138 * 139 * This function does not apply clipping on dst, i.e. the destination 140 * is at the top-left corner. 141 */ 142 void drm_fb_memcpy(void *dst, unsigned int dst_pitch, const void *vaddr, 143 const struct drm_framebuffer *fb, const struct drm_rect *clip) 144 { 145 unsigned int cpp = fb->format->cpp[0]; 146 size_t len = (clip->x2 - clip->x1) * cpp; 147 unsigned int y, lines = clip->y2 - clip->y1; 148 149 if (!dst_pitch) 150 dst_pitch = len; 151 152 vaddr += clip_offset(clip, fb->pitches[0], cpp); 153 for (y = 0; y < lines; y++) { 154 memcpy(dst, vaddr, len); 155 vaddr += fb->pitches[0]; 156 dst += dst_pitch; 157 } 158 } 159 EXPORT_SYMBOL(drm_fb_memcpy); 160 161 /** 162 * drm_fb_memcpy_toio - Copy clip buffer 163 * @dst: Destination buffer (iomem) 164 * @dst_pitch: Number of bytes between two consecutive scanlines within dst 165 * @vaddr: Source buffer 166 * @fb: DRM framebuffer 167 * @clip: Clip rectangle area to copy 168 * 169 * This function does not apply clipping on dst, i.e. the destination 170 * is at the top-left corner. 171 */ 172 void drm_fb_memcpy_toio(void __iomem *dst, unsigned int dst_pitch, const void *vaddr, 173 const struct drm_framebuffer *fb, const struct drm_rect *clip) 174 { 175 unsigned int cpp = fb->format->cpp[0]; 176 size_t len = (clip->x2 - clip->x1) * cpp; 177 unsigned int y, lines = clip->y2 - clip->y1; 178 179 if (!dst_pitch) 180 dst_pitch = len; 181 182 vaddr += clip_offset(clip, fb->pitches[0], cpp); 183 for (y = 0; y < lines; y++) { 184 memcpy_toio(dst, vaddr, len); 185 vaddr += fb->pitches[0]; 186 dst += dst_pitch; 187 } 188 } 189 EXPORT_SYMBOL(drm_fb_memcpy_toio); 190 191 static void drm_fb_swab16_line(void *dbuf, const void *sbuf, unsigned int pixels) 192 { 193 u16 *dbuf16 = dbuf; 194 const u16 *sbuf16 = sbuf; 195 const u16 *send16 = sbuf16 + pixels; 196 197 while (sbuf16 < send16) 198 *dbuf16++ = swab16(*sbuf16++); 199 } 200 201 static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels) 202 { 203 u32 *dbuf32 = dbuf; 204 const u32 *sbuf32 = sbuf; 205 const u32 *send32 = sbuf32 + pixels; 206 207 while (sbuf32 < send32) 208 *dbuf32++ = swab32(*sbuf32++); 209 } 210 211 /** 212 * drm_fb_swab - Swap bytes into clip buffer 213 * @dst: Destination buffer 214 * @dst_pitch: Number of bytes between two consecutive scanlines within dst 215 * @src: Source buffer 216 * @fb: DRM framebuffer 217 * @clip: Clip rectangle area to copy 218 * @cached: Source buffer is mapped cached (eg. not write-combined) 219 * 220 * If @cached is false a temporary buffer is used to cache one pixel line at a 221 * time to speed up slow uncached reads. 222 * 223 * This function does not apply clipping on dst, i.e. the destination 224 * is at the top-left corner. 225 */ 226 void drm_fb_swab(void *dst, unsigned int dst_pitch, const void *src, 227 const struct drm_framebuffer *fb, const struct drm_rect *clip, 228 bool cached) 229 { 230 u8 cpp = fb->format->cpp[0]; 231 232 switch (cpp) { 233 case 4: 234 drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab32_line); 235 break; 236 case 2: 237 drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab16_line); 238 break; 239 default: 240 drm_warn_once(fb->dev, "Format %p4cc has unsupported pixel size.\n", 241 &fb->format->format); 242 break; 243 } 244 } 245 EXPORT_SYMBOL(drm_fb_swab); 246 247 static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels) 248 { 249 u8 *dbuf8 = dbuf; 250 const __le32 *sbuf32 = sbuf; 251 unsigned int x; 252 u32 pix; 253 254 for (x = 0; x < pixels; x++) { 255 pix = le32_to_cpu(sbuf32[x]); 256 dbuf8[x] = ((pix & 0x00e00000) >> 16) | 257 ((pix & 0x0000e000) >> 11) | 258 ((pix & 0x000000c0) >> 6); 259 } 260 } 261 262 /** 263 * drm_fb_xrgb8888_to_rgb332 - Convert XRGB8888 to RGB332 clip buffer 264 * @dst: RGB332 destination buffer 265 * @dst_pitch: Number of bytes between two consecutive scanlines within dst 266 * @src: XRGB8888 source buffer 267 * @fb: DRM framebuffer 268 * @clip: Clip rectangle area to copy 269 * 270 * Drivers can use this function for RGB332 devices that don't natively support XRGB8888. 271 */ 272 void drm_fb_xrgb8888_to_rgb332(void *dst, unsigned int dst_pitch, const void *src, 273 const struct drm_framebuffer *fb, const struct drm_rect *clip) 274 { 275 drm_fb_xfrm(dst, dst_pitch, 1, src, fb, clip, false, drm_fb_xrgb8888_to_rgb332_line); 276 } 277 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332); 278 279 static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels) 280 { 281 u16 *dbuf16 = dbuf; 282 const __le32 *sbuf32 = sbuf; 283 unsigned int x; 284 u16 val16; 285 u32 pix; 286 287 for (x = 0; x < pixels; x++) { 288 pix = le32_to_cpu(sbuf32[x]); 289 val16 = ((pix & 0x00F80000) >> 8) | 290 ((pix & 0x0000FC00) >> 5) | 291 ((pix & 0x000000F8) >> 3); 292 dbuf16[x] = val16; 293 } 294 } 295 296 static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf, 297 unsigned int pixels) 298 { 299 u16 *dbuf16 = dbuf; 300 const __le32 *sbuf32 = sbuf; 301 unsigned int x; 302 u16 val16; 303 u32 pix; 304 305 for (x = 0; x < pixels; x++) { 306 pix = le32_to_cpu(sbuf32[x]); 307 val16 = ((pix & 0x00F80000) >> 8) | 308 ((pix & 0x0000FC00) >> 5) | 309 ((pix & 0x000000F8) >> 3); 310 dbuf16[x] = swab16(val16); 311 } 312 } 313 314 /** 315 * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer 316 * @dst: RGB565 destination buffer 317 * @dst_pitch: Number of bytes between two consecutive scanlines within dst 318 * @vaddr: XRGB8888 source buffer 319 * @fb: DRM framebuffer 320 * @clip: Clip rectangle area to copy 321 * @swab: Swap bytes 322 * 323 * Drivers can use this function for RGB565 devices that don't natively 324 * support XRGB8888. 325 */ 326 void drm_fb_xrgb8888_to_rgb565(void *dst, unsigned int dst_pitch, const void *vaddr, 327 const struct drm_framebuffer *fb, const struct drm_rect *clip, 328 bool swab) 329 { 330 if (swab) 331 drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false, 332 drm_fb_xrgb8888_to_rgb565_swab_line); 333 else 334 drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false, 335 drm_fb_xrgb8888_to_rgb565_line); 336 } 337 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); 338 339 /** 340 * drm_fb_xrgb8888_to_rgb565_toio - Convert XRGB8888 to RGB565 clip buffer 341 * @dst: RGB565 destination buffer (iomem) 342 * @dst_pitch: Number of bytes between two consecutive scanlines within dst 343 * @vaddr: XRGB8888 source buffer 344 * @fb: DRM framebuffer 345 * @clip: Clip rectangle area to copy 346 * @swab: Swap bytes 347 * 348 * Drivers can use this function for RGB565 devices that don't natively 349 * support XRGB8888. 350 */ 351 void drm_fb_xrgb8888_to_rgb565_toio(void __iomem *dst, unsigned int dst_pitch, 352 const void *vaddr, const struct drm_framebuffer *fb, 353 const struct drm_rect *clip, bool swab) 354 { 355 if (swab) 356 drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false, 357 drm_fb_xrgb8888_to_rgb565_swab_line); 358 else 359 drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false, 360 drm_fb_xrgb8888_to_rgb565_line); 361 } 362 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_toio); 363 364 static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels) 365 { 366 u8 *dbuf8 = dbuf; 367 const __le32 *sbuf32 = sbuf; 368 unsigned int x; 369 u32 pix; 370 371 for (x = 0; x < pixels; x++) { 372 pix = le32_to_cpu(sbuf32[x]); 373 *dbuf8++ = (pix & 0x000000FF) >> 0; 374 *dbuf8++ = (pix & 0x0000FF00) >> 8; 375 *dbuf8++ = (pix & 0x00FF0000) >> 16; 376 } 377 } 378 379 /** 380 * drm_fb_xrgb8888_to_rgb888 - Convert XRGB8888 to RGB888 clip buffer 381 * @dst: RGB888 destination buffer 382 * @dst_pitch: Number of bytes between two consecutive scanlines within dst 383 * @src: XRGB8888 source buffer 384 * @fb: DRM framebuffer 385 * @clip: Clip rectangle area to copy 386 * 387 * Drivers can use this function for RGB888 devices that don't natively 388 * support XRGB8888. 389 */ 390 void drm_fb_xrgb8888_to_rgb888(void *dst, unsigned int dst_pitch, const void *src, 391 const struct drm_framebuffer *fb, const struct drm_rect *clip) 392 { 393 drm_fb_xfrm(dst, dst_pitch, 3, src, fb, clip, false, drm_fb_xrgb8888_to_rgb888_line); 394 } 395 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888); 396 397 /** 398 * drm_fb_xrgb8888_to_rgb888_toio - Convert XRGB8888 to RGB888 clip buffer 399 * @dst: RGB565 destination buffer (iomem) 400 * @dst_pitch: Number of bytes between two consecutive scanlines within dst 401 * @vaddr: XRGB8888 source buffer 402 * @fb: DRM framebuffer 403 * @clip: Clip rectangle area to copy 404 * 405 * Drivers can use this function for RGB888 devices that don't natively 406 * support XRGB8888. 407 */ 408 void drm_fb_xrgb8888_to_rgb888_toio(void __iomem *dst, unsigned int dst_pitch, 409 const void *vaddr, const struct drm_framebuffer *fb, 410 const struct drm_rect *clip) 411 { 412 drm_fb_xfrm_toio(dst, dst_pitch, 3, vaddr, fb, clip, false, 413 drm_fb_xrgb8888_to_rgb888_line); 414 } 415 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_toio); 416 417 static void drm_fb_rgb565_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels) 418 { 419 __le32 *dbuf32 = dbuf; 420 const __le16 *sbuf16 = sbuf; 421 unsigned int x; 422 423 for (x = 0; x < pixels; x++) { 424 u16 val16 = le16_to_cpu(sbuf16[x]); 425 u32 val32 = ((val16 & 0xf800) << 8) | 426 ((val16 & 0x07e0) << 5) | 427 ((val16 & 0x001f) << 3); 428 val32 = 0xff000000 | val32 | 429 ((val32 >> 3) & 0x00070007) | 430 ((val32 >> 2) & 0x00000300); 431 dbuf32[x] = cpu_to_le32(val32); 432 } 433 } 434 435 static void drm_fb_rgb565_to_xrgb8888_toio(void __iomem *dst, unsigned int dst_pitch, 436 const void *vaddr, const struct drm_framebuffer *fb, 437 const struct drm_rect *clip) 438 { 439 drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false, 440 drm_fb_rgb565_to_xrgb8888_line); 441 } 442 443 static void drm_fb_rgb888_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels) 444 { 445 __le32 *dbuf32 = dbuf; 446 const u8 *sbuf8 = sbuf; 447 unsigned int x; 448 449 for (x = 0; x < pixels; x++) { 450 u8 r = *sbuf8++; 451 u8 g = *sbuf8++; 452 u8 b = *sbuf8++; 453 u32 pix = 0xff000000 | (r << 16) | (g << 8) | b; 454 dbuf32[x] = cpu_to_le32(pix); 455 } 456 } 457 458 static void drm_fb_rgb888_to_xrgb8888_toio(void __iomem *dst, unsigned int dst_pitch, 459 const void *vaddr, const struct drm_framebuffer *fb, 460 const struct drm_rect *clip) 461 { 462 drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false, 463 drm_fb_rgb888_to_xrgb8888_line); 464 } 465 466 static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels) 467 { 468 __le32 *dbuf32 = dbuf; 469 const __le32 *sbuf32 = sbuf; 470 unsigned int x; 471 u32 val32; 472 u32 pix; 473 474 for (x = 0; x < pixels; x++) { 475 pix = le32_to_cpu(sbuf32[x]); 476 val32 = ((pix & 0x000000FF) << 2) | 477 ((pix & 0x0000FF00) << 4) | 478 ((pix & 0x00FF0000) << 6); 479 pix = val32 | ((val32 >> 8) & 0x00300C03); 480 *dbuf32++ = cpu_to_le32(pix); 481 } 482 } 483 484 /** 485 * drm_fb_xrgb8888_to_xrgb2101010_toio - Convert XRGB8888 to XRGB2101010 clip 486 * buffer 487 * @dst: XRGB2101010 destination buffer (iomem) 488 * @dst_pitch: Number of bytes between two consecutive scanlines within dst 489 * @vaddr: XRGB8888 source buffer 490 * @fb: DRM framebuffer 491 * @clip: Clip rectangle area to copy 492 * 493 * Drivers can use this function for XRGB2101010 devices that don't natively 494 * support XRGB8888. 495 */ 496 void drm_fb_xrgb8888_to_xrgb2101010_toio(void __iomem *dst, 497 unsigned int dst_pitch, const void *vaddr, 498 const struct drm_framebuffer *fb, 499 const struct drm_rect *clip) 500 { 501 drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false, 502 drm_fb_xrgb8888_to_xrgb2101010_line); 503 } 504 EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010_toio); 505 506 static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels) 507 { 508 u8 *dbuf8 = dbuf; 509 const __le32 *sbuf32 = sbuf; 510 unsigned int x; 511 512 for (x = 0; x < pixels; x++) { 513 u32 pix = le32_to_cpu(sbuf32[x]); 514 u8 r = (pix & 0x00ff0000) >> 16; 515 u8 g = (pix & 0x0000ff00) >> 8; 516 u8 b = pix & 0x000000ff; 517 518 /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */ 519 *dbuf8++ = (3 * r + 6 * g + b) / 10; 520 } 521 } 522 523 /** 524 * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale 525 * @dst: 8-bit grayscale destination buffer 526 * @dst_pitch: Number of bytes between two consecutive scanlines within dst 527 * @vaddr: XRGB8888 source buffer 528 * @fb: DRM framebuffer 529 * @clip: Clip rectangle area to copy 530 * 531 * Drm doesn't have native monochrome or grayscale support. 532 * Such drivers can announce the commonly supported XR24 format to userspace 533 * and use this function to convert to the native format. 534 * 535 * Monochrome drivers will use the most significant bit, 536 * where 1 means foreground color and 0 background color. 537 * 538 * ITU BT.601 is used for the RGB -> luma (brightness) conversion. 539 */ 540 void drm_fb_xrgb8888_to_gray8(void *dst, unsigned int dst_pitch, const void *vaddr, 541 const struct drm_framebuffer *fb, const struct drm_rect *clip) 542 { 543 drm_fb_xfrm(dst, dst_pitch, 1, vaddr, fb, clip, false, drm_fb_xrgb8888_to_gray8_line); 544 } 545 EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); 546 547 /** 548 * drm_fb_blit_toio - Copy parts of a framebuffer to display memory 549 * @dst: The display memory to copy to 550 * @dst_pitch: Number of bytes between two consecutive scanlines within dst 551 * @dst_format: FOURCC code of the display's color format 552 * @vmap: The framebuffer memory to copy from 553 * @fb: The framebuffer to copy from 554 * @clip: Clip rectangle area to copy 555 * 556 * This function copies parts of a framebuffer to display memory. If the 557 * formats of the display and the framebuffer mismatch, the blit function 558 * will attempt to convert between them. 559 * 560 * Returns: 561 * 0 on success, or 562 * -EINVAL if the color-format conversion failed, or 563 * a negative error code otherwise. 564 */ 565 int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_format, 566 const void *vmap, const struct drm_framebuffer *fb, 567 const struct drm_rect *clip) 568 { 569 uint32_t fb_format = fb->format->format; 570 571 /* treat alpha channel like filler bits */ 572 if (fb_format == DRM_FORMAT_ARGB8888) 573 fb_format = DRM_FORMAT_XRGB8888; 574 if (dst_format == DRM_FORMAT_ARGB8888) 575 dst_format = DRM_FORMAT_XRGB8888; 576 if (fb_format == DRM_FORMAT_ARGB2101010) 577 fb_format = DRM_FORMAT_XRGB2101010; 578 if (dst_format == DRM_FORMAT_ARGB2101010) 579 dst_format = DRM_FORMAT_XRGB2101010; 580 581 if (dst_format == fb_format) { 582 drm_fb_memcpy_toio(dst, dst_pitch, vmap, fb, clip); 583 return 0; 584 585 } else if (dst_format == DRM_FORMAT_RGB565) { 586 if (fb_format == DRM_FORMAT_XRGB8888) { 587 drm_fb_xrgb8888_to_rgb565_toio(dst, dst_pitch, vmap, fb, clip, false); 588 return 0; 589 } 590 } else if (dst_format == DRM_FORMAT_RGB888) { 591 if (fb_format == DRM_FORMAT_XRGB8888) { 592 drm_fb_xrgb8888_to_rgb888_toio(dst, dst_pitch, vmap, fb, clip); 593 return 0; 594 } 595 } else if (dst_format == DRM_FORMAT_XRGB8888) { 596 if (fb_format == DRM_FORMAT_RGB888) { 597 drm_fb_rgb888_to_xrgb8888_toio(dst, dst_pitch, vmap, fb, clip); 598 return 0; 599 } else if (fb_format == DRM_FORMAT_RGB565) { 600 drm_fb_rgb565_to_xrgb8888_toio(dst, dst_pitch, vmap, fb, clip); 601 return 0; 602 } 603 } else if (dst_format == DRM_FORMAT_XRGB2101010) { 604 if (fb_format == DRM_FORMAT_XRGB8888) { 605 drm_fb_xrgb8888_to_xrgb2101010_toio(dst, dst_pitch, vmap, fb, clip); 606 return 0; 607 } 608 } 609 610 drm_warn_once(fb->dev, "No conversion helper from %p4cc to %p4cc found.\n", 611 &fb_format, &dst_format); 612 613 return -EINVAL; 614 } 615 EXPORT_SYMBOL(drm_fb_blit_toio); 616 617 618 static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int pixels) 619 { 620 u8 *dbuf8 = dbuf; 621 const u8 *sbuf8 = sbuf; 622 623 while (pixels) { 624 unsigned int i, bits = min(pixels, 8U); 625 u8 byte = 0; 626 627 for (i = 0; i < bits; i++, pixels--) { 628 if (*sbuf8++ >= 128) 629 byte |= BIT(i); 630 } 631 *dbuf8++ = byte; 632 } 633 } 634 635 /** 636 * drm_fb_xrgb8888_to_mono - Convert XRGB8888 to monochrome 637 * @dst: monochrome destination buffer (0=black, 1=white) 638 * @dst_pitch: Number of bytes between two consecutive scanlines within dst 639 * @vaddr: XRGB8888 source buffer 640 * @fb: DRM framebuffer 641 * @clip: Clip rectangle area to copy 642 * 643 * DRM doesn't have native monochrome support. 644 * Such drivers can announce the commonly supported XR24 format to userspace 645 * and use this function to convert to the native format. 646 * 647 * This function uses drm_fb_xrgb8888_to_gray8() to convert to grayscale and 648 * then the result is converted from grayscale to monochrome. 649 * 650 * The first pixel (upper left corner of the clip rectangle) will be converted 651 * and copied to the first bit (LSB) in the first byte of the monochrome 652 * destination buffer. 653 * If the caller requires that the first pixel in a byte must be located at an 654 * x-coordinate that is a multiple of 8, then the caller must take care itself 655 * of supplying a suitable clip rectangle. 656 */ 657 void drm_fb_xrgb8888_to_mono(void *dst, unsigned int dst_pitch, const void *vaddr, 658 const struct drm_framebuffer *fb, const struct drm_rect *clip) 659 { 660 unsigned int linepixels = drm_rect_width(clip); 661 unsigned int lines = drm_rect_height(clip); 662 unsigned int cpp = fb->format->cpp[0]; 663 unsigned int len_src32 = linepixels * cpp; 664 struct drm_device *dev = fb->dev; 665 unsigned int y; 666 u8 *mono = dst, *gray8; 667 u32 *src32; 668 669 if (drm_WARN_ON(dev, fb->format->format != DRM_FORMAT_XRGB8888)) 670 return; 671 672 /* 673 * The mono destination buffer contains 1 bit per pixel 674 */ 675 if (!dst_pitch) 676 dst_pitch = DIV_ROUND_UP(linepixels, 8); 677 678 /* 679 * The cma memory is write-combined so reads are uncached. 680 * Speed up by fetching one line at a time. 681 * 682 * Also, format conversion from XR24 to monochrome are done 683 * line-by-line but are converted to 8-bit grayscale as an 684 * intermediate step. 685 * 686 * Allocate a buffer to be used for both copying from the cma 687 * memory and to store the intermediate grayscale line pixels. 688 */ 689 src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL); 690 if (!src32) 691 return; 692 693 gray8 = (u8 *)src32 + len_src32; 694 695 vaddr += clip_offset(clip, fb->pitches[0], cpp); 696 for (y = 0; y < lines; y++) { 697 src32 = memcpy(src32, vaddr, len_src32); 698 drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels); 699 drm_fb_gray8_to_mono_line(mono, gray8, linepixels); 700 vaddr += fb->pitches[0]; 701 mono += dst_pitch; 702 } 703 704 kfree(src32); 705 } 706 EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono); 707