linux/drivers/gpu/drm/drm_format_helper.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   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_format_helper.h>
  16#include <drm/drm_framebuffer.h>
  17#include <drm/drm_fourcc.h>
  18#include <drm/drm_rect.h>
  19
  20static unsigned int clip_offset(struct drm_rect *clip,
  21                                unsigned int pitch, unsigned int cpp)
  22{
  23        return clip->y1 * pitch + clip->x1 * cpp;
  24}
  25
  26/**
  27 * drm_fb_memcpy - Copy clip buffer
  28 * @dst: Destination buffer
  29 * @vaddr: Source buffer
  30 * @fb: DRM framebuffer
  31 * @clip: Clip rectangle area to copy
  32 *
  33 * This function does not apply clipping on dst, i.e. the destination
  34 * is a small buffer containing the clip rect only.
  35 */
  36void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
  37                   struct drm_rect *clip)
  38{
  39        unsigned int cpp = fb->format->cpp[0];
  40        size_t len = (clip->x2 - clip->x1) * cpp;
  41        unsigned int y, lines = clip->y2 - clip->y1;
  42
  43        vaddr += clip_offset(clip, fb->pitches[0], cpp);
  44        for (y = 0; y < lines; y++) {
  45                memcpy(dst, vaddr, len);
  46                vaddr += fb->pitches[0];
  47                dst += len;
  48        }
  49}
  50EXPORT_SYMBOL(drm_fb_memcpy);
  51
  52/**
  53 * drm_fb_memcpy_dstclip - Copy clip buffer
  54 * @dst: Destination buffer (iomem)
  55 * @vaddr: Source buffer
  56 * @fb: DRM framebuffer
  57 * @clip: Clip rectangle area to copy
  58 *
  59 * This function applies clipping on dst, i.e. the destination is a
  60 * full (iomem) framebuffer but only the clip rect content is copied over.
  61 */
  62void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
  63                           struct drm_framebuffer *fb,
  64                           struct drm_rect *clip)
  65{
  66        unsigned int cpp = fb->format->cpp[0];
  67        unsigned int offset = clip_offset(clip, fb->pitches[0], cpp);
  68        size_t len = (clip->x2 - clip->x1) * cpp;
  69        unsigned int y, lines = clip->y2 - clip->y1;
  70
  71        vaddr += offset;
  72        dst += offset;
  73        for (y = 0; y < lines; y++) {
  74                memcpy_toio(dst, vaddr, len);
  75                vaddr += fb->pitches[0];
  76                dst += fb->pitches[0];
  77        }
  78}
  79EXPORT_SYMBOL(drm_fb_memcpy_dstclip);
  80
  81/**
  82 * drm_fb_swab16 - Swap bytes into clip buffer
  83 * @dst: RGB565 destination buffer
  84 * @vaddr: RGB565 source buffer
  85 * @fb: DRM framebuffer
  86 * @clip: Clip rectangle area to copy
  87 */
  88void drm_fb_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb,
  89                   struct drm_rect *clip)
  90{
  91        size_t len = (clip->x2 - clip->x1) * sizeof(u16);
  92        unsigned int x, y;
  93        u16 *src, *buf;
  94
  95        /*
  96         * The cma memory is write-combined so reads are uncached.
  97         * Speed up by fetching one line at a time.
  98         */
  99        buf = kmalloc(len, GFP_KERNEL);
 100        if (!buf)
 101                return;
 102
 103        for (y = clip->y1; y < clip->y2; y++) {
 104                src = vaddr + (y * fb->pitches[0]);
 105                src += clip->x1;
 106                memcpy(buf, src, len);
 107                src = buf;
 108                for (x = clip->x1; x < clip->x2; x++)
 109                        *dst++ = swab16(*src++);
 110        }
 111
 112        kfree(buf);
 113}
 114EXPORT_SYMBOL(drm_fb_swab16);
 115
 116static void drm_fb_xrgb8888_to_rgb565_line(u16 *dbuf, u32 *sbuf,
 117                                           unsigned int pixels,
 118                                           bool swab)
 119{
 120        unsigned int x;
 121        u16 val16;
 122
 123        for (x = 0; x < pixels; x++) {
 124                val16 = ((sbuf[x] & 0x00F80000) >> 8) |
 125                        ((sbuf[x] & 0x0000FC00) >> 5) |
 126                        ((sbuf[x] & 0x000000F8) >> 3);
 127                if (swab)
 128                        dbuf[x] = swab16(val16);
 129                else
 130                        dbuf[x] = val16;
 131        }
 132}
 133
 134/**
 135 * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
 136 * @dst: RGB565 destination buffer
 137 * @vaddr: XRGB8888 source buffer
 138 * @fb: DRM framebuffer
 139 * @clip: Clip rectangle area to copy
 140 * @swab: Swap bytes
 141 *
 142 * Drivers can use this function for RGB565 devices that don't natively
 143 * support XRGB8888.
 144 *
 145 * This function does not apply clipping on dst, i.e. the destination
 146 * is a small buffer containing the clip rect only.
 147 */
 148void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr,
 149                               struct drm_framebuffer *fb,
 150                               struct drm_rect *clip, bool swab)
 151{
 152        size_t linepixels = clip->x2 - clip->x1;
 153        size_t src_len = linepixels * sizeof(u32);
 154        size_t dst_len = linepixels * sizeof(u16);
 155        unsigned y, lines = clip->y2 - clip->y1;
 156        void *sbuf;
 157
 158        /*
 159         * The cma memory is write-combined so reads are uncached.
 160         * Speed up by fetching one line at a time.
 161         */
 162        sbuf = kmalloc(src_len, GFP_KERNEL);
 163        if (!sbuf)
 164                return;
 165
 166        vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
 167        for (y = 0; y < lines; y++) {
 168                memcpy(sbuf, vaddr, src_len);
 169                drm_fb_xrgb8888_to_rgb565_line(dst, sbuf, linepixels, swab);
 170                vaddr += fb->pitches[0];
 171                dst += dst_len;
 172        }
 173
 174        kfree(sbuf);
 175}
 176EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
 177
 178/**
 179 * drm_fb_xrgb8888_to_rgb565_dstclip - Convert XRGB8888 to RGB565 clip buffer
 180 * @dst: RGB565 destination buffer (iomem)
 181 * @dst_pitch: destination buffer pitch
 182 * @vaddr: XRGB8888 source buffer
 183 * @fb: DRM framebuffer
 184 * @clip: Clip rectangle area to copy
 185 * @swab: Swap bytes
 186 *
 187 * Drivers can use this function for RGB565 devices that don't natively
 188 * support XRGB8888.
 189 *
 190 * This function applies clipping on dst, i.e. the destination is a
 191 * full (iomem) framebuffer but only the clip rect content is copied over.
 192 */
 193void drm_fb_xrgb8888_to_rgb565_dstclip(void __iomem *dst, unsigned int dst_pitch,
 194                                       void *vaddr, struct drm_framebuffer *fb,
 195                                       struct drm_rect *clip, bool swab)
 196{
 197        size_t linepixels = clip->x2 - clip->x1;
 198        size_t dst_len = linepixels * sizeof(u16);
 199        unsigned y, lines = clip->y2 - clip->y1;
 200        void *dbuf;
 201
 202        dbuf = kmalloc(dst_len, GFP_KERNEL);
 203        if (!dbuf)
 204                return;
 205
 206        vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
 207        dst += clip_offset(clip, dst_pitch, sizeof(u16));
 208        for (y = 0; y < lines; y++) {
 209                drm_fb_xrgb8888_to_rgb565_line(dbuf, vaddr, linepixels, swab);
 210                memcpy_toio(dst, dbuf, dst_len);
 211                vaddr += fb->pitches[0];
 212                dst += dst_len;
 213        }
 214
 215        kfree(dbuf);
 216}
 217EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_dstclip);
 218
 219static void drm_fb_xrgb8888_to_rgb888_line(u8 *dbuf, u32 *sbuf,
 220                                           unsigned int pixels)
 221{
 222        unsigned int x;
 223
 224        for (x = 0; x < pixels; x++) {
 225                *dbuf++ = (sbuf[x] & 0x000000FF) >>  0;
 226                *dbuf++ = (sbuf[x] & 0x0000FF00) >>  8;
 227                *dbuf++ = (sbuf[x] & 0x00FF0000) >> 16;
 228        }
 229}
 230
 231/**
 232 * drm_fb_xrgb8888_to_rgb888_dstclip - Convert XRGB8888 to RGB888 clip buffer
 233 * @dst: RGB565 destination buffer (iomem)
 234 * @dst_pitch: destination buffer pitch
 235 * @vaddr: XRGB8888 source buffer
 236 * @fb: DRM framebuffer
 237 * @clip: Clip rectangle area to copy
 238 *
 239 * Drivers can use this function for RGB888 devices that don't natively
 240 * support XRGB8888.
 241 *
 242 * This function applies clipping on dst, i.e. the destination is a
 243 * full (iomem) framebuffer but only the clip rect content is copied over.
 244 */
 245void drm_fb_xrgb8888_to_rgb888_dstclip(void __iomem *dst, unsigned int dst_pitch,
 246                                       void *vaddr, struct drm_framebuffer *fb,
 247                                       struct drm_rect *clip)
 248{
 249        size_t linepixels = clip->x2 - clip->x1;
 250        size_t dst_len = linepixels * 3;
 251        unsigned y, lines = clip->y2 - clip->y1;
 252        void *dbuf;
 253
 254        dbuf = kmalloc(dst_len, GFP_KERNEL);
 255        if (!dbuf)
 256                return;
 257
 258        vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
 259        dst += clip_offset(clip, dst_pitch, sizeof(u16));
 260        for (y = 0; y < lines; y++) {
 261                drm_fb_xrgb8888_to_rgb888_line(dbuf, vaddr, linepixels);
 262                memcpy_toio(dst, dbuf, dst_len);
 263                vaddr += fb->pitches[0];
 264                dst += dst_len;
 265        }
 266
 267        kfree(dbuf);
 268}
 269EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_dstclip);
 270
 271/**
 272 * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
 273 * @dst: 8-bit grayscale destination buffer
 274 * @vaddr: XRGB8888 source buffer
 275 * @fb: DRM framebuffer
 276 * @clip: Clip rectangle area to copy
 277 *
 278 * Drm doesn't have native monochrome or grayscale support.
 279 * Such drivers can announce the commonly supported XR24 format to userspace
 280 * and use this function to convert to the native format.
 281 *
 282 * Monochrome drivers will use the most significant bit,
 283 * where 1 means foreground color and 0 background color.
 284 *
 285 * ITU BT.601 is used for the RGB -> luma (brightness) conversion.
 286 */
 287void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
 288                               struct drm_rect *clip)
 289{
 290        unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
 291        unsigned int x, y;
 292        void *buf;
 293        u32 *src;
 294
 295        if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
 296                return;
 297        /*
 298         * The cma memory is write-combined so reads are uncached.
 299         * Speed up by fetching one line at a time.
 300         */
 301        buf = kmalloc(len, GFP_KERNEL);
 302        if (!buf)
 303                return;
 304
 305        for (y = clip->y1; y < clip->y2; y++) {
 306                src = vaddr + (y * fb->pitches[0]);
 307                src += clip->x1;
 308                memcpy(buf, src, len);
 309                src = buf;
 310                for (x = clip->x1; x < clip->x2; x++) {
 311                        u8 r = (*src & 0x00ff0000) >> 16;
 312                        u8 g = (*src & 0x0000ff00) >> 8;
 313                        u8 b =  *src & 0x000000ff;
 314
 315                        /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
 316                        *dst++ = (3 * r + 6 * g + b) / 10;
 317                        src++;
 318                }
 319        }
 320
 321        kfree(buf);
 322}
 323EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
 324
 325