// SPDX-License-Identifier: GPL-2.0-only #include <linux/aperture.h>#include <linux/of_address.h>#include <linux/overflow.h>#include <linux/pci.h>#include <linux/platform_device.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 "drm_sysfb_helper.h" #define DRIVER_NAME "ofdrm"#define DRIVER_DESC "DRM driver for OF platform devices"#define DRIVER_MAJOR 1#define DRIVER_MINOR 0 #define PCI_VENDOR_ID_ATI_R520 0x7100#define PCI_VENDOR_ID_ATI_R600 0x9400 #define OFDRM_GAMMA_LUT_SIZE 256 /* Definitions used by the Avivo palette */#define AVIVO_DC_LUT_RW_SELECT 0x6480#define AVIVO_DC_LUT_RW_MODE 0x6484#define AVIVO_DC_LUT_RW_INDEX 0x6488#define AVIVO_DC_LUT_SEQ_COLOR 0x648c#define AVIVO_DC_LUT_PWL_DATA 0x6490#define AVIVO_DC_LUT_30_COLOR 0x6494#define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498#define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c#define AVIVO_DC_LUT_AUTOFILL 0x64a0#define AVIVO_DC_LUTA_CONTROL 0x64c0#define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4#define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8#define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc#define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0#define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4#define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8#define AVIVO_DC_LUTB_CONTROL 0x6cc0#define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4#define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8#define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc#define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0#define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4#define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8 enum ofdrm_model { OFDRM_MODEL_UNKNOWN, OFDRM_MODEL_MACH64, /* ATI Mach64 */ OFDRM_MODEL_RAGE128, /* ATI Rage128 */ OFDRM_MODEL_RAGE_M3A, /* ATI Rage Mobility M3 Head A */ OFDRM_MODEL_RAGE_M3B, /* ATI Rage Mobility M3 Head B */ OFDRM_MODEL_RADEON, /* ATI Radeon */ OFDRM_MODEL_GXT2000, /* IBM GXT2000 */ OFDRM_MODEL_AVIVO, /* ATI R5xx */ OFDRM_MODEL_QEMU, /* QEMU VGA */}; /* * Helpers for display nodes */ static int display_get_validated_int(struct drm_device *dev, const char *name, uint32_t value){ return drm_sysfb_get_validated_int(dev, name, value, INT_MAX);} static int display_get_validated_int0(struct drm_device *dev, const char *name, uint32_t value){ return drm_sysfb_get_validated_int0(dev, name, value, INT_MAX);} static const struct drm_format_info *display_get_validated_format(struct drm_device *dev, u32 depth, bool big_endian){ const struct drm_format_info *info; u32 format; switch (depth) { case 8: format = drm_mode_legacy_fb_format(8, 8); break; case 15: case 16: format = drm_mode_legacy_fb_format(16, depth); break; case 32: format = drm_mode_legacy_fb_format(32, 24); break; default: drm_err(dev, "unsupported framebuffer depth %u\n", depth); return ERR_PTR(-EINVAL); } /* * DRM formats assume little-endian byte order. Update the format * if the scanout buffer uses big-endian ordering. */ if (big_endian) { switch (format) { case DRM_FORMAT_XRGB8888: format = DRM_FORMAT_BGRX8888; break; case DRM_FORMAT_ARGB8888: format = DRM_FORMAT_BGRA8888; break; case DRM_FORMAT_RGB565: format = DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN; break; case DRM_FORMAT_XRGB1555: format = DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN; break; default: break; } } info = drm_format_info(format); if (!info) { drm_err(dev, "cannot find framebuffer format for depth %u\n", depth); return ERR_PTR(-EINVAL); } return info;} static int display_read_u32_of(struct drm_device *dev, struct device_node *of_node, const char *name, u32 *value){ int ret = of_property_read_u32(of_node, name, value); if (ret) drm_err(dev, "cannot parse framebuffer %s: error %d\n", name, ret); return ret;} static bool display_get_big_endian_of(struct drm_device *dev, struct device_node *of_node){ bool big_endian; #ifdef __BIG_ENDIAN big_endian = !of_property_read_bool(of_node, "little-endian");#else big_endian = of_property_read_bool(of_node, "big-endian");#endif return big_endian;} static int display_get_width_of(struct drm_device *dev, struct device_node *of_node){ u32 width; int ret = display_read_u32_of(dev, of_node, "width", &width); if (ret) return ret; return display_get_validated_int0(dev, "width", width);} static int display_get_height_of(struct drm_device *dev, struct device_node *of_node){ u32 height; int ret = display_read_u32_of(dev, of_node, "height", &height); if (ret) return ret; return display_get_validated_int0(dev, "height", height);} static int display_get_depth_of(struct drm_device *dev, struct device_node *of_node){ u32 depth; int ret = display_read_u32_of(dev, of_node, "depth", &depth); if (ret) return ret; return display_get_validated_int0(dev, "depth", depth);} static int display_get_linebytes_of(struct drm_device *dev, struct device_node *of_node){ u32 linebytes; int ret = display_read_u32_of(dev, of_node, "linebytes", &linebytes); if (ret) return ret; return display_get_validated_int(dev, "linebytes", linebytes);} static u64 display_get_address_of(struct drm_device *dev, struct device_node *of_node){ u32 address; int ret; /* * Not all devices provide an address property, it's not * a bug if this fails. The driver will try to find the * framebuffer base address from the device's memory regions. */ ret = of_property_read_u32(of_node, "address", &address); if (ret) return OF_BAD_ADDR; return address;} static const u8 *display_get_edid_of(struct drm_device *dev, struct device_node *of_node, u8 buf[EDID_LENGTH]){ int ret = of_property_read_u8_array(of_node, "EDID", buf, EDID_LENGTH); if (ret) return NULL; return buf;} static bool is_avivo(u32 vendor, u32 device){ /* This will match most R5xx */ return (vendor == PCI_VENDOR_ID_ATI) && ((device >= PCI_VENDOR_ID_ATI_R520 && device < 0x7800) || (device >= PCI_VENDOR_ID_ATI_R600));} static enum ofdrm_model display_get_model_of(struct drm_device *dev, struct device_node *of_node){ enum ofdrm_model model = OFDRM_MODEL_UNKNOWN; if (of_node_name_prefix(of_node, "ATY,Rage128")) { model = OFDRM_MODEL_RAGE128; } else if (of_node_name_prefix(of_node, "ATY,RageM3pA") || of_node_name_prefix(of_node, "ATY,RageM3p12A")) { model = OFDRM_MODEL_RAGE_M3A; } else if (of_node_name_prefix(of_node, "ATY,RageM3pB")) { model = OFDRM_MODEL_RAGE_M3B; } else if (of_node_name_prefix(of_node, "ATY,Rage6")) { model = OFDRM_MODEL_RADEON; } else if (of_node_name_prefix(of_node, "ATY,")) { return OFDRM_MODEL_MACH64; } else if (of_device_is_compatible(of_node, "pci1014,b7") || of_device_is_compatible(of_node, "pci1014,21c")) { model = OFDRM_MODEL_GXT2000; } else if (of_node_name_prefix(of_node, "vga,Display-")) { struct device_node *of_parent; const __be32 *vendor_p, *device_p; /* Look for AVIVO initialized by SLOF */ of_parent = of_get_parent(of_node); vendor_p = of_get_property(of_parent, "vendor-id", NULL); device_p = of_get_property(of_parent, "device-id", NULL); if (vendor_p && device_p) { u32 vendor = be32_to_cpup(vendor_p); u32 device = be32_to_cpup(device_p); if (is_avivo(vendor, device)) model = OFDRM_MODEL_AVIVO; } of_node_put(of_parent); } else if (of_device_is_compatible(of_node, "qemu,std-vga")) { model = OFDRM_MODEL_QEMU; } return model;} /* * Open Firmware display device */ struct ofdrm_device; struct ofdrm_device_funcs { void __iomem *(*cmap_ioremap)(struct ofdrm_device *odev, struct device_node *of_node, u64 fb_bas); void (*cmap_write)(struct ofdrm_device *odev, unsigned char index, unsigned char r, unsigned char g, unsigned char b);}; struct ofdrm_device { struct drm_sysfb_device sysfb; const struct ofdrm_device_funcs *funcs; /* colormap */ void __iomem *cmap_base; u8 edid[EDID_LENGTH]; /* 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 ofdrm_device *ofdrm_device_of_dev(struct drm_device *dev){ return container_of(to_drm_sysfb_device(dev), struct ofdrm_device, sysfb);} /* * Hardware */ #if defined(CONFIG_PCI)static struct pci_dev *display_get_pci_dev_of(struct drm_device *dev, struct device_node *of_node){ const __be32 *vendor_p, *device_p; u32 vendor, device; struct pci_dev *pcidev; vendor_p = of_get_property(of_node, "vendor-id", NULL); if (!vendor_p) return ERR_PTR(-ENODEV); vendor = be32_to_cpup(vendor_p); device_p = of_get_property(of_node, "device-id", NULL); if (!device_p) return ERR_PTR(-ENODEV); device = be32_to_cpup(device_p); pcidev = pci_get_device(vendor, device, NULL); if (!pcidev) return ERR_PTR(-ENODEV); return pcidev;} static void ofdrm_pci_release(void *data){ struct pci_dev *pcidev = data; pci_disable_device(pcidev); pci_dev_put(pcidev);} static int ofdrm_device_init_pci(struct ofdrm_device *odev){ struct drm_device *dev = &odev->sysfb.dev; struct platform_device *pdev = to_platform_device(dev->dev); struct device_node *of_node = pdev->dev.of_node; struct pci_dev *pcidev; int ret; /* * Never use pcim_ or other managed helpers on the returned PCI * device. Otherwise, probing the native driver will fail for * resource conflicts. PCI-device management has to be tied to * the lifetime of the platform device until the native driver * takes over. */ pcidev = display_get_pci_dev_of(dev, of_node); if (IS_ERR(pcidev)) return 0; /* no PCI device found; ignore the error */ ret = pci_enable_device(pcidev); if (ret) { drm_err(dev, "pci_enable_device(%s) failed: %d\n", dev_name(&pcidev->dev), ret); pci_dev_put(pcidev); return ret; } ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev); if (ret) return ret; return 0;}#elsestatic int ofdrm_device_init_pci(struct ofdrm_device *odev){ return 0;}#endif /* * OF display settings */ static struct resource *ofdrm_find_fb_resource(struct ofdrm_device *odev, struct resource *fb_res){ struct platform_device *pdev = to_platform_device(odev->sysfb.dev.dev); struct resource *res, *max_res = NULL; u32 i; for (i = 0; pdev->num_resources; ++i) { res = platform_get_resource(pdev, IORESOURCE_MEM, i); if (!res) break; /* all resources processed */ if (resource_size(res) < resource_size(fb_res)) continue; /* resource too small */ if (fb_res->start && resource_contains(res, fb_res)) return res; /* resource contains framebuffer */ if (!max_res || resource_size(res) > resource_size(max_res)) max_res = res; /* store largest resource as fallback */ } return max_res;} /* * Colormap / Palette */ static void __iomem *get_cmap_address_of(struct ofdrm_device *odev, struct device_node *of_node, int bar_no, unsigned long offset, unsigned long size){ struct drm_device *dev = &odev->sysfb.dev; const __be32 *addr_p; u64 max_size, address; unsigned int flags; void __iomem *mem; addr_p = of_get_pci_address(of_node, bar_no, &max_size, &flags); if (!addr_p) addr_p = of_get_address(of_node, bar_no, &max_size, &flags); if (!addr_p) return IOMEM_ERR_PTR(-ENODEV); if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) return IOMEM_ERR_PTR(-ENODEV); if ((offset + size) >= max_size) return IOMEM_ERR_PTR(-ENODEV); address = of_translate_address(of_node, addr_p); if (address == OF_BAD_ADDR) return IOMEM_ERR_PTR(-ENODEV); mem = devm_ioremap(dev->dev, address + offset, size); if (!mem) return IOMEM_ERR_PTR(-ENOMEM); return mem;} static void __iomem *ofdrm_mach64_cmap_ioremap(struct ofdrm_device *odev, struct device_node *of_node, u64 fb_base){ struct drm_device *dev = &odev->sysfb.dev; u64 address; void __iomem *cmap_base; address = fb_base & 0xff000000ul; address += 0x7ff000; cmap_base = devm_ioremap(dev->dev, address, 0x1000); if (!cmap_base) return IOMEM_ERR_PTR(-ENOMEM); return cmap_base;} static void ofdrm_mach64_cmap_write(struct ofdrm_device *odev, unsigned char index, unsigned char r, unsigned char g, unsigned char b){ void __iomem *addr = odev->cmap_base + 0xcc0; void __iomem *data = odev->cmap_base + 0xcc0 + 1; writeb(index, addr); writeb(r, data); writeb(g, data); writeb(b, data);} static void __iomem *ofdrm_rage128_cmap_ioremap(struct ofdrm_device *odev, struct device_node *of_node, u64 fb_base){ return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff);} static void ofdrm_rage128_cmap_write(struct ofdrm_device *odev, unsigned char index, unsigned char r, unsigned char g, unsigned char b){ void __iomem *addr = odev->cmap_base + 0xb0;Lines 1–500 of 1170. Load more
// SPDX-License-Identifier: GPL-2.0-only #include <linux/aperture.h> #include <linux/of_address.h> #include <linux/overflow.h> #include <linux/pci.h> #include <linux/platform_device.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 "drm_sysfb_helper.h" #define DRIVER_NAME "ofdrm" #define DRIVER_DESC "DRM driver for OF platform devices" #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 #define PCI_VENDOR_ID_ATI_R520 0x7100 #define PCI_VENDOR_ID_ATI_R600 0x9400 #define OFDRM_GAMMA_LUT_SIZE 256 /* Definitions used by the Avivo palette */ #define AVIVO_DC_LUT_RW_SELECT 0x6480 #define AVIVO_DC_LUT_RW_MODE 0x6484 #define AVIVO_DC_LUT_RW_INDEX 0x6488 #define AVIVO_DC_LUT_SEQ_COLOR 0x648c #define AVIVO_DC_LUT_PWL_DATA 0x6490 #define AVIVO_DC_LUT_30_COLOR 0x6494 #define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498 #define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c #define AVIVO_DC_LUT_AUTOFILL 0x64a0 #define AVIVO_DC_LUTA_CONTROL 0x64c0 #define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4 #define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8 #define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc #define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0 #define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4 #define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8 #define AVIVO_DC_LUTB_CONTROL 0x6cc0 #define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4 #define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8 #define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc #define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0 #define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4 #define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8 enum ofdrm_model { OFDRM_MODEL_UNKNOWN, OFDRM_MODEL_MACH64, /* ATI Mach64 */ OFDRM_MODEL_RAGE128, /* ATI Rage128 */ OFDRM_MODEL_RAGE_M3A, /* ATI Rage Mobility M3 Head A */ OFDRM_MODEL_RAGE_M3B, /* ATI Rage Mobility M3 Head B */ OFDRM_MODEL_RADEON, /* ATI Radeon */ OFDRM_MODEL_GXT2000, /* IBM GXT2000 */ OFDRM_MODEL_AVIVO, /* ATI R5xx */ OFDRM_MODEL_QEMU, /* QEMU VGA */ }; /* * Helpers for display nodes */ static int display_get_validated_int(struct drm_device *dev, const char *name, uint32_t value) { return drm_sysfb_get_validated_int(dev, name, value, INT_MAX); } static int display_get_validated_int0(struct drm_device *dev, const char *name, uint32_t value) { return drm_sysfb_get_validated_int0(dev, name, value, INT_MAX); } static const struct drm_format_info *display_get_validated_format(struct drm_device *dev, u32 depth, bool big_endian) { const struct drm_format_info *info; u32 format; switch (depth) { case 8: format = drm_mode_legacy_fb_format(8, 8); break; case 15: case 16: format = drm_mode_legacy_fb_format(16, depth); break; case 32: format = drm_mode_legacy_fb_format(32, 24); break; default: drm_err(dev, "unsupported framebuffer depth %u\n", depth); return ERR_PTR(-EINVAL); } /* * DRM formats assume little-endian byte order. Update the format * if the scanout buffer uses big-endian ordering. */ if (big_endian) { switch (format) { case DRM_FORMAT_XRGB8888: format = DRM_FORMAT_BGRX8888; break; case DRM_FORMAT_ARGB8888: format = DRM_FORMAT_BGRA8888; break; case DRM_FORMAT_RGB565: format = DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN; break; case DRM_FORMAT_XRGB1555: format = DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN; break; default: break; } } info = drm_format_info(format); if (!info) { drm_err(dev, "cannot find framebuffer format for depth %u\n", depth); return ERR_PTR(-EINVAL); } return info; } static int display_read_u32_of(struct drm_device *dev, struct device_node *of_node, const char *name, u32 *value) { int ret = of_property_read_u32(of_node, name, value); if (ret) drm_err(dev, "cannot parse framebuffer %s: error %d\n", name, ret); return ret; } static bool display_get_big_endian_of(struct drm_device *dev, struct device_node *of_node) { bool big_endian; #ifdef __BIG_ENDIAN big_endian = !of_property_read_bool(of_node, "little-endian"); #else big_endian = of_property_read_bool(of_node, "big-endian"); #endif return big_endian; } static int display_get_width_of(struct drm_device *dev, struct device_node *of_node) { u32 width; int ret = display_read_u32_of(dev, of_node, "width", &width); if (ret) return ret; return display_get_validated_int0(dev, "width", width); } static int display_get_height_of(struct drm_device *dev, struct device_node *of_node) { u32 height; int ret = display_read_u32_of(dev, of_node, "height", &height); if (ret) return ret; return display_get_validated_int0(dev, "height", height); } static int display_get_depth_of(struct drm_device *dev, struct device_node *of_node) { u32 depth; int ret = display_read_u32_of(dev, of_node, "depth", &depth); if (ret) return ret; return display_get_validated_int0(dev, "depth", depth); } static int display_get_linebytes_of(struct drm_device *dev, struct device_node *of_node) { u32 linebytes; int ret = display_read_u32_of(dev, of_node, "linebytes", &linebytes); if (ret) return ret; return display_get_validated_int(dev, "linebytes", linebytes); } static u64 display_get_address_of(struct drm_device *dev, struct device_node *of_node) { u32 address; int ret; /* * Not all devices provide an address property, it's not * a bug if this fails. The driver will try to find the * framebuffer base address from the device's memory regions. */ ret = of_property_read_u32(of_node, "address", &address); if (ret) return OF_BAD_ADDR; return address; } static const u8 *display_get_edid_of(struct drm_device *dev, struct device_node *of_node, u8 buf[EDID_LENGTH]) { int ret = of_property_read_u8_array(of_node, "EDID", buf, EDID_LENGTH); if (ret) return NULL; return buf; } static bool is_avivo(u32 vendor, u32 device) { /* This will match most R5xx */ return (vendor == PCI_VENDOR_ID_ATI) && ((device >= PCI_VENDOR_ID_ATI_R520 && device < 0x7800) || (device >= PCI_VENDOR_ID_ATI_R600)); } static enum ofdrm_model display_get_model_of(struct drm_device *dev, struct device_node *of_node) { enum ofdrm_model model = OFDRM_MODEL_UNKNOWN; if (of_node_name_prefix(of_node, "ATY,Rage128")) { model = OFDRM_MODEL_RAGE128; } else if (of_node_name_prefix(of_node, "ATY,RageM3pA") || of_node_name_prefix(of_node, "ATY,RageM3p12A")) { model = OFDRM_MODEL_RAGE_M3A; } else if (of_node_name_prefix(of_node, "ATY,RageM3pB")) { model = OFDRM_MODEL_RAGE_M3B; } else if (of_node_name_prefix(of_node, "ATY,Rage6")) { model = OFDRM_MODEL_RADEON; } else if (of_node_name_prefix(of_node, "ATY,")) { return OFDRM_MODEL_MACH64; } else if (of_device_is_compatible(of_node, "pci1014,b7") || of_device_is_compatible(of_node, "pci1014,21c")) { model = OFDRM_MODEL_GXT2000; } else if (of_node_name_prefix(of_node, "vga,Display-")) { struct device_node *of_parent; const __be32 *vendor_p, *device_p; /* Look for AVIVO initialized by SLOF */ of_parent = of_get_parent(of_node); vendor_p = of_get_property(of_parent, "vendor-id", NULL); device_p = of_get_property(of_parent, "device-id", NULL); if (vendor_p && device_p) { u32 vendor = be32_to_cpup(vendor_p); u32 device = be32_to_cpup(device_p); if (is_avivo(vendor, device)) model = OFDRM_MODEL_AVIVO; } of_node_put(of_parent); } else if (of_device_is_compatible(of_node, "qemu,std-vga")) { model = OFDRM_MODEL_QEMU; } return model; } /* * Open Firmware display device */ struct ofdrm_device; struct ofdrm_device_funcs { void __iomem *(*cmap_ioremap)(struct ofdrm_device *odev, struct device_node *of_node, u64 fb_bas); void (*cmap_write)(struct ofdrm_device *odev, unsigned char index, unsigned char r, unsigned char g, unsigned char b); }; struct ofdrm_device { struct drm_sysfb_device sysfb; const struct ofdrm_device_funcs *funcs; /* colormap */ void __iomem *cmap_base; u8 edid[EDID_LENGTH]; /* 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 ofdrm_device *ofdrm_device_of_dev(struct drm_device *dev) { return container_of(to_drm_sysfb_device(dev), struct ofdrm_device, sysfb); } /* * Hardware */ #if defined(CONFIG_PCI) static struct pci_dev *display_get_pci_dev_of(struct drm_device *dev, struct device_node *of_node) { const __be32 *vendor_p, *device_p; u32 vendor, device; struct pci_dev *pcidev; vendor_p = of_get_property(of_node, "vendor-id", NULL); if (!vendor_p) return ERR_PTR(-ENODEV); vendor = be32_to_cpup(vendor_p); device_p = of_get_property(of_node, "device-id", NULL); if (!device_p) return ERR_PTR(-ENODEV); device = be32_to_cpup(device_p); pcidev = pci_get_device(vendor, device, NULL); if (!pcidev) return ERR_PTR(-ENODEV); return pcidev; } static void ofdrm_pci_release(void *data) { struct pci_dev *pcidev = data; pci_disable_device(pcidev); pci_dev_put(pcidev); } static int ofdrm_device_init_pci(struct ofdrm_device *odev) { struct drm_device *dev = &odev->sysfb.dev; struct platform_device *pdev = to_platform_device(dev->dev); struct device_node *of_node = pdev->dev.of_node; struct pci_dev *pcidev; int ret; /* * Never use pcim_ or other managed helpers on the returned PCI * device. Otherwise, probing the native driver will fail for * resource conflicts. PCI-device management has to be tied to * the lifetime of the platform device until the native driver * takes over. */ pcidev = display_get_pci_dev_of(dev, of_node); if (IS_ERR(pcidev)) return 0; /* no PCI device found; ignore the error */ ret = pci_enable_device(pcidev); if (ret) { drm_err(dev, "pci_enable_device(%s) failed: %d\n", dev_name(&pcidev->dev), ret); pci_dev_put(pcidev); return ret; } ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev); if (ret) return ret; return 0; } #else static int ofdrm_device_init_pci(struct ofdrm_device *odev) { return 0; } #endif /* * OF display settings */ static struct resource *ofdrm_find_fb_resource(struct ofdrm_device *odev, struct resource *fb_res) { struct platform_device *pdev = to_platform_device(odev->sysfb.dev.dev); struct resource *res, *max_res = NULL; u32 i; for (i = 0; pdev->num_resources; ++i) { res = platform_get_resource(pdev, IORESOURCE_MEM, i); if (!res) break; /* all resources processed */ if (resource_size(res) < resource_size(fb_res)) continue; /* resource too small */ if (fb_res->start && resource_contains(res, fb_res)) return res; /* resource contains framebuffer */ if (!max_res || resource_size(res) > resource_size(max_res)) max_res = res; /* store largest resource as fallback */ } return max_res; } /* * Colormap / Palette */ static void __iomem *get_cmap_address_of(struct ofdrm_device *odev, struct device_node *of_node, int bar_no, unsigned long offset, unsigned long size) { struct drm_device *dev = &odev->sysfb.dev; const __be32 *addr_p; u64 max_size, address; unsigned int flags; void __iomem *mem; addr_p = of_get_pci_address(of_node, bar_no, &max_size, &flags); if (!addr_p) addr_p = of_get_address(of_node, bar_no, &max_size, &flags); if (!addr_p) return IOMEM_ERR_PTR(-ENODEV); if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) return IOMEM_ERR_PTR(-ENODEV); if ((offset + size) >= max_size) return IOMEM_ERR_PTR(-ENODEV); address = of_translate_address(of_node, addr_p); if (address == OF_BAD_ADDR) return IOMEM_ERR_PTR(-ENODEV); mem = devm_ioremap(dev->dev, address + offset, size); if (!mem) return IOMEM_ERR_PTR(-ENOMEM); return mem; } static void __iomem *ofdrm_mach64_cmap_ioremap(struct ofdrm_device *odev, struct device_node *of_node, u64 fb_base) { struct drm_device *dev = &odev->sysfb.dev; u64 address; void __iomem *cmap_base; address = fb_base & 0xff000000ul; address += 0x7ff000; cmap_base = devm_ioremap(dev->dev, address, 0x1000); if (!cmap_base) return IOMEM_ERR_PTR(-ENOMEM); return cmap_base; } static void ofdrm_mach64_cmap_write(struct ofdrm_device *odev, unsigned char index, unsigned char r, unsigned char g, unsigned char b) { void __iomem *addr = odev->cmap_base + 0xcc0; void __iomem *data = odev->cmap_base + 0xcc0 + 1; writeb(index, addr); writeb(r, data); writeb(g, data); writeb(b, data); } static void __iomem *ofdrm_rage128_cmap_ioremap(struct ofdrm_device *odev, struct device_node *of_node, u64 fb_base) { return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff); } static void ofdrm_rage128_cmap_write(struct ofdrm_device *odev, unsigned char index, unsigned char r, unsigned char g, unsigned char b) { void __iomem *addr = odev->cmap_base + 0xb0;