^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);