Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/panic: Add support for color format conversion

Add support for the following formats:
DRM_FORMAT_RGB565
DRM_FORMAT_RGBA5551
DRM_FORMAT_XRGB1555
DRM_FORMAT_ARGB1555
DRM_FORMAT_RGB888
DRM_FORMAT_XRGB8888
DRM_FORMAT_ARGB8888
DRM_FORMAT_XBGR8888
DRM_FORMAT_XRGB2101010
DRM_FORMAT_ARGB2101010

v10:
* move and simplify the functions from the drm format helper to drm_panic

v12:
* Use array for map and pitch in struct drm_scanout_buffer
to support multi-planar format later. (Thomas Zimmermann)

Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240409163432.352518-4-jfalempe@redhat.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>

+263 -10
+263 -10
drivers/gpu/drm/drm_panic.c
··· 81 81 PANIC_LINE(" \\___)=(___/"), 82 82 }; 83 83 84 - static void drm_panic_fill32(struct iosys_map *map, unsigned int pitch, 84 + /* 85 + * Color conversion 86 + */ 87 + 88 + static u16 convert_xrgb8888_to_rgb565(u32 pix) 89 + { 90 + return ((pix & 0x00F80000) >> 8) | 91 + ((pix & 0x0000FC00) >> 5) | 92 + ((pix & 0x000000F8) >> 3); 93 + } 94 + 95 + static u16 convert_xrgb8888_to_rgba5551(u32 pix) 96 + { 97 + return ((pix & 0x00f80000) >> 8) | 98 + ((pix & 0x0000f800) >> 5) | 99 + ((pix & 0x000000f8) >> 2) | 100 + BIT(0); /* set alpha bit */ 101 + } 102 + 103 + static u16 convert_xrgb8888_to_xrgb1555(u32 pix) 104 + { 105 + return ((pix & 0x00f80000) >> 9) | 106 + ((pix & 0x0000f800) >> 6) | 107 + ((pix & 0x000000f8) >> 3); 108 + } 109 + 110 + static u16 convert_xrgb8888_to_argb1555(u32 pix) 111 + { 112 + return BIT(15) | /* set alpha bit */ 113 + ((pix & 0x00f80000) >> 9) | 114 + ((pix & 0x0000f800) >> 6) | 115 + ((pix & 0x000000f8) >> 3); 116 + } 117 + 118 + static u32 convert_xrgb8888_to_argb8888(u32 pix) 119 + { 120 + return pix | GENMASK(31, 24); /* fill alpha bits */ 121 + } 122 + 123 + static u32 convert_xrgb8888_to_xbgr8888(u32 pix) 124 + { 125 + return ((pix & 0x00ff0000) >> 16) << 0 | 126 + ((pix & 0x0000ff00) >> 8) << 8 | 127 + ((pix & 0x000000ff) >> 0) << 16 | 128 + ((pix & 0xff000000) >> 24) << 24; 129 + } 130 + 131 + static u32 convert_xrgb8888_to_abgr8888(u32 pix) 132 + { 133 + return ((pix & 0x00ff0000) >> 16) << 0 | 134 + ((pix & 0x0000ff00) >> 8) << 8 | 135 + ((pix & 0x000000ff) >> 0) << 16 | 136 + GENMASK(31, 24); /* fill alpha bits */ 137 + } 138 + 139 + static u32 convert_xrgb8888_to_xrgb2101010(u32 pix) 140 + { 141 + pix = ((pix & 0x000000FF) << 2) | 142 + ((pix & 0x0000FF00) << 4) | 143 + ((pix & 0x00FF0000) << 6); 144 + return pix | ((pix >> 8) & 0x00300C03); 145 + } 146 + 147 + static u32 convert_xrgb8888_to_argb2101010(u32 pix) 148 + { 149 + pix = ((pix & 0x000000FF) << 2) | 150 + ((pix & 0x0000FF00) << 4) | 151 + ((pix & 0x00FF0000) << 6); 152 + return GENMASK(31, 30) /* set alpha bits */ | pix | ((pix >> 8) & 0x00300C03); 153 + } 154 + 155 + /* 156 + * convert_from_xrgb8888 - convert one pixel from xrgb8888 to the desired format 157 + * @color: input color, in xrgb8888 format 158 + * @format: output format 159 + * 160 + * Returns: 161 + * Color in the format specified, casted to u32. 162 + * Or 0 if the format is not supported. 163 + */ 164 + static u32 convert_from_xrgb8888(u32 color, u32 format) 165 + { 166 + switch (format) { 167 + case DRM_FORMAT_RGB565: 168 + return convert_xrgb8888_to_rgb565(color); 169 + case DRM_FORMAT_RGBA5551: 170 + return convert_xrgb8888_to_rgba5551(color); 171 + case DRM_FORMAT_XRGB1555: 172 + return convert_xrgb8888_to_xrgb1555(color); 173 + case DRM_FORMAT_ARGB1555: 174 + return convert_xrgb8888_to_argb1555(color); 175 + case DRM_FORMAT_RGB888: 176 + case DRM_FORMAT_XRGB8888: 177 + return color; 178 + case DRM_FORMAT_ARGB8888: 179 + return convert_xrgb8888_to_argb8888(color); 180 + case DRM_FORMAT_XBGR8888: 181 + return convert_xrgb8888_to_xbgr8888(color); 182 + case DRM_FORMAT_ABGR8888: 183 + return convert_xrgb8888_to_abgr8888(color); 184 + case DRM_FORMAT_XRGB2101010: 185 + return convert_xrgb8888_to_xrgb2101010(color); 186 + case DRM_FORMAT_ARGB2101010: 187 + return convert_xrgb8888_to_argb2101010(color); 188 + default: 189 + WARN_ONCE(1, "Can't convert to %p4cc\n", &format); 190 + return 0; 191 + } 192 + } 193 + 194 + /* 195 + * Blit & Fill 196 + */ 197 + static void drm_panic_blit16(struct iosys_map *dmap, unsigned int dpitch, 198 + const u8 *sbuf8, unsigned int spitch, 85 199 unsigned int height, unsigned int width, 86 - u32 color) 200 + u16 fg16, u16 bg16) 87 201 { 88 202 unsigned int y, x; 203 + u16 val16; 89 204 90 - for (y = 0; y < height; y++) 91 - for (x = 0; x < width; x++) 92 - iosys_map_wr(map, y * pitch + x * sizeof(u32), u32, color); 205 + for (y = 0; y < height; y++) { 206 + for (x = 0; x < width; x++) { 207 + val16 = (sbuf8[(y * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg16 : bg16; 208 + iosys_map_wr(dmap, y * dpitch + x * sizeof(u16), u16, val16); 209 + } 210 + } 211 + } 212 + 213 + static void drm_panic_blit24(struct iosys_map *dmap, unsigned int dpitch, 214 + const u8 *sbuf8, unsigned int spitch, 215 + unsigned int height, unsigned int width, 216 + u32 fg32, u32 bg32) 217 + { 218 + unsigned int y, x; 219 + u32 val32; 220 + 221 + for (y = 0; y < height; y++) { 222 + for (x = 0; x < width; x++) { 223 + u32 off = y * dpitch + x * 3; 224 + 225 + val32 = (sbuf8[(y * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32; 226 + 227 + /* write blue-green-red to output in little endianness */ 228 + iosys_map_wr(dmap, off, u8, (val32 & 0x000000FF) >> 0); 229 + iosys_map_wr(dmap, off + 1, u8, (val32 & 0x0000FF00) >> 8); 230 + iosys_map_wr(dmap, off + 2, u8, (val32 & 0x00FF0000) >> 16); 231 + } 232 + } 93 233 } 94 234 95 235 static void drm_panic_blit32(struct iosys_map *dmap, unsigned int dpitch, ··· 245 105 val32 = (sbuf8[(y * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32; 246 106 iosys_map_wr(dmap, y * dpitch + x * sizeof(u32), u32, val32); 247 107 } 108 + } 109 + } 110 + 111 + /* 112 + * drm_panic_blit - convert a monochrome image to a linear framebuffer 113 + * @dmap: destination iosys_map 114 + * @dpitch: destination pitch in bytes 115 + * @sbuf8: source buffer, in monochrome format, 8 pixels per byte. 116 + * @spitch: source pitch in bytes 117 + * @height: height of the image to copy, in pixels 118 + * @width: width of the image to copy, in pixels 119 + * @fg_color: foreground color, in destination format 120 + * @bg_color: background color, in destination format 121 + * @pixel_width: pixel width in bytes. 122 + * 123 + * This can be used to draw a font character, which is a monochrome image, to a 124 + * framebuffer in other supported format. 125 + */ 126 + static void drm_panic_blit(struct iosys_map *dmap, unsigned int dpitch, 127 + const u8 *sbuf8, unsigned int spitch, 128 + unsigned int height, unsigned int width, 129 + u32 fg_color, u32 bg_color, 130 + unsigned int pixel_width) 131 + { 132 + switch (pixel_width) { 133 + case 2: 134 + drm_panic_blit16(dmap, dpitch, sbuf8, spitch, 135 + height, width, fg_color, bg_color); 136 + break; 137 + case 3: 138 + drm_panic_blit24(dmap, dpitch, sbuf8, spitch, 139 + height, width, fg_color, bg_color); 140 + break; 141 + case 4: 142 + drm_panic_blit32(dmap, dpitch, sbuf8, spitch, 143 + height, width, fg_color, bg_color); 144 + break; 145 + default: 146 + WARN_ONCE(1, "Can't blit with pixel width %d\n", pixel_width); 147 + } 148 + } 149 + 150 + static void drm_panic_fill16(struct iosys_map *dmap, unsigned int dpitch, 151 + unsigned int height, unsigned int width, 152 + u16 color) 153 + { 154 + unsigned int y, x; 155 + 156 + for (y = 0; y < height; y++) 157 + for (x = 0; x < width; x++) 158 + iosys_map_wr(dmap, y * dpitch + x * sizeof(u16), u16, color); 159 + } 160 + 161 + static void drm_panic_fill24(struct iosys_map *dmap, unsigned int dpitch, 162 + unsigned int height, unsigned int width, 163 + u32 color) 164 + { 165 + unsigned int y, x; 166 + 167 + for (y = 0; y < height; y++) { 168 + for (x = 0; x < width; x++) { 169 + unsigned int off = y * dpitch + x * 3; 170 + 171 + /* write blue-green-red to output in little endianness */ 172 + iosys_map_wr(dmap, off, u8, (color & 0x000000FF) >> 0); 173 + iosys_map_wr(dmap, off + 1, u8, (color & 0x0000FF00) >> 8); 174 + iosys_map_wr(dmap, off + 2, u8, (color & 0x00FF0000) >> 16); 175 + } 176 + } 177 + } 178 + 179 + static void drm_panic_fill32(struct iosys_map *dmap, unsigned int dpitch, 180 + unsigned int height, unsigned int width, 181 + u32 color) 182 + { 183 + unsigned int y, x; 184 + 185 + for (y = 0; y < height; y++) 186 + for (x = 0; x < width; x++) 187 + iosys_map_wr(dmap, y * dpitch + x * sizeof(u32), u32, color); 188 + } 189 + 190 + /* 191 + * drm_panic_fill - Fill a rectangle with a color 192 + * @dmap: destination iosys_map, pointing to the top left corner of the rectangle 193 + * @dpitch: destination pitch in bytes 194 + * @height: height of the rectangle, in pixels 195 + * @width: width of the rectangle, in pixels 196 + * @color: color to fill the rectangle. 197 + * @pixel_width: pixel width in bytes 198 + * 199 + * Fill a rectangle with a color, in a linear framebuffer. 200 + */ 201 + static void drm_panic_fill(struct iosys_map *dmap, unsigned int dpitch, 202 + unsigned int height, unsigned int width, 203 + u32 color, unsigned int pixel_width) 204 + { 205 + switch (pixel_width) { 206 + case 2: 207 + drm_panic_fill16(dmap, dpitch, height, width, color); 208 + break; 209 + case 3: 210 + drm_panic_fill24(dmap, dpitch, height, width, color); 211 + break; 212 + case 4: 213 + drm_panic_fill32(dmap, dpitch, height, width, color); 214 + break; 215 + default: 216 + WARN_ONCE(1, "Can't fill with pixel width %d\n", pixel_width); 248 217 } 249 218 } 250 219 ··· 403 154 (clip->x1 + left) * px_width); 404 155 for (j = 0; j < line_len; j++) { 405 156 src = get_char_bitmap(font, msg[i].txt[j], font_pitch); 406 - drm_panic_blit32(&dst, sb->pitch[0], src, font_pitch, 407 - font->height, font->width, 408 - fg_color, bg_color); 157 + drm_panic_blit(&dst, sb->pitch[0], src, font_pitch, 158 + font->height, font->width, 159 + fg_color, bg_color, px_width); 409 160 iosys_map_incr(&dst, font->width * px_width); 410 161 } 411 162 } ··· 426 177 if (!font) 427 178 return; 428 179 180 + fg_color = convert_from_xrgb8888(fg_color, sb->format->format); 181 + bg_color = convert_from_xrgb8888(bg_color, sb->format->format); 182 + 429 183 r_logo = DRM_RECT_INIT(0, 0, 430 184 get_max_line_len(logo, logo_lines) * font->width, 431 185 logo_lines * font->height); ··· 440 188 drm_rect_translate(&r_msg, (sb->width - r_msg.x2) / 2, (sb->height - r_msg.y2) / 2); 441 189 442 190 /* Fill with the background color, and draw text on top */ 443 - drm_panic_fill32(&sb->map[0], sb->pitch[0], sb->height, sb->width, bg_color); 191 + drm_panic_fill(&sb->map[0], sb->pitch[0], sb->height, sb->width, 192 + bg_color, sb->format->cpp[0]); 444 193 445 194 if ((r_msg.x1 >= drm_rect_width(&r_logo) || r_msg.y1 >= drm_rect_height(&r_logo)) && 446 195 drm_rect_width(&r_logo) < sb->width && drm_rect_height(&r_logo) < sb->height) { ··· 461 208 { 462 209 if (format->num_planes != 1) 463 210 return false; 464 - return format->format == DRM_FORMAT_XRGB8888; 211 + return convert_from_xrgb8888(0xffffff, format->format) != 0; 465 212 } 466 213 467 214 static void draw_panic_plane(struct drm_plane *plane)