diff options
Diffstat (limited to 'drivers/ata/sata_dwc_460ex.c')
-rw-r--r-- | drivers/ata/sata_dwc_460ex.c | 552 |
1 files changed, 283 insertions, 269 deletions
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index 902034991517..00c2af1d211b 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -30,10 +30,12 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> +#include <linux/dmaengine.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/phy/phy.h> #include <linux/libata.h> #include <linux/slab.h> @@ -42,10 +44,6 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_cmnd.h> -/* Supported DMA engine drivers */ -#include <linux/platform_data/dma-dw.h> -#include <linux/dma/dw.h> - /* These two are defined in "libata.h" */ #undef DRV_NAME #undef DRV_VERSION @@ -53,19 +51,14 @@ #define DRV_NAME "sata-dwc" #define DRV_VERSION "1.3" -#ifndef out_le32 -#define out_le32(a, v) __raw_writel(__cpu_to_le32(v), (void __iomem *)(a)) -#endif - -#ifndef in_le32 -#define in_le32(a) __le32_to_cpu(__raw_readl((void __iomem *)(a))) -#endif +#define sata_dwc_writel(a, v) writel_relaxed(v, a) +#define sata_dwc_readl(a) readl_relaxed(a) #ifndef NO_IRQ #define NO_IRQ 0 #endif -#define AHB_DMA_BRST_DFLT 64 /* 16 data items burst length*/ +#define AHB_DMA_BRST_DFLT 64 /* 16 data items burst length */ enum { SATA_DWC_MAX_PORTS = 1, @@ -102,7 +95,7 @@ struct sata_dwc_regs { u32 versionr; /* Version Register */ u32 idr; /* ID Register */ u32 unimpl[192]; /* Unimplemented */ - u32 dmadr[256]; /* FIFO Locations in DMA Mode */ + u32 dmadr[256]; /* FIFO Locations in DMA Mode */ }; enum { @@ -146,9 +139,14 @@ struct sata_dwc_device { struct device *dev; /* generic device struct */ struct ata_probe_ent *pe; /* ptr to probe-ent */ struct ata_host *host; - u8 __iomem *reg_base; - struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */ + struct sata_dwc_regs __iomem *sata_dwc_regs; /* DW SATA specific */ + u32 sactive_issued; + u32 sactive_queued; + struct phy *phy; + phys_addr_t dmadr; +#ifdef CONFIG_SATA_DWC_OLD_DMA struct dw_dma_chip *dma; +#endif }; #define SATA_DWC_QCMD_MAX 32 @@ -159,25 +157,19 @@ struct sata_dwc_device_port { int dma_pending[SATA_DWC_QCMD_MAX]; /* DMA info */ - struct dw_dma_slave *dws; struct dma_chan *chan; struct dma_async_tx_descriptor *desc[SATA_DWC_QCMD_MAX]; u32 dma_interrupt_count; }; /* - * Commonly used DWC SATA driver Macros + * Commonly used DWC SATA driver macros */ -#define HSDEV_FROM_HOST(host) ((struct sata_dwc_device *)\ - (host)->private_data) -#define HSDEV_FROM_AP(ap) ((struct sata_dwc_device *)\ - (ap)->host->private_data) -#define HSDEVP_FROM_AP(ap) ((struct sata_dwc_device_port *)\ - (ap)->private_data) -#define HSDEV_FROM_QC(qc) ((struct sata_dwc_device *)\ - (qc)->ap->host->private_data) -#define HSDEV_FROM_HSDEVP(p) ((struct sata_dwc_device *)\ - (hsdevp)->hsdev) +#define HSDEV_FROM_HOST(host) ((struct sata_dwc_device *)(host)->private_data) +#define HSDEV_FROM_AP(ap) ((struct sata_dwc_device *)(ap)->host->private_data) +#define HSDEVP_FROM_AP(ap) ((struct sata_dwc_device_port *)(ap)->private_data) +#define HSDEV_FROM_QC(qc) ((struct sata_dwc_device *)(qc)->ap->host->private_data) +#define HSDEV_FROM_HSDEVP(p) ((struct sata_dwc_device *)(p)->hsdev) enum { SATA_DWC_CMD_ISSUED_NOT = 0, @@ -190,21 +182,6 @@ enum { SATA_DWC_DMA_PENDING_RX = 2, }; -struct sata_dwc_host_priv { - void __iomem *scr_addr_sstatus; - u32 sata_dwc_sactive_issued ; - u32 sata_dwc_sactive_queued ; -}; - -static struct sata_dwc_host_priv host_pvt; - -static struct dw_dma_slave sata_dwc_dma_dws = { - .src_id = 0, - .dst_id = 0, - .src_master = 0, - .dst_master = 1, -}; - /* * Prototypes */ @@ -215,6 +192,93 @@ static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status); static void sata_dwc_port_stop(struct ata_port *ap); static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag); +#ifdef CONFIG_SATA_DWC_OLD_DMA + +#include <linux/platform_data/dma-dw.h> +#include <linux/dma/dw.h> + +static struct dw_dma_slave sata_dwc_dma_dws = { + .src_id = 0, + .dst_id = 0, + .m_master = 1, + .p_master = 0, +}; + +static bool sata_dwc_dma_filter(struct dma_chan *chan, void *param) +{ + struct dw_dma_slave *dws = &sata_dwc_dma_dws; + + if (dws->dma_dev != chan->device->dev) + return false; + + chan->private = dws; + return true; +} + +static int sata_dwc_dma_get_channel_old(struct sata_dwc_device_port *hsdevp) +{ + struct sata_dwc_device *hsdev = hsdevp->hsdev; + struct dw_dma_slave *dws = &sata_dwc_dma_dws; + dma_cap_mask_t mask; + + dws->dma_dev = hsdev->dev; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + /* Acquire DMA channel */ + hsdevp->chan = dma_request_channel(mask, sata_dwc_dma_filter, hsdevp); + if (!hsdevp->chan) { + dev_err(hsdev->dev, "%s: dma channel unavailable\n", + __func__); + return -EAGAIN; + } + + return 0; +} + +static int sata_dwc_dma_init_old(struct platform_device *pdev, + struct sata_dwc_device *hsdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res; + + hsdev->dma = devm_kzalloc(&pdev->dev, sizeof(*hsdev->dma), GFP_KERNEL); + if (!hsdev->dma) + return -ENOMEM; + + hsdev->dma->dev = &pdev->dev; + + /* Get SATA DMA interrupt number */ + hsdev->dma->irq = irq_of_parse_and_map(np, 1); + if (hsdev->dma->irq == NO_IRQ) { + dev_err(&pdev->dev, "no SATA DMA irq\n"); + return -ENODEV; + } + + /* Get physical SATA DMA register base address */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + hsdev->dma->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hsdev->dma->regs)) { + dev_err(&pdev->dev, + "ioremap failed for AHBDMA register address\n"); + return PTR_ERR(hsdev->dma->regs); + } + + /* Initialize AHB DMAC */ + return dw_dma_probe(hsdev->dma); +} + +static void sata_dwc_dma_exit_old(struct sata_dwc_device *hsdev) +{ + if (!hsdev->dma) + return; + + dw_dma_remove(hsdev->dma); +} + +#endif + static const char *get_prot_descript(u8 protocol) { switch ((enum ata_tf_protocols)protocol) { @@ -305,21 +369,20 @@ static struct dma_async_tx_descriptor *dma_dwc_xfer_setup(struct ata_queued_cmd struct ata_port *ap = qc->ap; struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); - dma_addr_t addr = (dma_addr_t)&hsdev->sata_dwc_regs->dmadr; struct dma_slave_config sconf; struct dma_async_tx_descriptor *desc; if (qc->dma_dir == DMA_DEV_TO_MEM) { - sconf.src_addr = addr; - sconf.device_fc = true; + sconf.src_addr = hsdev->dmadr; + sconf.device_fc = false; } else { /* DMA_MEM_TO_DEV */ - sconf.dst_addr = addr; + sconf.dst_addr = hsdev->dmadr; sconf.device_fc = false; } sconf.direction = qc->dma_dir; - sconf.src_maxburst = AHB_DMA_BRST_DFLT; - sconf.dst_maxburst = AHB_DMA_BRST_DFLT; + sconf.src_maxburst = AHB_DMA_BRST_DFLT / 4; /* in items */ + sconf.dst_maxburst = AHB_DMA_BRST_DFLT / 4; /* in items */ sconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; sconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -336,8 +399,8 @@ static struct dma_async_tx_descriptor *dma_dwc_xfer_setup(struct ata_queued_cmd desc->callback = dma_dwc_xfer_done; desc->callback_param = hsdev; - dev_dbg(hsdev->dev, "%s sg: 0x%p, count: %d addr: %pad\n", - __func__, qc->sg, qc->n_elem, &addr); + dev_dbg(hsdev->dev, "%s sg: 0x%p, count: %d addr: %pa\n", __func__, + qc->sg, qc->n_elem, &hsdev->dmadr); return desc; } @@ -350,48 +413,38 @@ static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val) return -EINVAL; } - *val = in_le32(link->ap->ioaddr.scr_addr + (scr * 4)); - dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n", - __func__, link->ap->print_id, scr, *val); + *val = sata_dwc_readl(link->ap->ioaddr.scr_addr + (scr * 4)); + dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=0x%08x\n", __func__, + link->ap->print_id, scr, *val); return 0; } static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr, u32 val) { - dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n", - __func__, link->ap->print_id, scr, val); + dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=0x%08x\n", __func__, + link->ap->print_id, scr, val); if (scr > SCR_NOTIFICATION) { dev_err(link->ap->dev, "%s: Incorrect SCR offset 0x%02x\n", __func__, scr); return -EINVAL; } - out_le32(link->ap->ioaddr.scr_addr + (scr * 4), val); + sata_dwc_writel(link->ap->ioaddr.scr_addr + (scr * 4), val); return 0; } -static u32 core_scr_read(unsigned int scr) -{ - return in_le32(host_pvt.scr_addr_sstatus + (scr * 4)); -} - -static void core_scr_write(unsigned int scr, u32 val) -{ - out_le32(host_pvt.scr_addr_sstatus + (scr * 4), val); -} - -static void clear_serror(void) +static void clear_serror(struct ata_port *ap) { u32 val; - val = core_scr_read(SCR_ERROR); - core_scr_write(SCR_ERROR, val); + sata_dwc_scr_read(&ap->link, SCR_ERROR, &val); + sata_dwc_scr_write(&ap->link, SCR_ERROR, val); } static void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit) { - out_le32(&hsdev->sata_dwc_regs->intpr, - in_le32(&hsdev->sata_dwc_regs->intpr)); + sata_dwc_writel(&hsdev->sata_dwc_regs->intpr, + sata_dwc_readl(&hsdev->sata_dwc_regs->intpr)); } static u32 qcmd_tag_to_mask(u8 tag) @@ -412,7 +465,7 @@ static void sata_dwc_error_intr(struct ata_port *ap, ata_ehi_clear_desc(ehi); - serror = core_scr_read(SCR_ERROR); + sata_dwc_scr_read(&ap->link, SCR_ERROR, &serror); status = ap->ops->sff_check_status(ap); tag = ap->link.active_tag; @@ -423,7 +476,7 @@ static void sata_dwc_error_intr(struct ata_port *ap, hsdevp->dma_pending[tag], hsdevp->cmd_issued[tag]); /* Clear error register and interrupt bit */ - clear_serror(); + clear_serror(ap); clear_interrupt_bit(hsdev, SATA_DWC_INTPR_ERR); /* This is the only error happening now. TODO check for exact error */ @@ -462,12 +515,12 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance) int handled, num_processed, port = 0; uint intpr, sactive, sactive2, tag_mask; struct sata_dwc_device_port *hsdevp; - host_pvt.sata_dwc_sactive_issued = 0; + hsdev->sactive_issued = 0; spin_lock_irqsave(&host->lock, flags); /* Read the interrupt register */ - intpr = in_le32(&hsdev->sata_dwc_regs->intpr); + intpr = sata_dwc_readl(&hsdev->sata_dwc_regs->intpr); ap = host->ports[port]; hsdevp = HSDEVP_FROM_AP(ap); @@ -486,12 +539,12 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance) if (intpr & SATA_DWC_INTPR_NEWFP) { clear_interrupt_bit(hsdev, SATA_DWC_INTPR_NEWFP); - tag = (u8)(in_le32(&hsdev->sata_dwc_regs->fptagr)); + tag = (u8)(sata_dwc_readl(&hsdev->sata_dwc_regs->fptagr)); dev_dbg(ap->dev, "%s: NEWFP tag=%d\n", __func__, tag); if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_PEND) dev_warn(ap->dev, "CMD tag=%d not pending?\n", tag); - host_pvt.sata_dwc_sactive_issued |= qcmd_tag_to_mask(tag); + hsdev->sactive_issued |= qcmd_tag_to_mask(tag); qc = ata_qc_from_tag(ap, tag); /* @@ -505,11 +558,11 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance) handled = 1; goto DONE; } - sactive = core_scr_read(SCR_ACTIVE); - tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive; + sata_dwc_scr_read(&ap->link, SCR_ACTIVE, &sactive); + tag_mask = (hsdev->sactive_issued | sactive) ^ sactive; /* If no sactive issued and tag_mask is zero then this is not NCQ */ - if (host_pvt.sata_dwc_sactive_issued == 0 && tag_mask == 0) { + if (hsdev->sactive_issued == 0 && tag_mask == 0) { if (ap->link.active_tag == ATA_TAG_POISON) tag = 0; else @@ -579,22 +632,19 @@ DRVSTILLBUSY: */ /* process completed commands */ - sactive = core_scr_read(SCR_ACTIVE); - tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive; + sata_dwc_scr_read(&ap->link, SCR_ACTIVE, &sactive); + tag_mask = (hsdev->sactive_issued | sactive) ^ sactive; - if (sactive != 0 || (host_pvt.sata_dwc_sactive_issued) > 1 || \ - tag_mask > 1) { + if (sactive != 0 || hsdev->sactive_issued > 1 || tag_mask > 1) { dev_dbg(ap->dev, "%s NCQ:sactive=0x%08x sactive_issued=0x%08x tag_mask=0x%08x\n", - __func__, sactive, host_pvt.sata_dwc_sactive_issued, - tag_mask); + __func__, sactive, hsdev->sactive_issued, tag_mask); } - if ((tag_mask | (host_pvt.sata_dwc_sactive_issued)) != \ - (host_pvt.sata_dwc_sactive_issued)) { + if ((tag_mask | hsdev->sactive_issued) != hsdev->sactive_issued) { dev_warn(ap->dev, - "Bad tag mask? sactive=0x%08x (host_pvt.sata_dwc_sactive_issued)=0x%08x tag_mask=0x%08x\n", - sactive, host_pvt.sata_dwc_sactive_issued, tag_mask); + "Bad tag mask? sactive=0x%08x sactive_issued=0x%08x tag_mask=0x%08x\n", + sactive, hsdev->sactive_issued, tag_mask); } /* read just to clear ... not bad if currently still busy */ @@ -656,7 +706,7 @@ STILLBUSY: * we were processing --we read status as part of processing a completed * command). */ - sactive2 = core_scr_read(SCR_ACTIVE); + sata_dwc_scr_read(&ap->link, SCR_ACTIVE, &sactive2); if (sactive2 != sactive) { dev_dbg(ap->dev, "More completed - sactive=0x%x sactive2=0x%x\n", @@ -672,15 +722,14 @@ DONE: static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag) { struct sata_dwc_device *hsdev = HSDEV_FROM_HSDEVP(hsdevp); + u32 dmacr = sata_dwc_readl(&hsdev->sata_dwc_regs->dmacr); if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX) { - out_le32(&(hsdev->sata_dwc_regs->dmacr), - SATA_DWC_DMACR_RX_CLEAR( - in_le32(&(hsdev->sata_dwc_regs->dmacr)))); + dmacr = SATA_DWC_DMACR_RX_CLEAR(dmacr); + sata_dwc_writel(&hsdev->sata_dwc_regs->dmacr, dmacr); } else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX) { - out_le32(&(hsdev->sata_dwc_regs->dmacr), - SATA_DWC_DMACR_TX_CLEAR( - in_le32(&(hsdev->sata_dwc_regs->dmacr)))); + dmacr = SATA_DWC_DMACR_TX_CLEAR(dmacr); + sata_dwc_writel(&hsdev->sata_dwc_regs->dmacr, dmacr); } else { /* * This should not happen, it indicates the driver is out of @@ -688,10 +737,9 @@ static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag) */ dev_err(hsdev->dev, "%s DMA protocol RX and TX DMA not pending tag=0x%02x pending=%d dmacr: 0x%08x\n", - __func__, tag, hsdevp->dma_pending[tag], - in_le32(&hsdev->sata_dwc_regs->dmacr)); - out_le32(&(hsdev->sata_dwc_regs->dmacr), - SATA_DWC_DMACR_TXRXCH_CLEAR); + __func__, tag, hsdevp->dma_pending[tag], dmacr); + sata_dwc_writel(&hsdev->sata_dwc_regs->dmacr, + SATA_DWC_DMACR_TXRXCH_CLEAR); } } @@ -716,7 +764,7 @@ static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status) __func__, qc->tag, qc->tf.command, get_dma_dir_descript(qc->dma_dir), get_prot_descript(qc->tf.protocol), - in_le32(&(hsdev->sata_dwc_regs->dmacr))); + sata_dwc_readl(&hsdev->sata_dwc_regs->dmacr)); } #endif @@ -725,7 +773,7 @@ static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status) dev_err(ap->dev, "%s DMA protocol RX and TX DMA not pending dmacr: 0x%08x\n", __func__, - in_le32(&(hsdev->sata_dwc_regs->dmacr))); + sata_dwc_readl(&hsdev->sata_dwc_regs->dmacr)); } hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_NONE; @@ -742,8 +790,9 @@ static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc, u8 status = 0; u32 mask = 0x0; u8 tag = qc->tag; + struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); - host_pvt.sata_dwc_sactive_queued = 0; + hsdev->sactive_queued = 0; dev_dbg(ap->dev, "%s checkstatus? %x\n", __func__, check_status); if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX) @@ -756,10 +805,8 @@ static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc, /* clear active bit */ mask = (~(qcmd_tag_to_mask(tag))); - host_pvt.sata_dwc_sactive_queued = (host_pvt.sata_dwc_sactive_queued) \ - & mask; - host_pvt.sata_dwc_sactive_issued = (host_pvt.sata_dwc_sactive_issued) \ - & mask; + hsdev->sactive_queued = hsdev->sactive_queued & mask; + hsdev->sactive_issued = hsdev->sactive_issued & mask; ata_qc_complete(qc); return 0; } @@ -767,54 +814,62 @@ static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc, static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev) { /* Enable selective interrupts by setting the interrupt maskregister*/ - out_le32(&hsdev->sata_dwc_regs->intmr, - SATA_DWC_INTMR_ERRM | - SATA_DWC_INTMR_NEWFPM | - SATA_DWC_INTMR_PMABRTM | - SATA_DWC_INTMR_DMATM); + sata_dwc_writel(&hsdev->sata_dwc_regs->intmr, + SATA_DWC_INTMR_ERRM | + SATA_DWC_INTMR_NEWFPM | + SATA_DWC_INTMR_PMABRTM | + SATA_DWC_INTMR_DMATM); /* * Unmask the error bits that should trigger an error interrupt by * setting the error mask register. */ - out_le32(&hsdev->sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS); + sata_dwc_writel(&hsdev->sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS); dev_dbg(hsdev->dev, "%s: INTMR = 0x%08x, ERRMR = 0x%08x\n", - __func__, in_le32(&hsdev->sata_dwc_regs->intmr), - in_le32(&hsdev->sata_dwc_regs->errmr)); + __func__, sata_dwc_readl(&hsdev->sata_dwc_regs->intmr), + sata_dwc_readl(&hsdev->sata_dwc_regs->errmr)); } -static bool sata_dwc_dma_filter(struct dma_chan *chan, void *param) +static void sata_dwc_setup_port(struct ata_ioports *port, void __iomem *base) { - struct sata_dwc_device_port *hsdevp = param; - struct dw_dma_slave *dws = hsdevp->dws; + port->cmd_addr = base + 0x00; + port->data_addr = base + 0x00; - if (dws->dma_dev != chan->device->dev) - return false; + port->error_addr = base + 0x04; + port->feature_addr = base + 0x04; - chan->private = dws; - return true; -} + port->nsect_addr = base + 0x08; -static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base) -{ - port->cmd_addr = (void __iomem *)base + 0x00; - port->data_addr = (void __iomem *)base + 0x00; + port->lbal_addr = base + 0x0c; + port->lbam_addr = base + 0x10; + port->lbah_addr = base + 0x14; - port->error_addr = (void __iomem *)base + 0x04; - port->feature_addr = (void __iomem *)base + 0x04; + port->device_addr = base + 0x18; + port->command_addr = base + 0x1c; + port->status_addr = base + 0x1c; - port->nsect_addr = (void __iomem *)base + 0x08; + port->altstatus_addr = base + 0x20; + port->ctl_addr = base + 0x20; +} + +static int sata_dwc_dma_get_channel(struct sata_dwc_device_port *hsdevp) +{ + struct sata_dwc_device *hsdev = hsdevp->hsdev; + struct device *dev = hsdev->dev; - port->lbal_addr = (void __iomem *)base + 0x0c; - port->lbam_addr = (void __iomem *)base + 0x10; - port->lbah_addr = (void __iomem *)base + 0x14; +#ifdef CONFIG_SATA_DWC_OLD_DMA + if (!of_find_property(dev->of_node, "dmas", NULL)) + return sata_dwc_dma_get_channel_old(hsdevp); +#endif - port->device_addr = (void __iomem *)base + 0x18; - port->command_addr = (void __iomem *)base + 0x1c; - port->status_addr = (void __iomem *)base + 0x1c; + hsdevp->chan = dma_request_chan(dev, "sata-dma"); + if (IS_ERR(hsdevp->chan)) { + dev_err(dev, "failed to allocate dma channel: %ld\n", + PTR_ERR(hsdevp->chan)); + return PTR_ERR(hsdevp->chan); + } - port->altstatus_addr = (void __iomem *)base + 0x20; - port->ctl_addr = (void __iomem *)base + 0x20; + return 0; } /* @@ -829,7 +884,6 @@ static int sata_dwc_port_start(struct ata_port *ap) struct sata_dwc_device *hsdev; struct sata_dwc_device_port *hsdevp = NULL; struct device *pdev; - dma_cap_mask_t mask; int i; hsdev = HSDEV_FROM_AP(ap); @@ -853,20 +907,13 @@ static int sata_dwc_port_start(struct ata_port *ap) } hsdevp->hsdev = hsdev; - hsdevp->dws = &sata_dwc_dma_dws; - hsdevp->dws->dma_dev = hsdev->dev; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + err = sata_dwc_dma_get_channel(hsdevp); + if (err) + goto CLEANUP_ALLOC; - /* Acquire DMA channel */ - hsdevp->chan = dma_request_channel(mask, sata_dwc_dma_filter, hsdevp); - if (!hsdevp->chan) { - dev_err(hsdev->dev, "%s: dma channel unavailable\n", - __func__); - err = -EAGAIN; + err = phy_power_on(hsdev->phy); + if (err) goto CLEANUP_ALLOC; - } for (i = 0; i < SATA_DWC_QCMD_MAX; i++) hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; @@ -877,18 +924,18 @@ static int sata_dwc_port_start(struct ata_port *ap) if (ap->port_no == 0) { dev_dbg(ap->dev, "%s: clearing TXCHEN, RXCHEN in DMAC\n", __func__); - out_le32(&hsdev->sata_dwc_regs->dmacr, - SATA_DWC_DMACR_TXRXCH_CLEAR); + sata_dwc_writel(&hsdev->sata_dwc_regs->dmacr, + SATA_DWC_DMACR_TXRXCH_CLEAR); dev_dbg(ap->dev, "%s: setting burst size in DBTSR\n", __func__); - out_le32(&hsdev->sata_dwc_regs->dbtsr, - (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) | - SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT))); + sata_dwc_writel(&hsdev->sata_dwc_regs->dbtsr, + (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) | + SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT))); } /* Clear any error bits before libata starts issuing commands */ - clear_serror(); + clear_serror(ap); ap->private_data = hsdevp; dev_dbg(ap->dev, "%s: done\n", __func__); return 0; @@ -903,11 +950,13 @@ CLEANUP: static void sata_dwc_port_stop(struct ata_port *ap) { struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); dev_dbg(ap->dev, "%s: ap->id = %d\n", __func__, ap->print_id); - dmaengine_terminate_all(hsdevp->chan); + dmaengine_terminate_sync(hsdevp->chan); dma_release_channel(hsdevp->chan); + phy_power_off(hsdev->phy); kfree(hsdevp); ap->private_data = NULL; @@ -924,22 +973,20 @@ static void sata_dwc_exec_command_by_tag(struct ata_port *ap, struct ata_taskfile *tf, u8 tag, u32 cmd_issued) { - unsigned long flags; struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); dev_dbg(ap->dev, "%s cmd(0x%02x): %s tag=%d\n", __func__, tf->command, ata_get_cmd_descript(tf->command), tag); - spin_lock_irqsave(&ap->host->lock, flags); hsdevp->cmd_issued[tag] = cmd_issued; - spin_unlock_irqrestore(&ap->host->lock, flags); + /* * Clear SError before executing a new command. * sata_dwc_scr_write and read can not be used here. Clearing the PM * managed SError register for the disk needs to be done before the * task file is loaded. */ - clear_serror(); + clear_serror(ap); ata_sff_exec_command(ap, tf); } @@ -992,18 +1039,18 @@ static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag) sata_dwc_tf_dump(ap, &qc->tf); if (start_dma) { - reg = core_scr_read(SCR_ERROR); + sata_dwc_scr_read(&ap->link, SCR_ERROR, ®); if (reg & SATA_DWC_SERROR_ERR_BITS) { dev_err(ap->dev, "%s: ****** SError=0x%08x ******\n", __func__, reg); } if (dir == DMA_TO_DEVICE) - out_le32(&hsdev->sata_dwc_regs->dmacr, - SATA_DWC_DMACR_TXCHEN); + sata_dwc_writel(&hsdev->sata_dwc_regs->dmacr, + SATA_DWC_DMACR_TXCHEN); else - out_le32(&hsdev->sata_dwc_regs->dmacr, - SATA_DWC_DMACR_RXCHEN); + sata_dwc_writel(&hsdev->sata_dwc_regs->dmacr, + SATA_DWC_DMACR_RXCHEN); /* Enable AHB DMA transfer on the specified channel */ dmaengine_submit(desc); @@ -1025,36 +1072,12 @@ static void sata_dwc_bmdma_start(struct ata_queued_cmd *qc) sata_dwc_bmdma_start_by_tag(qc, tag); } -/* - * Function : sata_dwc_qc_prep_by_tag - * arguments : ata_queued_cmd *qc, u8 tag - * Return value : None - * qc_prep for a particular queued command based on tag - */ -static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag) -{ - struct dma_async_tx_descriptor *desc; - struct ata_port *ap = qc->ap; - struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); - - dev_dbg(ap->dev, "%s: port=%d dma dir=%s n_elem=%d\n", - __func__, ap->port_no, get_dma_dir_descript(qc->dma_dir), - qc->n_elem); - - desc = dma_dwc_xfer_setup(qc); - if (!desc) { - dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns NULL\n", - __func__); - return; - } - hsdevp->desc[tag] = desc; -} - static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc) { u32 sactive; u8 tag = qc->tag; struct ata_port *ap = qc->ap; + struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); #ifdef DEBUG_NCQ if (qc->tag > 0 || ap->link.sactive > 1) @@ -1068,47 +1091,33 @@ static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc) if (!ata_is_ncq(qc->tf.protocol)) tag = 0; - sata_dwc_qc_prep_by_tag(qc, tag); + + if (ata_is_dma(qc->tf.protocol)) { + hsdevp->desc[tag] = dma_dwc_xfer_setup(qc); + if (!hsdevp->desc[tag]) + return AC_ERR_SYSTEM; + } else { + hsdevp->desc[tag] = NULL; + } if (ata_is_ncq(qc->tf.protocol)) { - sactive = core_scr_read(SCR_ACTIVE); + sata_dwc_scr_read(&ap->link, SCR_ACTIVE, &sactive); sactive |= (0x00000001 << tag); - core_scr_write(SCR_ACTIVE, sactive); + sata_dwc_scr_write(&ap->link, SCR_ACTIVE, sactive); dev_dbg(qc->ap->dev, "%s: tag=%d ap->link.sactive = 0x%08x sactive=0x%08x\n", __func__, tag, qc->ap->link.sactive, sactive); ap->ops->sff_tf_load(ap, &qc->tf); - sata_dwc_exec_command_by_tag(ap, &qc->tf, qc->tag, + sata_dwc_exec_command_by_tag(ap, &qc->tf, tag, SATA_DWC_CMD_ISSUED_PEND); } else { - ata_sff_qc_issue(qc); + return ata_bmdma_qc_issue(qc); } return 0; } -/* - * Function : sata_dwc_qc_prep - * arguments : ata_queued_cmd *qc - * Return value : None - * qc_prep for a particular queued command - */ - -static void sata_dwc_qc_prep(struct ata_queued_cmd *qc) -{ - if ((qc->dma_dir == DMA_NONE) || (qc->tf.protocol == ATA_PROT_PIO)) - return; - -#ifdef DEBUG_NCQ - if (qc->tag > 0) - dev_info(qc->ap->dev, "%s: qc->tag=%d ap->active_tag=0x%08x\n", - __func__, qc->tag, qc->ap->link.active_tag); - - return ; -#endif -} - static void sata_dwc_error_handler(struct ata_port *ap) { ata_sff_error_handler(ap); @@ -1125,17 +1134,22 @@ static int sata_dwc_hardreset(struct ata_link *link, unsigned int *class, sata_dwc_enable_interrupts(hsdev); /* Reconfigure the DMA control register */ - out_le32(&hsdev->sata_dwc_regs->dmacr, - SATA_DWC_DMACR_TXRXCH_CLEAR); + sata_dwc_writel(&hsdev->sata_dwc_regs->dmacr, + SATA_DWC_DMACR_TXRXCH_CLEAR); /* Reconfigure the DMA Burst Transaction Size register */ - out_le32(&hsdev->sata_dwc_regs->dbtsr, - SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) | - SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT)); + sata_dwc_writel(&hsdev->sata_dwc_regs->dbtsr, + SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) | + SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT)); return ret; } +static void sata_dwc_dev_select(struct ata_port *ap, unsigned int device) +{ + /* SATA DWC is master only */ +} + /* * scsi mid-layer and libata interface structures */ @@ -1148,7 +1162,13 @@ static struct scsi_host_template sata_dwc_sht = { */ .sg_tablesize = LIBATA_MAX_PRD, /* .can_queue = ATA_MAX_QUEUE, */ - .dma_boundary = ATA_DMA_BOUNDARY, + /* + * Make sure a LLI block is not created that will span 8K max FIS + * boundary. If the block spans such a FIS boundary, there is a chance + * that a DMA burst will cross that boundary -- this results in an + * error in the host controller. + */ + .dma_boundary = 0x1fff /* ATA_DMA_BOUNDARY */, }; static struct ata_port_operations sata_dwc_ops = { @@ -1157,7 +1177,6 @@ static struct ata_port_operations sata_dwc_ops = { .error_handler = sata_dwc_error_handler, .hardreset = sata_dwc_hardreset, - .qc_prep = sata_dwc_qc_prep, .qc_issue = sata_dwc_qc_issue, .scr_read = sata_dwc_scr_read, @@ -1166,6 +1185,8 @@ static struct ata_port_operations sata_dwc_ops = { .port_start = sata_dwc_port_start, .port_stop = sata_dwc_port_stop, + .sff_dev_select = sata_dwc_dev_select, + .bmdma_setup = sata_dwc_bmdma_setup, .bmdma_start = sata_dwc_bmdma_start, }; @@ -1184,13 +1205,14 @@ static int sata_dwc_probe(struct platform_device *ofdev) struct sata_dwc_device *hsdev; u32 idr, versionr; char *ver = (char *)&versionr; - u8 __iomem *base; + void __iomem *base; int err = 0; int irq; struct ata_host *host; struct ata_port_info pi = sata_dwc_port_info[0]; const struct ata_port_info *ppi[] = { &pi, NULL }; struct device_node *np = ofdev->dev.of_node; + struct resource *res; /* Allocate DWC SATA device */ host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS); @@ -1201,57 +1223,33 @@ static int sata_dwc_probe(struct platform_device *ofdev) host->private_data = hsdev; /* Ioremap SATA registers */ - base = of_iomap(np, 0); - if (!base) { + res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&ofdev->dev, res); + if (IS_ERR(base)) { dev_err(&ofdev->dev, "ioremap failed for SATA register address\n"); - return -ENODEV; + return PTR_ERR(base); } - hsdev->reg_base = base; dev_dbg(&ofdev->dev, "ioremap done for SATA register address\n"); /* Synopsys DWC SATA specific Registers */ - hsdev->sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); + hsdev->sata_dwc_regs = base + SATA_DWC_REG_OFFSET; + hsdev->dmadr = res->start + SATA_DWC_REG_OFFSET + offsetof(struct sata_dwc_regs, dmadr); /* Setup port */ host->ports[0]->ioaddr.cmd_addr = base; host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; - host_pvt.scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET; - sata_dwc_setup_port(&host->ports[0]->ioaddr, (unsigned long)base); + sata_dwc_setup_port(&host->ports[0]->ioaddr, base); /* Read the ID and Version Registers */ - idr = in_le32(&hsdev->sata_dwc_regs->idr); - versionr = in_le32(&hsdev->sata_dwc_regs->versionr); + idr = sata_dwc_readl(&hsdev->sata_dwc_regs->idr); + versionr = sata_dwc_readl(&hsdev->sata_dwc_regs->versionr); dev_notice(&ofdev->dev, "id %d, controller version %c.%c%c\n", idr, ver[0], ver[1], ver[2]); - /* Get SATA DMA interrupt number */ - hsdev->dma->irq = irq_of_parse_and_map(np, 1); - if (hsdev->dma->irq == NO_IRQ) { - dev_err(&ofdev->dev, "no SATA DMA irq\n"); - err = -ENODEV; - goto error_iomap; - } - - /* Get physical SATA DMA register base address */ - hsdev->dma->regs = of_iomap(np, 1); - if (!hsdev->dma->regs) { - dev_err(&ofdev->dev, - "ioremap failed for AHBDMA register address\n"); - err = -ENODEV; - goto error_iomap; - } - /* Save dev for later use in dev_xxx() routines */ hsdev->dev = &ofdev->dev; - hsdev->dma->dev = &ofdev->dev; - - /* Initialize AHB DMAC */ - err = dw_dma_probe(hsdev->dma, NULL); - if (err) - goto error_dma_iomap; - /* Enable SATA Interrupts */ sata_dwc_enable_interrupts(hsdev); @@ -1263,6 +1261,25 @@ static int sata_dwc_probe(struct platform_device *ofdev) goto error_out; } +#ifdef CONFIG_SATA_DWC_OLD_DMA + if (!of_find_property(np, "dmas", NULL)) { + err = sata_dwc_dma_init_old(ofdev, hsdev); + if (err) + goto error_out; + } +#endif + + hsdev->phy = devm_phy_optional_get(hsdev->dev, "sata-phy"); + if (IS_ERR(hsdev->phy)) { + err = PTR_ERR(hsdev->phy); + hsdev->phy = NULL; + goto error_out; + } + + err = phy_init(hsdev->phy); + if (err) + goto error_out; + /* * Now, register with libATA core, this will also initiate the * device discovery process, invoking our port_start() handler & @@ -1276,12 +1293,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) return 0; error_out: - /* Free SATA DMA resources */ - dw_dma_remove(hsdev->dma); -error_dma_iomap: - iounmap(hsdev->dma->regs); -error_iomap: - iounmap(base); + phy_exit(hsdev->phy); return err; } @@ -1293,11 +1305,13 @@ static int sata_dwc_remove(struct platform_device *ofdev) ata_host_detach(host); + phy_exit(hsdev->phy); + +#ifdef CONFIG_SATA_DWC_OLD_DMA /* Free SATA DMA resources */ - dw_dma_remove(hsdev->dma); + sata_dwc_dma_exit_old(hsdev); +#endif - iounmap(hsdev->dma->regs); - iounmap(hsdev->reg_base); dev_dbg(&ofdev->dev, "done\n"); return 0; } |