132ae90c6SThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-only 232ae90c6SThomas Zimmermann 332ae90c6SThomas Zimmermann #include <linux/aperture.h> 432ae90c6SThomas Zimmermann #include <linux/efi.h> 532ae90c6SThomas Zimmermann #include <linux/limits.h> 632ae90c6SThomas Zimmermann #include <linux/platform_device.h> 732ae90c6SThomas Zimmermann #include <linux/screen_info.h> 832ae90c6SThomas Zimmermann 932ae90c6SThomas Zimmermann #include <drm/clients/drm_client_setup.h> 1032ae90c6SThomas Zimmermann #include <drm/drm_atomic.h> 1132ae90c6SThomas Zimmermann #include <drm/drm_atomic_state_helper.h> 1232ae90c6SThomas Zimmermann #include <drm/drm_connector.h> 1332ae90c6SThomas Zimmermann #include <drm/drm_damage_helper.h> 1432ae90c6SThomas Zimmermann #include <drm/drm_device.h> 1532ae90c6SThomas Zimmermann #include <drm/drm_drv.h> 16305396acSThomas Zimmermann #include <drm/drm_edid.h> 1732ae90c6SThomas Zimmermann #include <drm/drm_fbdev_shmem.h> 1832ae90c6SThomas Zimmermann #include <drm/drm_framebuffer.h> 1932ae90c6SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h> 2032ae90c6SThomas Zimmermann #include <drm/drm_gem_framebuffer_helper.h> 2132ae90c6SThomas Zimmermann #include <drm/drm_gem_shmem_helper.h> 2232ae90c6SThomas Zimmermann #include <drm/drm_managed.h> 2332ae90c6SThomas Zimmermann #include <drm/drm_modeset_helper_vtables.h> 2432ae90c6SThomas Zimmermann #include <drm/drm_probe_helper.h> 2532ae90c6SThomas Zimmermann 26305396acSThomas Zimmermann #include <video/edid.h> 2732ae90c6SThomas Zimmermann #include <video/pixel_format.h> 2832ae90c6SThomas Zimmermann 2932ae90c6SThomas Zimmermann #include "drm_sysfb_helper.h" 3032ae90c6SThomas Zimmermann 3132ae90c6SThomas Zimmermann #define DRIVER_NAME "efidrm" 3232ae90c6SThomas Zimmermann #define DRIVER_DESC "DRM driver for EFI platform devices" 3332ae90c6SThomas Zimmermann #define DRIVER_MAJOR 1 3432ae90c6SThomas Zimmermann #define DRIVER_MINOR 0 3532ae90c6SThomas Zimmermann 3632ae90c6SThomas Zimmermann static const struct drm_format_info *efidrm_get_format_si(struct drm_device *dev, 3732ae90c6SThomas Zimmermann const struct screen_info *si) 3832ae90c6SThomas Zimmermann { 39e8c08688SThomas Zimmermann static const struct drm_sysfb_format formats[] = { 4032ae90c6SThomas Zimmermann { PIXEL_FORMAT_XRGB1555, DRM_FORMAT_XRGB1555, }, 4132ae90c6SThomas Zimmermann { PIXEL_FORMAT_RGB565, DRM_FORMAT_RGB565, }, 4232ae90c6SThomas Zimmermann { PIXEL_FORMAT_RGB888, DRM_FORMAT_RGB888, }, 4332ae90c6SThomas Zimmermann { PIXEL_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888, }, 4432ae90c6SThomas Zimmermann { PIXEL_FORMAT_XBGR8888, DRM_FORMAT_XBGR8888, }, 4532ae90c6SThomas Zimmermann { PIXEL_FORMAT_XRGB2101010, DRM_FORMAT_XRGB2101010, }, 4632ae90c6SThomas Zimmermann }; 4732ae90c6SThomas Zimmermann 48e8c08688SThomas Zimmermann return drm_sysfb_get_format_si(dev, formats, ARRAY_SIZE(formats), si); 4932ae90c6SThomas Zimmermann } 5032ae90c6SThomas Zimmermann 5132ae90c6SThomas Zimmermann static u64 efidrm_get_mem_flags(struct drm_device *dev, resource_size_t start, 5232ae90c6SThomas Zimmermann resource_size_t len) 5332ae90c6SThomas Zimmermann { 5432ae90c6SThomas Zimmermann u64 attribute = EFI_MEMORY_UC | EFI_MEMORY_WC | 5532ae90c6SThomas Zimmermann EFI_MEMORY_WT | EFI_MEMORY_WB; 5632ae90c6SThomas Zimmermann u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC; 5732ae90c6SThomas Zimmermann resource_size_t end = start + len; 5832ae90c6SThomas Zimmermann efi_memory_desc_t md; 5932ae90c6SThomas Zimmermann u64 md_end; 6032ae90c6SThomas Zimmermann 6132ae90c6SThomas Zimmermann if (!efi_enabled(EFI_MEMMAP) || efi_mem_desc_lookup(start, &md)) 6232ae90c6SThomas Zimmermann goto out; 6332ae90c6SThomas Zimmermann 6432ae90c6SThomas Zimmermann md_end = md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT); 6532ae90c6SThomas Zimmermann if (end > md_end) 6632ae90c6SThomas Zimmermann goto out; 6732ae90c6SThomas Zimmermann 6832ae90c6SThomas Zimmermann attribute &= md.attribute; 6932ae90c6SThomas Zimmermann if (attribute) { 7032ae90c6SThomas Zimmermann mem_flags |= EFI_MEMORY_WT | EFI_MEMORY_WB; 7132ae90c6SThomas Zimmermann mem_flags &= attribute; 7232ae90c6SThomas Zimmermann } 7332ae90c6SThomas Zimmermann 7432ae90c6SThomas Zimmermann out: 7532ae90c6SThomas Zimmermann return mem_flags; 7632ae90c6SThomas Zimmermann } 7732ae90c6SThomas Zimmermann 7832ae90c6SThomas Zimmermann /* 7932ae90c6SThomas Zimmermann * EFI device 8032ae90c6SThomas Zimmermann */ 8132ae90c6SThomas Zimmermann 8232ae90c6SThomas Zimmermann struct efidrm_device { 8332ae90c6SThomas Zimmermann struct drm_sysfb_device sysfb; 8432ae90c6SThomas Zimmermann 8532ae90c6SThomas Zimmermann /* modesetting */ 8632ae90c6SThomas Zimmermann u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)]; 8732ae90c6SThomas Zimmermann struct drm_plane primary_plane; 8832ae90c6SThomas Zimmermann struct drm_crtc crtc; 8932ae90c6SThomas Zimmermann struct drm_encoder encoder; 9032ae90c6SThomas Zimmermann struct drm_connector connector; 9132ae90c6SThomas Zimmermann }; 9232ae90c6SThomas Zimmermann 9332ae90c6SThomas Zimmermann /* 9432ae90c6SThomas Zimmermann * Modesetting 9532ae90c6SThomas Zimmermann */ 9632ae90c6SThomas Zimmermann 9732ae90c6SThomas Zimmermann static const u64 efidrm_primary_plane_format_modifiers[] = { 9832ae90c6SThomas Zimmermann DRM_SYSFB_PLANE_FORMAT_MODIFIERS, 9932ae90c6SThomas Zimmermann }; 10032ae90c6SThomas Zimmermann 10132ae90c6SThomas Zimmermann static const struct drm_plane_helper_funcs efidrm_primary_plane_helper_funcs = { 10232ae90c6SThomas Zimmermann DRM_SYSFB_PLANE_HELPER_FUNCS, 10332ae90c6SThomas Zimmermann }; 10432ae90c6SThomas Zimmermann 10532ae90c6SThomas Zimmermann static const struct drm_plane_funcs efidrm_primary_plane_funcs = { 10632ae90c6SThomas Zimmermann DRM_SYSFB_PLANE_FUNCS, 10732ae90c6SThomas Zimmermann .destroy = drm_plane_cleanup, 10832ae90c6SThomas Zimmermann }; 10932ae90c6SThomas Zimmermann 11032ae90c6SThomas Zimmermann static const struct drm_crtc_helper_funcs efidrm_crtc_helper_funcs = { 11132ae90c6SThomas Zimmermann DRM_SYSFB_CRTC_HELPER_FUNCS, 11232ae90c6SThomas Zimmermann }; 11332ae90c6SThomas Zimmermann 11432ae90c6SThomas Zimmermann static const struct drm_crtc_funcs efidrm_crtc_funcs = { 11532ae90c6SThomas Zimmermann DRM_SYSFB_CRTC_FUNCS, 11632ae90c6SThomas Zimmermann .destroy = drm_crtc_cleanup, 11732ae90c6SThomas Zimmermann }; 11832ae90c6SThomas Zimmermann 11932ae90c6SThomas Zimmermann static const struct drm_encoder_funcs efidrm_encoder_funcs = { 12032ae90c6SThomas Zimmermann .destroy = drm_encoder_cleanup, 12132ae90c6SThomas Zimmermann }; 12232ae90c6SThomas Zimmermann 12332ae90c6SThomas Zimmermann static const struct drm_connector_helper_funcs efidrm_connector_helper_funcs = { 12432ae90c6SThomas Zimmermann DRM_SYSFB_CONNECTOR_HELPER_FUNCS, 12532ae90c6SThomas Zimmermann }; 12632ae90c6SThomas Zimmermann 12732ae90c6SThomas Zimmermann static const struct drm_connector_funcs efidrm_connector_funcs = { 12832ae90c6SThomas Zimmermann DRM_SYSFB_CONNECTOR_FUNCS, 12932ae90c6SThomas Zimmermann .destroy = drm_connector_cleanup, 13032ae90c6SThomas Zimmermann }; 13132ae90c6SThomas Zimmermann 13232ae90c6SThomas Zimmermann static const struct drm_mode_config_funcs efidrm_mode_config_funcs = { 13332ae90c6SThomas Zimmermann DRM_SYSFB_MODE_CONFIG_FUNCS, 13432ae90c6SThomas Zimmermann }; 13532ae90c6SThomas Zimmermann 13632ae90c6SThomas Zimmermann /* 13732ae90c6SThomas Zimmermann * Init / Cleanup 13832ae90c6SThomas Zimmermann */ 13932ae90c6SThomas Zimmermann 14032ae90c6SThomas Zimmermann static struct efidrm_device *efidrm_device_create(struct drm_driver *drv, 14132ae90c6SThomas Zimmermann struct platform_device *pdev) 14232ae90c6SThomas Zimmermann { 14332ae90c6SThomas Zimmermann const struct screen_info *si; 14432ae90c6SThomas Zimmermann const struct drm_format_info *format; 14532ae90c6SThomas Zimmermann int width, height, stride; 14632ae90c6SThomas Zimmermann u64 vsize, mem_flags; 14732ae90c6SThomas Zimmermann struct resource resbuf; 14832ae90c6SThomas Zimmermann struct resource *res; 14932ae90c6SThomas Zimmermann struct efidrm_device *efi; 15032ae90c6SThomas Zimmermann struct drm_sysfb_device *sysfb; 15132ae90c6SThomas Zimmermann struct drm_device *dev; 15232ae90c6SThomas Zimmermann struct resource *mem = NULL; 15374637552SNathan Chancellor void __iomem *screen_base = NULL; 15432ae90c6SThomas Zimmermann struct drm_plane *primary_plane; 15532ae90c6SThomas Zimmermann struct drm_crtc *crtc; 15632ae90c6SThomas Zimmermann struct drm_encoder *encoder; 15732ae90c6SThomas Zimmermann struct drm_connector *connector; 15832ae90c6SThomas Zimmermann unsigned long max_width, max_height; 15932ae90c6SThomas Zimmermann size_t nformats; 16032ae90c6SThomas Zimmermann int ret; 16132ae90c6SThomas Zimmermann 16232ae90c6SThomas Zimmermann si = dev_get_platdata(&pdev->dev); 16332ae90c6SThomas Zimmermann if (!si) 16432ae90c6SThomas Zimmermann return ERR_PTR(-ENODEV); 16532ae90c6SThomas Zimmermann if (screen_info_video_type(si) != VIDEO_TYPE_EFI) 16632ae90c6SThomas Zimmermann return ERR_PTR(-ENODEV); 16732ae90c6SThomas Zimmermann 16832ae90c6SThomas Zimmermann /* 16932ae90c6SThomas Zimmermann * EFI DRM driver 17032ae90c6SThomas Zimmermann */ 17132ae90c6SThomas Zimmermann 17232ae90c6SThomas Zimmermann efi = devm_drm_dev_alloc(&pdev->dev, drv, struct efidrm_device, sysfb.dev); 17332ae90c6SThomas Zimmermann if (IS_ERR(efi)) 17432ae90c6SThomas Zimmermann return ERR_CAST(efi); 17532ae90c6SThomas Zimmermann sysfb = &efi->sysfb; 17632ae90c6SThomas Zimmermann dev = &sysfb->dev; 17732ae90c6SThomas Zimmermann platform_set_drvdata(pdev, dev); 17832ae90c6SThomas Zimmermann 17932ae90c6SThomas Zimmermann /* 18032ae90c6SThomas Zimmermann * Hardware settings 18132ae90c6SThomas Zimmermann */ 18232ae90c6SThomas Zimmermann 18332ae90c6SThomas Zimmermann format = efidrm_get_format_si(dev, si); 184e8c08688SThomas Zimmermann if (!format) 185e8c08688SThomas Zimmermann return ERR_PTR(-EINVAL); 186e8c08688SThomas Zimmermann width = drm_sysfb_get_width_si(dev, si); 18732ae90c6SThomas Zimmermann if (width < 0) 18832ae90c6SThomas Zimmermann return ERR_PTR(width); 189e8c08688SThomas Zimmermann height = drm_sysfb_get_height_si(dev, si); 19032ae90c6SThomas Zimmermann if (height < 0) 19132ae90c6SThomas Zimmermann return ERR_PTR(height); 192e8c08688SThomas Zimmermann res = drm_sysfb_get_memory_si(dev, si, &resbuf); 19332ae90c6SThomas Zimmermann if (!res) 19432ae90c6SThomas Zimmermann return ERR_PTR(-EINVAL); 195e8c08688SThomas Zimmermann stride = drm_sysfb_get_stride_si(dev, si, format, width, height, resource_size(res)); 19632ae90c6SThomas Zimmermann if (stride < 0) 19732ae90c6SThomas Zimmermann return ERR_PTR(stride); 198e8c08688SThomas Zimmermann vsize = drm_sysfb_get_visible_size_si(dev, si, height, stride, resource_size(res)); 19932ae90c6SThomas Zimmermann if (!vsize) 20032ae90c6SThomas Zimmermann return ERR_PTR(-EINVAL); 20132ae90c6SThomas Zimmermann 20232ae90c6SThomas Zimmermann drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n", 20332ae90c6SThomas Zimmermann &format->format, width, height, stride); 20432ae90c6SThomas Zimmermann 20533b4e4fcSThomas Zimmermann #if defined(CONFIG_FIRMWARE_EDID) 206305396acSThomas Zimmermann if (drm_edid_header_is_valid(edid_info.dummy) == 8) 207305396acSThomas Zimmermann sysfb->edid = edid_info.dummy; 208305396acSThomas Zimmermann #endif 20932ae90c6SThomas Zimmermann sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0); 21032ae90c6SThomas Zimmermann sysfb->fb_format = format; 21132ae90c6SThomas Zimmermann sysfb->fb_pitch = stride; 21232ae90c6SThomas Zimmermann 21332ae90c6SThomas Zimmermann /* 21432ae90c6SThomas Zimmermann * Memory management 21532ae90c6SThomas Zimmermann */ 21632ae90c6SThomas Zimmermann 21732ae90c6SThomas Zimmermann ret = devm_aperture_acquire_for_platform_device(pdev, res->start, vsize); 21832ae90c6SThomas Zimmermann if (ret) { 21932ae90c6SThomas Zimmermann drm_err(dev, "could not acquire memory range %pr: %d\n", res, ret); 22032ae90c6SThomas Zimmermann return ERR_PTR(ret); 22132ae90c6SThomas Zimmermann } 22232ae90c6SThomas Zimmermann 22332ae90c6SThomas Zimmermann drm_dbg(dev, "using I/O memory framebuffer at %pr\n", res); 22432ae90c6SThomas Zimmermann 22532ae90c6SThomas Zimmermann mem = devm_request_mem_region(&pdev->dev, res->start, vsize, drv->name); 22632ae90c6SThomas Zimmermann if (!mem) { 22732ae90c6SThomas Zimmermann /* 22832ae90c6SThomas Zimmermann * We cannot make this fatal. Sometimes this comes from magic 22932ae90c6SThomas Zimmermann * spaces our resource handlers simply don't know about. Use 23032ae90c6SThomas Zimmermann * the I/O-memory resource as-is and try to map that instead. 23132ae90c6SThomas Zimmermann */ 23232ae90c6SThomas Zimmermann drm_warn(dev, "could not acquire memory region %pr\n", res); 23332ae90c6SThomas Zimmermann mem = res; 23432ae90c6SThomas Zimmermann } 23532ae90c6SThomas Zimmermann 23632ae90c6SThomas Zimmermann mem_flags = efidrm_get_mem_flags(dev, res->start, vsize); 23732ae90c6SThomas Zimmermann 23832ae90c6SThomas Zimmermann if (mem_flags & EFI_MEMORY_WC) 23932ae90c6SThomas Zimmermann screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem)); 24032ae90c6SThomas Zimmermann else if (mem_flags & EFI_MEMORY_UC) 24132ae90c6SThomas Zimmermann screen_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); 24232ae90c6SThomas Zimmermann else if (mem_flags & EFI_MEMORY_WT) 24332ae90c6SThomas Zimmermann screen_base = devm_memremap(&pdev->dev, mem->start, resource_size(mem), 24432ae90c6SThomas Zimmermann MEMREMAP_WT); 24532ae90c6SThomas Zimmermann else if (mem_flags & EFI_MEMORY_WB) 24632ae90c6SThomas Zimmermann screen_base = devm_memremap(&pdev->dev, mem->start, resource_size(mem), 24732ae90c6SThomas Zimmermann MEMREMAP_WB); 24874637552SNathan Chancellor else 24974637552SNathan Chancellor drm_err(dev, "invalid mem_flags: 0x%llx\n", mem_flags); 25032ae90c6SThomas Zimmermann if (!screen_base) 25132ae90c6SThomas Zimmermann return ERR_PTR(-ENOMEM); 25232ae90c6SThomas Zimmermann iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base); 25332ae90c6SThomas Zimmermann 25432ae90c6SThomas Zimmermann /* 25532ae90c6SThomas Zimmermann * Modesetting 25632ae90c6SThomas Zimmermann */ 25732ae90c6SThomas Zimmermann 25832ae90c6SThomas Zimmermann ret = drmm_mode_config_init(dev); 25932ae90c6SThomas Zimmermann if (ret) 26032ae90c6SThomas Zimmermann return ERR_PTR(ret); 26132ae90c6SThomas Zimmermann 26232ae90c6SThomas Zimmermann max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH); 26332ae90c6SThomas Zimmermann max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT); 26432ae90c6SThomas Zimmermann 26532ae90c6SThomas Zimmermann dev->mode_config.min_width = width; 26632ae90c6SThomas Zimmermann dev->mode_config.max_width = max_width; 26732ae90c6SThomas Zimmermann dev->mode_config.min_height = height; 26832ae90c6SThomas Zimmermann dev->mode_config.max_height = max_height; 26932ae90c6SThomas Zimmermann dev->mode_config.preferred_depth = format->depth; 27032ae90c6SThomas Zimmermann dev->mode_config.funcs = &efidrm_mode_config_funcs; 27132ae90c6SThomas Zimmermann 27232ae90c6SThomas Zimmermann /* Primary plane */ 27332ae90c6SThomas Zimmermann 274*1a45ef02SThomas Zimmermann nformats = drm_sysfb_build_fourcc_list(dev, &format->format, 1, 27532ae90c6SThomas Zimmermann efi->formats, ARRAY_SIZE(efi->formats)); 27632ae90c6SThomas Zimmermann 27732ae90c6SThomas Zimmermann primary_plane = &efi->primary_plane; 27832ae90c6SThomas Zimmermann ret = drm_universal_plane_init(dev, primary_plane, 0, &efidrm_primary_plane_funcs, 27932ae90c6SThomas Zimmermann efi->formats, nformats, 28032ae90c6SThomas Zimmermann efidrm_primary_plane_format_modifiers, 28132ae90c6SThomas Zimmermann DRM_PLANE_TYPE_PRIMARY, NULL); 28232ae90c6SThomas Zimmermann if (ret) 28332ae90c6SThomas Zimmermann return ERR_PTR(ret); 28432ae90c6SThomas Zimmermann drm_plane_helper_add(primary_plane, &efidrm_primary_plane_helper_funcs); 28532ae90c6SThomas Zimmermann drm_plane_enable_fb_damage_clips(primary_plane); 28632ae90c6SThomas Zimmermann 28732ae90c6SThomas Zimmermann /* CRTC */ 28832ae90c6SThomas Zimmermann 28932ae90c6SThomas Zimmermann crtc = &efi->crtc; 29032ae90c6SThomas Zimmermann ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, 29132ae90c6SThomas Zimmermann &efidrm_crtc_funcs, NULL); 29232ae90c6SThomas Zimmermann if (ret) 29332ae90c6SThomas Zimmermann return ERR_PTR(ret); 29432ae90c6SThomas Zimmermann drm_crtc_helper_add(crtc, &efidrm_crtc_helper_funcs); 29532ae90c6SThomas Zimmermann 29632ae90c6SThomas Zimmermann /* Encoder */ 29732ae90c6SThomas Zimmermann 29832ae90c6SThomas Zimmermann encoder = &efi->encoder; 29932ae90c6SThomas Zimmermann ret = drm_encoder_init(dev, encoder, &efidrm_encoder_funcs, 30032ae90c6SThomas Zimmermann DRM_MODE_ENCODER_NONE, NULL); 30132ae90c6SThomas Zimmermann if (ret) 30232ae90c6SThomas Zimmermann return ERR_PTR(ret); 30332ae90c6SThomas Zimmermann encoder->possible_crtcs = drm_crtc_mask(crtc); 30432ae90c6SThomas Zimmermann 30532ae90c6SThomas Zimmermann /* Connector */ 30632ae90c6SThomas Zimmermann 30732ae90c6SThomas Zimmermann connector = &efi->connector; 30832ae90c6SThomas Zimmermann ret = drm_connector_init(dev, connector, &efidrm_connector_funcs, 30932ae90c6SThomas Zimmermann DRM_MODE_CONNECTOR_Unknown); 31032ae90c6SThomas Zimmermann if (ret) 31132ae90c6SThomas Zimmermann return ERR_PTR(ret); 31232ae90c6SThomas Zimmermann drm_connector_helper_add(connector, &efidrm_connector_helper_funcs); 31332ae90c6SThomas Zimmermann drm_connector_set_panel_orientation_with_quirk(connector, 31432ae90c6SThomas Zimmermann DRM_MODE_PANEL_ORIENTATION_UNKNOWN, 31532ae90c6SThomas Zimmermann width, height); 316305396acSThomas Zimmermann if (sysfb->edid) 317305396acSThomas Zimmermann drm_connector_attach_edid_property(connector); 31832ae90c6SThomas Zimmermann 31932ae90c6SThomas Zimmermann ret = drm_connector_attach_encoder(connector, encoder); 32032ae90c6SThomas Zimmermann if (ret) 32132ae90c6SThomas Zimmermann return ERR_PTR(ret); 32232ae90c6SThomas Zimmermann 32332ae90c6SThomas Zimmermann drm_mode_config_reset(dev); 32432ae90c6SThomas Zimmermann 32532ae90c6SThomas Zimmermann return efi; 32632ae90c6SThomas Zimmermann } 32732ae90c6SThomas Zimmermann 32832ae90c6SThomas Zimmermann /* 32932ae90c6SThomas Zimmermann * DRM driver 33032ae90c6SThomas Zimmermann */ 33132ae90c6SThomas Zimmermann 33232ae90c6SThomas Zimmermann DEFINE_DRM_GEM_FOPS(efidrm_fops); 33332ae90c6SThomas Zimmermann 33432ae90c6SThomas Zimmermann static struct drm_driver efidrm_driver = { 33532ae90c6SThomas Zimmermann DRM_GEM_SHMEM_DRIVER_OPS, 33632ae90c6SThomas Zimmermann DRM_FBDEV_SHMEM_DRIVER_OPS, 33732ae90c6SThomas Zimmermann .name = DRIVER_NAME, 33832ae90c6SThomas Zimmermann .desc = DRIVER_DESC, 33932ae90c6SThomas Zimmermann .major = DRIVER_MAJOR, 34032ae90c6SThomas Zimmermann .minor = DRIVER_MINOR, 34132ae90c6SThomas Zimmermann .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, 34232ae90c6SThomas Zimmermann .fops = &efidrm_fops, 34332ae90c6SThomas Zimmermann }; 34432ae90c6SThomas Zimmermann 34532ae90c6SThomas Zimmermann /* 34632ae90c6SThomas Zimmermann * Platform driver 34732ae90c6SThomas Zimmermann */ 34832ae90c6SThomas Zimmermann 34932ae90c6SThomas Zimmermann static int efidrm_probe(struct platform_device *pdev) 35032ae90c6SThomas Zimmermann { 35132ae90c6SThomas Zimmermann struct efidrm_device *efi; 35232ae90c6SThomas Zimmermann struct drm_sysfb_device *sysfb; 35332ae90c6SThomas Zimmermann struct drm_device *dev; 35432ae90c6SThomas Zimmermann int ret; 35532ae90c6SThomas Zimmermann 35632ae90c6SThomas Zimmermann efi = efidrm_device_create(&efidrm_driver, pdev); 35732ae90c6SThomas Zimmermann if (IS_ERR(efi)) 35832ae90c6SThomas Zimmermann return PTR_ERR(efi); 35932ae90c6SThomas Zimmermann sysfb = &efi->sysfb; 36032ae90c6SThomas Zimmermann dev = &sysfb->dev; 36132ae90c6SThomas Zimmermann 36232ae90c6SThomas Zimmermann ret = drm_dev_register(dev, 0); 36332ae90c6SThomas Zimmermann if (ret) 36432ae90c6SThomas Zimmermann return ret; 36532ae90c6SThomas Zimmermann 36632ae90c6SThomas Zimmermann drm_client_setup(dev, sysfb->fb_format); 36732ae90c6SThomas Zimmermann 36832ae90c6SThomas Zimmermann return 0; 36932ae90c6SThomas Zimmermann } 37032ae90c6SThomas Zimmermann 37132ae90c6SThomas Zimmermann static void efidrm_remove(struct platform_device *pdev) 37232ae90c6SThomas Zimmermann { 37332ae90c6SThomas Zimmermann struct drm_device *dev = platform_get_drvdata(pdev); 37432ae90c6SThomas Zimmermann 37532ae90c6SThomas Zimmermann drm_dev_unplug(dev); 37632ae90c6SThomas Zimmermann } 37732ae90c6SThomas Zimmermann 37832ae90c6SThomas Zimmermann static struct platform_driver efidrm_platform_driver = { 37932ae90c6SThomas Zimmermann .driver = { 38032ae90c6SThomas Zimmermann .name = "efi-framebuffer", 38132ae90c6SThomas Zimmermann }, 38232ae90c6SThomas Zimmermann .probe = efidrm_probe, 38332ae90c6SThomas Zimmermann .remove = efidrm_remove, 38432ae90c6SThomas Zimmermann }; 38532ae90c6SThomas Zimmermann 38632ae90c6SThomas Zimmermann module_platform_driver(efidrm_platform_driver); 38732ae90c6SThomas Zimmermann 38832ae90c6SThomas Zimmermann MODULE_DESCRIPTION(DRIVER_DESC); 38932ae90c6SThomas Zimmermann MODULE_LICENSE("GPL"); 390