via82cxxx: add support for VT6415 PCIE PATA IDE Host Controller
[safe/jmp/linux-2.6] / drivers / ide / pmac.c
index 74625e8..7a4e788 100644 (file)
 #include <asm/pmac_feature.h>
 #include <asm/sections.h>
 #include <asm/irq.h>
-
-#ifndef CONFIG_PPC64
 #include <asm/mediabay.h>
-#endif
 
 #define DRV_NAME "ide-pmac"
 
@@ -59,13 +56,14 @@ typedef struct pmac_ide_hwif {
        int                             irq;
        int                             kind;
        int                             aapl_bus_id;
-       unsigned                        mediabay : 1;
        unsigned                        broken_dma : 1;
        unsigned                        broken_dma_warn : 1;
        struct device_node*             node;
        struct macio_dev                *mdev;
        u32                             timings[4];
        volatile u32 __iomem *          *kauai_fcr;
+       ide_hwif_t                      *hwif;
+
        /* Those fields are duplicating what is in hwif. We currently
         * can't use the hwif ones because of some assumptions that are
         * beeing done by the generic code about the kind of dma controller
@@ -404,9 +402,6 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
 #define IDE_WAKEUP_DELAY       (1*HZ)
 
 static int pmac_ide_init_dma(ide_hwif_t *, const struct ide_port_info *);
-static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq);
-static void pmac_ide_selectproc(ide_drive_t *drive);
-static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
 
 #define PMAC_IDE_REG(x) \
        ((void __iomem *)((drive)->hwif->io_ports.data_addr + (x)))
@@ -416,8 +411,7 @@ static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
  * timing register when selecting that unit. This version is for
  * ASICs with a single timing register
  */
-static void
-pmac_ide_selectproc(ide_drive_t *drive)
+static void pmac_ide_apply_timings(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
@@ -435,8 +429,7 @@ pmac_ide_selectproc(ide_drive_t *drive)
  * timing register when selecting that unit. This version is for
  * ASICs with a dual timing register (Kauai)
  */
-static void
-pmac_ide_kauai_selectproc(ide_drive_t *drive)
+static void pmac_ide_kauai_apply_timings(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
@@ -465,9 +458,25 @@ pmac_ide_do_update_timings(ide_drive_t *drive)
        if (pmif->kind == controller_sh_ata6 ||
            pmif->kind == controller_un_ata6 ||
            pmif->kind == controller_k2_ata6)
-               pmac_ide_kauai_selectproc(drive);
+               pmac_ide_kauai_apply_timings(drive);
        else
-               pmac_ide_selectproc(drive);
+               pmac_ide_apply_timings(drive);
+}
+
+static void pmac_dev_select(ide_drive_t *drive)
+{
+       pmac_ide_apply_timings(drive);
+
+       writeb(drive->select | ATA_DEVICE_OBS,
+              (void __iomem *)drive->hwif->io_ports.device_addr);
+}
+
+static void pmac_kauai_dev_select(ide_drive_t *drive)
+{
+       pmac_ide_kauai_apply_timings(drive);
+
+       writeb(drive->select | ATA_DEVICE_OBS,
+              (void __iomem *)drive->hwif->io_ports.device_addr);
 }
 
 static void pmac_exec_command(ide_hwif_t *hwif, u8 cmd)
@@ -477,17 +486,8 @@ static void pmac_exec_command(ide_hwif_t *hwif, u8 cmd)
                                     + IDE_TIMING_CONFIG));
 }
 
-static void pmac_set_irq(ide_hwif_t *hwif, int on)
+static void pmac_write_devctl(ide_hwif_t *hwif, u8 ctl)
 {
-       u8 ctl = ATA_DEVCTL_OBS;
-
-       if (on == 4) { /* hack for SRST */
-               ctl |= 4;
-               on &= ~4;
-       }
-
-       ctl |= on ? 0 : 2;
-
        writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
        (void)readl((void __iomem *)(hwif->io_ports.data_addr
                                     + IDE_TIMING_CONFIG));
@@ -852,6 +852,11 @@ sanitize_timings(pmac_ide_hwif_t *pmif)
        pmif->timings[2] = pmif->timings[3] = value2;
 }
 
+static int on_media_bay(pmac_ide_hwif_t *pmif)
+{
+       return pmif->mdev && pmif->mdev->media_bay != NULL;
+}
+
 /* Suspend call back, should be called after the child devices
  * have actually been suspended
  */
@@ -864,7 +869,7 @@ static int pmac_ide_do_suspend(pmac_ide_hwif_t *pmif)
        disable_irq(pmif->irq);
 
        /* The media bay will handle itself just fine */
-       if (pmif->mediabay)
+       if (on_media_bay(pmif))
                return 0;
        
        /* Kauai has bus control FCRs directly here */
@@ -887,7 +892,7 @@ static int pmac_ide_do_suspend(pmac_ide_hwif_t *pmif)
 static int pmac_ide_do_resume(pmac_ide_hwif_t *pmif)
 {
        /* Hard reset & re-enable controller (do we really need to reset ? -BenH) */
-       if (!pmif->mediabay) {
+       if (!on_media_bay(pmif)) {
                ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 1);
                ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1);
                msleep(10);
@@ -917,10 +922,18 @@ static u8 pmac_ide_cable_detect(ide_hwif_t *hwif)
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
        struct device_node *np = pmif->node;
        const char *cable = of_get_property(np, "cable-type", NULL);
+       struct device_node *root = of_find_node_by_path("/");
+       const char *model = of_get_property(root, "model", NULL);
 
        /* Get cable type from device-tree. */
-       if (cable && !strncmp(cable, "80-", 3))
-               return ATA_CBL_PATA80;
+       if (cable && !strncmp(cable, "80-", 3)) {
+               /* Some drives fail to detect 80c cable in PowerBook */
+               /* These machine use proprietary short IDE cable anyway */
+               if (!strncmp(model, "PowerBook", 9))
+                       return ATA_CBL_PATA40_SHORT;
+               else
+                       return ATA_CBL_PATA80;
+       }
 
        /*
         * G5's seem to have incorrect cable type in device-tree.
@@ -940,13 +953,11 @@ static void pmac_ide_init_dev(ide_drive_t *drive)
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
 
-       if (pmif->mediabay) {
-#ifdef CONFIG_PMAC_MEDIABAY
-               if (check_media_bay_by_base(pmif->regbase, MB_CD) == 0) {
+       if (on_media_bay(pmif)) {
+               if (check_media_bay(pmif->mdev->media_bay) == MB_CD) {
                        drive->dev_flags &= ~IDE_DFLAG_NOPROBE;
                        return;
                }
-#endif
                drive->dev_flags |= IDE_DFLAG_NOPROBE;
        }
 }
@@ -955,9 +966,9 @@ static const struct ide_tp_ops pmac_tp_ops = {
        .exec_command           = pmac_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = pmac_write_devctl,
 
-       .set_irq                = pmac_set_irq,
-
+       .dev_select             = pmac_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = ide_tf_read,
 
@@ -965,19 +976,24 @@ static const struct ide_tp_ops pmac_tp_ops = {
        .output_data            = ide_output_data,
 };
 
-static const struct ide_port_ops pmac_ide_ata6_port_ops = {
-       .init_dev               = pmac_ide_init_dev,
-       .set_pio_mode           = pmac_ide_set_pio_mode,
-       .set_dma_mode           = pmac_ide_set_dma_mode,
-       .selectproc             = pmac_ide_kauai_selectproc,
-       .cable_detect           = pmac_ide_cable_detect,
+static const struct ide_tp_ops pmac_ata6_tp_ops = {
+       .exec_command           = pmac_exec_command,
+       .read_status            = ide_read_status,
+       .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = pmac_write_devctl,
+
+       .dev_select             = pmac_kauai_dev_select,
+       .tf_load                = ide_tf_load,
+       .tf_read                = ide_tf_read,
+
+       .input_data             = ide_input_data,
+       .output_data            = ide_output_data,
 };
 
 static const struct ide_port_ops pmac_ide_ata4_port_ops = {
        .init_dev               = pmac_ide_init_dev,
        .set_pio_mode           = pmac_ide_set_pio_mode,
        .set_dma_mode           = pmac_ide_set_dma_mode,
-       .selectproc             = pmac_ide_selectproc,
        .cable_detect           = pmac_ide_cable_detect,
 };
 
@@ -985,7 +1001,6 @@ static const struct ide_port_ops pmac_ide_port_ops = {
        .init_dev               = pmac_ide_init_dev,
        .set_pio_mode           = pmac_ide_set_pio_mode,
        .set_dma_mode           = pmac_ide_set_dma_mode,
-       .selectproc             = pmac_ide_selectproc,
 };
 
 static const struct ide_dma_ops pmac_dma_ops;
@@ -1009,28 +1024,32 @@ static const struct ide_port_info pmac_port_info = {
  * Setup, register & probe an IDE channel driven by this driver, this is
  * called by one of the 2 probe functions (macio or PCI).
  */
-static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
+static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif,
+                                          struct ide_hw *hw)
 {
        struct device_node *np = pmif->node;
        const int *bidp;
        struct ide_host *host;
        ide_hwif_t *hwif;
-       hw_regs_t *hws[] = { hw, NULL, NULL, NULL };
+       struct ide_hw *hws[] = { hw };
        struct ide_port_info d = pmac_port_info;
        int rc;
 
        pmif->broken_dma = pmif->broken_dma_warn = 0;
        if (of_device_is_compatible(np, "shasta-ata")) {
                pmif->kind = controller_sh_ata6;
-               d.port_ops = &pmac_ide_ata6_port_ops;
+               d.tp_ops = &pmac_ata6_tp_ops;
+               d.port_ops = &pmac_ide_ata4_port_ops;
                d.udma_mask = ATA_UDMA6;
        } else if (of_device_is_compatible(np, "kauai-ata")) {
                pmif->kind = controller_un_ata6;
-               d.port_ops = &pmac_ide_ata6_port_ops;
+               d.tp_ops = &pmac_ata6_tp_ops;
+               d.port_ops = &pmac_ide_ata4_port_ops;
                d.udma_mask = ATA_UDMA5;
        } else if (of_device_is_compatible(np, "K2-UATA")) {
                pmif->kind = controller_k2_ata6;
-               d.port_ops = &pmac_ide_ata6_port_ops;
+               d.tp_ops = &pmac_ata6_tp_ops;
+               d.port_ops = &pmac_ide_ata4_port_ops;
                d.udma_mask = ATA_UDMA5;
        } else if (of_device_is_compatible(np, "keylargo-ata")) {
                if (strcmp(np->name, "ata-4") == 0) {
@@ -1054,26 +1073,23 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
                writel(KAUAI_FCR_UATA_MAGIC |
                       KAUAI_FCR_UATA_RESET_N |
                       KAUAI_FCR_UATA_ENABLE, pmif->kauai_fcr);
-
-       pmif->mediabay = 0;
        
        /* Make sure we have sane timings */
        sanitize_timings(pmif);
 
-       host = ide_host_alloc(&d, hws);
-       if (host == NULL)
-               return -ENOMEM;
-       hwif = host->ports[0];
+       /* If we are on a media bay, wait for it to settle and lock it */
+       if (pmif->mdev)
+               lock_media_bay(pmif->mdev->media_bay);
 
-#ifndef CONFIG_PPC64
-       /* XXX FIXME: Media bay stuff need re-organizing */
-       if (np->parent && np->parent->name
-           && strcasecmp(np->parent->name, "media-bay") == 0) {
-#ifdef CONFIG_PMAC_MEDIABAY
-               media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq,
-                                       hwif);
-#endif /* CONFIG_PMAC_MEDIABAY */
-               pmif->mediabay = 1;
+       host = ide_host_alloc(&d, hws, 1);
+       if (host == NULL) {
+               rc = -ENOMEM;
+               goto bail;
+       }
+       hwif = pmif->hwif = host->ports[0];
+
+       if (on_media_bay(pmif)) {
+               /* Fixup bus ID for media bay */
                if (!bidp)
                        pmif->aapl_bus_id = 1;
        } else if (pmif->kind == controller_ohare) {
@@ -1082,9 +1098,7 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
                 * units, I keep the old way
                 */
                ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
-       } else
-#endif
-       {
+       } else {
                /* This is necessary to enable IDE when net-booting */
                ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
                ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
@@ -1094,20 +1108,24 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
        }
 
        printk(KERN_INFO DRV_NAME ": Found Apple %s controller (%s), "
-                        "bus ID %d%s, irq %d\n", model_name[pmif->kind],
-                        pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id,
-                        pmif->mediabay ? " (mediabay)" : "", hw->irq);
+              "bus ID %d%s, irq %d\n", model_name[pmif->kind],
+              pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id,
+              on_media_bay(pmif) ? " (mediabay)" : "", hw->irq);
 
        rc = ide_host_register(host, &d, hws);
-       if (rc) {
-               ide_host_free(host);
-               return rc;
-       }
+       if (rc)
+               pmif->hwif = NULL;
 
-       return 0;
+       if (pmif->mdev)
+               unlock_media_bay(pmif->mdev->media_bay);
+
+ bail:
+       if (rc && host)
+               ide_host_free(host);
+       return rc;
 }
 
-static void __devinit pmac_ide_init_ports(hw_regs_t *hw, unsigned long base)
+static void __devinit pmac_ide_init_ports(struct ide_hw *hw, unsigned long base)
 {
        int i;
 
@@ -1127,7 +1145,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
        unsigned long regbase;
        pmac_ide_hwif_t *pmif;
        int irq, rc;
-       hw_regs_t hw;
+       struct ide_hw hw;
 
        pmif = kzalloc(sizeof(*pmif), GFP_KERNEL);
        if (pmif == NULL)
@@ -1251,7 +1269,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        void __iomem *base;
        unsigned long rbase, rlen;
        int rc;
-       hw_regs_t hw;
+       struct ide_hw hw;
 
        np = pci_device_to_OF_node(pdev);
        if (np == NULL) {
@@ -1344,6 +1362,25 @@ pmac_ide_pci_resume(struct pci_dev *pdev)
        return rc;
 }
 
+#ifdef CONFIG_PMAC_MEDIABAY
+static void pmac_ide_macio_mb_event(struct macio_dev* mdev, int mb_state)
+{
+       pmac_ide_hwif_t *pmif =
+               (pmac_ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
+
+       switch(mb_state) {
+       case MB_CD:
+               if (!pmif->hwif->present)
+                       ide_port_scan(pmif->hwif);
+               break;
+       default:
+               if (pmif->hwif->present)
+                       ide_port_unregister_devices(pmif->hwif);
+       }
+}
+#endif /* CONFIG_PMAC_MEDIABAY */
+
+
 static struct of_device_id pmac_ide_macio_match[] = 
 {
        {
@@ -1368,6 +1405,9 @@ static struct macio_driver pmac_ide_macio_driver =
        .probe          = pmac_ide_macio_attach,
        .suspend        = pmac_ide_macio_suspend,
        .resume         = pmac_ide_macio_resume,
+#ifdef CONFIG_PMAC_MEDIABAY
+       .mediabay_event = pmac_ide_macio_mb_event,
+#endif
 };
 
 static const struct pci_device_id pmac_ide_pci_match[] = {
@@ -1422,17 +1462,16 @@ out:
  * pmac_ide_build_dmatable builds the DBDMA command list
  * for a transfer and sets the DBDMA channel to point to it.
  */
-static int
-pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
+static int pmac_ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
        struct dbdma_cmd *table;
-       int i, count = 0;
        volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
        struct scatterlist *sg;
-       int wr = (rq_data_dir(rq) == WRITE);
+       int wr = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
+       int i = cmd->sg_nents, count = 0;
 
        /* DMA table is already aligned */
        table = (struct dbdma_cmd *) pmif->dma_table_cpu;
@@ -1442,11 +1481,6 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
        while (readl(&dma->status) & RUN)
                udelay(1);
 
-       hwif->sg_nents = i = ide_build_sglist(drive, rq);
-
-       if (!i)
-               return 0;
-
        /* Build DBDMA commands list */
        sg = hwif->sg_table;
        while (i && sg_dma_len(sg)) {
@@ -1462,7 +1496,7 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
                                       "switching to PIO on Ohare chipset\n", drive->name);
                                pmif->broken_dma_warn = 1;
                        }
-                       goto use_pio_instead;
+                       return 0;
                }
                while (cur_len) {
                        unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
@@ -1470,7 +1504,7 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
                        if (count++ >= MAX_DCMDS) {
                                printk(KERN_WARNING "%s: DMA table too small\n",
                                       drive->name);
-                               goto use_pio_instead;
+                               return 0;
                        }
                        st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
                        st_le16(&table->req_count, tc);
@@ -1499,9 +1533,6 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
 
        printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
 
-use_pio_instead:
-       ide_destroy_dmatable(drive);
-
        return 0; /* revert to PIO for this request */
 }
 
@@ -1509,39 +1540,27 @@ use_pio_instead:
  * Prepare a DMA transfer. We build the DMA table, adjust the timings for
  * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion
  */
-static int
-pmac_ide_dma_setup(ide_drive_t *drive)
+static int pmac_ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
-       struct request *rq = hwif->rq;
        u8 unit = drive->dn & 1, ata4 = (pmif->kind == controller_kl_ata4);
+       u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
 
-       if (!pmac_ide_build_dmatable(drive, rq)) {
-               ide_map_sg(drive, rq);
+       if (pmac_ide_build_dmatable(drive, cmd) == 0)
                return 1;
-       }
 
        /* Apple adds 60ns to wrDataSetup on reads */
        if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
-               writel(pmif->timings[unit] + (!rq_data_dir(rq) ? 0x00800000UL : 0),
+               writel(pmif->timings[unit] + (write ? 0 : 0x00800000UL),
                        PMAC_IDE_REG(IDE_TIMING_CONFIG));
                (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG));
        }
 
-       drive->waiting_for_dma = 1;
-
        return 0;
 }
 
-static void
-pmac_ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
-{
-       /* issue cmd to drive */
-       ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, NULL);
-}
-
 /*
  * Kick the DMA controller into life after the DMA command has been issued
  * to the drive.
@@ -1573,12 +1592,9 @@ pmac_ide_dma_end (ide_drive_t *drive)
        volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
        u32 dstat;
 
-       drive->waiting_for_dma = 0;
        dstat = readl(&dma->status);
        writel(((RUN|WAKE|DEAD) << 16), &dma->control);
 
-       ide_destroy_dmatable(drive);
-
        /* verify good dma status. we don't check for ACTIVE beeing 0. We should...
         * in theory, but with ATAPI decices doing buffer underruns, that would
         * cause us to disable DMA, which isn't what we want
@@ -1662,11 +1678,9 @@ pmac_ide_dma_lost_irq (ide_drive_t *drive)
 static const struct ide_dma_ops pmac_dma_ops = {
        .dma_host_set           = pmac_ide_dma_host_set,
        .dma_setup              = pmac_ide_dma_setup,
-       .dma_exec_cmd           = pmac_ide_dma_exec_cmd,
        .dma_start              = pmac_ide_dma_start,
        .dma_end                = pmac_ide_dma_end,
        .dma_test_irq           = pmac_ide_dma_test_irq,
-       .dma_timeout            = ide_dma_timeout,
        .dma_lost_irq           = pmac_ide_dma_lost_irq,
 };
 
@@ -1691,7 +1705,7 @@ static int __devinit pmac_ide_init_dma(ide_hwif_t *hwif,
         * The +2 is +1 for the stop command and +1 to allow for
         * aligning the start address to a multiple of 16 bytes.
         */
-       pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
+       pmif->dma_table_cpu = pci_alloc_consistent(
                dev,
                (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
                &hwif->dmatable_dma);