]> git.neil.brown.name Git - history.git/commitdiff
[ARM] icside: use MMIO for board specific registers.
authorRussell King <rmk@flint.arm.linux.org.uk>
Sun, 14 Nov 2004 16:58:25 +0000 (16:58 +0000)
committerRussell King <rmk@flint.arm.linux.org.uk>
Sun, 14 Nov 2004 16:58:25 +0000 (16:58 +0000)
drivers/ide/arm/icside.c

index e240b0a092f642c5c971333804361fb3d7495ba4..9cbf3821bddc62ea2b7c6769958fbc4592691c52 100644 (file)
@@ -1,7 +1,9 @@
 /*
  * linux/drivers/ide/arm/icside.c
  *
- * Copyright (c) 1996-2003 Russell King.
+ * Copyright (c) 1996-2004 Russell King.
+ *
+ * Please note that this platform does not support 32-bit IDE IO.
  */
 
 #include <linux/config.h>
 
 #define ICS_IDENT_OFFSET               0x2280
 
-#define ICS_ARCIN_V5_INTRSTAT          0x000
-#define ICS_ARCIN_V5_INTROFFSET                0x001
+#define ICS_ARCIN_V5_INTRSTAT          0x0000
+#define ICS_ARCIN_V5_INTROFFSET                0x0004
 #define ICS_ARCIN_V5_IDEOFFSET         0xa00
 #define ICS_ARCIN_V5_IDEALTOFFSET      0xae0
 #define ICS_ARCIN_V5_IDESTEPPING       4
 
 #define ICS_ARCIN_V6_IDEOFFSET_1       0x800
-#define ICS_ARCIN_V6_INTROFFSET_1      0x880
-#define ICS_ARCIN_V6_INTRSTAT_1                0x8a4
+#define ICS_ARCIN_V6_INTROFFSET_1      0x2200
+#define ICS_ARCIN_V6_INTRSTAT_1                0x2290
 #define ICS_ARCIN_V6_IDEALTOFFSET_1    0x8e0
 #define ICS_ARCIN_V6_IDEOFFSET_2       0xc00
-#define ICS_ARCIN_V6_INTROFFSET_2      0xc80
-#define ICS_ARCIN_V6_INTRSTAT_2                0xca4
+#define ICS_ARCIN_V6_INTROFFSET_2      0x3200
+#define ICS_ARCIN_V6_INTRSTAT_2                0x3290
 #define ICS_ARCIN_V6_IDEALTOFFSET_2    0xce0
 #define ICS_ARCIN_V6_IDESTEPPING       4
 
@@ -47,28 +49,28 @@ struct cardinfo {
 };
 
 static struct cardinfo icside_cardinfo_v5 = {
-       ICS_ARCIN_V5_IDEOFFSET,
-       ICS_ARCIN_V5_IDEALTOFFSET,
-       ICS_ARCIN_V5_IDESTEPPING
+       .dataoffset     = ICS_ARCIN_V5_IDEOFFSET,
+       .ctrloffset     = ICS_ARCIN_V5_IDEALTOFFSET,
+       .stepping       = ICS_ARCIN_V5_IDESTEPPING,
 };
 
 static struct cardinfo icside_cardinfo_v6_1 = {
-       ICS_ARCIN_V6_IDEOFFSET_1,
-       ICS_ARCIN_V6_IDEALTOFFSET_1,
-       ICS_ARCIN_V6_IDESTEPPING
+       .dataoffset     = ICS_ARCIN_V6_IDEOFFSET_1,
+       .ctrloffset     = ICS_ARCIN_V6_IDEALTOFFSET_1,
+       .stepping       = ICS_ARCIN_V6_IDESTEPPING,
 };
 
 static struct cardinfo icside_cardinfo_v6_2 = {
-       ICS_ARCIN_V6_IDEOFFSET_2,
-       ICS_ARCIN_V6_IDEALTOFFSET_2,
-       ICS_ARCIN_V6_IDESTEPPING
+       .dataoffset     = ICS_ARCIN_V6_IDEOFFSET_2,
+       .ctrloffset     = ICS_ARCIN_V6_IDEALTOFFSET_2,
+       .stepping       = ICS_ARCIN_V6_IDESTEPPING,
 };
 
 struct icside_state {
        unsigned int channel;
        unsigned int enabled;
-       unsigned long irq_port;
-       unsigned long slot_port;
+       void __iomem *irq_port;
+       void __iomem *ioc_base;
        unsigned int type;
        /* parent device... until the IDE core gets one of its own */
        struct device *dev;
@@ -88,9 +90,8 @@ struct icside_state {
 static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
 {
        struct icside_state *state = ec->irq_data;
-       unsigned int base = state->irq_port;
 
-       outb(0, base + ICS_ARCIN_V5_INTROFFSET);
+       writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET);
 }
 
 /* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
@@ -99,9 +100,8 @@ static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
 static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
 {
        struct icside_state *state = ec->irq_data;
-       unsigned int base = state->irq_port;
 
-       inb(base + ICS_ARCIN_V5_INTROFFSET);
+       readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET);
 }
 
 static const expansioncard_ops_t icside_ops_arcin_v5 = {
@@ -117,18 +117,18 @@ static const expansioncard_ops_t icside_ops_arcin_v5 = {
 static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
 {
        struct icside_state *state = ec->irq_data;
-       unsigned int base = state->irq_port;
+       void __iomem *base = state->irq_port;
 
        state->enabled = 1;
 
        switch (state->channel) {
        case 0:
-               outb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
-               inb(base + ICS_ARCIN_V6_INTROFFSET_2);
+               writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
+               readb(base + ICS_ARCIN_V6_INTROFFSET_2);
                break;
        case 1:
-               outb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
-               inb(base + ICS_ARCIN_V6_INTROFFSET_1);
+               writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
+               readb(base + ICS_ARCIN_V6_INTROFFSET_1);
                break;
        }
 }
@@ -142,8 +142,8 @@ static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
 
        state->enabled = 0;
 
-       inb (state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-       inb (state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
 }
 
 /* Prototype: icside_irqprobe(struct expansion_card *ec)
@@ -153,8 +153,8 @@ static int icside_irqpending_arcin_v6(struct expansion_card *ec)
 {
        struct icside_state *state = ec->irq_data;
 
-       return inb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
-              inb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+       return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+              readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
 }
 
 static const expansioncard_ops_t icside_ops_arcin_v6 = {
@@ -180,17 +180,17 @@ static void icside_maskproc(ide_drive_t *drive, int mask)
        if (state->enabled && !mask) {
                switch (hwif->channel) {
                case 0:
-                       outb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-                       inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+                       writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+                       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
                        break;
                case 1:
-                       outb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-                       inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+                       writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+                       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
                        break;
                }
        } else {
-               inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-               inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+               readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+               readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
        }
 
        local_irq_restore(flags);
@@ -452,7 +452,7 @@ static int icside_dma_setup(ide_drive_t *drive)
        /*
         * Route the DMA signals to the correct interface.
         */
-       outb(hwif->select_data, hwif->config_data);
+       writeb(hwif->select_data, hwif->config_data);
 
        /*
         * Select the correct timing for this drive.
@@ -482,8 +482,8 @@ static int icside_dma_test_irq(ide_drive_t *drive)
        ide_hwif_t *hwif = HWIF(drive);
        struct icside_state *state = hwif->hwif_data;
 
-       return inb(state->irq_port +
-                  (hwif->channel ?
+       return readb(state->irq_port +
+                    (hwif->channel ?
                        ICS_ARCIN_V6_INTRSTAT_2 :
                        ICS_ARCIN_V6_INTRSTAT_1)) & 1;
 }
@@ -604,12 +604,17 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec)
 {
        unsigned long slot_port;
        ide_hwif_t *hwif;
+       void __iomem *base;
 
        slot_port = ecard_address(ec, ECARD_MEMC, 0);
+       base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+                      ecard_resource_len(ec, ECARD_RES_MEMC));
+       if (!base)
+               return -ENOMEM;
 
-       state->irq_port = slot_port;
+       state->irq_port = base;
 
-       ec->irqaddr  = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
+       ec->irqaddr  = base + ICS_ARCIN_V5_INTRSTAT;
        ec->irqmask  = 1;
        ec->irq_data = state;
        ec->ops      = &icside_ops_arcin_v5;
@@ -617,13 +622,17 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec)
        /*
         * Be on the safe side - disable interrupts
         */
-       inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
+       icside_irqdisable_arcin_v5(ec, 0);
 
        hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec);
+       if (!hwif) {
+               iounmap(base);
+               return -ENODEV;
+       }
 
        state->hwif[0] = hwif;
 
-       return hwif ? 0 : -ENODEV;
+       return 0;
 }
 
 static int __init
@@ -631,23 +640,50 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
 {
        unsigned long slot_port, port;
        ide_hwif_t *hwif, *mate;
+       void __iomem *ioc_base, *easi_base;
        unsigned int sel = 0;
+       int ret;
 
        slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
        port      = ecard_address(ec, ECARD_EASI, ECARD_FAST);
-
        if (port == 0)
                port = slot_port;
-       else
+
+       ioc_base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST),
+                          ecard_resource_len(ec, ECARD_RES_IOCFAST));
+       if (!ioc_base) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       easi_base = ioc_base;
+
+       if (ecard_resource_flags(ec, ECARD_RES_EASI)) {
+               easi_base = ioremap(ecard_resource_start(ec, ECARD_RES_EASI),
+                                   ecard_resource_len(ec, ECARD_RES_EASI));
+               if (!easi_base) {
+                       ret = -ENOMEM;
+                       goto unmap_slot;
+               }
+
+               /*
+                * Enable access to the EASI region.
+                */
                sel = 1 << 5;
+       }
+
+       writeb(sel, ioc_base);
+
+       ec->irq_data      = state;
+       ec->ops           = &icside_ops_arcin_v6;
 
-       outb(sel, slot_port);
+       state->irq_port   = easi_base;
+       state->ioc_base   = ioc_base;
 
        /*
         * Be on the safe side - disable interrupts
         */
-       inb(port + ICS_ARCIN_V6_INTROFFSET_1);
-       inb(port + ICS_ARCIN_V6_INTROFFSET_2);
+       icside_irqdisable_arcin_v6(ec, 0);
 
        /*
         * Find and register the interfaces.
@@ -655,23 +691,20 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
        hwif = icside_setup(port, &icside_cardinfo_v6_1, ec);
        mate = icside_setup(port, &icside_cardinfo_v6_2, ec);
 
-       if (!hwif || !mate)
-               return -ENODEV;
+       if (!hwif || !mate) {
+               ret = -ENODEV;
+               goto unmap_port;
+       }
 
-       state->irq_port   = port;
-       state->slot_port  = slot_port;
        state->hwif[0]    = hwif;
        state->hwif[1]    = mate;
 
-       ec->irq_data      = state;
-       ec->ops           = &icside_ops_arcin_v6;
-
        hwif->maskproc    = icside_maskproc;
        hwif->channel     = 0;
        hwif->hwif_data   = state;
        hwif->mate        = mate;
        hwif->serialized  = 1;
-       hwif->config_data = slot_port;
+       hwif->config_data = (unsigned long)ioc_base;
        hwif->select_data = sel;
        hwif->hw.dma      = ec->dma;
 
@@ -680,7 +713,7 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
        mate->hwif_data   = state;
        mate->mate        = hwif;
        mate->serialized  = 1;
-       mate->config_data = slot_port;
+       mate->config_data = (unsigned long)ioc_base;
        mate->select_data = sel | 1;
        mate->hw.dma      = ec->dma;
 
@@ -690,6 +723,14 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
        }
 
        return 0;
+
+ unmap_port:
+       if (easi_base != ioc_base)
+               iounmap(easi_base);
+ unmap_slot:
+       iounmap(ioc_base);
+ out:
+       return ret;
 }
 
 static int __devinit
@@ -699,10 +740,14 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id)
        void *idmem;
        int ret;
 
+       ret = ecard_request_resources(ec);
+       if (ret)
+               goto out;
+
        state = kmalloc(sizeof(struct icside_state), GFP_KERNEL);
        if (!state) {
                ret = -ENOMEM;
-               goto out;
+               goto release;
        }
 
        memset(state, 0, sizeof(state));
@@ -725,12 +770,12 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id)
 
        switch (state->type) {
        case ICS_TYPE_A3IN:
-               printk(KERN_WARNING "icside: A3IN unsupported\n");
+               dev_warn(&ec->dev, "A3IN unsupported\n");
                ret = -ENODEV;
                break;
 
        case ICS_TYPE_A3USER:
-               printk(KERN_WARNING "icside: A3USER unsupported\n");
+               dev_warn(&ec->dev, "A3USER unsupported\n");
                ret = -ENODEV;
                break;
 
@@ -743,15 +788,19 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id)
                break;
 
        default:
-               printk(KERN_WARNING "icside: unknown interface type\n");
+               dev_warn(&ec->dev, "unknown interface type\n");
                ret = -ENODEV;
                break;
        }
 
-       if (ret == 0)
+       if (ret == 0) {
                ecard_set_drvdata(ec, state);
-       else
-               kfree(state);
+               goto out;
+       }
+
+       kfree(state);
+ release:
+       ecard_release_resources(ec);
  out:
        return ret;
 }
@@ -765,7 +814,7 @@ static void __devexit icside_remove(struct expansion_card *ec)
                /* FIXME: tell IDE to stop using the interface */
 
                /* Disable interrupts */
-               inb(state->slot_port + ICS_ARCIN_V5_INTROFFSET);
+               icside_irqdisable_arcin_v5(ec, 0);
                break;
 
        case ICS_TYPE_V6:
@@ -774,11 +823,10 @@ static void __devexit icside_remove(struct expansion_card *ec)
                        free_dma(ec->dma);
 
                /* Disable interrupts */
-               inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-               inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+               icside_irqdisable_arcin_v6(ec, 0);
 
                /* Reset the ROM pointer/EASI selection */
-               outb(0, state->slot_port);
+               writeb(0, state->ioc_base);
                break;
        }
 
@@ -786,28 +834,36 @@ static void __devexit icside_remove(struct expansion_card *ec)
        ec->ops = NULL;
        ec->irq_data = NULL;
 
+       if (state->ioc_base)
+               iounmap(state->ioc_base);
+       if (state->ioc_base != state->irq_port)
+               iounmap(state->irq_port);
+
        kfree(state);
+       ecard_release_resources(ec);
 }
 
 static void icside_shutdown(struct expansion_card *ec)
 {
        struct icside_state *state = ecard_get_drvdata(ec);
+       unsigned long flags;
 
-       switch (state->type) {
-       case ICS_TYPE_V5:
-               /* Disable interrupts */
-               inb(state->slot_port + ICS_ARCIN_V5_INTROFFSET);
-               break;
-
-       case ICS_TYPE_V6:
-               /* Disable interrupts */
-               inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-               inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+       /*
+        * Disable interrupts from this card.  We need to do
+        * this before disabling EASI since we may be accessing
+        * this register via that region.
+        */
+       local_irq_save(flags);
+       ec->ops->irqdisable(ec, 0);
+       local_irq_restore(flags);
 
-               /* Reset the ROM pointer/EASI selection */
-               outb(0, state->slot_port);
-               break;
-       }
+       /*
+        * Reset the ROM pointer so that we can read the ROM
+        * after a soft reboot.  This also disables access to
+        * the IDE taskfile via the EASI region.
+        */
+       if (state->ioc_base)
+               writeb(0, state->ioc_base);
 }
 
 static const struct ecard_id icside_ids[] = {