* bfin_set_dmamode - Initialize host controller PATA DMA timings
* @ap: Port whose timings we are configuring
* @adev: um
- * @udma: udma mode, 0 - 6
*
* Set UDMA mode for device.
*
/* Reset all transfer count */
ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);
- /* Set transfer length to buffer len */
+ /* Set ATAPI state machine contorl in terminate sequence */
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | END_ON_TERM);
+
+ /* Set transfer length to buffer len */
for_each_sg(qc->sg, sg, qc->n_elem, si) {
ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
}
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
unsigned int dev0 = devmask & (1 << 0);
unsigned int dev1 = devmask & (1 << 1);
- unsigned long timeout;
+ unsigned long deadline;
/* if device 0 was found in ata_devchk, wait for its
* BSY bit to clear
/* if device 1 was found in ata_devchk, wait for
* register access, then wait for BSY to clear
*/
- timeout = jiffies + ATA_TMOUT_BOOT;
+ deadline = ata_deadline(jiffies, ATA_TMOUT_BOOT);
while (dev1) {
u8 nsect, lbal;
lbal = read_atapi_register(base, ATA_REG_LBAL);
if ((nsect == 1) && (lbal == 1))
break;
- if (time_after(jiffies, timeout)) {
+ if (time_after(jiffies, deadline)) {
dev1 = 0;
break;
}
void bfin_thaw(struct ata_port *ap)
{
+ dev_dbg(ap->dev, "in atapi dma thaw\n");
bfin_check_status(ap);
- bfin_irq_clear(ap);
bfin_irq_on(ap);
}
return 0;
}
+static unsigned int bfin_ata_host_intr(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
+{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ u8 status, host_stat = 0;
+
+ VPRINTK("ata%u: protocol %d task_state %d\n",
+ ap->print_id, qc->tf.protocol, ap->hsm_task_state);
+
+ /* Check whether we are expecting interrupt in this state */
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
+ /* Some pre-ATAPI-4 devices assert INTRQ
+ * at this state when ready to receive CDB.
+ */
+
+ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+ * The flag was turned on only for atapi devices.
+ * No need to check is_atapi_taskfile(&qc->tf) again.
+ */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ goto idle_irq;
+ break;
+ case HSM_ST_LAST:
+ if (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATAPI_PROT_DMA) {
+ /* check status of DMA engine */
+ host_stat = ap->ops->bmdma_status(ap);
+ VPRINTK("ata%u: host_stat 0x%X\n",
+ ap->print_id, host_stat);
+
+ /* if it's not our irq... */
+ if (!(host_stat & ATA_DMA_INTR))
+ goto idle_irq;
+
+ /* before we do anything else, clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+
+ if (unlikely(host_stat & ATA_DMA_ERR)) {
+ /* error when transfering data to/from memory */
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ ap->hsm_task_state = HSM_ST_ERR;
+ }
+ }
+ break;
+ case HSM_ST:
+ break;
+ default:
+ goto idle_irq;
+ }
+
+ /* check altstatus */
+ status = ap->ops->sff_check_altstatus(ap);
+ if (status & ATA_BUSY)
+ goto busy_ata;
+
+ /* check main status, clearing INTRQ */
+ status = ap->ops->sff_check_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ goto busy_ata;
+
+ /* ack bmdma irq events */
+ ap->ops->sff_irq_clear(ap);
+
+ ata_sff_hsm_move(ap, qc, status, 0);
+
+ if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATAPI_PROT_DMA))
+ ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
+
+busy_ata:
+ return 1; /* irq handled */
+
+idle_irq:
+ ap->stats.idle_irq++;
+
+#ifdef ATA_IRQ_TRAP
+ if ((ap->stats.idle_irq % 1000) == 0) {
+ ap->ops->irq_ack(ap, 0); /* debug trap */
+ ata_port_printk(ap, KERN_WARNING, "irq trap\n");
+ return 1;
+ }
+#endif
+ return 0; /* irq not handled */
+}
+
+static irqreturn_t bfin_ata_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ unsigned int i;
+ unsigned int handled = 0;
+ unsigned long flags;
+
+ /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
+ spin_lock_irqsave(&host->lock, flags);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap;
+
+ ap = host->ports[i];
+ if (ap &&
+ !(ap->flags & ATA_FLAG_DISABLED)) {
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
+ (qc->flags & ATA_QCFLAG_ACTIVE))
+ handled |= bfin_ata_host_intr(ap, qc);
+ }
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+
static struct scsi_host_template bfin_sht = {
ATA_BASE_SHT(DRV_NAME),
.sg_tablesize = SG_NONE,
.dma_boundary = ATA_DMA_BOUNDARY,
};
-static const struct ata_port_operations bfin_pata_ops = {
+static struct ata_port_operations bfin_pata_ops = {
.inherits = &ata_sff_port_ops,
.set_piomode = bfin_set_piomode,
.thaw = bfin_thaw,
.softreset = bfin_softreset,
.postreset = bfin_postreset,
- .post_internal_cmd = bfin_bmdma_stop,
.sff_irq_clear = bfin_irq_clear,
.sff_irq_on = bfin_irq_on,
.flags = ATA_FLAG_SLAVE_POSS
| ATA_FLAG_MMIO
| ATA_FLAG_NO_LEGACY,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
.mwdma_mask = 0,
.udma_mask = 0,
.port_ops = &bfin_pata_ops,
count = 10000000;
do {
status = read_atapi_register(base, ATA_REG_STATUS);
- } while (count-- && (status & ATA_BUSY));
+ } while (--count && (status & ATA_BUSY));
/* Enable only ATAPI Device interrupt */
ATAPI_SET_INT_MASK(base, 1);
}
if (ata_host_activate(host, platform_get_irq(pdev, 0),
- ata_sff_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
+ bfin_ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
peripheral_free_list(atapi_io_port);
dev_err(&pdev->dev, "Fail to attach ATAPI device\n");
return -ENODEV;
}
+ dev_set_drvdata(&pdev->dev, host);
+
return 0;
}
struct ata_host *host = dev_get_drvdata(dev);
ata_host_detach(host);
+ dev_set_drvdata(&pdev->dev, NULL);
peripheral_free_list(atapi_io_port);
}
#ifdef CONFIG_PM
-int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
+static int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
{
- return 0;
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ if (host)
+ return ata_host_suspend(host, state);
+ else
+ return 0;
}
-int bfin_atapi_resume(struct platform_device *pdev)
+static int bfin_atapi_resume(struct platform_device *pdev)
{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int ret;
+
+ if (host) {
+ ret = bfin_reset_controller(host);
+ if (ret) {
+ printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+ return ret;
+ }
+ ata_host_resume(host);
+ }
+
return 0;
}
+#else
+#define bfin_atapi_suspend NULL
+#define bfin_atapi_resume NULL
#endif
static struct platform_driver bfin_atapi_driver = {
.probe = bfin_atapi_probe,
.remove = __devexit_p(bfin_atapi_remove),
+ .suspend = bfin_atapi_suspend,
+ .resume = bfin_atapi_resume,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .suspend = bfin_atapi_suspend,
- .resume = bfin_atapi_resume,
-#endif
},
};
MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);