Commit 1d421ca9 authored by Thomas Bogendoerfer's avatar Thomas Bogendoerfer Committed by Ralf Baechle

MIPS: IP22/IP28: Improve GIO support

- added interrupt support for GIO devices
- improved detection of GIO cards on Indigo2
- added more known GIO cards
Signed-off-by: default avatarThomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/7055/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent a53825ef
...@@ -50,7 +50,7 @@ static inline void gio_device_free(struct gio_device *dev) ...@@ -50,7 +50,7 @@ static inline void gio_device_free(struct gio_device *dev)
extern int gio_register_driver(struct gio_driver *); extern int gio_register_driver(struct gio_driver *);
extern void gio_unregister_driver(struct gio_driver *); extern void gio_unregister_driver(struct gio_driver *);
#define gio_get_drvdata(_dev) drv_get_drvdata(&(_dev)->dev) #define gio_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev)
#define gio_set_drvdata(_dev, data) drv_set_drvdata(&(_dev)->dev, (data)) #define gio_set_drvdata(_dev, data) dev_set_drvdata(&(_dev)->dev, (data))
extern void gio_set_master(struct gio_device *); extern void gio_set_master(struct gio_device *);
...@@ -69,6 +69,8 @@ ...@@ -69,6 +69,8 @@
#define SGI_EISA_IRQ SGINT_LOCAL2 + 3 /* EISA interrupts */ #define SGI_EISA_IRQ SGINT_LOCAL2 + 3 /* EISA interrupts */
#define SGI_KEYBD_IRQ SGINT_LOCAL2 + 4 /* keyboard */ #define SGI_KEYBD_IRQ SGINT_LOCAL2 + 4 /* keyboard */
#define SGI_SERIAL_IRQ SGINT_LOCAL2 + 5 /* onboard serial */ #define SGI_SERIAL_IRQ SGINT_LOCAL2 + 5 /* onboard serial */
#define SGI_GIOEXP0_IRQ (SGINT_LOCAL2 + 6) /* Indy GIO EXP0 */
#define SGI_GIOEXP1_IRQ (SGINT_LOCAL2 + 7) /* Indy GIO EXP1 */
#define ip22_is_fullhouse() (sgioc->sysid & SGIOC_SYSID_FULLHOUSE) #define ip22_is_fullhouse() (sgioc->sysid & SGIOC_SYSID_FULLHOUSE)
......
...@@ -19,6 +19,9 @@ static struct { ...@@ -19,6 +19,9 @@ static struct {
} gio_name_table[] = { } gio_name_table[] = {
{ .name = "SGI Impact", .id = 0x10 }, { .name = "SGI Impact", .id = 0x10 },
{ .name = "Phobos G160", .id = 0x35 }, { .name = "Phobos G160", .id = 0x35 },
{ .name = "Phobos G130", .id = 0x36 },
{ .name = "Phobos G100", .id = 0x37 },
{ .name = "Set Engineering GFE", .id = 0x38 },
/* fake IDs */ /* fake IDs */
{ .name = "SGI Newport", .id = 0x7e }, { .name = "SGI Newport", .id = 0x7e },
{ .name = "SGI GR2/GR3", .id = 0x7f }, { .name = "SGI GR2/GR3", .id = 0x7f },
...@@ -293,7 +296,16 @@ static int ip22_gio_id(unsigned long addr, u32 *res) ...@@ -293,7 +296,16 @@ static int ip22_gio_id(unsigned long addr, u32 *res)
* data matches * data matches
*/ */
ptr8 = (void *)CKSEG1ADDR(addr + 3); ptr8 = (void *)CKSEG1ADDR(addr + 3);
get_dbe(tmp8, ptr8); if (get_dbe(tmp8, ptr8)) {
/*
* 32bit access worked, but 8bit doesn't
* so we don't see phantom reads on
* a pipelined bus, but a real card which
* doesn't support 8 bit reads
*/
*res = tmp32;
return 1;
}
ptr16 = (void *)CKSEG1ADDR(addr + 2); ptr16 = (void *)CKSEG1ADDR(addr + 2);
get_dbe(tmp16, ptr16); get_dbe(tmp16, ptr16);
if (tmp8 == (tmp16 & 0xff) && if (tmp8 == (tmp16 & 0xff) &&
...@@ -324,7 +336,7 @@ static int ip22_is_gr2(unsigned long addr) ...@@ -324,7 +336,7 @@ static int ip22_is_gr2(unsigned long addr)
} }
static void ip22_check_gio(int slotno, unsigned long addr) static void ip22_check_gio(int slotno, unsigned long addr, int irq)
{ {
const char *name = "Unknown"; const char *name = "Unknown";
struct gio_device *gio_dev; struct gio_device *gio_dev;
...@@ -338,9 +350,9 @@ static void ip22_check_gio(int slotno, unsigned long addr) ...@@ -338,9 +350,9 @@ static void ip22_check_gio(int slotno, unsigned long addr)
else { else {
if (!ip22_gio_id(addr, &tmp)) { if (!ip22_gio_id(addr, &tmp)) {
/* /*
* no GIO signature at start address of slot, but * no GIO signature at start address of slot
* Newport doesn't have one, so let's check usea * since Newport doesn't have one, we check if
* status register * user status register is readable
*/ */
if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp)) if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp))
tmp = 0x7e; tmp = 0x7e;
...@@ -369,6 +381,7 @@ static void ip22_check_gio(int slotno, unsigned long addr) ...@@ -369,6 +381,7 @@ static void ip22_check_gio(int slotno, unsigned long addr)
gio_dev->resource.start = addr; gio_dev->resource.start = addr;
gio_dev->resource.end = addr + 0x3fffff; gio_dev->resource.end = addr + 0x3fffff;
gio_dev->resource.flags = IORESOURCE_MEM; gio_dev->resource.flags = IORESOURCE_MEM;
gio_dev->irq = irq;
dev_set_name(&gio_dev->dev, "%d", slotno); dev_set_name(&gio_dev->dev, "%d", slotno);
gio_device_register(gio_dev); gio_device_register(gio_dev);
} else } else
...@@ -408,16 +421,17 @@ int __init ip22_gio_init(void) ...@@ -408,16 +421,17 @@ int __init ip22_gio_init(void)
request_resource(&iomem_resource, &gio_bus_resource); request_resource(&iomem_resource, &gio_bus_resource);
printk(KERN_INFO "GIO: Probing bus...\n"); printk(KERN_INFO "GIO: Probing bus...\n");
if (ip22_is_fullhouse() || if (ip22_is_fullhouse()) {
!get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) { /* Indigo2 */
/* Indigo2 and ChallengeS */ ip22_check_gio(0, GIO_SLOT_GFX_BASE, SGI_GIO_1_IRQ);
ip22_check_gio(0, GIO_SLOT_GFX_BASE); ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIO_1_IRQ);
ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
} else { } else {
/* Indy */ /* Indy/Challenge S */
ip22_check_gio(0, GIO_SLOT_GFX_BASE); if (get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1]))
ip22_check_gio(1, GIO_SLOT_EXP0_BASE); ip22_check_gio(0, GIO_SLOT_GFX_BASE,
ip22_check_gio(2, GIO_SLOT_EXP1_BASE); SGI_GIO_0_IRQ);
ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIOEXP0_IRQ);
ip22_check_gio(2, GIO_SLOT_EXP1_BASE, SGI_GIOEXP1_IRQ);
} }
} else } else
device_unregister(&gio_bus); device_unregister(&gio_bus);
......
...@@ -119,9 +119,14 @@ static void indy_local0_irqdispatch(void) ...@@ -119,9 +119,14 @@ static void indy_local0_irqdispatch(void)
} else } else
irq = lc0msk_to_irqnr[mask]; irq = lc0msk_to_irqnr[mask];
/* if irq == 0, then the interrupt has already been cleared */ /*
* workaround for INT2 bug; if irq == 0, INT2 has seen a fifo full
* irq, but failed to latch it into status register
*/
if (irq) if (irq)
do_IRQ(irq); do_IRQ(irq);
else
do_IRQ(SGINT_LOCAL0 + 0);
} }
static void indy_local1_irqdispatch(void) static void indy_local1_irqdispatch(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment