1170 lines · 31.0 KB · C
RawDownload
// 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.