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

drm/vesadrm: Support DRM_FORMAT_C8

Add support for DRM_FORMAT_C8 to vesadrm. The new pixel-format
description PIXEL_FORMAT_C8 describes the layout. Vesadrm's helpers
vesadrm_fill_palette_lut() and vesadrm_load_palette_lut() set the
hardware palette according to the CRTC's output format.

The driver emulates XRGB8888 by converting the source buffer to
RGB332 and using the resulting 256 colors as index into the hardware
palette. The hardware palette converts back to RGB during scanout.
This has no overhead compared to other format conversion, but allows
common userspace, such as Wayland compositors, to operate on the
display.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Link: https://lore.kernel.org/r/20250714151513.309475-10-tzimmermann@suse.de

+116 -1
+113 -1
drivers/gpu/drm/sysfb/vesadrm.c
··· 46 46 { PIXEL_FORMAT_RGB888, DRM_FORMAT_RGB888, }, 47 47 { PIXEL_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888, }, 48 48 { PIXEL_FORMAT_XBGR8888, DRM_FORMAT_XBGR8888, }, 49 + { PIXEL_FORMAT_C8, DRM_FORMAT_C8, }, 49 50 }; 50 51 51 52 return drm_sysfb_get_format_si(dev, formats, ARRAY_SIZE(formats), si); ··· 193 192 } 194 193 } 195 194 195 + static void vesadrm_fill_palette_lut(struct vesadrm_device *vesa, 196 + const struct drm_format_info *format) 197 + { 198 + struct drm_device *dev = &vesa->sysfb.dev; 199 + struct drm_crtc *crtc = &vesa->crtc; 200 + 201 + switch (format->format) { 202 + case DRM_FORMAT_C8: 203 + drm_crtc_fill_palette_8(crtc, vesadrm_set_color_lut); 204 + break; 205 + case DRM_FORMAT_RGB332: 206 + drm_crtc_fill_palette_332(crtc, vesadrm_set_color_lut); 207 + break; 208 + default: 209 + drm_warn_once(dev, "Unsupported format %p4cc for palette\n", 210 + &format->format); 211 + break; 212 + } 213 + } 214 + 215 + static void vesadrm_load_palette_lut(struct vesadrm_device *vesa, 216 + const struct drm_format_info *format, 217 + struct drm_color_lut *lut) 218 + { 219 + struct drm_device *dev = &vesa->sysfb.dev; 220 + struct drm_crtc *crtc = &vesa->crtc; 221 + 222 + switch (format->format) { 223 + case DRM_FORMAT_C8: 224 + drm_crtc_load_palette_8(crtc, lut, vesadrm_set_color_lut); 225 + break; 226 + default: 227 + drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n", 228 + &format->format); 229 + break; 230 + } 231 + } 232 + 196 233 /* 197 234 * Modesetting 198 235 */ ··· 239 200 DRM_SYSFB_PLANE_FORMAT_MODIFIERS, 240 201 }; 241 202 203 + static int vesadrm_primary_plane_helper_atomic_check(struct drm_plane *plane, 204 + struct drm_atomic_state *new_state) 205 + { 206 + struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev); 207 + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); 208 + struct drm_framebuffer *new_fb = new_plane_state->fb; 209 + struct drm_crtc_state *new_crtc_state; 210 + struct drm_sysfb_crtc_state *new_sysfb_crtc_state; 211 + int ret; 212 + 213 + ret = drm_sysfb_plane_helper_atomic_check(plane, new_state); 214 + if (ret) 215 + return ret; 216 + else if (!new_plane_state->visible) 217 + return 0; 218 + 219 + /* 220 + * Fix up format conversion for specific cases 221 + */ 222 + 223 + switch (sysfb->fb_format->format) { 224 + case DRM_FORMAT_C8: 225 + new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc); 226 + new_sysfb_crtc_state = to_drm_sysfb_crtc_state(new_crtc_state); 227 + 228 + switch (new_fb->format->format) { 229 + case DRM_FORMAT_XRGB8888: 230 + /* 231 + * Reduce XRGB8888 to RGB332. Each resulting pixel is an index 232 + * into the C8 hardware palette, which stores RGB332 colors. 233 + */ 234 + if (new_sysfb_crtc_state->format->format != DRM_FORMAT_RGB332) { 235 + new_sysfb_crtc_state->format = 236 + drm_format_info(DRM_FORMAT_RGB332); 237 + new_crtc_state->color_mgmt_changed = true; 238 + } 239 + break; 240 + case DRM_FORMAT_C8: 241 + /* 242 + * Restore original output. Emulation of XRGB8888 set RBG332 243 + * output format and hardware palette. This needs to be undone 244 + * when we switch back to DRM_FORMAT_C8. 245 + */ 246 + if (new_sysfb_crtc_state->format->format == DRM_FORMAT_RGB332) { 247 + new_sysfb_crtc_state->format = sysfb->fb_format; 248 + new_crtc_state->color_mgmt_changed = true; 249 + } 250 + break; 251 + } 252 + break; 253 + }; 254 + 255 + return 0; 256 + } 257 + 242 258 static const struct drm_plane_helper_funcs vesadrm_primary_plane_helper_funcs = { 243 - DRM_SYSFB_PLANE_HELPER_FUNCS, 259 + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, 260 + .atomic_check = vesadrm_primary_plane_helper_atomic_check, 261 + .atomic_update = drm_sysfb_plane_helper_atomic_update, 262 + .atomic_disable = drm_sysfb_plane_helper_atomic_disable, 263 + .get_scanout_buffer = drm_sysfb_plane_helper_get_scanout_buffer, 244 264 }; 245 265 246 266 static const struct drm_plane_funcs vesadrm_primary_plane_funcs = { ··· 322 224 */ 323 225 if (crtc_state->enable && crtc_state->color_mgmt_changed) { 324 226 switch (sysfb->fb_format->format) { 227 + /* 228 + * Index formats 229 + */ 230 + case DRM_FORMAT_C8: 231 + if (sysfb_crtc_state->format->format == DRM_FORMAT_RGB332) { 232 + vesadrm_fill_palette_lut(vesa, sysfb_crtc_state->format); 233 + } else if (crtc->state->gamma_lut) { 234 + vesadrm_load_palette_lut(vesa, 235 + sysfb_crtc_state->format, 236 + crtc_state->gamma_lut->data); 237 + } else { 238 + vesadrm_fill_palette_lut(vesa, sysfb_crtc_state->format); 239 + } 240 + break; 325 241 /* 326 242 * Component formats 327 243 */
+3
include/video/pixel_format.h
··· 20 20 }; 21 21 }; 22 22 23 + #define PIXEL_FORMAT_C8 \ 24 + { 8, true, { .index = {0, 8}, } } 25 + 23 26 #define PIXEL_FORMAT_XRGB1555 \ 24 27 { 16, false, { .alpha = {0, 0}, .red = {10, 5}, .green = {5, 5}, .blue = {0, 5} } } 25 28