From e1c1bee34f077baf88f78b24d08c0ba1ba506abd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 26 Apr 2016 12:03:07 +0300 Subject: ata: sata_dwc_460ex: select only core part of DMA driver There is no need to have a platform driver compiled since the DMA driver is used as a library. Tested-by: Christian Lamparter Signed-off-by: Andy Shevchenko Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/ata/Kconfig') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 5083f85efea7..0f528d332ece 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -306,7 +306,7 @@ config ATA_PIIX config SATA_DWC tristate "DesignWare Cores SATA support" depends on 460EX - select DW_DMAC + select DW_DMAC_CORE help This option enables support for the on-chip SATA controller of the AppliedMicro processor 460EX. -- cgit v1.2.3 From 50b433753df69262ed1c098328f692e882a31001 Mon Sep 17 00:00:00 2001 From: Mans Rullgard Date: Tue, 26 Apr 2016 12:03:10 +0300 Subject: ata: sata_dwc_460ex: use "dmas" DT property to find dma channel Currently this driver only works with a DesignWare DMA engine which it registers manually using the second "reg" address range and interrupt number from the DT node. This patch makes the driver instead use the "dmas" property if present, otherwise optionally falling back on the old way so existing device trees can continue to work. With this change, there is no longer any reason to depend on the 460EX machine type so drop that from Kconfig. Tested-by: Christian Lamparter Signed-off-by: Mans Rullgard Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 11 ++- drivers/ata/sata_dwc_460ex.c | 198 ++++++++++++++++++++++++++++--------------- 2 files changed, 138 insertions(+), 71 deletions(-) (limited to 'drivers/ata/Kconfig') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 0f528d332ece..fec561957e16 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -305,14 +305,21 @@ config ATA_PIIX config SATA_DWC tristate "DesignWare Cores SATA support" - depends on 460EX - select DW_DMAC_CORE help This option enables support for the on-chip SATA controller of the AppliedMicro processor 460EX. If unsure, say N. +config SATA_DWC_OLD_DMA + bool "Support old device trees" + depends on SATA_DWC + select DW_DMAC_CORE + default y if 460EX + help + This option enables support for old device trees without the + "dmas" property. + config SATA_DWC_DEBUG bool "Debugging driver version" depends on SATA_DWC diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index f1a4d498ad2d..200af36e8602 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -42,10 +43,6 @@ #include #include -/* Supported DMA engine drivers */ -#include -#include - /* 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 +#include + +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; -- cgit v1.2.3 From 0f48debdb90601ec37cdcb81f796ca120aae60f4 Mon Sep 17 00:00:00 2001 From: Mans Rullgard Date: Tue, 26 Apr 2016 12:03:11 +0300 Subject: ata: sata_dwc_460ex: add phy support This adds support for powering on an optional PHY when activating the device. Tested-by: Christian Lamparter Signed-off-by: Mans Rullgard Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 1 + drivers/ata/sata_dwc_460ex.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'drivers/ata/Kconfig') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index fec561957e16..3f9bbbf89941 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -305,6 +305,7 @@ config ATA_PIIX config SATA_DWC tristate "DesignWare Cores SATA support" + select GENERIC_PHY help This option enables support for the on-chip SATA controller of the AppliedMicro processor 460EX. diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index 200af36e8602..4b8eded09c06 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -145,6 +146,7 @@ struct sata_dwc_device { struct ata_host *host; u8 __iomem *reg_base; struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */ + struct phy *phy; #ifdef CONFIG_SATA_DWC_OLD_DMA struct dw_dma_chip *dma; #endif @@ -948,6 +950,10 @@ static int sata_dwc_port_start(struct ata_port *ap) if (err) goto CLEANUP_ALLOC; + 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; @@ -983,11 +989,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); dma_release_channel(hsdevp->chan); + phy_power_off(hsdev->phy); kfree(hsdevp); ap->private_data = NULL; @@ -1321,6 +1329,17 @@ static int sata_dwc_probe(struct platform_device *ofdev) } #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 & @@ -1334,6 +1353,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) return 0; error_out: + phy_exit(hsdev->phy); iounmap(base); return err; } @@ -1346,6 +1366,8 @@ 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 */ sata_dwc_dma_exit_old(hsdev); -- cgit v1.2.3 From 7598469a6184e1017a77ebe78b5b66c52a6afc1c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 May 2016 15:42:08 +0200 Subject: ata: dwc: add DMADEVICES dependency The dwc_460ex SATA driver has become available on non-powerpc architectures and may cause randconfig build errors when CONFIG_DMADEVICES is not set and SATA_DWC_OLD_DMA is enabled: warning: (SATA_DWC_OLD_DMA) selects DW_DMAC_CORE which has unmet direct dependencies (DMADEVICES) ERROR: "dw_dma_probe" [drivers/ata/sata_dwc_460ex.ko] undefined! ERROR: "dw_dma_remove" [drivers/ata/sata_dwc_460ex.ko] undefined! This adds an explcit Kconfig dependency to CONFIG_SATA_DWC so we cannot run into broken configurations. While it would also be possible to build the driver with both CONFIG_DMADEVICES and SATA_DWC_OLD_DMA disabled, that case is not useful because there is no fallback to PIO mode when the DMA engine is not usable. Signed-off-by: Arnd Bergmann Fixes: 50b433753df6 ("ata: sata_dwc_460ex: use "dmas" DT property to find dma channel") Reviewed-by: Andy Shevchenko Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/ata/Kconfig') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 3f9bbbf89941..2fbf355d9142 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -305,6 +305,7 @@ config ATA_PIIX config SATA_DWC tristate "DesignWare Cores SATA support" + depends on DMADEVICES select GENERIC_PHY help This option enables support for the on-chip SATA controller of the -- cgit v1.2.3