|
@@ -30,6 +30,7 @@
|
|
|
#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>
|
|
@@ -42,10 +43,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
|
|
@@ -148,7 +145,9 @@ struct sata_dwc_device {
|
|
|
struct ata_host *host;
|
|
|
u8 __iomem *reg_base;
|
|
|
struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */
|
|
|
+#ifdef CONFIG_SATA_DWC_OLD_DMA
|
|
|
struct dw_dma_chip *dma;
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
#define SATA_DWC_QCMD_MAX 32
|
|
@@ -159,7 +158,6 @@ 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;
|
|
@@ -198,13 +196,6 @@ struct sata_dwc_host_priv {
|
|
|
|
|
|
static struct sata_dwc_host_priv host_pvt;
|
|
|
|
|
|
-static struct dw_dma_slave sata_dwc_dma_dws = {
|
|
|
- .src_id = 0,
|
|
|
- .dst_id = 0,
|
|
|
- .m_master = 1,
|
|
|
- .p_master = 0,
|
|
|
-};
|
|
|
-
|
|
|
/*
|
|
|
* Prototypes
|
|
|
*/
|
|
@@ -215,6 +206,99 @@ 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;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ 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 */
|
|
|
+ hsdev->dma->regs = of_iomap(np, 1);
|
|
|
+ if (!hsdev->dma->regs) {
|
|
|
+ dev_err(&pdev->dev,
|
|
|
+ "ioremap failed for AHBDMA register address\n");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Initialize AHB DMAC */
|
|
|
+ err = dw_dma_probe(hsdev->dma);
|
|
|
+ if (err) {
|
|
|
+ iounmap(hsdev->dma->regs);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void sata_dwc_dma_exit_old(struct sata_dwc_device *hsdev)
|
|
|
+{
|
|
|
+ if (!hsdev->dma)
|
|
|
+ return;
|
|
|
+
|
|
|
+ dw_dma_remove(hsdev->dma);
|
|
|
+ iounmap(hsdev->dma->regs);
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
static const char *get_prot_descript(u8 protocol)
|
|
|
{
|
|
|
switch ((enum ata_tf_protocols)protocol) {
|
|
@@ -783,18 +867,6 @@ static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev)
|
|
|
in_le32(&hsdev->sata_dwc_regs->errmr));
|
|
|
}
|
|
|
|
|
|
-static bool sata_dwc_dma_filter(struct dma_chan *chan, void *param)
|
|
|
-{
|
|
|
- struct sata_dwc_device_port *hsdevp = param;
|
|
|
- struct dw_dma_slave *dws = hsdevp->dws;
|
|
|
-
|
|
|
- if (dws->dma_dev != chan->device->dev)
|
|
|
- return false;
|
|
|
-
|
|
|
- chan->private = dws;
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base)
|
|
|
{
|
|
|
port->cmd_addr = (void __iomem *)base + 0x00;
|
|
@@ -817,6 +889,26 @@ static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base)
|
|
|
port->ctl_addr = (void __iomem *)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;
|
|
|
+
|
|
|
+#ifdef CONFIG_SATA_DWC_OLD_DMA
|
|
|
+ if (!of_find_property(dev->of_node, "dmas", NULL))
|
|
|
+ return sata_dwc_dma_get_channel_old(hsdevp);
|
|
|
+#endif
|
|
|
+
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Function : sata_dwc_port_start
|
|
|
* arguments : struct ata_ioports *port
|
|
@@ -829,7 +921,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 +944,9 @@ 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);
|
|
|
-
|
|
|
- /* 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 = sata_dwc_dma_get_channel(hsdevp);
|
|
|
+ if (err)
|
|
|
goto CLEANUP_ALLOC;
|
|
|
- }
|
|
|
|
|
|
for (i = 0; i < SATA_DWC_QCMD_MAX; i++)
|
|
|
hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT;
|
|
@@ -1219,33 +1299,9 @@ static int sata_dwc_probe(struct platform_device *ofdev)
|
|
|
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);
|
|
|
- if (err)
|
|
|
- goto error_dma_iomap;
|
|
|
-
|
|
|
/* Enable SATA Interrupts */
|
|
|
sata_dwc_enable_interrupts(hsdev);
|
|
|
|
|
@@ -1257,6 +1313,14 @@ 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
|
|
|
+
|
|
|
/*
|
|
|
* Now, register with libATA core, this will also initiate the
|
|
|
* device discovery process, invoking our port_start() handler &
|
|
@@ -1270,11 +1334,6 @@ 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);
|
|
|
return err;
|
|
|
}
|
|
@@ -1287,10 +1346,11 @@ static int sata_dwc_remove(struct platform_device *ofdev)
|
|
|
|
|
|
ata_host_detach(host);
|
|
|
|
|
|
+#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;
|