vserver 1.9.5.x5
[linux-2.6.git] / drivers / ide / pci / ns87415.c
index 44f7824..205a32f 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 1997-1998     Mark Lord <mlord@pobox.com>
  * Copyright (C) 1998          Eddie C. Dost <ecd@skynet.be>
  * Copyright (C) 1999-2000     Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2004          Grant Grundler <grundler at parisc-linux.org>
  *
  * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
  */
 
 #include <asm/io.h>
 
+#ifdef CONFIG_SUPERIO
+/* SUPERIO 87560 is a PoS chip that NatSem denies exists.
+ * Unfortunately, it's built-in on all Astro-based PA-RISC workstations
+ * which use the integrated NS87514 cell for CD-ROM support.
+ * i.e we have to support for CD-ROM installs.
+ * See drivers/parisc/superio.c for more gory details.
+ */
+#include <asm/superio.h>
+
+static unsigned long superio_ide_status[2];
+static unsigned long superio_ide_select[2];
+static unsigned long superio_ide_dma_status[2];
+
+#define SUPERIO_IDE_MAX_RETRIES 25
+
+/* Because of a defect in Super I/O, all reads of the PCI DMA status 
+ * registers, IDE status register and the IDE select register need to be 
+ * retried
+ */
+static u8 superio_ide_inb (unsigned long port)
+{
+       if (port == superio_ide_status[0] ||
+           port == superio_ide_status[1] ||
+           port == superio_ide_select[0] ||
+           port == superio_ide_select[1] ||
+           port == superio_ide_dma_status[0] ||
+           port == superio_ide_dma_status[1]) {
+               u8 tmp;
+               int retries = SUPERIO_IDE_MAX_RETRIES;
+
+               /* printk(" [ reading port 0x%x with retry ] ", port); */
+
+               do {
+                       tmp = inb(port);
+                       if (tmp == 0)
+                               udelay(50);
+               } while (tmp == 0 && retries-- > 0);
+
+               return tmp;
+       }
+
+       return inb(port);
+}
+
+static void __devinit superio_ide_init_iops (struct hwif_s *hwif)
+{
+       u32 base, dmabase;
+       u8 tmp;
+       struct pci_dev *pdev = hwif->pci_dev;
+       u8 port = hwif->channel;
+
+       base = pci_resource_start(pdev, port * 2) & ~3;
+       dmabase = pci_resource_start(pdev, 4) & ~3;
+
+       superio_ide_status[port] = base + IDE_STATUS_OFFSET;
+       superio_ide_select[port] = base + IDE_SELECT_OFFSET;
+       superio_ide_dma_status[port] = dmabase + (!port ? 2 : 0xa);
+
+       /* Clear error/interrupt, enable dma */
+       tmp = superio_ide_inb(superio_ide_dma_status[port]);
+       outb(tmp | 0x66, superio_ide_dma_status[port]);
+
+       /* We need to override inb to workaround a SuperIO errata */
+       hwif->INB = superio_ide_inb;
+}
+
+static void __devinit init_iops_ns87415(ide_hwif_t *hwif)
+{
+       if (PCI_SLOT(hwif->pci_dev->devfn) == 0xE) {
+               /* Built-in - assume it's under superio. */
+               superio_ide_init_iops(hwif);
+       }
+}
+#endif
+
 static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
 
 /*
@@ -101,22 +177,11 @@ static int ns87415_ide_dma_end (ide_drive_t *drive)
        return (dma_stat & 7) != 4;
 }
 
-static int ns87415_ide_dma_read (ide_drive_t *drive)
-{
-       /* select DMA xfer */
-       ns87415_prepare_drive(drive, 1);
-       if (!(__ide_dma_read(drive)))
-               return 0;
-       /* DMA failed: select PIO xfer */
-       ns87415_prepare_drive(drive, 0);
-       return 1;
-}
-
-static int ns87415_ide_dma_write (ide_drive_t *drive)
+static int ns87415_ide_dma_setup(ide_drive_t *drive)
 {
        /* select DMA xfer */
        ns87415_prepare_drive(drive, 1);
-       if (!(__ide_dma_write(drive)))
+       if (!ide_dma_setup(drive))
                return 0;
        /* DMA failed: select PIO xfer */
        ns87415_prepare_drive(drive, 0);
@@ -143,10 +208,6 @@ static void __init init_hwif_ns87415 (ide_hwif_t *hwif)
        hwif->autodma = 0;
        hwif->selectproc = &ns87415_selectproc;
 
-       /* Set a good latency timer and cache line size value. */
-       (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-       /* FIXME: use pci_set_master() to ensure good latency timer value */
-
        /*
         * We cannot probe for IRQ: both ports share common IRQ on INTA.
         * Also, leave IRQ masked during drive probing, to prevent infinite
@@ -204,8 +265,7 @@ static void __init init_hwif_ns87415 (ide_hwif_t *hwif)
                return;
 
        hwif->OUTB(0x60, hwif->dma_status);
-       hwif->ide_dma_read = &ns87415_ide_dma_read;
-       hwif->ide_dma_write = &ns87415_ide_dma_write;
+       hwif->dma_setup = &ns87415_ide_dma_setup;
        hwif->ide_dma_check = &ns87415_ide_dma_check;
        hwif->ide_dma_end = &ns87415_ide_dma_end;
 
@@ -217,6 +277,9 @@ static void __init init_hwif_ns87415 (ide_hwif_t *hwif)
 
 static ide_pci_device_t ns87415_chipset __devinitdata = {
        .name           = "NS87415",
+#ifdef CONFIG_SUPERIO
+       .init_iops      = init_iops_ns87415,
+#endif
        .init_hwif      = init_hwif_ns87415,
        .channels       = 2,
        .autodma        = AUTODMA,
@@ -225,8 +288,7 @@ static ide_pci_device_t ns87415_chipset __devinitdata = {
 
 static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
-       ide_setup_pci_device(dev, &ns87415_chipset);
-       return 0;
+       return ide_setup_pci_device(dev, &ns87415_chipset);
 }
 
 static struct pci_device_id ns87415_pci_tbl[] = {