162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#include <linux/export.h> 362306a36Sopenharmony_ci#include <linux/kernel.h> 462306a36Sopenharmony_ci#include <linux/init.h> 562306a36Sopenharmony_ci#include <linux/slab.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <asm/addrspace.h> 862306a36Sopenharmony_ci#include <asm/paccess.h> 962306a36Sopenharmony_ci#include <asm/gio_device.h> 1062306a36Sopenharmony_ci#include <asm/sgi/gio.h> 1162306a36Sopenharmony_ci#include <asm/sgi/hpc3.h> 1262306a36Sopenharmony_ci#include <asm/sgi/mc.h> 1362306a36Sopenharmony_ci#include <asm/sgi/ip22.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic struct bus_type gio_bus_type; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic struct { 1862306a36Sopenharmony_ci const char *name; 1962306a36Sopenharmony_ci __u8 id; 2062306a36Sopenharmony_ci} gio_name_table[] = { 2162306a36Sopenharmony_ci { .name = "SGI Impact", .id = 0x10 }, 2262306a36Sopenharmony_ci { .name = "Phobos G160", .id = 0x35 }, 2362306a36Sopenharmony_ci { .name = "Phobos G130", .id = 0x36 }, 2462306a36Sopenharmony_ci { .name = "Phobos G100", .id = 0x37 }, 2562306a36Sopenharmony_ci { .name = "Set Engineering GFE", .id = 0x38 }, 2662306a36Sopenharmony_ci /* fake IDs */ 2762306a36Sopenharmony_ci { .name = "SGI Newport", .id = 0x7e }, 2862306a36Sopenharmony_ci { .name = "SGI GR2/GR3", .id = 0x7f }, 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void gio_bus_release(struct device *dev) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci kfree(dev); 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic struct device gio_bus = { 3762306a36Sopenharmony_ci .init_name = "gio", 3862306a36Sopenharmony_ci .release = &gio_bus_release, 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/** 4262306a36Sopenharmony_ci * gio_match_device - Tell if an of_device structure has a matching 4362306a36Sopenharmony_ci * gio_match structure 4462306a36Sopenharmony_ci * @ids: array of of device match structures to search in 4562306a36Sopenharmony_ci * @dev: the of device structure to match against 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * Used by a driver to check whether an of_device present in the 4862306a36Sopenharmony_ci * system is in its list of supported devices. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_cistatic const struct gio_device_id * 5162306a36Sopenharmony_cigio_match_device(const struct gio_device_id *match, 5262306a36Sopenharmony_ci const struct gio_device *dev) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci const struct gio_device_id *ids; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci for (ids = match; ids->id != 0xff; ids++) 5762306a36Sopenharmony_ci if (ids->id == dev->id.id) 5862306a36Sopenharmony_ci return ids; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return NULL; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct gio_device *gio_dev_get(struct gio_device *dev) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct device *tmp; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (!dev) 6862306a36Sopenharmony_ci return NULL; 6962306a36Sopenharmony_ci tmp = get_device(&dev->dev); 7062306a36Sopenharmony_ci if (tmp) 7162306a36Sopenharmony_ci return to_gio_device(tmp); 7262306a36Sopenharmony_ci else 7362306a36Sopenharmony_ci return NULL; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gio_dev_get); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_civoid gio_dev_put(struct gio_device *dev) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci if (dev) 8062306a36Sopenharmony_ci put_device(&dev->dev); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gio_dev_put); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/** 8562306a36Sopenharmony_ci * gio_release_dev - free an gio device structure when all users of it are finished. 8662306a36Sopenharmony_ci * @dev: device that's been disconnected 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * Will be called only by the device core when all users of this gio device are 8962306a36Sopenharmony_ci * done. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_civoid gio_release_dev(struct device *dev) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct gio_device *giodev; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci giodev = to_gio_device(dev); 9662306a36Sopenharmony_ci kfree(giodev); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gio_release_dev); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ciint gio_device_register(struct gio_device *giodev) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci giodev->dev.bus = &gio_bus_type; 10362306a36Sopenharmony_ci giodev->dev.parent = &gio_bus; 10462306a36Sopenharmony_ci return device_register(&giodev->dev); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gio_device_register); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_civoid gio_device_unregister(struct gio_device *giodev) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci device_unregister(&giodev->dev); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gio_device_unregister); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int gio_bus_match(struct device *dev, struct device_driver *drv) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct gio_device *gio_dev = to_gio_device(dev); 11762306a36Sopenharmony_ci struct gio_driver *gio_drv = to_gio_driver(drv); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return gio_match_device(gio_drv->id_table, gio_dev) != NULL; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic int gio_device_probe(struct device *dev) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci int error = -ENODEV; 12562306a36Sopenharmony_ci struct gio_driver *drv; 12662306a36Sopenharmony_ci struct gio_device *gio_dev; 12762306a36Sopenharmony_ci const struct gio_device_id *match; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci drv = to_gio_driver(dev->driver); 13062306a36Sopenharmony_ci gio_dev = to_gio_device(dev); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (!drv->probe) 13362306a36Sopenharmony_ci return error; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci gio_dev_get(gio_dev); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci match = gio_match_device(drv->id_table, gio_dev); 13862306a36Sopenharmony_ci if (match) 13962306a36Sopenharmony_ci error = drv->probe(gio_dev, match); 14062306a36Sopenharmony_ci if (error) 14162306a36Sopenharmony_ci gio_dev_put(gio_dev); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return error; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic void gio_device_remove(struct device *dev) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct gio_device *gio_dev = to_gio_device(dev); 14962306a36Sopenharmony_ci struct gio_driver *drv = to_gio_driver(dev->driver); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (drv->remove) 15262306a36Sopenharmony_ci drv->remove(gio_dev); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic void gio_device_shutdown(struct device *dev) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct gio_device *gio_dev = to_gio_device(dev); 15862306a36Sopenharmony_ci struct gio_driver *drv = to_gio_driver(dev->driver); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (dev->driver && drv->shutdown) 16162306a36Sopenharmony_ci drv->shutdown(gio_dev); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic ssize_t modalias_show(struct device *dev, struct device_attribute *a, 16562306a36Sopenharmony_ci char *buf) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct gio_device *gio_dev = to_gio_device(dev); 16862306a36Sopenharmony_ci int len = snprintf(buf, PAGE_SIZE, "gio:%x\n", gio_dev->id.id); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(modalias); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic ssize_t name_show(struct device *dev, 17562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci struct gio_device *giodev; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci giodev = to_gio_device(dev); 18062306a36Sopenharmony_ci return sprintf(buf, "%s", giodev->name); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(name); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic ssize_t id_show(struct device *dev, 18562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct gio_device *giodev; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci giodev = to_gio_device(dev); 19062306a36Sopenharmony_ci return sprintf(buf, "%x", giodev->id.id); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(id); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic struct attribute *gio_dev_attrs[] = { 19562306a36Sopenharmony_ci &dev_attr_modalias.attr, 19662306a36Sopenharmony_ci &dev_attr_name.attr, 19762306a36Sopenharmony_ci &dev_attr_id.attr, 19862306a36Sopenharmony_ci NULL, 19962306a36Sopenharmony_ci}; 20062306a36Sopenharmony_ciATTRIBUTE_GROUPS(gio_dev); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic int gio_device_uevent(const struct device *dev, struct kobj_uevent_env *env) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci const struct gio_device *gio_dev = to_gio_device(dev); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci add_uevent_var(env, "MODALIAS=gio:%x", gio_dev->id.id); 20762306a36Sopenharmony_ci return 0; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ciint gio_register_driver(struct gio_driver *drv) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci /* initialize common driver fields */ 21362306a36Sopenharmony_ci if (!drv->driver.name) 21462306a36Sopenharmony_ci drv->driver.name = drv->name; 21562306a36Sopenharmony_ci if (!drv->driver.owner) 21662306a36Sopenharmony_ci drv->driver.owner = drv->owner; 21762306a36Sopenharmony_ci drv->driver.bus = &gio_bus_type; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* register with core */ 22062306a36Sopenharmony_ci return driver_register(&drv->driver); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gio_register_driver); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_civoid gio_unregister_driver(struct gio_driver *drv) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci driver_unregister(&drv->driver); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gio_unregister_driver); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_civoid gio_set_master(struct gio_device *dev) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci u32 tmp = sgimc->giopar; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci switch (dev->slotno) { 23562306a36Sopenharmony_ci case 0: 23662306a36Sopenharmony_ci tmp |= SGIMC_GIOPAR_MASTERGFX; 23762306a36Sopenharmony_ci break; 23862306a36Sopenharmony_ci case 1: 23962306a36Sopenharmony_ci tmp |= SGIMC_GIOPAR_MASTEREXP0; 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci case 2: 24262306a36Sopenharmony_ci tmp |= SGIMC_GIOPAR_MASTEREXP1; 24362306a36Sopenharmony_ci break; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci sgimc->giopar = tmp; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gio_set_master); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_civoid ip22_gio_set_64bit(int slotno) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci u32 tmp = sgimc->giopar; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci switch (slotno) { 25462306a36Sopenharmony_ci case 0: 25562306a36Sopenharmony_ci tmp |= SGIMC_GIOPAR_GFX64; 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci case 1: 25862306a36Sopenharmony_ci tmp |= SGIMC_GIOPAR_EXP064; 25962306a36Sopenharmony_ci break; 26062306a36Sopenharmony_ci case 2: 26162306a36Sopenharmony_ci tmp |= SGIMC_GIOPAR_EXP164; 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci sgimc->giopar = tmp; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int ip22_gio_id(unsigned long addr, u32 *res) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci u8 tmp8; 27062306a36Sopenharmony_ci u8 tmp16; 27162306a36Sopenharmony_ci u32 tmp32; 27262306a36Sopenharmony_ci u8 *ptr8; 27362306a36Sopenharmony_ci u16 *ptr16; 27462306a36Sopenharmony_ci u32 *ptr32; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci ptr32 = (void *)CKSEG1ADDR(addr); 27762306a36Sopenharmony_ci if (!get_dbe(tmp32, ptr32)) { 27862306a36Sopenharmony_ci /* 27962306a36Sopenharmony_ci * We got no DBE, but this doesn't mean anything. 28062306a36Sopenharmony_ci * If GIO is pipelined (which can't be disabled 28162306a36Sopenharmony_ci * for GFX slot) we don't get a DBE, but we see 28262306a36Sopenharmony_ci * the transfer size as data. So we do an 8bit 28362306a36Sopenharmony_ci * and a 16bit access and check whether the common 28462306a36Sopenharmony_ci * data matches 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_ci ptr8 = (void *)CKSEG1ADDR(addr + 3); 28762306a36Sopenharmony_ci if (get_dbe(tmp8, ptr8)) { 28862306a36Sopenharmony_ci /* 28962306a36Sopenharmony_ci * 32bit access worked, but 8bit doesn't 29062306a36Sopenharmony_ci * so we don't see phantom reads on 29162306a36Sopenharmony_ci * a pipelined bus, but a real card which 29262306a36Sopenharmony_ci * doesn't support 8 bit reads 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ci *res = tmp32; 29562306a36Sopenharmony_ci return 1; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci ptr16 = (void *)CKSEG1ADDR(addr + 2); 29862306a36Sopenharmony_ci get_dbe(tmp16, ptr16); 29962306a36Sopenharmony_ci if (tmp8 == (tmp16 & 0xff) && 30062306a36Sopenharmony_ci tmp8 == (tmp32 & 0xff) && 30162306a36Sopenharmony_ci tmp16 == (tmp32 & 0xffff)) { 30262306a36Sopenharmony_ci *res = tmp32; 30362306a36Sopenharmony_ci return 1; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci return 0; /* nothing here */ 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci#define HQ2_MYSTERY_OFFS 0x6A07C 31062306a36Sopenharmony_ci#define NEWPORT_USTATUS_OFFS 0xF133C 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic int ip22_is_gr2(unsigned long addr) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci u32 tmp; 31562306a36Sopenharmony_ci u32 *ptr; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* HQ2 only allows 32bit accesses */ 31862306a36Sopenharmony_ci ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS); 31962306a36Sopenharmony_ci if (!get_dbe(tmp, ptr)) { 32062306a36Sopenharmony_ci if (tmp == 0xdeadbeef) 32162306a36Sopenharmony_ci return 1; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void ip22_check_gio(int slotno, unsigned long addr, int irq) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci const char *name = "Unknown"; 33062306a36Sopenharmony_ci struct gio_device *gio_dev; 33162306a36Sopenharmony_ci u32 tmp; 33262306a36Sopenharmony_ci __u8 id; 33362306a36Sopenharmony_ci int i; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* first look for GR2/GR3 by checking mystery register */ 33662306a36Sopenharmony_ci if (ip22_is_gr2(addr)) 33762306a36Sopenharmony_ci tmp = 0x7f; 33862306a36Sopenharmony_ci else { 33962306a36Sopenharmony_ci if (!ip22_gio_id(addr, &tmp)) { 34062306a36Sopenharmony_ci /* 34162306a36Sopenharmony_ci * no GIO signature at start address of slot 34262306a36Sopenharmony_ci * since Newport doesn't have one, we check if 34362306a36Sopenharmony_ci * user status register is readable 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_ci if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp)) 34662306a36Sopenharmony_ci tmp = 0x7e; 34762306a36Sopenharmony_ci else 34862306a36Sopenharmony_ci tmp = 0; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci if (tmp) { 35262306a36Sopenharmony_ci id = GIO_ID(tmp); 35362306a36Sopenharmony_ci if (tmp & GIO_32BIT_ID) { 35462306a36Sopenharmony_ci if (tmp & GIO_64BIT_IFACE) 35562306a36Sopenharmony_ci ip22_gio_set_64bit(slotno); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) { 35862306a36Sopenharmony_ci if (id == gio_name_table[i].id) { 35962306a36Sopenharmony_ci name = gio_name_table[i].name; 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci printk(KERN_INFO "GIO: slot %d : %s (id %x)\n", 36462306a36Sopenharmony_ci slotno, name, id); 36562306a36Sopenharmony_ci gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL); 36662306a36Sopenharmony_ci if (!gio_dev) 36762306a36Sopenharmony_ci return; 36862306a36Sopenharmony_ci gio_dev->name = name; 36962306a36Sopenharmony_ci gio_dev->slotno = slotno; 37062306a36Sopenharmony_ci gio_dev->id.id = id; 37162306a36Sopenharmony_ci gio_dev->resource.start = addr; 37262306a36Sopenharmony_ci gio_dev->resource.end = addr + 0x3fffff; 37362306a36Sopenharmony_ci gio_dev->resource.flags = IORESOURCE_MEM; 37462306a36Sopenharmony_ci gio_dev->irq = irq; 37562306a36Sopenharmony_ci dev_set_name(&gio_dev->dev, "%d", slotno); 37662306a36Sopenharmony_ci gio_device_register(gio_dev); 37762306a36Sopenharmony_ci } else 37862306a36Sopenharmony_ci printk(KERN_INFO "GIO: slot %d : Empty\n", slotno); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic struct bus_type gio_bus_type = { 38262306a36Sopenharmony_ci .name = "gio", 38362306a36Sopenharmony_ci .dev_groups = gio_dev_groups, 38462306a36Sopenharmony_ci .match = gio_bus_match, 38562306a36Sopenharmony_ci .probe = gio_device_probe, 38662306a36Sopenharmony_ci .remove = gio_device_remove, 38762306a36Sopenharmony_ci .shutdown = gio_device_shutdown, 38862306a36Sopenharmony_ci .uevent = gio_device_uevent, 38962306a36Sopenharmony_ci}; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic struct resource gio_bus_resource = { 39262306a36Sopenharmony_ci .start = GIO_SLOT_GFX_BASE, 39362306a36Sopenharmony_ci .end = GIO_SLOT_GFX_BASE + 0x9fffff, 39462306a36Sopenharmony_ci .name = "GIO Bus", 39562306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 39662306a36Sopenharmony_ci}; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ciint __init ip22_gio_init(void) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci unsigned int pbdma __maybe_unused; 40162306a36Sopenharmony_ci int ret; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci ret = device_register(&gio_bus); 40462306a36Sopenharmony_ci if (ret) { 40562306a36Sopenharmony_ci put_device(&gio_bus); 40662306a36Sopenharmony_ci return ret; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci ret = bus_register(&gio_bus_type); 41062306a36Sopenharmony_ci if (!ret) { 41162306a36Sopenharmony_ci request_resource(&iomem_resource, &gio_bus_resource); 41262306a36Sopenharmony_ci printk(KERN_INFO "GIO: Probing bus...\n"); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (ip22_is_fullhouse()) { 41562306a36Sopenharmony_ci /* Indigo2 */ 41662306a36Sopenharmony_ci ip22_check_gio(0, GIO_SLOT_GFX_BASE, SGI_GIO_1_IRQ); 41762306a36Sopenharmony_ci ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIO_1_IRQ); 41862306a36Sopenharmony_ci } else { 41962306a36Sopenharmony_ci /* Indy/Challenge S */ 42062306a36Sopenharmony_ci if (get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) 42162306a36Sopenharmony_ci ip22_check_gio(0, GIO_SLOT_GFX_BASE, 42262306a36Sopenharmony_ci SGI_GIO_0_IRQ); 42362306a36Sopenharmony_ci ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIOEXP0_IRQ); 42462306a36Sopenharmony_ci ip22_check_gio(2, GIO_SLOT_EXP1_BASE, SGI_GIOEXP1_IRQ); 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci } else 42762306a36Sopenharmony_ci device_unregister(&gio_bus); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci return ret; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cisubsys_initcall(ip22_gio_init); 433