// SPDX-License-Identifier: GPL-2.0-only #include <linux/aperture.h>#include <linux/ioport.h>#include <linux/limits.h>#include <linux/platform_device.h>#include <linux/sysfb.h>#include <linux/pm.h> #include <drm/clients/drm_client_setup.h>#include <drm/drm_atomic.h>#include <drm/drm_atomic_state_helper.h>#include <drm/drm_color_mgmt.h>#include <drm/drm_connector.h>#include <drm/drm_damage_helper.h>#include <drm/drm_device.h>#include <drm/drm_drv.h>#include <drm/drm_edid.h>#include <drm/drm_fbdev_shmem.h>#include <drm/drm_framebuffer.h>#include <drm/drm_gem_atomic_helper.h>#include <drm/drm_gem_framebuffer_helper.h>#include <drm/drm_gem_shmem_helper.h>#include <drm/drm_managed.h>#include <drm/drm_modeset_helper.h>#include <drm/drm_modeset_helper_vtables.h>#include <drm/drm_print.h>#include <drm/drm_probe_helper.h> #include <video/pixel_format.h>#include <video/vga.h> #include "drm_sysfb_helper.h" #define DRIVER_NAME "vesadrm"#define DRIVER_DESC "DRM driver for VESA platform devices"#define DRIVER_MAJOR 1#define DRIVER_MINOR 0 #define VESADRM_GAMMA_LUT_SIZE 256 static const struct drm_format_info *vesadrm_get_format_si(struct drm_device *dev, const struct screen_info *si){ static const struct drm_sysfb_format formats[] = { { PIXEL_FORMAT_XRGB1555, DRM_FORMAT_XRGB1555, }, { PIXEL_FORMAT_RGB565, DRM_FORMAT_RGB565, }, { PIXEL_FORMAT_RGB888, DRM_FORMAT_RGB888, }, { PIXEL_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888, }, { PIXEL_FORMAT_XBGR8888, DRM_FORMAT_XBGR8888, }, { PIXEL_FORMAT_C8, DRM_FORMAT_C8, }, }; struct pixel_format pixel; int ret; ret = screen_info_pixel_format(si, &pixel); if (ret) return NULL; return drm_sysfb_get_format(dev, formats, ARRAY_SIZE(formats), &pixel);} /* * VESA device */ struct vesadrm_device { struct drm_sysfb_device sysfb; #if defined(CONFIG_X86_32) /* VESA Protected Mode interface */ struct { const u8 *PrimaryPalette; } pmi;#endif void (*cmap_write)(struct vesadrm_device *vesa, unsigned int index, u16 red, u16 green, u16 blue); /* modesetting */ u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)]; struct drm_plane primary_plane; struct drm_crtc crtc; struct drm_encoder encoder; struct drm_connector connector;}; static struct vesadrm_device *to_vesadrm_device(struct drm_device *dev){ return container_of(to_drm_sysfb_device(dev), struct vesadrm_device, sysfb);} /* * Color LUT */ static void vesadrm_vga_cmap_write(struct vesadrm_device *vesa, unsigned int index, u16 red, u16 green, u16 blue){ u8 i8 = index; u8 r8 = red >> 8; u8 g8 = green >> 8; u8 b8 = blue >> 8; outb_p(i8, VGA_PEL_IW); outb_p(r8, VGA_PEL_D); outb_p(g8, VGA_PEL_D); outb_p(b8, VGA_PEL_D);} #if defined(CONFIG_X86_32)static void vesadrm_pmi_cmap_write(struct vesadrm_device *vesa, unsigned int index, u16 red, u16 green, u16 blue){ u32 i32 = index; struct { u8 b8; u8 g8; u8 r8; u8 x8; } PaletteEntry = { blue >> 8, green >> 8, red >> 8, 0x00, }; __asm__ __volatile__ ( "call *(%%esi)" : /* no return value */ : "a" (0x4f09), "b" (0), "c" (1), "d" (i32), "D" (&PaletteEntry), "S" (&vesa->pmi.PrimaryPalette));}#endif static void vesadrm_set_color_lut(struct drm_crtc *crtc, unsigned int index, u16 red, u16 green, u16 blue){ struct drm_device *dev = crtc->dev; struct vesadrm_device *vesa = to_vesadrm_device(dev); u8 i8 = index & 0xff; if (drm_WARN_ON_ONCE(dev, index != i8)) return; /* driver bug */ vesa->cmap_write(vesa, i8, red, green, blue);} static void vesadrm_fill_gamma_lut(struct vesadrm_device *vesa, const struct drm_format_info *format){ struct drm_device *dev = &vesa->sysfb.dev; struct drm_crtc *crtc = &vesa->crtc; switch (format->format) { case DRM_FORMAT_XRGB1555: drm_crtc_fill_gamma_555(crtc, vesadrm_set_color_lut); break; case DRM_FORMAT_RGB565: drm_crtc_fill_gamma_565(crtc, vesadrm_set_color_lut); break; case DRM_FORMAT_RGB888: case DRM_FORMAT_XRGB8888: case DRM_FORMAT_BGRX8888: drm_crtc_fill_gamma_888(crtc, vesadrm_set_color_lut); break; default: drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n", &format->format); break; }} static void vesadrm_load_gamma_lut(struct vesadrm_device *vesa, const struct drm_format_info *format, struct drm_color_lut *lut){ struct drm_device *dev = &vesa->sysfb.dev; struct drm_crtc *crtc = &vesa->crtc; switch (format->format) { case DRM_FORMAT_XRGB1555: drm_crtc_load_gamma_555_from_888(crtc, lut, vesadrm_set_color_lut); break; case DRM_FORMAT_RGB565: drm_crtc_load_gamma_565_from_888(crtc, lut, vesadrm_set_color_lut); break; case DRM_FORMAT_RGB888: case DRM_FORMAT_XRGB8888: case DRM_FORMAT_BGRX8888: drm_crtc_load_gamma_888(crtc, lut, vesadrm_set_color_lut); break; default: drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n", &format->format); break; }} static void vesadrm_fill_palette_lut(struct vesadrm_device *vesa, const struct drm_format_info *format){ struct drm_device *dev = &vesa->sysfb.dev; struct drm_crtc *crtc = &vesa->crtc; switch (format->format) { case DRM_FORMAT_C8: drm_crtc_fill_palette_8(crtc, vesadrm_set_color_lut); break; case DRM_FORMAT_RGB332: drm_crtc_fill_palette_332(crtc, vesadrm_set_color_lut); break; default: drm_warn_once(dev, "Unsupported format %p4cc for palette\n", &format->format); break; }} static void vesadrm_load_palette_lut(struct vesadrm_device *vesa, const struct drm_format_info *format, struct drm_color_lut *lut){ struct drm_device *dev = &vesa->sysfb.dev; struct drm_crtc *crtc = &vesa->crtc; switch (format->format) { case DRM_FORMAT_C8: drm_crtc_load_palette_8(crtc, lut, vesadrm_set_color_lut); break; default: drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n", &format->format); break; }} /* * Modesetting */ static const u64 vesadrm_primary_plane_format_modifiers[] = { DRM_SYSFB_PLANE_FORMAT_MODIFIERS,}; static int vesadrm_primary_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_commit *new_state){ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev); struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); struct drm_framebuffer *new_fb = new_plane_state->fb; struct drm_crtc_state *new_crtc_state; struct drm_sysfb_crtc_state *new_sysfb_crtc_state; int ret; ret = drm_sysfb_plane_helper_atomic_check(plane, new_state); if (ret) return ret; else if (!new_plane_state->visible) return 0; /* * Fix up format conversion for specific cases */ switch (sysfb->fb_format->format) { case DRM_FORMAT_C8: new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc); new_sysfb_crtc_state = to_drm_sysfb_crtc_state(new_crtc_state); switch (new_fb->format->format) { case DRM_FORMAT_XRGB8888: /* * Reduce XRGB8888 to RGB332. Each resulting pixel is an index * into the C8 hardware palette, which stores RGB332 colors. */ if (new_sysfb_crtc_state->format->format != DRM_FORMAT_RGB332) { new_sysfb_crtc_state->format = drm_format_info(DRM_FORMAT_RGB332); new_crtc_state->color_mgmt_changed = true; } break; case DRM_FORMAT_C8: /* * Restore original output. Emulation of XRGB8888 set RBG332 * output format and hardware palette. This needs to be undone * when we switch back to DRM_FORMAT_C8. */ if (new_sysfb_crtc_state->format->format == DRM_FORMAT_RGB332) { new_sysfb_crtc_state->format = sysfb->fb_format; new_crtc_state->color_mgmt_changed = true; } break; } break; } return 0;} static const struct drm_plane_helper_funcs vesadrm_primary_plane_helper_funcs = { .begin_fb_access = drm_sysfb_plane_helper_begin_fb_access, .end_fb_access = drm_gem_end_shadow_fb_access, .atomic_check = vesadrm_primary_plane_helper_atomic_check, .atomic_update = drm_sysfb_plane_helper_atomic_update, .atomic_disable = drm_sysfb_plane_helper_atomic_disable, .get_scanout_buffer = drm_sysfb_plane_helper_get_scanout_buffer,}; static const struct drm_plane_funcs vesadrm_primary_plane_funcs = { DRM_SYSFB_PLANE_FUNCS, .destroy = drm_plane_cleanup,}; static void vesadrm_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_commit *state){ struct drm_device *dev = crtc->dev; struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev); struct vesadrm_device *vesa = to_vesadrm_device(dev); struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); struct drm_sysfb_crtc_state *sysfb_crtc_state = to_drm_sysfb_crtc_state(crtc_state); /* * The gamma LUT has to be reloaded after changing the primary * plane's color format. */ if (crtc_state->enable && crtc_state->color_mgmt_changed) { switch (sysfb->fb_format->format) { /* * Index formats */ case DRM_FORMAT_C8: if (sysfb_crtc_state->format->format == DRM_FORMAT_RGB332) { vesadrm_fill_palette_lut(vesa, sysfb_crtc_state->format); } else if (crtc->state->gamma_lut) { vesadrm_load_palette_lut(vesa, sysfb_crtc_state->format, crtc_state->gamma_lut->data); } else { vesadrm_fill_palette_lut(vesa, sysfb_crtc_state->format); } break; /* * Component formats */ default: if (sysfb_crtc_state->format == sysfb->fb_format) { if (crtc_state->gamma_lut) vesadrm_load_gamma_lut(vesa, sysfb_crtc_state->format, crtc_state->gamma_lut->data); else vesadrm_fill_gamma_lut(vesa, sysfb_crtc_state->format); } else { vesadrm_fill_gamma_lut(vesa, sysfb_crtc_state->format); } break; } }} static const struct drm_crtc_helper_funcs vesadrm_crtc_helper_funcs = { DRM_SYSFB_CRTC_HELPER_FUNCS, .atomic_flush = vesadrm_crtc_helper_atomic_flush,}; static const struct drm_crtc_funcs vesadrm_crtc_funcs = { DRM_SYSFB_CRTC_FUNCS, .destroy = drm_crtc_cleanup,}; static const struct drm_encoder_funcs vesadrm_encoder_funcs = { .destroy = drm_encoder_cleanup,}; static const struct drm_connector_helper_funcs vesadrm_connector_helper_funcs = { DRM_SYSFB_CONNECTOR_HELPER_FUNCS,}; static const struct drm_connector_funcs vesadrm_connector_funcs = { DRM_SYSFB_CONNECTOR_FUNCS, .destroy = drm_connector_cleanup,}; static const struct drm_mode_config_funcs vesadrm_mode_config_funcs = { DRM_SYSFB_MODE_CONFIG_FUNCS,}; /* * Init / Cleanup */ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv, struct platform_device *pdev){ const struct sysfb_display_info *dpy; const struct screen_info *si; const struct drm_format_info *format; int width, height, stride; s64 vsize; struct resource resbuf; struct resource *res; struct vesadrm_device *vesa; struct drm_sysfb_device *sysfb; struct drm_device *dev; struct resource *mem = NULL; void __iomem *screen_base; struct drm_plane *primary_plane; struct drm_crtc *crtc; struct drm_encoder *encoder; struct drm_connector *connector; unsigned long max_width, max_height; size_t nformats; int ret; dpy = dev_get_platdata(&pdev->dev); if (!dpy) return ERR_PTR(-ENODEV); si = &dpy->screen; if (screen_info_video_type(si) != VIDEO_TYPE_VLFB) return ERR_PTR(-ENODEV); /* * VESA DRM driver */ vesa = devm_drm_dev_alloc(&pdev->dev, drv, struct vesadrm_device, sysfb.dev); if (IS_ERR(vesa)) return ERR_CAST(vesa); sysfb = &vesa->sysfb; dev = &sysfb->dev; platform_set_drvdata(pdev, dev); /* * Hardware settings */ format = vesadrm_get_format_si(dev, si); if (!format) return ERR_PTR(-EINVAL); width = drm_sysfb_get_width_si(dev, si); if (width < 0) return ERR_PTR(width); height = drm_sysfb_get_height_si(dev, si); if (height < 0) return ERR_PTR(height); res = drm_sysfb_get_memory_si(dev, si, &resbuf); if (!res) return ERR_PTR(-EINVAL); stride = drm_sysfb_get_stride_si(dev, si, format, width, height, resource_size(res)); if (stride < 0) return ERR_PTR(stride); vsize = drm_sysfb_get_visible_size_si(dev, si, height, stride, resource_size(res)); if (vsize < 0) return ERR_PTR(vsize); drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n", &format->format, width, height, stride); if (!__screen_info_vbe_mode_nonvga(si)) { vesa->cmap_write = vesadrm_vga_cmap_write; } else {#if defined(CONFIG_X86_32) phys_addr_t pmi_base = __screen_info_vesapm_info_base(si); if (pmi_base) { const u16 *pmi_addr = phys_to_virt(pmi_base); vesa->pmi.PrimaryPalette = (u8 *)pmi_addr + pmi_addr[2]; vesa->cmap_write = vesadrm_pmi_cmap_write; } else#endif if (format->is_color_indexed) drm_warn(dev, "hardware palette is unchangeable, colors may be incorrect\n"); } #if defined(CONFIG_FIRMWARE_EDID) if (drm_edid_header_is_valid(dpy->edid.dummy) == 8) sysfb->edid = dpy->edid.dummy;#endif sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0); sysfb->fb_format = format; sysfb->fb_pitch = stride; if (vesa->cmap_write) sysfb->fb_gamma_lut_size = VESADRM_GAMMA_LUT_SIZE; /* * Memory management */ ret = devm_aperture_acquire_for_platform_device(pdev, res->start, vsize); if (ret) { drm_err(dev, "could not acquire memory range %pr: %d\n", res, ret); return ERR_PTR(ret);Lines 1–500 of 679. Load more
// SPDX-License-Identifier: GPL-2.0-only #include <linux/aperture.h> #include <linux/ioport.h> #include <linux/limits.h> #include <linux/platform_device.h> #include <linux/sysfb.h> #include <linux/pm.h> #include <drm/clients/drm_client_setup.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_state_helper.h> #include <drm/drm_color_mgmt.h> #include <drm/drm_connector.h> #include <drm/drm_damage_helper.h> #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_edid.h> #include <drm/drm_fbdev_shmem.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_shmem_helper.h> #include <drm/drm_managed.h> #include <drm/drm_modeset_helper.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <video/pixel_format.h> #include <video/vga.h> #include "drm_sysfb_helper.h" #define DRIVER_NAME "vesadrm" #define DRIVER_DESC "DRM driver for VESA platform devices" #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 #define VESADRM_GAMMA_LUT_SIZE 256 static const struct drm_format_info *vesadrm_get_format_si(struct drm_device *dev, const struct screen_info *si) { static const struct drm_sysfb_format formats[] = { { PIXEL_FORMAT_XRGB1555, DRM_FORMAT_XRGB1555, }, { PIXEL_FORMAT_RGB565, DRM_FORMAT_RGB565, }, { PIXEL_FORMAT_RGB888, DRM_FORMAT_RGB888, }, { PIXEL_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888, }, { PIXEL_FORMAT_XBGR8888, DRM_FORMAT_XBGR8888, }, { PIXEL_FORMAT_C8, DRM_FORMAT_C8, }, }; struct pixel_format pixel; int ret; ret = screen_info_pixel_format(si, &pixel); if (ret) return NULL; return drm_sysfb_get_format(dev, formats, ARRAY_SIZE(formats), &pixel); } /* * VESA device */ struct vesadrm_device { struct drm_sysfb_device sysfb; #if defined(CONFIG_X86_32) /* VESA Protected Mode interface */ struct { const u8 *PrimaryPalette; } pmi; #endif void (*cmap_write)(struct vesadrm_device *vesa, unsigned int index, u16 red, u16 green, u16 blue); /* modesetting */ u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)]; struct drm_plane primary_plane; struct drm_crtc crtc; struct drm_encoder encoder; struct drm_connector connector; }; static struct vesadrm_device *to_vesadrm_device(struct drm_device *dev) { return container_of(to_drm_sysfb_device(dev), struct vesadrm_device, sysfb); } /* * Color LUT */ static void vesadrm_vga_cmap_write(struct vesadrm_device *vesa, unsigned int index, u16 red, u16 green, u16 blue) { u8 i8 = index; u8 r8 = red >> 8; u8 g8 = green >> 8; u8 b8 = blue >> 8; outb_p(i8, VGA_PEL_IW); outb_p(r8, VGA_PEL_D); outb_p(g8, VGA_PEL_D); outb_p(b8, VGA_PEL_D); } #if defined(CONFIG_X86_32) static void vesadrm_pmi_cmap_write(struct vesadrm_device *vesa, unsigned int index, u16 red, u16 green, u16 blue) { u32 i32 = index; struct { u8 b8; u8 g8; u8 r8; u8 x8; } PaletteEntry = { blue >> 8, green >> 8, red >> 8, 0x00, }; __asm__ __volatile__ ( "call *(%%esi)" : /* no return value */ : "a" (0x4f09), "b" (0), "c" (1), "d" (i32), "D" (&PaletteEntry), "S" (&vesa->pmi.PrimaryPalette)); } #endif static void vesadrm_set_color_lut(struct drm_crtc *crtc, unsigned int index, u16 red, u16 green, u16 blue) { struct drm_device *dev = crtc->dev; struct vesadrm_device *vesa = to_vesadrm_device(dev); u8 i8 = index & 0xff; if (drm_WARN_ON_ONCE(dev, index != i8)) return; /* driver bug */ vesa->cmap_write(vesa, i8, red, green, blue); } static void vesadrm_fill_gamma_lut(struct vesadrm_device *vesa, const struct drm_format_info *format) { struct drm_device *dev = &vesa->sysfb.dev; struct drm_crtc *crtc = &vesa->crtc; switch (format->format) { case DRM_FORMAT_XRGB1555: drm_crtc_fill_gamma_555(crtc, vesadrm_set_color_lut); break; case DRM_FORMAT_RGB565: drm_crtc_fill_gamma_565(crtc, vesadrm_set_color_lut); break; case DRM_FORMAT_RGB888: case DRM_FORMAT_XRGB8888: case DRM_FORMAT_BGRX8888: drm_crtc_fill_gamma_888(crtc, vesadrm_set_color_lut); break; default: drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n", &format->format); break; } } static void vesadrm_load_gamma_lut(struct vesadrm_device *vesa, const struct drm_format_info *format, struct drm_color_lut *lut) { struct drm_device *dev = &vesa->sysfb.dev; struct drm_crtc *crtc = &vesa->crtc; switch (format->format) { case DRM_FORMAT_XRGB1555: drm_crtc_load_gamma_555_from_888(crtc, lut, vesadrm_set_color_lut); break; case DRM_FORMAT_RGB565: drm_crtc_load_gamma_565_from_888(crtc, lut, vesadrm_set_color_lut); break; case DRM_FORMAT_RGB888: case DRM_FORMAT_XRGB8888: case DRM_FORMAT_BGRX8888: drm_crtc_load_gamma_888(crtc, lut, vesadrm_set_color_lut); break; default: drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n", &format->format); break; } } static void vesadrm_fill_palette_lut(struct vesadrm_device *vesa, const struct drm_format_info *format) { struct drm_device *dev = &vesa->sysfb.dev; struct drm_crtc *crtc = &vesa->crtc; switch (format->format) { case DRM_FORMAT_C8: drm_crtc_fill_palette_8(crtc, vesadrm_set_color_lut); break; case DRM_FORMAT_RGB332: drm_crtc_fill_palette_332(crtc, vesadrm_set_color_lut); break; default: drm_warn_once(dev, "Unsupported format %p4cc for palette\n", &format->format); break; } } static void vesadrm_load_palette_lut(struct vesadrm_device *vesa, const struct drm_format_info *format, struct drm_color_lut *lut) { struct drm_device *dev = &vesa->sysfb.dev; struct drm_crtc *crtc = &vesa->crtc; switch (format->format) { case DRM_FORMAT_C8: drm_crtc_load_palette_8(crtc, lut, vesadrm_set_color_lut); break; default: drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n", &format->format); break; } } /* * Modesetting */ static const u64 vesadrm_primary_plane_format_modifiers[] = { DRM_SYSFB_PLANE_FORMAT_MODIFIERS, }; static int vesadrm_primary_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_commit *new_state) { struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev); struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); struct drm_framebuffer *new_fb = new_plane_state->fb; struct drm_crtc_state *new_crtc_state; struct drm_sysfb_crtc_state *new_sysfb_crtc_state; int ret; ret = drm_sysfb_plane_helper_atomic_check(plane, new_state); if (ret) return ret; else if (!new_plane_state->visible) return 0; /* * Fix up format conversion for specific cases */ switch (sysfb->fb_format->format) { case DRM_FORMAT_C8: new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc); new_sysfb_crtc_state = to_drm_sysfb_crtc_state(new_crtc_state); switch (new_fb->format->format) { case DRM_FORMAT_XRGB8888: /* * Reduce XRGB8888 to RGB332. Each resulting pixel is an index * into the C8 hardware palette, which stores RGB332 colors. */ if (new_sysfb_crtc_state->format->format != DRM_FORMAT_RGB332) { new_sysfb_crtc_state->format = drm_format_info(DRM_FORMAT_RGB332); new_crtc_state->color_mgmt_changed = true; } break; case DRM_FORMAT_C8: /* * Restore original output. Emulation of XRGB8888 set RBG332 * output format and hardware palette. This needs to be undone * when we switch back to DRM_FORMAT_C8. */ if (new_sysfb_crtc_state->format->format == DRM_FORMAT_RGB332) { new_sysfb_crtc_state->format = sysfb->fb_format; new_crtc_state->color_mgmt_changed = true; } break; } break; } return 0; } static const struct drm_plane_helper_funcs vesadrm_primary_plane_helper_funcs = { .begin_fb_access = drm_sysfb_plane_helper_begin_fb_access, .end_fb_access = drm_gem_end_shadow_fb_access, .atomic_check = vesadrm_primary_plane_helper_atomic_check, .atomic_update = drm_sysfb_plane_helper_atomic_update, .atomic_disable = drm_sysfb_plane_helper_atomic_disable, .get_scanout_buffer = drm_sysfb_plane_helper_get_scanout_buffer, }; static const struct drm_plane_funcs vesadrm_primary_plane_funcs = { DRM_SYSFB_PLANE_FUNCS, .destroy = drm_plane_cleanup, }; static void vesadrm_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_commit *state) { struct drm_device *dev = crtc->dev; struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev); struct vesadrm_device *vesa = to_vesadrm_device(dev); struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); struct drm_sysfb_crtc_state *sysfb_crtc_state = to_drm_sysfb_crtc_state(crtc_state); /* * The gamma LUT has to be reloaded after changing the primary * plane's color format. */ if (crtc_state->enable && crtc_state->color_mgmt_changed) { switch (sysfb->fb_format->format) { /* * Index formats */ case DRM_FORMAT_C8: if (sysfb_crtc_state->format->format == DRM_FORMAT_RGB332) { vesadrm_fill_palette_lut(vesa, sysfb_crtc_state->format); } else if (crtc->state->gamma_lut) { vesadrm_load_palette_lut(vesa, sysfb_crtc_state->format, crtc_state->gamma_lut->data); } else { vesadrm_fill_palette_lut(vesa, sysfb_crtc_state->format); } break; /* * Component formats */ default: if (sysfb_crtc_state->format == sysfb->fb_format) { if (crtc_state->gamma_lut) vesadrm_load_gamma_lut(vesa, sysfb_crtc_state->format, crtc_state->gamma_lut->data); else vesadrm_fill_gamma_lut(vesa, sysfb_crtc_state->format); } else { vesadrm_fill_gamma_lut(vesa, sysfb_crtc_state->format); } break; } } } static const struct drm_crtc_helper_funcs vesadrm_crtc_helper_funcs = { DRM_SYSFB_CRTC_HELPER_FUNCS, .atomic_flush = vesadrm_crtc_helper_atomic_flush, }; static const struct drm_crtc_funcs vesadrm_crtc_funcs = { DRM_SYSFB_CRTC_FUNCS, .destroy = drm_crtc_cleanup, }; static const struct drm_encoder_funcs vesadrm_encoder_funcs = { .destroy = drm_encoder_cleanup, }; static const struct drm_connector_helper_funcs vesadrm_connector_helper_funcs = { DRM_SYSFB_CONNECTOR_HELPER_FUNCS, }; static const struct drm_connector_funcs vesadrm_connector_funcs = { DRM_SYSFB_CONNECTOR_FUNCS, .destroy = drm_connector_cleanup, }; static const struct drm_mode_config_funcs vesadrm_mode_config_funcs = { DRM_SYSFB_MODE_CONFIG_FUNCS, }; /* * Init / Cleanup */ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv, struct platform_device *pdev) { const struct sysfb_display_info *dpy; const struct screen_info *si; const struct drm_format_info *format; int width, height, stride; s64 vsize; struct resource resbuf; struct resource *res; struct vesadrm_device *vesa; struct drm_sysfb_device *sysfb; struct drm_device *dev; struct resource *mem = NULL; void __iomem *screen_base; struct drm_plane *primary_plane; struct drm_crtc *crtc; struct drm_encoder *encoder; struct drm_connector *connector; unsigned long max_width, max_height; size_t nformats; int ret; dpy = dev_get_platdata(&pdev->dev); if (!dpy) return ERR_PTR(-ENODEV); si = &dpy->screen; if (screen_info_video_type(si) != VIDEO_TYPE_VLFB) return ERR_PTR(-ENODEV); /* * VESA DRM driver */ vesa = devm_drm_dev_alloc(&pdev->dev, drv, struct vesadrm_device, sysfb.dev); if (IS_ERR(vesa)) return ERR_CAST(vesa); sysfb = &vesa->sysfb; dev = &sysfb->dev; platform_set_drvdata(pdev, dev); /* * Hardware settings */ format = vesadrm_get_format_si(dev, si); if (!format) return ERR_PTR(-EINVAL); width = drm_sysfb_get_width_si(dev, si); if (width < 0) return ERR_PTR(width); height = drm_sysfb_get_height_si(dev, si); if (height < 0) return ERR_PTR(height); res = drm_sysfb_get_memory_si(dev, si, &resbuf); if (!res) return ERR_PTR(-EINVAL); stride = drm_sysfb_get_stride_si(dev, si, format, width, height, resource_size(res)); if (stride < 0) return ERR_PTR(stride); vsize = drm_sysfb_get_visible_size_si(dev, si, height, stride, resource_size(res)); if (vsize < 0) return ERR_PTR(vsize); drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n", &format->format, width, height, stride); if (!__screen_info_vbe_mode_nonvga(si)) { vesa->cmap_write = vesadrm_vga_cmap_write; } else { #if defined(CONFIG_X86_32) phys_addr_t pmi_base = __screen_info_vesapm_info_base(si); if (pmi_base) { const u16 *pmi_addr = phys_to_virt(pmi_base); vesa->pmi.PrimaryPalette = (u8 *)pmi_addr + pmi_addr[2]; vesa->cmap_write = vesadrm_pmi_cmap_write; } else #endif if (format->is_color_indexed) drm_warn(dev, "hardware palette is unchangeable, colors may be incorrect\n"); } #if defined(CONFIG_FIRMWARE_EDID) if (drm_edid_header_is_valid(dpy->edid.dummy) == 8) sysfb->edid = dpy->edid.dummy; #endif sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0); sysfb->fb_format = format; sysfb->fb_pitch = stride; if (vesa->cmap_write) sysfb->fb_gamma_lut_size = VESADRM_GAMMA_LUT_SIZE; /* * Memory management */ ret = devm_aperture_acquire_for_platform_device(pdev, res->start, vsize); if (ret) { drm_err(dev, "could not acquire memory range %pr: %d\n", res, ret); return ERR_PTR(ret);