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