+ if (unlikely(slop)) {
+ u32 pad;
+ if (rw == WRITE) {
+ memcpy(&pad, buf + buflen - slop, slop);
+ pad = le32_to_cpu(pad);
+ iowrite32(pad, ap->ioaddr.data_addr);
+ } else {
+ pad = ioread32(ap->ioaddr.data_addr);
+ pad = cpu_to_le32(pad);
+ memcpy(buf + buflen - slop, &pad, slop);
+ }
+ }
+ return (buflen + 3) & ~3;
+ } else
+ return ata_data_xfer(adev, buf, buflen, rw);
+}
+
+static int qdi_port(struct platform_device *dev,
+ struct legacy_probe *lp, struct legacy_data *ld)
+{
+ if (devm_request_region(&dev->dev, lp->private, 4, "qdi") == NULL)
+ return -EBUSY;
+ ld->timing = lp->private;
+ return 0;
+}
+
+static struct ata_port_operations qdi6500_port_ops = {
+ .set_piomode = qdi6500_set_piomode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = qdi_qc_issue_prot,
+
+ .data_xfer = vlb32_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ .port_start = ata_sff_port_start,
+};
+
+static struct ata_port_operations qdi6580_port_ops = {
+ .set_piomode = qdi6580_set_piomode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = vlb32_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ .port_start = ata_sff_port_start,
+};
+
+static struct ata_port_operations qdi6580dp_port_ops = {
+ .set_piomode = qdi6580dp_set_piomode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = qdi_qc_issue_prot,
+
+ .data_xfer = vlb32_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ .port_start = ata_sff_port_start,
+};
+
+static DEFINE_SPINLOCK(winbond_lock);
+
+static void winbond_writecfg(unsigned long port, u8 reg, u8 val)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&winbond_lock, flags);
+ outb(reg, port + 0x01);
+ outb(val, port + 0x02);
+ spin_unlock_irqrestore(&winbond_lock, flags);
+}
+
+static u8 winbond_readcfg(unsigned long port, u8 reg)
+{
+ u8 val;
+
+ unsigned long flags;
+ spin_lock_irqsave(&winbond_lock, flags);
+ outb(reg, port + 0x01);
+ val = inb(port + 0x02);
+ spin_unlock_irqrestore(&winbond_lock, flags);
+
+ return val;
+}
+
+static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_timing t;
+ struct legacy_data *winbond = ap->host->private_data;
+ int active, recovery;
+ u8 reg;
+ int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2);
+
+ reg = winbond_readcfg(winbond->timing, 0x81);
+
+ /* Get the timing data in cycles */
+ if (reg & 0x40) /* Fast VLB bus, assume 50MHz */
+ ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
+ else
+ ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+
+ active = (FIT(t.active, 3, 17) - 1) & 0x0F;
+ recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F;
+ timing = (active << 4) | recovery;
+ winbond_writecfg(winbond->timing, timing, reg);
+
+ /* Load the setup timing */
+
+ reg = 0x35;
+ if (adev->class != ATA_DEV_ATA)
+ reg |= 0x08; /* FIFO off */
+ if (!ata_pio_need_iordy(adev))
+ reg |= 0x02; /* IORDY off */
+ reg |= (FIT(t.setup, 0, 3) << 6);
+ winbond_writecfg(winbond->timing, timing + 1, reg);
+}
+
+static int winbond_port(struct platform_device *dev,
+ struct legacy_probe *lp, struct legacy_data *ld)
+{
+ if (devm_request_region(&dev->dev, lp->private, 4, "winbond") == NULL)
+ return -EBUSY;
+ ld->timing = lp->private;
+ return 0;
+}
+
+static struct ata_port_operations winbond_port_ops = {
+ .set_piomode = winbond_set_piomode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = vlb32_data_xfer,
+
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ .port_start = ata_sff_port_start,
+};
+
+static struct legacy_controller controllers[] = {
+ {"BIOS", &legacy_port_ops, 0x1F,
+ ATA_FLAG_NO_IORDY, NULL },
+ {"Snooping", &simple_port_ops, 0x1F,
+ 0 , NULL },
+ {"PDC20230", &pdc20230_port_ops, 0x7,
+ ATA_FLAG_NO_IORDY, NULL },
+ {"HT6560A", &ht6560a_port_ops, 0x07,
+ ATA_FLAG_NO_IORDY, NULL },
+ {"HT6560B", &ht6560b_port_ops, 0x1F,
+ ATA_FLAG_NO_IORDY, NULL },
+ {"OPTI82C611A", &opti82c611a_port_ops, 0x0F,
+ 0 , NULL },
+ {"OPTI82C46X", &opti82c46x_port_ops, 0x0F,
+ 0 , NULL },
+ {"QDI6500", &qdi6500_port_ops, 0x07,
+ ATA_FLAG_NO_IORDY, qdi_port },
+ {"QDI6580", &qdi6580_port_ops, 0x1F,
+ 0 , qdi_port },
+ {"QDI6580DP", &qdi6580dp_port_ops, 0x1F,
+ 0 , qdi_port },
+ {"W83759A", &winbond_port_ops, 0x1F,
+ 0 , winbond_port }
+};