X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-kernel.git;a=blobdiff_plain;f=drivers%2Fide%2Fpci%2Fscc_pata.c;h=789c66dfbde5a424f841cb8e5874a1e887f6959f;hp=ad7cdf9060ca3e1367951fe7221981590ebce041;hb=64a8f00ff19508b3962c8a932375dbae88bee4d6;hpb=fba5c1af5c4fd6645fe62ea84ccde0981282cf66 diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index ad7cdf9060ca..789c66dfbde5 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -126,12 +126,6 @@ static u8 scc_ide_inb(unsigned long port) return (u8)data; } -static u16 scc_ide_inw(unsigned long port) -{ - u32 data = in_be32((void*)port); - return (u16)data; -} - static void scc_ide_insw(unsigned long port, void *addr, u32 count) { u16 *ptr = (u16 *)addr; @@ -154,17 +148,9 @@ static void scc_ide_outb(u8 addr, unsigned long port) out_be32((void*)port, addr); } -static void scc_ide_outw(u16 addr, unsigned long port) +static void scc_ide_outbsync(ide_hwif_t *hwif, u8 addr, unsigned long port) { out_be32((void*)port, addr); -} - -static void -scc_ide_outbsync(ide_drive_t * drive, u8 addr, unsigned long port) -{ - ide_hwif_t *hwif = HWIF(drive); - - out_be32((void*)port, addr); eieio(); in_be32((void*)(hwif->dma_base + 0x01c)); eieio(); @@ -271,6 +257,20 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed) out_be32((void __iomem *)udenvt_port, reg); } +static void scc_dma_host_set(ide_drive_t *drive, int on) +{ + ide_hwif_t *hwif = drive->hwif; + u8 unit = (drive->select.b.unit & 0x01); + u8 dma_stat = scc_ide_inb(hwif->dma_status); + + if (on) + dma_stat |= (1 << (5 + unit)); + else + dma_stat &= ~(1 << (5 + unit)); + + scc_ide_outb(dma_stat, hwif->dma_status); +} + /** * scc_ide_dma_setup - begin a DMA phase * @drive: target device @@ -301,7 +301,7 @@ static int scc_dma_setup(ide_drive_t *drive) } /* PRD table */ - out_be32((void __iomem *)hwif->dma_prdtable, hwif->dmatable_dma); + out_be32((void __iomem *)(hwif->dma_base + 8), hwif->dmatable_dma); /* specify r/w */ out_be32((void __iomem *)hwif->dma_command, reading); @@ -315,13 +315,45 @@ static int scc_dma_setup(ide_drive_t *drive) return 0; } +static void scc_dma_start(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_cmd = scc_ide_inb(hwif->dma_command); + + /* start DMA */ + scc_ide_outb(dma_cmd | 1, hwif->dma_command); + hwif->dma = 1; + wmb(); +} + +static int __scc_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_stat, dma_cmd; + + drive->waiting_for_dma = 0; + /* get DMA command mode */ + dma_cmd = scc_ide_inb(hwif->dma_command); + /* stop DMA */ + scc_ide_outb(dma_cmd & ~1, hwif->dma_command); + /* get DMA status */ + dma_stat = scc_ide_inb(hwif->dma_status); + /* clear the INTR & ERROR bits */ + scc_ide_outb(dma_stat | 6, hwif->dma_status); + /* purge DMA mappings */ + ide_destroy_dmatable(drive); + /* verify good DMA status */ + hwif->dma = 0; + wmb(); + return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; +} /** * scc_dma_end - Stop DMA * @drive: IDE drive * * Check and clear INT Status register. - * Then call __ide_dma_end(). + * Then call __scc_dma_end(). */ static int scc_dma_end(ide_drive_t *drive) @@ -425,7 +457,7 @@ static int scc_dma_end(ide_drive_t *drive) break; } - dma_stat = __ide_dma_end(drive); + dma_stat = __scc_dma_end(drive); if (data_loss) dma_stat |= 2; /* emulate DMA error (to retry command) */ return dma_stat; @@ -526,12 +558,9 @@ static int scc_ide_setup_pci_device(struct pci_dev *dev, u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; int i; - hwif = ide_find_port(); - if (hwif == NULL) { - printk(KERN_ERR "%s: too many IDE interfaces, " - "no room in table\n", SCC_PATA_NAME); + hwif = ide_find_port_slot(d); + if (hwif == NULL) return -ENOMEM; - } memset(&hw, 0, sizeof(hw)); for (i = 0; i <= 8; i++) @@ -540,7 +569,6 @@ static int scc_ide_setup_pci_device(struct pci_dev *dev, hw.dev = &dev->dev; hw.chipset = ide_pci; ide_init_port_hw(hwif, &hw); - hwif->dev = &dev->dev; idx[0] = hwif->index; @@ -618,6 +646,120 @@ static int __devinit init_setup_scc(struct pci_dev *dev, return rc; } +static void scc_tf_load(ide_drive_t *drive, ide_task_t *task) +{ + struct ide_io_ports *io_ports = &drive->hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; + + if (task->tf_flags & IDE_TFLAG_FLAGGED) + HIHI = 0xFF; + + if (task->tf_flags & IDE_TFLAG_OUT_DATA) + out_be32((void *)io_ports->data_addr, + (tf->hob_data << 8) | tf->data); + + if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) + scc_ide_outb(tf->hob_feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) + scc_ide_outb(tf->hob_nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) + scc_ide_outb(tf->hob_lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) + scc_ide_outb(tf->hob_lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) + scc_ide_outb(tf->hob_lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_FEATURE) + scc_ide_outb(tf->feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_NSECT) + scc_ide_outb(tf->nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAL) + scc_ide_outb(tf->lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAM) + scc_ide_outb(tf->lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAH) + scc_ide_outb(tf->lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) + scc_ide_outb((tf->device & HIHI) | drive->select.all, + io_ports->device_addr); +} + +static void scc_tf_read(ide_drive_t *drive, ide_task_t *task) +{ + struct ide_io_ports *io_ports = &drive->hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + + if (task->tf_flags & IDE_TFLAG_IN_DATA) { + u16 data = (u16)in_be32((void *)io_ports->data_addr); + + tf->data = data & 0xff; + tf->hob_data = (data >> 8) & 0xff; + } + + /* be sure we're looking at the low order bits */ + scc_ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_NSECT) + tf->nsect = scc_ide_inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAL) + tf->lbal = scc_ide_inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAM) + tf->lbam = scc_ide_inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAH) + tf->lbah = scc_ide_inb(io_ports->lbah_addr); + if (task->tf_flags & IDE_TFLAG_IN_DEVICE) + tf->device = scc_ide_inb(io_ports->device_addr); + + if (task->tf_flags & IDE_TFLAG_LBA48) { + scc_ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) + tf->hob_feature = scc_ide_inb(io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) + tf->hob_nsect = scc_ide_inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) + tf->hob_lbal = scc_ide_inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) + tf->hob_lbam = scc_ide_inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) + tf->hob_lbah = scc_ide_inb(io_ports->lbah_addr); + } +} + +static void scc_input_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + len++; + + if (drive->io_32bit) { + scc_ide_insl(data_addr, buf, len / 4); + + if ((len & 3) >= 2) + scc_ide_insw(data_addr, (u8 *)buf + (len & ~3), 1); + } else + scc_ide_insw(data_addr, buf, len / 2); +} + +static void scc_output_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + len++; + + if (drive->io_32bit) { + scc_ide_outsl(data_addr, buf, len / 4); + + if ((len & 3) >= 2) + scc_ide_outsw(data_addr, (u8 *)buf + (len & ~3), 1); + } else + scc_ide_outsw(data_addr, buf, len / 2); +} + /** * init_mmio_iops_scc - set up the iops for MMIO * @hwif: interface to set up @@ -632,19 +774,18 @@ static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif) ide_set_hwifdata(hwif, ports); + hwif->tf_load = scc_tf_load; + hwif->tf_read = scc_tf_read; + + hwif->input_data = scc_input_data; + hwif->output_data = scc_output_data; + hwif->INB = scc_ide_inb; - hwif->INW = scc_ide_inw; - hwif->INSW = scc_ide_insw; - hwif->INSL = scc_ide_insl; hwif->OUTB = scc_ide_outb; hwif->OUTBSYNC = scc_ide_outbsync; - hwif->OUTW = scc_ide_outw; - hwif->OUTSW = scc_ide_outsw; - hwif->OUTSL = scc_ide_outsl; hwif->dma_base = dma_base; hwif->config_data = ports->ctl; - hwif->mmio = 1; } /** @@ -687,7 +828,6 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif) hwif->dma_command = hwif->dma_base; hwif->dma_status = hwif->dma_base + 0x04; - hwif->dma_prdtable = hwif->dma_base + 0x08; /* PTERADD */ out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma); @@ -706,10 +846,10 @@ static const struct ide_port_ops scc_port_ops = { }; static const struct ide_dma_ops scc_dma_ops = { - .dma_host_set = ide_dma_host_set, + .dma_host_set = scc_dma_host_set, .dma_setup = scc_dma_setup, .dma_exec_cmd = ide_dma_exec_cmd, - .dma_start = ide_dma_start, + .dma_start = scc_dma_start, .dma_end = scc_dma_end, .dma_test_irq = scc_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq,