Provide format-independent conversion helpers for system and I/O memory. Implement most existing helpers on top of it. The source and destination formats of each conversion is handled by a per-line helper that is given to the generic implementation. Signed-off-by: Thomas Zimmermann <tzimmermann@xxxxxxx> --- drivers/gpu/drm/drm_format_helper.c | 370 ++++++++++------------------ 1 file changed, 124 insertions(+), 246 deletions(-) diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index 21d0d282c6a1..6f8030ebb56d 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -40,6 +40,95 @@ unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info } EXPORT_SYMBOL(drm_fb_clip_offset); +/* TODO: Make this functon work with multi-plane formats. */ +static int drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize, + const void *vaddr, const struct drm_framebuffer *fb, + const struct drm_rect *clip, bool vaddr_cached_hint, + void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) +{ + unsigned long linepixels = drm_rect_width(clip); + unsigned long lines = drm_rect_height(clip); + size_t sbuf_len = linepixels * fb->format->cpp[0]; + void *stmp = NULL; + unsigned long i; + const void *sbuf; + + /* + * Some source buffers, such as CMA memory, use write-combine + * caching, so reads are uncached. Speed up access by fetching + * one line at a time. + */ + if (!vaddr_cached_hint) { + stmp = kmalloc(sbuf_len, GFP_KERNEL); + if (!stmp) + return -ENOMEM; + } + + if (!dst_pitch) + dst_pitch = drm_rect_width(clip) * dst_pixsize; + vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]); + + for (i = 0; i < lines; ++i) { + if (stmp) + sbuf = memcpy(stmp, vaddr, sbuf_len); + else + sbuf = vaddr; + xfrm_line(dst, sbuf, linepixels); + vaddr += fb->pitches[0]; + dst += dst_pitch; + } + + kfree(stmp); + + return 0; +} + +/* TODO: Make this functon work with multi-plane formats. */ +static int drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize, + const void *vaddr, const struct drm_framebuffer *fb, + const struct drm_rect *clip, bool vaddr_cached_hint, + void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) +{ + unsigned long linepixels = drm_rect_width(clip); + unsigned long lines = drm_rect_height(clip); + size_t dbuf_len = linepixels * dst_pixsize; + size_t stmp_off = round_up(dbuf_len, ARCH_KMALLOC_MINALIGN); /* for sbuf alignment */ + size_t sbuf_len = linepixels * fb->format->cpp[0]; + void *stmp = NULL; + unsigned long i; + const void *sbuf; + void *dbuf; + + if (vaddr_cached_hint) { + dbuf = kmalloc(dbuf_len, GFP_KERNEL); + } else { + dbuf = kmalloc(stmp_off + sbuf_len, GFP_KERNEL); + stmp = dbuf + stmp_off; + } + if (!dbuf) + return -ENOMEM; + + if (!dst_pitch) + dst_pitch = linepixels * dst_pixsize; + vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]); + + for (i = 0; i < lines; ++i) { + if (stmp) + sbuf = memcpy(stmp, vaddr, sbuf_len); + else + sbuf = vaddr; + xfrm_line(dbuf, sbuf, linepixels); + memcpy_toio(dst, dbuf, dbuf_len); + vaddr += fb->pitches[0]; + dst += dst_pitch; + } + + kfree(dbuf); + + return 0; +} + + /** * drm_fb_memcpy - Copy clip buffer * @dst: Destination buffer @@ -140,45 +229,23 @@ void drm_fb_swab(void *dst, unsigned int dst_pitch, const void *src, bool cached) { u8 cpp = fb->format->cpp[0]; - unsigned long linepixels = drm_rect_width(clip); - size_t len = linepixels * cpp; - const void *sbuf; - void *dbuf; - unsigned int y; - void *buf = NULL; - - if (WARN_ON_ONCE(cpp != 2 && cpp != 4)) - return; - - if (!dst_pitch) - dst_pitch = len; - src += clip_offset(clip, fb->pitches[0], cpp); - - if (!cached) - buf = kmalloc(len, GFP_KERNEL); - for (y = clip->y1; y < clip->y2; y++) { - if (buf) - sbuf = memcpy(buf, src, len); - else - sbuf = src; - dbuf = dst + clip->x1 * cpp; - - if (cpp == 4) - drm_fb_swab32_line(dbuf, sbuf, linepixels); - else - drm_fb_swab16_line(dbuf, sbuf, linepixels); - - src += fb->pitches[0]; - dst += dst_pitch; + switch (cpp) { + case 4: + drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab32_line); + break; + case 2: + drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab16_line); + break; + default: + drm_warn_once(fb->dev, "Format %p4cc has unsupported pixel size.\n", + &fb->format->format); + break; } - - kfree(buf); } EXPORT_SYMBOL(drm_fb_swab); -static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels, - bool swab) +static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels) { u8 *dbuf8 = dbuf; const __le32 *sbuf32 = sbuf; @@ -206,28 +273,7 @@ static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigne void drm_fb_xrgb8888_to_rgb332(void *dst, unsigned int dst_pitch, const void *src, const struct drm_framebuffer *fb, const struct drm_rect *clip) { - size_t width = drm_rect_width(clip); - size_t src_len = width * sizeof(u32); - unsigned int y; - void *sbuf; - - if (!dst_pitch) - dst_pitch = width; - - /* Use a buffer to speed up access on buffers with uncached read mapping (i.e. WC) */ - sbuf = kmalloc(src_len, GFP_KERNEL); - if (!sbuf) - return; - - src += clip_offset(clip, fb->pitches[0], sizeof(u32)); - for (y = 0; y < drm_rect_height(clip); y++) { - memcpy(sbuf, src, src_len); - drm_fb_xrgb8888_to_rgb332_line(dst, sbuf, width, false); - src += fb->pitches[0]; - dst += dst_pitch; - } - - kfree(sbuf); + drm_fb_xfrm(dst, dst_pitch, 1, src, fb, clip, false, drm_fb_xrgb8888_to_rgb332_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332); @@ -278,35 +324,12 @@ void drm_fb_xrgb8888_to_rgb565(void *dst, unsigned int dst_pitch, const void *va const struct drm_framebuffer *fb, const struct drm_rect *clip, bool swab) { - size_t linepixels = clip->x2 - clip->x1; - size_t src_len = linepixels * sizeof(u32); - size_t dst_len = linepixels * sizeof(u16); - unsigned y, lines = clip->y2 - clip->y1; - void *sbuf; - - if (!dst_pitch) - dst_pitch = dst_len; - - /* - * The cma memory is write-combined so reads are uncached. - * Speed up by fetching one line at a time. - */ - sbuf = kmalloc(src_len, GFP_KERNEL); - if (!sbuf) - return; - - vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32)); - for (y = 0; y < lines; y++) { - memcpy(sbuf, vaddr, src_len); - if (swab) - drm_fb_xrgb8888_to_rgb565_swab_line(dst, sbuf, linepixels); - else - drm_fb_xrgb8888_to_rgb565_line(dst, sbuf, linepixels); - vaddr += fb->pitches[0]; - dst += dst_pitch; - } - - kfree(sbuf); + if (swab) + drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false, + drm_fb_xrgb8888_to_rgb565_swab_line); + else + drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false, + drm_fb_xrgb8888_to_rgb565_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); @@ -326,30 +349,12 @@ void drm_fb_xrgb8888_to_rgb565_toio(void __iomem *dst, unsigned int dst_pitch, const void *vaddr, const struct drm_framebuffer *fb, const struct drm_rect *clip, bool swab) { - size_t linepixels = clip->x2 - clip->x1; - size_t dst_len = linepixels * sizeof(u16); - unsigned y, lines = clip->y2 - clip->y1; - void *dbuf; - - if (!dst_pitch) - dst_pitch = dst_len; - - dbuf = kmalloc(dst_len, GFP_KERNEL); - if (!dbuf) - return; - - vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32)); - for (y = 0; y < lines; y++) { - if (swab) - drm_fb_xrgb8888_to_rgb565_swab_line(dbuf, vaddr, linepixels); - else - drm_fb_xrgb8888_to_rgb565_line(dbuf, vaddr, linepixels); - memcpy_toio(dst, dbuf, dst_len); - vaddr += fb->pitches[0]; - dst += dst_pitch; - } - - kfree(dbuf); + if (swab) + drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false, + drm_fb_xrgb8888_to_rgb565_swab_line); + else + drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false, + drm_fb_xrgb8888_to_rgb565_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_toio); @@ -380,28 +385,7 @@ static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigne void drm_fb_xrgb8888_to_rgb888(void *dst, unsigned int dst_pitch, const void *src, const struct drm_framebuffer *fb, const struct drm_rect *clip) { - size_t width = drm_rect_width(clip); - size_t src_len = width * sizeof(u32); - unsigned int y; - void *sbuf; - - if (!dst_pitch) - dst_pitch = width * 3; - - /* Use a buffer to speed up access on buffers with uncached read mapping (i.e. WC) */ - sbuf = kmalloc(src_len, GFP_KERNEL); - if (!sbuf) - return; - - src += clip_offset(clip, fb->pitches[0], sizeof(u32)); - for (y = 0; y < drm_rect_height(clip); y++) { - memcpy(sbuf, src, src_len); - drm_fb_xrgb8888_to_rgb888_line(dst, sbuf, width); - src += fb->pitches[0]; - dst += dst_pitch; - } - - kfree(sbuf); + drm_fb_xfrm(dst, dst_pitch, 3, src, fb, clip, false, drm_fb_xrgb8888_to_rgb888_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888); @@ -420,27 +404,8 @@ void drm_fb_xrgb8888_to_rgb888_toio(void __iomem *dst, unsigned int dst_pitch, const void *vaddr, const struct drm_framebuffer *fb, const struct drm_rect *clip) { - size_t linepixels = clip->x2 - clip->x1; - size_t dst_len = linepixels * 3; - unsigned y, lines = clip->y2 - clip->y1; - void *dbuf; - - if (!dst_pitch) - dst_pitch = dst_len; - - dbuf = kmalloc(dst_len, GFP_KERNEL); - if (!dbuf) - return; - - vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32)); - for (y = 0; y < lines; y++) { - drm_fb_xrgb8888_to_rgb888_line(dbuf, vaddr, linepixels); - memcpy_toio(dst, dbuf, dst_len); - vaddr += fb->pitches[0]; - dst += dst_pitch; - } - - kfree(dbuf); + drm_fb_xfrm_toio(dst, dst_pitch, 3, vaddr, fb, clip, false, + drm_fb_xrgb8888_to_rgb888_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_toio); @@ -464,27 +429,8 @@ static void drm_fb_rgb565_to_xrgb8888_toio(void __iomem *dst, unsigned int dst_p const void *vaddr, const struct drm_framebuffer *fb, const struct drm_rect *clip) { - size_t linepixels = drm_rect_width(clip); - size_t dst_len = linepixels * 4; - unsigned int y, lines = drm_rect_height(clip); - void *dbuf; - - if (!dst_pitch) - dst_pitch = dst_len; - - dbuf = kmalloc(dst_len, GFP_KERNEL); - if (!dbuf) - return; - - vaddr += clip_offset(clip, fb->pitches[0], 2); - for (y = 0; y < lines; y++) { - drm_fb_rgb565_to_xrgb8888_line(dbuf, vaddr, linepixels); - memcpy_toio(dst, dbuf, dst_len); - vaddr += fb->pitches[0]; - dst += dst_pitch; - } - - kfree(dbuf); + drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false, + drm_fb_rgb565_to_xrgb8888_line); } static void drm_fb_rgb888_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels) @@ -505,27 +451,8 @@ static void drm_fb_rgb888_to_xrgb8888_toio(void __iomem *dst, unsigned int dst_p const void *vaddr, const struct drm_framebuffer *fb, const struct drm_rect *clip) { - size_t linepixels = drm_rect_width(clip); - size_t dst_len = linepixels * 4; - unsigned int y, lines = drm_rect_height(clip); - void *dbuf; - - if (!dst_pitch) - dst_pitch = dst_len; - - dbuf = kmalloc(dst_len, GFP_KERNEL); - if (!dbuf) - return; - - vaddr += clip_offset(clip, fb->pitches[0], 3); - for (y = 0; y < lines; y++) { - drm_fb_rgb888_to_xrgb8888_line(dbuf, vaddr, linepixels); - memcpy_toio(dst, dbuf, dst_len); - vaddr += fb->pitches[0]; - dst += dst_pitch; - } - - kfree(dbuf); + drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false, + drm_fb_rgb888_to_xrgb8888_line); } static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels) @@ -560,27 +487,8 @@ void drm_fb_xrgb8888_to_xrgb2101010_toio(void __iomem *dst, const struct drm_framebuffer *fb, const struct drm_rect *clip) { - size_t linepixels = clip->x2 - clip->x1; - size_t dst_len = linepixels * sizeof(u32); - unsigned int y, lines = clip->y2 - clip->y1; - void *dbuf; - - if (!dst_pitch) - dst_pitch = dst_len; - - dbuf = kmalloc(dst_len, GFP_KERNEL); - if (!dbuf) - return; - - vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32)); - for (y = 0; y < lines; y++) { - drm_fb_xrgb8888_to_xrgb2101010_line(dbuf, vaddr, linepixels); - memcpy_toio(dst, dbuf, dst_len); - vaddr += fb->pitches[0]; - dst += dst_pitch; - } - - kfree(dbuf); + drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false, + drm_fb_xrgb8888_to_xrgb2101010_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010_toio); @@ -621,37 +529,7 @@ static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned void drm_fb_xrgb8888_to_gray8(void *dst, unsigned int dst_pitch, const void *vaddr, const struct drm_framebuffer *fb, const struct drm_rect *clip) { - unsigned int linepixels = clip->x2 - clip->x1; - unsigned int len = linepixels * sizeof(u32); - unsigned int y; - void *buf; - u8 *dst8; - u32 *src32; - - if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888)) - return; - - if (!dst_pitch) - dst_pitch = drm_rect_width(clip); - - /* - * The cma memory is write-combined so reads are uncached. - * Speed up by fetching one line at a time. - */ - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - return; - - vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32)); - for (y = clip->y1; y < clip->y2; y++) { - dst8 = dst; - src32 = memcpy(buf, vaddr, len); - drm_fb_xrgb8888_to_gray8_line(dst8, src32, linepixels); - vaddr += fb->pitches[0]; - dst += dst_pitch; - } - - kfree(buf); + drm_fb_xfrm(dst, dst_pitch, 1, vaddr, fb, clip, false, drm_fb_xrgb8888_to_gray8_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); -- 2.36.0