linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] GIO bus support for SGI IP22/28
@ 2011-10-20 22:19 Thomas Bogendoerfer
  2011-10-30 15:53 ` Florian Tobias Schandinat
  2011-10-30 20:43 ` Joshua Kinard
  0 siblings, 2 replies; 6+ messages in thread
From: Thomas Bogendoerfer @ 2011-10-20 22:19 UTC (permalink / raw)
  To: linux-mips, linux-fbdev; +Cc: ralf, FlorianSchandinat

SGI IP22/IP28 machines have GIO busses for adding graphics and other
extension cards. This patch adds support for GIO driver/device
handling and converts the newport console driver to a GIO driver.

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
---

Changes to last version:
- use EXPORT_SYMBOL_GPL
- ChallengeS has only 2 slots
- use subsys_initcall for gio detection

Florian, the whole patch should go through the MIPS tree, if it's ok for
you.

 arch/mips/include/asm/gio_device.h  |   56 +++++
 arch/mips/sgi-ip22/Makefile         |    2 +-
 arch/mips/sgi-ip22/ip22-gio.c       |  414 +++++++++++++++++++++++++++++++++++
 arch/mips/sgi-ip22/ip22-mc.c        |   10 +-
 arch/mips/sgi-ip22/ip22-setup.c     |   21 --
 drivers/video/console/newport_con.c |   61 ++++--
 6 files changed, 518 insertions(+), 46 deletions(-)

diff --git a/arch/mips/include/asm/gio_device.h b/arch/mips/include/asm/gio_device.h
new file mode 100644
index 0000000..5437c84
--- /dev/null
+++ b/arch/mips/include/asm/gio_device.h
@@ -0,0 +1,56 @@
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+struct gio_device_id {
+	__u8 id;
+};
+
+struct gio_device {
+	struct device   dev;
+	struct resource resource;
+	unsigned int    irq;
+	unsigned int    slotno;
+
+	const char      *name;
+	struct gio_device_id id;
+	unsigned        id32:1;
+	unsigned        gio64:1;
+};
+#define to_gio_device(d) container_of(d, struct gio_device, dev)
+
+struct gio_driver {
+	const char    *name;
+	struct module *owner;
+	const struct gio_device_id *id_table;
+
+	int  (*probe)(struct gio_device *, const struct gio_device_id *);
+	void (*remove)(struct gio_device *);
+	int  (*suspend)(struct gio_device *, pm_message_t);
+	int  (*resume)(struct gio_device *);
+	void (*shutdown)(struct gio_device *);
+
+	struct device_driver driver;
+};
+#define to_gio_driver(drv) container_of(drv, struct gio_driver, driver)
+
+extern const struct gio_device_id *gio_match_device(const struct gio_device_id *,
+						    const struct gio_device *);
+extern struct gio_device *gio_dev_get(struct gio_device *);
+extern void gio_dev_put(struct gio_device *);
+
+extern int gio_device_register(struct gio_device *);
+extern void gio_device_unregister(struct gio_device *);
+extern void gio_release_dev(struct device *);
+
+static inline void gio_device_free(struct gio_device *dev)
+{
+	gio_release_dev(&dev->dev);
+}
+
+extern int gio_register_driver(struct gio_driver *);
+extern void gio_unregister_driver(struct gio_driver *);
+
+#define gio_get_drvdata(_dev)        drv_get_drvdata(&(_dev)->dev)
+#define gio_set_drvdata(_dev, data)  drv_set_drvdata(&(_dev)->dev, (data))
+
+extern void gio_set_master(struct gio_device *);
diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile
index cc53849..411cda9 100644
--- a/arch/mips/sgi-ip22/Makefile
+++ b/arch/mips/sgi-ip22/Makefile
@@ -4,7 +4,7 @@
 #
 
 obj-y	+= ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \
-	   ip22-platform.o ip22-reset.o ip22-setup.o
+	   ip22-platform.o ip22-reset.o ip22-setup.o ip22-gio.o
 
 obj-$(CONFIG_SGI_IP22) += ip22-berr.o
 obj-$(CONFIG_SGI_IP28) += ip28-berr.o
diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c
new file mode 100644
index 0000000..d841529
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-gio.c
@@ -0,0 +1,414 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include <asm/addrspace.h>
+#include <asm/paccess.h>
+#include <asm/gio_device.h>
+#include <asm/sgi/gio.h>
+#include <asm/sgi/hpc3.h>
+#include <asm/sgi/mc.h>
+#include <asm/sgi/ip22.h>
+
+static struct bus_type gio_bus;
+
+static struct {
+	const char *name;
+	__u8       id;
+} gio_name_table[] = {
+	{ .name = "SGI Impact", .id = 0x10 },
+	{ .name = "Phobos G160", .id = 0x35 },
+	/* fake IDs */
+	{ .name = "SGI Newport", .id = 0x7e },
+	{ .name = "SGI GR2/GR3", .id = 0x7f },
+};
+
+/**
+ * gio_match_device - Tell if an of_device structure has a matching
+ * gio_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct gio_device_id *gio_match_device(const struct gio_device_id *match,
+		     const struct gio_device *dev)
+{
+	const struct gio_device_id *ids;
+
+	for (ids = match; ids->id != 0xff; ids++)
+		if (ids->id = dev->id.id)
+			return ids;
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(gio_match_device);
+
+struct gio_device *gio_dev_get(struct gio_device *dev)
+{
+	struct device *tmp;
+
+	if (!dev)
+		return NULL;
+	tmp = get_device(&dev->dev);
+	if (tmp)
+		return to_gio_device(tmp);
+	else
+		return NULL;
+}
+EXPORT_SYMBOL_GPL(gio_dev_get);
+
+void gio_dev_put(struct gio_device *dev)
+{
+	if (dev)
+		put_device(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(gio_dev_put);
+
+static ssize_t dev_show_name(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct gio_device *giodev;
+
+	giodev = to_gio_device(dev);
+	return sprintf(buf, "%s", giodev->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, dev_show_name, NULL);
+
+static ssize_t dev_show_id(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct gio_device *giodev;
+
+	giodev = to_gio_device(dev);
+	return sprintf(buf, "%x", giodev->id.id);
+}
+
+static DEVICE_ATTR(id, S_IRUGO, dev_show_id, NULL);
+
+/**
+ * gio_release_dev - free an gio device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this gio device are
+ * done.
+ */
+void gio_release_dev(struct device *dev)
+{
+	struct gio_device *giodev;
+
+	giodev = to_gio_device(dev);
+	kfree(giodev);
+}
+EXPORT_SYMBOL_GPL(gio_release_dev);
+
+int gio_device_register(struct gio_device *giodev)
+{
+	int rc;
+
+	giodev->dev.bus = &gio_bus;
+	rc = device_register(&giodev->dev);
+	if (rc)
+		return rc;
+
+	rc = device_create_file(&giodev->dev, &dev_attr_name);
+	if (rc)
+		goto err;
+	rc = device_create_file(&giodev->dev, &dev_attr_id);
+	if (rc)
+		goto err;
+
+	return 0;
+
+err:
+	device_unregister(&giodev->dev);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(gio_device_register);
+
+void gio_device_unregister(struct gio_device *giodev)
+{
+	device_remove_file(&giodev->dev, &dev_attr_id);
+	device_remove_file(&giodev->dev, &dev_attr_name);
+	device_unregister(&giodev->dev);
+}
+EXPORT_SYMBOL_GPL(gio_device_unregister);
+
+static int gio_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct gio_device *gio_dev = to_gio_device(dev);
+	struct gio_driver *gio_drv = to_gio_driver(drv);
+
+	return gio_match_device(gio_drv->id_table, gio_dev) != NULL;
+}
+
+static int gio_device_probe(struct device *dev)
+{
+	int error = -ENODEV;
+	struct gio_driver *drv;
+	struct gio_device *gio_dev;
+	const struct gio_device_id *match;
+
+	drv = to_gio_driver(dev->driver);
+	gio_dev = to_gio_device(dev);
+
+	if (!drv->probe)
+		return error;
+
+	gio_dev_get(gio_dev);
+
+	match = gio_match_device(drv->id_table, gio_dev);
+	if (match)
+		error = drv->probe(gio_dev, match);
+	if (error)
+		gio_dev_put(gio_dev);
+
+	return error;
+}
+
+static int gio_device_remove(struct device *dev)
+{
+	struct gio_device *gio_dev = to_gio_device(dev);
+	struct gio_driver *drv = to_gio_driver(dev->driver);
+
+	if (dev->driver && drv->remove)
+		drv->remove(gio_dev);
+	return 0;
+}
+
+static int gio_device_suspend(struct device *dev, pm_message_t state)
+{
+	struct gio_device *gio_dev = to_gio_device(dev);
+	struct gio_driver *drv = to_gio_driver(dev->driver);
+	int error = 0;
+
+	if (dev->driver && drv->suspend)
+		error = drv->suspend(gio_dev, state);
+	return error;
+}
+
+static int gio_device_resume(struct device *dev)
+{
+	struct gio_device *gio_dev = to_gio_device(dev);
+	struct gio_driver *drv = to_gio_driver(dev->driver);
+	int error = 0;
+
+	if (dev->driver && drv->resume)
+		error = drv->resume(gio_dev);
+	return error;
+}
+
+static void gio_device_shutdown(struct device *dev)
+{
+	struct gio_device *gio_dev = to_gio_device(dev);
+	struct gio_driver *drv = to_gio_driver(dev->driver);
+
+	if (dev->driver && drv->shutdown)
+		drv->shutdown(gio_dev);
+}
+
+int gio_register_driver(struct gio_driver *drv)
+{
+	/* initialize common driver fields */
+	if (!drv->driver.name)
+		drv->driver.name = drv->name;
+	if (!drv->driver.owner)
+		drv->driver.owner = drv->owner;
+	drv->driver.bus = &gio_bus;
+
+	/* register with core */
+	return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(gio_register_driver);
+
+void gio_unregister_driver(struct gio_driver *drv)
+{
+	driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(gio_unregister_driver);
+
+void gio_set_master(struct gio_device *dev)
+{
+	u32 tmp = sgimc->giopar;
+
+	switch (dev->slotno) {
+	case 0:
+		tmp |= SGIMC_GIOPAR_MASTERGFX;
+		break;
+	case 1:
+		tmp |= SGIMC_GIOPAR_MASTEREXP0;
+		break;
+	case 2:
+		tmp |= SGIMC_GIOPAR_MASTEREXP1;
+		break;
+	}
+	sgimc->giopar = tmp;
+}
+EXPORT_SYMBOL_GPL(gio_set_master);
+
+void ip22_gio_set_64bit(int slotno)
+{
+	u32 tmp = sgimc->giopar;
+
+	switch (slotno) {
+	case 0:
+		tmp |= SGIMC_GIOPAR_GFX64;
+		break;
+	case 1:
+		tmp |= SGIMC_GIOPAR_EXP064;
+		break;
+	case 2:
+		tmp |= SGIMC_GIOPAR_EXP164;
+		break;
+	}
+	sgimc->giopar = tmp;
+}
+
+static int ip22_gio_id(unsigned long addr, u32 *res)
+{
+	u8 tmp8;
+	u8 tmp16;
+	u32 tmp32;
+	u8 *ptr8;
+	u16 *ptr16;
+	u32 *ptr32;
+
+	ptr32 = (void *)CKSEG1ADDR(addr);
+	if (!get_dbe(tmp32, ptr32)) {
+		/*
+		 * We got no DBE, but this doesn't mean anything.
+		 * If GIO is pipelined (which can't be disabled
+		 * for GFX slot) we don't get a DBE, but we see
+		 * the transfer size as data. So we do an 8bit
+		 * and a 16bit access and check whether the common
+		 * data matches
+		 */
+		ptr8 = (void *)CKSEG1ADDR(addr + 3);
+		get_dbe(tmp8, ptr8);
+		ptr16 = (void *)CKSEG1ADDR(addr + 2);
+		get_dbe(tmp16, ptr16);
+		if (tmp8 = (tmp16 & 0xff) &&
+		    tmp8 = (tmp32 & 0xff) &&
+		    tmp16 = (tmp32 & 0xffff)) {
+			*res = tmp32;
+			return 1;
+		}
+	}
+	return 0; /* nothing here */
+}
+
+#define HQ2_MYSTERY_OFFS       0x6A07C
+#define NEWPORT_USTATUS_OFFS   0xF133C
+
+static int ip22_is_gr2(unsigned long addr)
+{
+	u32 tmp;
+	u32 *ptr;
+
+	/* HQ2 only allows 32bit accesses */
+	ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS);
+	if (!get_dbe(tmp, ptr)) {
+		if (tmp = 0xdeadbeef)
+			return 1;
+	}
+	return 0;
+}
+
+
+static void ip22_check_gio(int slotno, unsigned long addr)
+{
+	const char *name = "Unknown";
+	struct gio_device *gio_dev;
+	u32 tmp;
+	__u8 id;
+	int i;
+
+	/* first look for GR2/GR3 by checking mystery register */
+	if (ip22_is_gr2(addr))
+		tmp = 0x7f;
+	else {
+		if (!ip22_gio_id(addr, &tmp)) {
+			/*
+			 * no GIO signature at start address of slot, but
+			 * Newport doesn't have one, so let's check usea
+			 * status register
+			 */
+			if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp))
+				tmp = 0x7e;
+			else
+				tmp = 0;
+		}
+	}
+	if (tmp) {
+		id = GIO_ID(tmp);
+		if (tmp & GIO_32BIT_ID) {
+			if (tmp & GIO_64BIT_IFACE)
+				ip22_gio_set_64bit(slotno);
+		}
+		for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) {
+			if (id = gio_name_table[i].id) {
+				name = gio_name_table[i].name;
+				break;
+			}
+		}
+		printk(KERN_INFO "GIO: slot %d : %s (id %x)\n",
+		       slotno, name, id);
+		gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL);
+		gio_dev->name = name;
+		gio_dev->slotno = slotno;
+		gio_dev->id.id = id;
+		gio_dev->resource.start = addr;
+		gio_dev->resource.end = addr + 0x3fffff;
+		gio_dev->resource.flags = IORESOURCE_MEM;
+		dev_set_name(&gio_dev->dev, "gio%d", slotno);
+		gio_device_register(gio_dev);
+	} else
+		printk(KERN_INFO "GIO: slot %d : Empty\n", slotno);
+}
+
+static struct bus_type gio_bus = {
+	.name     = "gio",
+	.match    = gio_bus_match,
+	.probe    = gio_device_probe,
+	.remove   = gio_device_remove,
+	.suspend  = gio_device_suspend,
+	.resume   = gio_device_resume,
+	.shutdown = gio_device_shutdown,
+};
+
+static struct resource gio_bus_resource = {
+	.start = GIO_SLOT_GFX_BASE,
+	.end   = GIO_SLOT_GFX_BASE + 0x9fffff,
+	.name  = "GIO Bus",
+	.flags = IORESOURCE_MEM,
+};
+
+int __init ip22_gio_init(void)
+{
+	unsigned int pbdma __maybe_unused;
+	int ret;
+
+	ret = bus_register(&gio_bus);
+	if (!ret) {
+		request_resource(&iomem_resource, &gio_bus_resource);
+		printk(KERN_INFO "GIO: Probing bus...\n");
+
+		if (ip22_is_fullhouse() ||
+		    !get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) {
+			/* Indigo2 and ChallengeS */
+			ip22_check_gio(0, GIO_SLOT_GFX_BASE);
+			ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
+		} else {
+			/* Indy */
+			ip22_check_gio(0, GIO_SLOT_GFX_BASE);
+			ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
+			ip22_check_gio(2, GIO_SLOT_EXP1_BASE);
+		}
+	}
+	return ret;
+}
+
+subsys_initcall(ip22_gio_init);
+
diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c
index d22262e..75ada8a 100644
--- a/arch/mips/sgi-ip22/ip22-mc.c
+++ b/arch/mips/sgi-ip22/ip22-mc.c
@@ -139,11 +139,11 @@ void __init sgimc_init(void)
 	 *         zero.
 	 */
 	/* don't touch parity settings for IP28 */
-#ifndef CONFIG_SGI_IP28
 	tmp = sgimc->cpuctrl0;
-	tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM |
-		SGIMC_CCTRL0_R4KNOCHKPARR);
+#ifndef CONFIG_SGI_IP28
+	tmp |= SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM;
 #endif
+	tmp |= SGIMC_CCTRL0_R4KNOCHKPARR;
 	sgimc->cpuctrl0 = tmp;
 
 	/* Step 3: Setup the MC write buffer depth, this is controlled
@@ -178,7 +178,8 @@ void __init sgimc_init(void)
 	 */
 
 	/* First the basic invariants across all GIO64 implementations. */
-	tmp = SGIMC_GIOPAR_HPC64;	/* All 1st HPC's interface at 64bits */
+	tmp = sgimc->giopar & SGIMC_GIOPAR_GFX64; /* keep gfx 64bit settings */
+	tmp |= SGIMC_GIOPAR_HPC64;	/* All 1st HPC's interface at 64bits */
 	tmp |= SGIMC_GIOPAR_ONEBUS;	/* Only one physical GIO bus exists */
 
 	if (ip22_is_fullhouse()) {
@@ -193,7 +194,6 @@ void __init sgimc_init(void)
 			tmp |= SGIMC_GIOPAR_PLINEEXP0;	/* exp[01] pipelined */
 			tmp |= SGIMC_GIOPAR_PLINEEXP1;
 			tmp |= SGIMC_GIOPAR_MASTEREISA;	/* EISA masters */
-			tmp |= SGIMC_GIOPAR_GFX64;	/* GFX at 64 bits */
 		}
 	} else {
 		/* Guiness specific settings. */
diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c
index 5e66213..c7bdfe4 100644
--- a/arch/mips/sgi-ip22/ip22-setup.c
+++ b/arch/mips/sgi-ip22/ip22-setup.c
@@ -26,9 +26,6 @@
 #include <asm/sgi/hpc3.h>
 #include <asm/sgi/ip22.h>
 
-unsigned long sgi_gfxaddr;
-EXPORT_SYMBOL_GPL(sgi_gfxaddr);
-
 extern void ip22_be_init(void) __init;
 
 void __init plat_mem_setup(void)
@@ -78,22 +75,4 @@ void __init plat_mem_setup(void)
 		prom_flags |= PROM_FLAG_USE_AS_CONSOLE;
 		add_preferred_console("arc", 0, NULL);
 	}
-
-#if defined(CONFIG_VT) && defined(CONFIG_SGI_NEWPORT_CONSOLE)
-	{
-		ULONG *gfxinfo;
-		ULONG * (*__vec)(void) = (void *) (long)
-			*((_PULONG *)(long)((PROMBLOCK)->pvector + 0x20));
-
-		gfxinfo = __vec();
-		sgi_gfxaddr = ((gfxinfo[1] >= 0xa0000000
-			       && gfxinfo[1] <= 0xc0000000)
-			       ? gfxinfo[1] - 0xa0000000 : 0);
-
-		/* newport addresses? */
-		if (sgi_gfxaddr = 0x1f0f0000 || sgi_gfxaddr = 0x1f4f0000) {
-			conswitchp = &newport_con;
-		}
-	}
-#endif
 }
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index 93317b5..628b7ec 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -25,14 +25,13 @@
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/gio_device.h>
+
 #include <video/newport.h>
 
 #include <linux/linux_logo.h>
 #include <linux/font.h>
 
-
-extern unsigned long sgi_gfxaddr;
-
 #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
 
 /* borrowed from fbcon.c */
@@ -304,12 +303,6 @@ static const char *newport_startup(void)
 {
 	int i;
 
-	if (!sgi_gfxaddr)
-		return NULL;
-
-	if (!npregs)
-		npregs = (struct newport_regs *)/* ioremap cannot fail */
-			ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
 	npregs->cset.config = NPORT_CFG_GD0;
 
 	if (newport_wait(npregs))
@@ -743,26 +736,56 @@ const struct consw newport_con = {
 	.con_save_screen  = DUMMY
 };
 
-#ifdef MODULE
-static int __init newport_console_init(void)
+static int newport_probe(struct gio_device *dev,
+			 const struct gio_device_id *id)
 {
-	if (!sgi_gfxaddr)
-		return 0;
+	unsigned long newport_addr;
 
-	if (!npregs)
-		npregs = (struct newport_regs *)/* ioremap cannot fail */
-			ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
+	if (!dev->resource.start)
+		return -EINVAL;
+
+	if (npregs)
+		return -EBUSY; /* we only support one Newport as console */
+
+	newport_addr = dev->resource.start + 0xF0000;
+	if (!request_mem_region(newport_addr, 0x10000, "Newport"))
+		return -ENODEV;
+
+	npregs = (struct newport_regs *)/* ioremap cannot fail */
+		ioremap(newport_addr, sizeof(struct newport_regs));
 
 	return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
 }
-module_init(newport_console_init);
 
-static void __exit newport_console_exit(void)
+static void newport_remove(struct gio_device *dev)
 {
 	give_up_console(&newport_con);
 	iounmap((void *)npregs);
 }
+
+static struct gio_device_id newport_ids[] = {
+	{ .id = 0x7e },
+	{ .id = 0xff }
+};
+
+static struct gio_driver newport_driver = {
+	.name = "newport",
+	.id_table = newport_ids,
+	.probe = newport_probe,
+	.remove = newport_remove,
+};
+
+int __init newport_console_init(void)
+{
+	return gio_register_driver(&newport_driver);
+}
+
+void __exit newport_console_exit(void)
+{
+	gio_unregister_driver(&newport_driver);
+}
+
+module_init(newport_console_init);
 module_exit(newport_console_exit);
-#endif
 
 MODULE_LICENSE("GPL");

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] GIO bus support for SGI IP22/28
  2011-10-20 22:19 [PATCH v2] GIO bus support for SGI IP22/28 Thomas Bogendoerfer
@ 2011-10-30 15:53 ` Florian Tobias Schandinat
  2011-10-30 20:43 ` Joshua Kinard
  1 sibling, 0 replies; 6+ messages in thread
From: Florian Tobias Schandinat @ 2011-10-30 15:53 UTC (permalink / raw)
  To: Thomas Bogendoerfer; +Cc: linux-mips, linux-fbdev, ralf

On 10/20/2011 10:19 PM, Thomas Bogendoerfer wrote:
> SGI IP22/IP28 machines have GIO busses for adding graphics and other
> extension cards. This patch adds support for GIO driver/device
> handling and converts the newport console driver to a GIO driver.
> 
> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> ---
> 
> Changes to last version:
> - use EXPORT_SYMBOL_GPL
> - ChallengeS has only 2 slots
> - use subsys_initcall for gio detection
> 
> Florian, the whole patch should go through the MIPS tree, if it's ok for
> you.

No problem. I'm not even sure whether I'm responsible for it as it is not a
framebuffer but a console driver. Anyway I had a look at the console code so you
may add an
	Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
if you like.


Best regards,

Florian Tobias Schandinat

>  arch/mips/include/asm/gio_device.h  |   56 +++++
>  arch/mips/sgi-ip22/Makefile         |    2 +-
>  arch/mips/sgi-ip22/ip22-gio.c       |  414 +++++++++++++++++++++++++++++++++++
>  arch/mips/sgi-ip22/ip22-mc.c        |   10 +-
>  arch/mips/sgi-ip22/ip22-setup.c     |   21 --
>  drivers/video/console/newport_con.c |   61 ++++--
>  6 files changed, 518 insertions(+), 46 deletions(-)
> 
> diff --git a/arch/mips/include/asm/gio_device.h b/arch/mips/include/asm/gio_device.h
> new file mode 100644
> index 0000000..5437c84
> --- /dev/null
> +++ b/arch/mips/include/asm/gio_device.h
> @@ -0,0 +1,56 @@
> +#include <linux/device.h>
> +#include <linux/mod_devicetable.h>
> +
> +struct gio_device_id {
> +	__u8 id;
> +};
> +
> +struct gio_device {
> +	struct device   dev;
> +	struct resource resource;
> +	unsigned int    irq;
> +	unsigned int    slotno;
> +
> +	const char      *name;
> +	struct gio_device_id id;
> +	unsigned        id32:1;
> +	unsigned        gio64:1;
> +};
> +#define to_gio_device(d) container_of(d, struct gio_device, dev)
> +
> +struct gio_driver {
> +	const char    *name;
> +	struct module *owner;
> +	const struct gio_device_id *id_table;
> +
> +	int  (*probe)(struct gio_device *, const struct gio_device_id *);
> +	void (*remove)(struct gio_device *);
> +	int  (*suspend)(struct gio_device *, pm_message_t);
> +	int  (*resume)(struct gio_device *);
> +	void (*shutdown)(struct gio_device *);
> +
> +	struct device_driver driver;
> +};
> +#define to_gio_driver(drv) container_of(drv, struct gio_driver, driver)
> +
> +extern const struct gio_device_id *gio_match_device(const struct gio_device_id *,
> +						    const struct gio_device *);
> +extern struct gio_device *gio_dev_get(struct gio_device *);
> +extern void gio_dev_put(struct gio_device *);
> +
> +extern int gio_device_register(struct gio_device *);
> +extern void gio_device_unregister(struct gio_device *);
> +extern void gio_release_dev(struct device *);
> +
> +static inline void gio_device_free(struct gio_device *dev)
> +{
> +	gio_release_dev(&dev->dev);
> +}
> +
> +extern int gio_register_driver(struct gio_driver *);
> +extern void gio_unregister_driver(struct gio_driver *);
> +
> +#define gio_get_drvdata(_dev)        drv_get_drvdata(&(_dev)->dev)
> +#define gio_set_drvdata(_dev, data)  drv_set_drvdata(&(_dev)->dev, (data))
> +
> +extern void gio_set_master(struct gio_device *);
> diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile
> index cc53849..411cda9 100644
> --- a/arch/mips/sgi-ip22/Makefile
> +++ b/arch/mips/sgi-ip22/Makefile
> @@ -4,7 +4,7 @@
>  #
>  
>  obj-y	+= ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \
> -	   ip22-platform.o ip22-reset.o ip22-setup.o
> +	   ip22-platform.o ip22-reset.o ip22-setup.o ip22-gio.o
>  
>  obj-$(CONFIG_SGI_IP22) += ip22-berr.o
>  obj-$(CONFIG_SGI_IP28) += ip28-berr.o
> diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c
> new file mode 100644
> index 0000000..d841529
> --- /dev/null
> +++ b/arch/mips/sgi-ip22/ip22-gio.c
> @@ -0,0 +1,414 @@
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +
> +#include <asm/addrspace.h>
> +#include <asm/paccess.h>
> +#include <asm/gio_device.h>
> +#include <asm/sgi/gio.h>
> +#include <asm/sgi/hpc3.h>
> +#include <asm/sgi/mc.h>
> +#include <asm/sgi/ip22.h>
> +
> +static struct bus_type gio_bus;
> +
> +static struct {
> +	const char *name;
> +	__u8       id;
> +} gio_name_table[] = {
> +	{ .name = "SGI Impact", .id = 0x10 },
> +	{ .name = "Phobos G160", .id = 0x35 },
> +	/* fake IDs */
> +	{ .name = "SGI Newport", .id = 0x7e },
> +	{ .name = "SGI GR2/GR3", .id = 0x7f },
> +};
> +
> +/**
> + * gio_match_device - Tell if an of_device structure has a matching
> + * gio_match structure
> + * @ids: array of of device match structures to search in
> + * @dev: the of device structure to match against
> + *
> + * Used by a driver to check whether an of_device present in the
> + * system is in its list of supported devices.
> + */
> +const struct gio_device_id *gio_match_device(const struct gio_device_id *match,
> +		     const struct gio_device *dev)
> +{
> +	const struct gio_device_id *ids;
> +
> +	for (ids = match; ids->id != 0xff; ids++)
> +		if (ids->id = dev->id.id)
> +			return ids;
> +
> +	return NULL;
> +}
> +EXPORT_SYMBOL_GPL(gio_match_device);
> +
> +struct gio_device *gio_dev_get(struct gio_device *dev)
> +{
> +	struct device *tmp;
> +
> +	if (!dev)
> +		return NULL;
> +	tmp = get_device(&dev->dev);
> +	if (tmp)
> +		return to_gio_device(tmp);
> +	else
> +		return NULL;
> +}
> +EXPORT_SYMBOL_GPL(gio_dev_get);
> +
> +void gio_dev_put(struct gio_device *dev)
> +{
> +	if (dev)
> +		put_device(&dev->dev);
> +}
> +EXPORT_SYMBOL_GPL(gio_dev_put);
> +
> +static ssize_t dev_show_name(struct device *dev,
> +			     struct device_attribute *attr, char *buf)
> +{
> +	struct gio_device *giodev;
> +
> +	giodev = to_gio_device(dev);
> +	return sprintf(buf, "%s", giodev->name);
> +}
> +
> +static DEVICE_ATTR(name, S_IRUGO, dev_show_name, NULL);
> +
> +static ssize_t dev_show_id(struct device *dev,
> +			   struct device_attribute *attr, char *buf)
> +{
> +	struct gio_device *giodev;
> +
> +	giodev = to_gio_device(dev);
> +	return sprintf(buf, "%x", giodev->id.id);
> +}
> +
> +static DEVICE_ATTR(id, S_IRUGO, dev_show_id, NULL);
> +
> +/**
> + * gio_release_dev - free an gio device structure when all users of it are finished.
> + * @dev: device that's been disconnected
> + *
> + * Will be called only by the device core when all users of this gio device are
> + * done.
> + */
> +void gio_release_dev(struct device *dev)
> +{
> +	struct gio_device *giodev;
> +
> +	giodev = to_gio_device(dev);
> +	kfree(giodev);
> +}
> +EXPORT_SYMBOL_GPL(gio_release_dev);
> +
> +int gio_device_register(struct gio_device *giodev)
> +{
> +	int rc;
> +
> +	giodev->dev.bus = &gio_bus;
> +	rc = device_register(&giodev->dev);
> +	if (rc)
> +		return rc;
> +
> +	rc = device_create_file(&giodev->dev, &dev_attr_name);
> +	if (rc)
> +		goto err;
> +	rc = device_create_file(&giodev->dev, &dev_attr_id);
> +	if (rc)
> +		goto err;
> +
> +	return 0;
> +
> +err:
> +	device_unregister(&giodev->dev);
> +	return rc;
> +}
> +EXPORT_SYMBOL_GPL(gio_device_register);
> +
> +void gio_device_unregister(struct gio_device *giodev)
> +{
> +	device_remove_file(&giodev->dev, &dev_attr_id);
> +	device_remove_file(&giodev->dev, &dev_attr_name);
> +	device_unregister(&giodev->dev);
> +}
> +EXPORT_SYMBOL_GPL(gio_device_unregister);
> +
> +static int gio_bus_match(struct device *dev, struct device_driver *drv)
> +{
> +	struct gio_device *gio_dev = to_gio_device(dev);
> +	struct gio_driver *gio_drv = to_gio_driver(drv);
> +
> +	return gio_match_device(gio_drv->id_table, gio_dev) != NULL;
> +}
> +
> +static int gio_device_probe(struct device *dev)
> +{
> +	int error = -ENODEV;
> +	struct gio_driver *drv;
> +	struct gio_device *gio_dev;
> +	const struct gio_device_id *match;
> +
> +	drv = to_gio_driver(dev->driver);
> +	gio_dev = to_gio_device(dev);
> +
> +	if (!drv->probe)
> +		return error;
> +
> +	gio_dev_get(gio_dev);
> +
> +	match = gio_match_device(drv->id_table, gio_dev);
> +	if (match)
> +		error = drv->probe(gio_dev, match);
> +	if (error)
> +		gio_dev_put(gio_dev);
> +
> +	return error;
> +}
> +
> +static int gio_device_remove(struct device *dev)
> +{
> +	struct gio_device *gio_dev = to_gio_device(dev);
> +	struct gio_driver *drv = to_gio_driver(dev->driver);
> +
> +	if (dev->driver && drv->remove)
> +		drv->remove(gio_dev);
> +	return 0;
> +}
> +
> +static int gio_device_suspend(struct device *dev, pm_message_t state)
> +{
> +	struct gio_device *gio_dev = to_gio_device(dev);
> +	struct gio_driver *drv = to_gio_driver(dev->driver);
> +	int error = 0;
> +
> +	if (dev->driver && drv->suspend)
> +		error = drv->suspend(gio_dev, state);
> +	return error;
> +}
> +
> +static int gio_device_resume(struct device *dev)
> +{
> +	struct gio_device *gio_dev = to_gio_device(dev);
> +	struct gio_driver *drv = to_gio_driver(dev->driver);
> +	int error = 0;
> +
> +	if (dev->driver && drv->resume)
> +		error = drv->resume(gio_dev);
> +	return error;
> +}
> +
> +static void gio_device_shutdown(struct device *dev)
> +{
> +	struct gio_device *gio_dev = to_gio_device(dev);
> +	struct gio_driver *drv = to_gio_driver(dev->driver);
> +
> +	if (dev->driver && drv->shutdown)
> +		drv->shutdown(gio_dev);
> +}
> +
> +int gio_register_driver(struct gio_driver *drv)
> +{
> +	/* initialize common driver fields */
> +	if (!drv->driver.name)
> +		drv->driver.name = drv->name;
> +	if (!drv->driver.owner)
> +		drv->driver.owner = drv->owner;
> +	drv->driver.bus = &gio_bus;
> +
> +	/* register with core */
> +	return driver_register(&drv->driver);
> +}
> +EXPORT_SYMBOL_GPL(gio_register_driver);
> +
> +void gio_unregister_driver(struct gio_driver *drv)
> +{
> +	driver_unregister(&drv->driver);
> +}
> +EXPORT_SYMBOL_GPL(gio_unregister_driver);
> +
> +void gio_set_master(struct gio_device *dev)
> +{
> +	u32 tmp = sgimc->giopar;
> +
> +	switch (dev->slotno) {
> +	case 0:
> +		tmp |= SGIMC_GIOPAR_MASTERGFX;
> +		break;
> +	case 1:
> +		tmp |= SGIMC_GIOPAR_MASTEREXP0;
> +		break;
> +	case 2:
> +		tmp |= SGIMC_GIOPAR_MASTEREXP1;
> +		break;
> +	}
> +	sgimc->giopar = tmp;
> +}
> +EXPORT_SYMBOL_GPL(gio_set_master);
> +
> +void ip22_gio_set_64bit(int slotno)
> +{
> +	u32 tmp = sgimc->giopar;
> +
> +	switch (slotno) {
> +	case 0:
> +		tmp |= SGIMC_GIOPAR_GFX64;
> +		break;
> +	case 1:
> +		tmp |= SGIMC_GIOPAR_EXP064;
> +		break;
> +	case 2:
> +		tmp |= SGIMC_GIOPAR_EXP164;
> +		break;
> +	}
> +	sgimc->giopar = tmp;
> +}
> +
> +static int ip22_gio_id(unsigned long addr, u32 *res)
> +{
> +	u8 tmp8;
> +	u8 tmp16;
> +	u32 tmp32;
> +	u8 *ptr8;
> +	u16 *ptr16;
> +	u32 *ptr32;
> +
> +	ptr32 = (void *)CKSEG1ADDR(addr);
> +	if (!get_dbe(tmp32, ptr32)) {
> +		/*
> +		 * We got no DBE, but this doesn't mean anything.
> +		 * If GIO is pipelined (which can't be disabled
> +		 * for GFX slot) we don't get a DBE, but we see
> +		 * the transfer size as data. So we do an 8bit
> +		 * and a 16bit access and check whether the common
> +		 * data matches
> +		 */
> +		ptr8 = (void *)CKSEG1ADDR(addr + 3);
> +		get_dbe(tmp8, ptr8);
> +		ptr16 = (void *)CKSEG1ADDR(addr + 2);
> +		get_dbe(tmp16, ptr16);
> +		if (tmp8 = (tmp16 & 0xff) &&
> +		    tmp8 = (tmp32 & 0xff) &&
> +		    tmp16 = (tmp32 & 0xffff)) {
> +			*res = tmp32;
> +			return 1;
> +		}
> +	}
> +	return 0; /* nothing here */
> +}
> +
> +#define HQ2_MYSTERY_OFFS       0x6A07C
> +#define NEWPORT_USTATUS_OFFS   0xF133C
> +
> +static int ip22_is_gr2(unsigned long addr)
> +{
> +	u32 tmp;
> +	u32 *ptr;
> +
> +	/* HQ2 only allows 32bit accesses */
> +	ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS);
> +	if (!get_dbe(tmp, ptr)) {
> +		if (tmp = 0xdeadbeef)
> +			return 1;
> +	}
> +	return 0;
> +}
> +
> +
> +static void ip22_check_gio(int slotno, unsigned long addr)
> +{
> +	const char *name = "Unknown";
> +	struct gio_device *gio_dev;
> +	u32 tmp;
> +	__u8 id;
> +	int i;
> +
> +	/* first look for GR2/GR3 by checking mystery register */
> +	if (ip22_is_gr2(addr))
> +		tmp = 0x7f;
> +	else {
> +		if (!ip22_gio_id(addr, &tmp)) {
> +			/*
> +			 * no GIO signature at start address of slot, but
> +			 * Newport doesn't have one, so let's check usea
> +			 * status register
> +			 */
> +			if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp))
> +				tmp = 0x7e;
> +			else
> +				tmp = 0;
> +		}
> +	}
> +	if (tmp) {
> +		id = GIO_ID(tmp);
> +		if (tmp & GIO_32BIT_ID) {
> +			if (tmp & GIO_64BIT_IFACE)
> +				ip22_gio_set_64bit(slotno);
> +		}
> +		for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) {
> +			if (id = gio_name_table[i].id) {
> +				name = gio_name_table[i].name;
> +				break;
> +			}
> +		}
> +		printk(KERN_INFO "GIO: slot %d : %s (id %x)\n",
> +		       slotno, name, id);
> +		gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL);
> +		gio_dev->name = name;
> +		gio_dev->slotno = slotno;
> +		gio_dev->id.id = id;
> +		gio_dev->resource.start = addr;
> +		gio_dev->resource.end = addr + 0x3fffff;
> +		gio_dev->resource.flags = IORESOURCE_MEM;
> +		dev_set_name(&gio_dev->dev, "gio%d", slotno);
> +		gio_device_register(gio_dev);
> +	} else
> +		printk(KERN_INFO "GIO: slot %d : Empty\n", slotno);
> +}
> +
> +static struct bus_type gio_bus = {
> +	.name     = "gio",
> +	.match    = gio_bus_match,
> +	.probe    = gio_device_probe,
> +	.remove   = gio_device_remove,
> +	.suspend  = gio_device_suspend,
> +	.resume   = gio_device_resume,
> +	.shutdown = gio_device_shutdown,
> +};
> +
> +static struct resource gio_bus_resource = {
> +	.start = GIO_SLOT_GFX_BASE,
> +	.end   = GIO_SLOT_GFX_BASE + 0x9fffff,
> +	.name  = "GIO Bus",
> +	.flags = IORESOURCE_MEM,
> +};
> +
> +int __init ip22_gio_init(void)
> +{
> +	unsigned int pbdma __maybe_unused;
> +	int ret;
> +
> +	ret = bus_register(&gio_bus);
> +	if (!ret) {
> +		request_resource(&iomem_resource, &gio_bus_resource);
> +		printk(KERN_INFO "GIO: Probing bus...\n");
> +
> +		if (ip22_is_fullhouse() ||
> +		    !get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) {
> +			/* Indigo2 and ChallengeS */
> +			ip22_check_gio(0, GIO_SLOT_GFX_BASE);
> +			ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
> +		} else {
> +			/* Indy */
> +			ip22_check_gio(0, GIO_SLOT_GFX_BASE);
> +			ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
> +			ip22_check_gio(2, GIO_SLOT_EXP1_BASE);
> +		}
> +	}
> +	return ret;
> +}
> +
> +subsys_initcall(ip22_gio_init);
> +
> diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c
> index d22262e..75ada8a 100644
> --- a/arch/mips/sgi-ip22/ip22-mc.c
> +++ b/arch/mips/sgi-ip22/ip22-mc.c
> @@ -139,11 +139,11 @@ void __init sgimc_init(void)
>  	 *         zero.
>  	 */
>  	/* don't touch parity settings for IP28 */
> -#ifndef CONFIG_SGI_IP28
>  	tmp = sgimc->cpuctrl0;
> -	tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM |
> -		SGIMC_CCTRL0_R4KNOCHKPARR);
> +#ifndef CONFIG_SGI_IP28
> +	tmp |= SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM;
>  #endif
> +	tmp |= SGIMC_CCTRL0_R4KNOCHKPARR;
>  	sgimc->cpuctrl0 = tmp;
>  
>  	/* Step 3: Setup the MC write buffer depth, this is controlled
> @@ -178,7 +178,8 @@ void __init sgimc_init(void)
>  	 */
>  
>  	/* First the basic invariants across all GIO64 implementations. */
> -	tmp = SGIMC_GIOPAR_HPC64;	/* All 1st HPC's interface at 64bits */
> +	tmp = sgimc->giopar & SGIMC_GIOPAR_GFX64; /* keep gfx 64bit settings */
> +	tmp |= SGIMC_GIOPAR_HPC64;	/* All 1st HPC's interface at 64bits */
>  	tmp |= SGIMC_GIOPAR_ONEBUS;	/* Only one physical GIO bus exists */
>  
>  	if (ip22_is_fullhouse()) {
> @@ -193,7 +194,6 @@ void __init sgimc_init(void)
>  			tmp |= SGIMC_GIOPAR_PLINEEXP0;	/* exp[01] pipelined */
>  			tmp |= SGIMC_GIOPAR_PLINEEXP1;
>  			tmp |= SGIMC_GIOPAR_MASTEREISA;	/* EISA masters */
> -			tmp |= SGIMC_GIOPAR_GFX64;	/* GFX at 64 bits */
>  		}
>  	} else {
>  		/* Guiness specific settings. */
> diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c
> index 5e66213..c7bdfe4 100644
> --- a/arch/mips/sgi-ip22/ip22-setup.c
> +++ b/arch/mips/sgi-ip22/ip22-setup.c
> @@ -26,9 +26,6 @@
>  #include <asm/sgi/hpc3.h>
>  #include <asm/sgi/ip22.h>
>  
> -unsigned long sgi_gfxaddr;
> -EXPORT_SYMBOL_GPL(sgi_gfxaddr);
> -
>  extern void ip22_be_init(void) __init;
>  
>  void __init plat_mem_setup(void)
> @@ -78,22 +75,4 @@ void __init plat_mem_setup(void)
>  		prom_flags |= PROM_FLAG_USE_AS_CONSOLE;
>  		add_preferred_console("arc", 0, NULL);
>  	}
> -
> -#if defined(CONFIG_VT) && defined(CONFIG_SGI_NEWPORT_CONSOLE)
> -	{
> -		ULONG *gfxinfo;
> -		ULONG * (*__vec)(void) = (void *) (long)
> -			*((_PULONG *)(long)((PROMBLOCK)->pvector + 0x20));
> -
> -		gfxinfo = __vec();
> -		sgi_gfxaddr = ((gfxinfo[1] >= 0xa0000000
> -			       && gfxinfo[1] <= 0xc0000000)
> -			       ? gfxinfo[1] - 0xa0000000 : 0);
> -
> -		/* newport addresses? */
> -		if (sgi_gfxaddr = 0x1f0f0000 || sgi_gfxaddr = 0x1f4f0000) {
> -			conswitchp = &newport_con;
> -		}
> -	}
> -#endif
>  }
> diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
> index 93317b5..628b7ec 100644
> --- a/drivers/video/console/newport_con.c
> +++ b/drivers/video/console/newport_con.c
> @@ -25,14 +25,13 @@
>  #include <asm/system.h>
>  #include <asm/page.h>
>  #include <asm/pgtable.h>
> +#include <asm/gio_device.h>
> +
>  #include <video/newport.h>
>  
>  #include <linux/linux_logo.h>
>  #include <linux/font.h>
>  
> -
> -extern unsigned long sgi_gfxaddr;
> -
>  #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
>  
>  /* borrowed from fbcon.c */
> @@ -304,12 +303,6 @@ static const char *newport_startup(void)
>  {
>  	int i;
>  
> -	if (!sgi_gfxaddr)
> -		return NULL;
> -
> -	if (!npregs)
> -		npregs = (struct newport_regs *)/* ioremap cannot fail */
> -			ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
>  	npregs->cset.config = NPORT_CFG_GD0;
>  
>  	if (newport_wait(npregs))
> @@ -743,26 +736,56 @@ const struct consw newport_con = {
>  	.con_save_screen  = DUMMY
>  };
>  
> -#ifdef MODULE
> -static int __init newport_console_init(void)
> +static int newport_probe(struct gio_device *dev,
> +			 const struct gio_device_id *id)
>  {
> -	if (!sgi_gfxaddr)
> -		return 0;
> +	unsigned long newport_addr;
>  
> -	if (!npregs)
> -		npregs = (struct newport_regs *)/* ioremap cannot fail */
> -			ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
> +	if (!dev->resource.start)
> +		return -EINVAL;
> +
> +	if (npregs)
> +		return -EBUSY; /* we only support one Newport as console */
> +
> +	newport_addr = dev->resource.start + 0xF0000;
> +	if (!request_mem_region(newport_addr, 0x10000, "Newport"))
> +		return -ENODEV;
> +
> +	npregs = (struct newport_regs *)/* ioremap cannot fail */
> +		ioremap(newport_addr, sizeof(struct newport_regs));
>  
>  	return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
>  }
> -module_init(newport_console_init);
>  
> -static void __exit newport_console_exit(void)
> +static void newport_remove(struct gio_device *dev)
>  {
>  	give_up_console(&newport_con);
>  	iounmap((void *)npregs);
>  }
> +
> +static struct gio_device_id newport_ids[] = {
> +	{ .id = 0x7e },
> +	{ .id = 0xff }
> +};
> +
> +static struct gio_driver newport_driver = {
> +	.name = "newport",
> +	.id_table = newport_ids,
> +	.probe = newport_probe,
> +	.remove = newport_remove,
> +};
> +
> +int __init newport_console_init(void)
> +{
> +	return gio_register_driver(&newport_driver);
> +}
> +
> +void __exit newport_console_exit(void)
> +{
> +	gio_unregister_driver(&newport_driver);
> +}
> +
> +module_init(newport_console_init);
>  module_exit(newport_console_exit);
> -#endif
>  
>  MODULE_LICENSE("GPL");
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] GIO bus support for SGI IP22/28
  2011-10-20 22:19 [PATCH v2] GIO bus support for SGI IP22/28 Thomas Bogendoerfer
  2011-10-30 15:53 ` Florian Tobias Schandinat
@ 2011-10-30 20:43 ` Joshua Kinard
  2011-10-30 22:34   ` Thomas Bogendoerfer
  1 sibling, 1 reply; 6+ messages in thread
From: Joshua Kinard @ 2011-10-30 20:43 UTC (permalink / raw)
  To: Thomas Bogendoerfer; +Cc: linux-mips, linux-fbdev, ralf, FlorianSchandinat

On 10/20/2011 18:19, Thomas Bogendoerfer wrote:

> SGI IP22/IP28 machines have GIO busses for adding graphics and other
> extension cards. This patch adds support for GIO driver/device
> handling and converts the newport console driver to a GIO driver.
> 
> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>


Does this handle any glue logic for add-on NIC cards found for Indy and I2?
 I have a G130 Phobus and a rare ThunderLAN card in my Indy.  The Phobus has
an Altera GIO/PCI glue chip.  Not sure about the ThunderLAN.  Both have
normal driver support in the kernel (Phobus is just a Tulip chip).

-- 
Joshua Kinard
Gentoo/MIPS
kumba@gentoo.org
4096R/D25D95E3 2011-03-28

"The past tempts us, the present confuses us, the future frightens us.  And
our lives slip away, moment by moment, lost in that vast, terrible in-between."

--Emperor Turhan, Centauri Republic

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] GIO bus support for SGI IP22/28
  2011-10-30 20:43 ` Joshua Kinard
@ 2011-10-30 22:34   ` Thomas Bogendoerfer
  2011-10-31  8:04     ` Joshua Kinard
  0 siblings, 1 reply; 6+ messages in thread
From: Thomas Bogendoerfer @ 2011-10-30 22:34 UTC (permalink / raw)
  To: Joshua Kinard; +Cc: linux-mips, linux-fbdev, ralf, FlorianSchandinat

On Sun, Oct 30, 2011 at 04:43:45PM -0400, Joshua Kinard wrote:
> Does this handle any glue logic for add-on NIC cards found for Indy and I2?

no, but it will make live a lot easier, because address and interrupts don't
need to be probed by the driver. Right now interrupts are on my todo, since
there is some weirdness between guiness and fullhouse boxes...

>  I have a G130 Phobus and a rare ThunderLAN card in my Indy.  The Phobus has
> an Altera GIO/PCI glue chip.  Not sure about the ThunderLAN.  Both have
> normal driver support in the kernel (Phobus is just a Tulip chip).

it still needs something to setup the PCI bus on the card and issue
the probing. The problem with the Tulip Phobos cards is, that they
messed up the endianess, so that none of the Linux Tulip drivers will
work out of the box...

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea.                                                [ RFC1925, 2.3 ]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] GIO bus support for SGI IP22/28
  2011-10-30 22:34   ` Thomas Bogendoerfer
@ 2011-10-31  8:04     ` Joshua Kinard
  2011-11-01 10:00       ` Thomas Bogendoerfer
  0 siblings, 1 reply; 6+ messages in thread
From: Joshua Kinard @ 2011-10-31  8:04 UTC (permalink / raw)
  To: Thomas Bogendoerfer; +Cc: linux-mips, linux-fbdev, ralf, FlorianSchandinat

On 10/30/2011 18:34, Thomas Bogendoerfer wrote:

> 
> no, but it will make live a lot easier, because address and interrupts don't
> need to be probed by the driver. Right now interrupts are on my todo, since
> there is some weirdness between guiness and fullhouse boxes...


It wouldn't be an SGI machine if it didn't implement something weird or just
plain backwards...


> it still needs something to setup the PCI bus on the card and issue
> the probing. The problem with the Tulip Phobos cards is, that they
> messed up the endianess, so that none of the Linux Tulip drivers will
> work out of the box...


A.k.a., Tulip (and possibly ThunderLAN) assume little-endian, when we're
talking big-endian archs here.  Interesting.  Simple fix, as in defining a
few driver structures with little- and big-endian versions (if they're doing
something like packing bits or using bitfields)?  Or is it more complex than
that?

-- 
Joshua Kinard
Gentoo/MIPS
kumba@gentoo.org
4096R/D25D95E3 2011-03-28

"The past tempts us, the present confuses us, the future frightens us.  And
our lives slip away, moment by moment, lost in that vast, terrible in-between."

--Emperor Turhan, Centauri Republic

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] GIO bus support for SGI IP22/28
  2011-10-31  8:04     ` Joshua Kinard
@ 2011-11-01 10:00       ` Thomas Bogendoerfer
  0 siblings, 0 replies; 6+ messages in thread
From: Thomas Bogendoerfer @ 2011-11-01 10:00 UTC (permalink / raw)
  To: Joshua Kinard; +Cc: linux-mips, linux-fbdev, ralf, FlorianSchandinat

On Mon, Oct 31, 2011 at 04:04:17AM -0400, Joshua Kinard wrote:
> A.k.a., Tulip (and possibly ThunderLAN) assume little-endian, when we're
> talking big-endian archs here.  Interesting.  Simple fix, as in defining a
> few driver structures with little- and big-endian versions (if they're doing
> something like packing bits or using bitfields)?  Or is it more complex than
> that?

iirc, the PCI bridge on the cards do 32bit swaps (address invariant) so
tulip chips need to run in big endian mode, which in turn makes descriptors
also big endian. But none of the tulip driver supports big endian descriptors.
That's fixable of course.

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea.                                                [ RFC1925, 2.3 ]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-11-01 10:00 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-20 22:19 [PATCH v2] GIO bus support for SGI IP22/28 Thomas Bogendoerfer
2011-10-30 15:53 ` Florian Tobias Schandinat
2011-10-30 20:43 ` Joshua Kinard
2011-10-30 22:34   ` Thomas Bogendoerfer
2011-10-31  8:04     ` Joshua Kinard
2011-11-01 10:00       ` Thomas Bogendoerfer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).