Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) #include <asm/addrspace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <asm/paccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <asm/gio_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <asm/sgi/gio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <asm/sgi/hpc3.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <asm/sgi/mc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <asm/sgi/ip22.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) static struct bus_type gio_bus_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) static struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 	const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) 	__u8	   id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) } gio_name_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 	{ .name = "SGI Impact", .id = 0x10 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	{ .name = "Phobos G160", .id = 0x35 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 	{ .name = "Phobos G130", .id = 0x36 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	{ .name = "Phobos G100", .id = 0x37 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 	{ .name = "Set Engineering GFE", .id = 0x38 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 	/* fake IDs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 	{ .name = "SGI Newport", .id = 0x7e },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 	{ .name = "SGI GR2/GR3", .id = 0x7f },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) static void gio_bus_release(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 	kfree(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) static struct device gio_bus = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	.init_name = "gio",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	.release = &gio_bus_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42)  * gio_match_device - Tell if an of_device structure has a matching
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43)  * gio_match structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44)  * @ids: array of of device match structures to search in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45)  * @dev: the of device structure to match against
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47)  * Used by a driver to check whether an of_device present in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48)  * system is in its list of supported devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) static const struct gio_device_id *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) gio_match_device(const struct gio_device_id *match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 		 const struct gio_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	const struct gio_device_id *ids;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	for (ids = match; ids->id != 0xff; ids++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 		if (ids->id == dev->id.id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 			return ids;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) struct gio_device *gio_dev_get(struct gio_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	struct device *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	if (!dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	tmp = get_device(&dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	if (tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		return to_gio_device(tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) EXPORT_SYMBOL_GPL(gio_dev_get);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) void gio_dev_put(struct gio_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	if (dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 		put_device(&dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) EXPORT_SYMBOL_GPL(gio_dev_put);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85)  * gio_release_dev - free an gio device structure when all users of it are finished.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86)  * @dev: device that's been disconnected
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88)  * Will be called only by the device core when all users of this gio device are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89)  * done.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) void gio_release_dev(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	struct gio_device *giodev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	giodev = to_gio_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	kfree(giodev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) EXPORT_SYMBOL_GPL(gio_release_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) int gio_device_register(struct gio_device *giodev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	giodev->dev.bus = &gio_bus_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	giodev->dev.parent = &gio_bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	return device_register(&giodev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) EXPORT_SYMBOL_GPL(gio_device_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) void gio_device_unregister(struct gio_device *giodev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	device_unregister(&giodev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) EXPORT_SYMBOL_GPL(gio_device_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static int gio_bus_match(struct device *dev, struct device_driver *drv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	struct gio_device *gio_dev = to_gio_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	struct gio_driver *gio_drv = to_gio_driver(drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	return gio_match_device(gio_drv->id_table, gio_dev) != NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static int gio_device_probe(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	int error = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	struct gio_driver *drv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	struct gio_device *gio_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	const struct gio_device_id *match;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	drv = to_gio_driver(dev->driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	gio_dev = to_gio_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	if (!drv->probe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	gio_dev_get(gio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	match = gio_match_device(drv->id_table, gio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	if (match)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 		error = drv->probe(gio_dev, match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 		gio_dev_put(gio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static int gio_device_remove(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	struct gio_device *gio_dev = to_gio_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	struct gio_driver *drv = to_gio_driver(dev->driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	if (dev->driver && drv->remove)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 		drv->remove(gio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) static void gio_device_shutdown(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	struct gio_device *gio_dev = to_gio_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	struct gio_driver *drv = to_gio_driver(dev->driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	if (dev->driver && drv->shutdown)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 		drv->shutdown(gio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 			     char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	struct gio_device *gio_dev = to_gio_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	int len = snprintf(buf, PAGE_SIZE, "gio:%x\n", gio_dev->id.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static DEVICE_ATTR_RO(modalias);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) static ssize_t name_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 			 struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	struct gio_device *giodev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	giodev = to_gio_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	return sprintf(buf, "%s", giodev->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) static DEVICE_ATTR_RO(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static ssize_t id_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 		       struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	struct gio_device *giodev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	giodev = to_gio_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	return sprintf(buf, "%x", giodev->id.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) static DEVICE_ATTR_RO(id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) static struct attribute *gio_dev_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	&dev_attr_modalias.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	&dev_attr_name.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	&dev_attr_id.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) ATTRIBUTE_GROUPS(gio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) static int gio_device_uevent(struct device *dev, struct kobj_uevent_env *env)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	struct gio_device *gio_dev = to_gio_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	add_uevent_var(env, "MODALIAS=gio:%x", gio_dev->id.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) int gio_register_driver(struct gio_driver *drv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	/* initialize common driver fields */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 	if (!drv->driver.name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 		drv->driver.name = drv->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 	if (!drv->driver.owner)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 		drv->driver.owner = drv->owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	drv->driver.bus = &gio_bus_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	/* register with core */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	return driver_register(&drv->driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) EXPORT_SYMBOL_GPL(gio_register_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) void gio_unregister_driver(struct gio_driver *drv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 	driver_unregister(&drv->driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) EXPORT_SYMBOL_GPL(gio_unregister_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) void gio_set_master(struct gio_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	u32 tmp = sgimc->giopar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	switch (dev->slotno) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 		tmp |= SGIMC_GIOPAR_MASTERGFX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 		tmp |= SGIMC_GIOPAR_MASTEREXP0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 		tmp |= SGIMC_GIOPAR_MASTEREXP1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	sgimc->giopar = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) EXPORT_SYMBOL_GPL(gio_set_master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) void ip22_gio_set_64bit(int slotno)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	u32 tmp = sgimc->giopar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	switch (slotno) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 		tmp |= SGIMC_GIOPAR_GFX64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 		tmp |= SGIMC_GIOPAR_EXP064;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 		tmp |= SGIMC_GIOPAR_EXP164;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	sgimc->giopar = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) static int ip22_gio_id(unsigned long addr, u32 *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	u8 tmp8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	u8 tmp16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	u32 tmp32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	u8 *ptr8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	u16 *ptr16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	u32 *ptr32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 	ptr32 = (void *)CKSEG1ADDR(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 	if (!get_dbe(tmp32, ptr32)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 		 * We got no DBE, but this doesn't mean anything.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 		 * If GIO is pipelined (which can't be disabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 		 * for GFX slot) we don't get a DBE, but we see
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 		 * the transfer size as data. So we do an 8bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 		 * and a 16bit access and check whether the common
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 		 * data matches
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 		ptr8 = (void *)CKSEG1ADDR(addr + 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 		if (get_dbe(tmp8, ptr8)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 			/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 			 * 32bit access worked, but 8bit doesn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 			 * so we don't see phantom reads on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 			 * a pipelined bus, but a real card which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 			 * doesn't support 8 bit reads
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 			 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 			*res = tmp32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 			return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 		ptr16 = (void *)CKSEG1ADDR(addr + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 		get_dbe(tmp16, ptr16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 		if (tmp8 == (tmp16 & 0xff) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 		    tmp8 == (tmp32 & 0xff) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 		    tmp16 == (tmp32 & 0xffff)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 			*res = tmp32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 			return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	return 0; /* nothing here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) #define HQ2_MYSTERY_OFFS       0x6A07C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) #define NEWPORT_USTATUS_OFFS   0xF133C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) static int ip22_is_gr2(unsigned long addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 	u32 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	u32 *ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 	/* HQ2 only allows 32bit accesses */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 	ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	if (!get_dbe(tmp, ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 		if (tmp == 0xdeadbeef)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 			return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) static void ip22_check_gio(int slotno, unsigned long addr, int irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 	const char *name = "Unknown";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 	struct gio_device *gio_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	u32 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	__u8 id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	/* first look for GR2/GR3 by checking mystery register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	if (ip22_is_gr2(addr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 		tmp = 0x7f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 		if (!ip22_gio_id(addr, &tmp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 			/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 			 * no GIO signature at start address of slot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 			 * since Newport doesn't have one, we check if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 			 * user status register is readable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 			 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 			if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 				tmp = 0x7e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 			else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 				tmp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 	if (tmp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 		id = GIO_ID(tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 		if (tmp & GIO_32BIT_ID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 			if (tmp & GIO_64BIT_IFACE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 				ip22_gio_set_64bit(slotno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 		for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 			if (id == gio_name_table[i].id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 				name = gio_name_table[i].name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 		printk(KERN_INFO "GIO: slot %d : %s (id %x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 		       slotno, name, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 		gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 		gio_dev->name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 		gio_dev->slotno = slotno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 		gio_dev->id.id = id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 		gio_dev->resource.start = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 		gio_dev->resource.end = addr + 0x3fffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 		gio_dev->resource.flags = IORESOURCE_MEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 		gio_dev->irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 		dev_set_name(&gio_dev->dev, "%d", slotno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 		gio_device_register(gio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 		printk(KERN_INFO "GIO: slot %d : Empty\n", slotno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) static struct bus_type gio_bus_type = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 	.name	   = "gio",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 	.dev_groups = gio_dev_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 	.match	   = gio_bus_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 	.probe	   = gio_device_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	.remove	   = gio_device_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	.shutdown  = gio_device_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	.uevent	   = gio_device_uevent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) static struct resource gio_bus_resource = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 	.start = GIO_SLOT_GFX_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 	.end   = GIO_SLOT_GFX_BASE + 0x9fffff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 	.name  = "GIO Bus",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 	.flags = IORESOURCE_MEM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) int __init ip22_gio_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 	unsigned int pbdma __maybe_unused;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	ret = device_register(&gio_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 		put_device(&gio_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 	ret = bus_register(&gio_bus_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 	if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 		request_resource(&iomem_resource, &gio_bus_resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 		printk(KERN_INFO "GIO: Probing bus...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 		if (ip22_is_fullhouse()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 			/* Indigo2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 			ip22_check_gio(0, GIO_SLOT_GFX_BASE, SGI_GIO_1_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 			ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIO_1_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 			/* Indy/Challenge S */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 			if (get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 				ip22_check_gio(0, GIO_SLOT_GFX_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 					       SGI_GIO_0_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 			ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIOEXP0_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 			ip22_check_gio(2, GIO_SLOT_EXP1_BASE, SGI_GIOEXP1_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 		device_unregister(&gio_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) subsys_initcall(ip22_gio_init);