* [PATCH 0/2] spi: stm32-qspi: add dma support @ 2019-03-22 14:35 ` Ludovic Barre 0 siblings, 0 replies; 19+ messages in thread From: Ludovic Barre @ 2019-03-22 14:35 UTC (permalink / raw) To: Mark Brown, Marek Vasut, Boris Brezillon, Rob Herring Cc: Maxime Coquelin, Alexandre Torgue, linux-mtd, linux-spi, linux-arm-kernel, linux-kernel, linux-stm32, devicetree, Ludovic Barre From: Ludovic Barre <ludovic.barre@st.com> This patch series adds dma support for the stm32-qspi. In read mode, the memory map is preferred vs dma (due to better throughput). If the dma transfer fails the buffer is sent by polling. Ludovic Barre (2): spi: stm32-qspi: add spi_master_put in release function spi: stm32-qspi: add dma support drivers/spi/spi-stm32-qspi.c | 182 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 163 insertions(+), 19 deletions(-) -- 2.7.4 ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 0/2] spi: stm32-qspi: add dma support @ 2019-03-22 14:35 ` Ludovic Barre 0 siblings, 0 replies; 19+ messages in thread From: Ludovic Barre @ 2019-03-22 14:35 UTC (permalink / raw) To: Mark Brown, Marek Vasut, Boris Brezillon, Rob Herring Cc: devicetree, Alexandre Torgue, linux-kernel, linux-spi, linux-mtd, Ludovic Barre, Maxime Coquelin, linux-stm32, linux-arm-kernel From: Ludovic Barre <ludovic.barre@st.com> This patch series adds dma support for the stm32-qspi. In read mode, the memory map is preferred vs dma (due to better throughput). If the dma transfer fails the buffer is sent by polling. Ludovic Barre (2): spi: stm32-qspi: add spi_master_put in release function spi: stm32-qspi: add dma support drivers/spi/spi-stm32-qspi.c | 182 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 163 insertions(+), 19 deletions(-) -- 2.7.4 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 0/2] spi: stm32-qspi: add dma support @ 2019-03-22 14:35 ` Ludovic Barre 0 siblings, 0 replies; 19+ messages in thread From: Ludovic Barre @ 2019-03-22 14:35 UTC (permalink / raw) To: Mark Brown, Marek Vasut, Boris Brezillon, Rob Herring Cc: devicetree, Alexandre Torgue, linux-kernel, linux-spi, linux-mtd, Ludovic Barre, Maxime Coquelin, linux-stm32, linux-arm-kernel From: Ludovic Barre <ludovic.barre@st.com> This patch series adds dma support for the stm32-qspi. In read mode, the memory map is preferred vs dma (due to better throughput). If the dma transfer fails the buffer is sent by polling. Ludovic Barre (2): spi: stm32-qspi: add spi_master_put in release function spi: stm32-qspi: add dma support drivers/spi/spi-stm32-qspi.c | 182 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 163 insertions(+), 19 deletions(-) -- 2.7.4 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 0/2] spi: stm32-qspi: add dma support @ 2019-03-22 14:35 ` Ludovic Barre 0 siblings, 0 replies; 19+ messages in thread From: Ludovic Barre @ 2019-03-22 14:35 UTC (permalink / raw) To: Mark Brown, Marek Vasut, Boris Brezillon, Rob Herring Cc: Maxime Coquelin, Alexandre Torgue, linux-mtd, linux-spi, linux-arm-kernel, linux-kernel, linux-stm32, devicetree, Ludovic Barre From: Ludovic Barre <ludovic.barre@st.com> This patch series adds dma support for the stm32-qspi. In read mode, the memory map is preferred vs dma (due to better throughput). If the dma transfer fails the buffer is sent by polling. Ludovic Barre (2): spi: stm32-qspi: add spi_master_put in release function spi: stm32-qspi: add dma support drivers/spi/spi-stm32-qspi.c | 182 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 163 insertions(+), 19 deletions(-) -- 2.7.4 ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 1/2] spi: stm32-qspi: add spi_master_put in release function 2019-03-22 14:35 ` Ludovic Barre (?) (?) @ 2019-03-22 14:35 ` Ludovic Barre -1 siblings, 0 replies; 19+ messages in thread From: Ludovic Barre @ 2019-03-22 14:35 UTC (permalink / raw) To: Mark Brown, Marek Vasut, Boris Brezillon, Rob Herring Cc: Maxime Coquelin, Alexandre Torgue, linux-mtd, linux-spi, linux-arm-kernel, linux-kernel, linux-stm32, devicetree, Ludovic Barre From: Ludovic Barre <ludovic.barre@st.com> This patch adds spi_master_put in release function to drop the controller's refcount. Signed-off-by: Ludovic Barre <ludovic.barre@st.com> --- drivers/spi/spi-stm32-qspi.c | 48 +++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 7879a52..983584d 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -93,6 +93,7 @@ struct stm32_qspi_flash { struct stm32_qspi { struct device *dev; + struct spi_controller *ctrl; void __iomem *io_base; void __iomem *mm_base; resource_size_t mm_size; @@ -400,6 +401,7 @@ static void stm32_qspi_release(struct stm32_qspi *qspi) writel_relaxed(0, qspi->io_base + QSPI_CR); mutex_destroy(&qspi->lock); clk_disable_unprepare(qspi->clk); + spi_master_put(qspi->ctrl); } static int stm32_qspi_probe(struct platform_device *pdev) @@ -416,43 +418,56 @@ static int stm32_qspi_probe(struct platform_device *pdev) return -ENOMEM; qspi = spi_controller_get_devdata(ctrl); + qspi->ctrl = ctrl; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi"); qspi->io_base = devm_ioremap_resource(dev, res); - if (IS_ERR(qspi->io_base)) - return PTR_ERR(qspi->io_base); + if (IS_ERR(qspi->io_base)) { + ret = PTR_ERR(qspi->io_base); + goto err; + } + + qspi->phys_base = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm"); qspi->mm_base = devm_ioremap_resource(dev, res); - if (IS_ERR(qspi->mm_base)) - return PTR_ERR(qspi->mm_base); + if (IS_ERR(qspi->mm_base)) { + ret = PTR_ERR(qspi->mm_base); + goto err; + } qspi->mm_size = resource_size(res); - if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) - return -EINVAL; + if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) { + ret = -EINVAL; + goto err; + } irq = platform_get_irq(pdev, 0); ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0, dev_name(dev), qspi); if (ret) { dev_err(dev, "failed to request irq\n"); - return ret; + goto err; } init_completion(&qspi->data_completion); qspi->clk = devm_clk_get(dev, NULL); - if (IS_ERR(qspi->clk)) - return PTR_ERR(qspi->clk); + if (IS_ERR(qspi->clk)) { + ret = PTR_ERR(qspi->clk); + goto err; + } qspi->clk_rate = clk_get_rate(qspi->clk); - if (!qspi->clk_rate) - return -EINVAL; + if (!qspi->clk_rate) { + ret = -EINVAL; + goto err; + } ret = clk_prepare_enable(qspi->clk); if (ret) { dev_err(dev, "can not enable the clock\n"); - return ret; + goto err; } rstc = devm_reset_control_get_exclusive(dev, NULL); @@ -475,14 +490,11 @@ static int stm32_qspi_probe(struct platform_device *pdev) ctrl->dev.of_node = dev->of_node; ret = devm_spi_register_master(dev, ctrl); - if (ret) - goto err_spi_register; - - return 0; + if (!ret) + return 0; -err_spi_register: +err: stm32_qspi_release(qspi); - return ret; } -- 2.7.4 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 1/2] spi: stm32-qspi: add spi_master_put in release function @ 2019-03-22 14:35 ` Ludovic Barre 0 siblings, 0 replies; 19+ messages in thread From: Ludovic Barre @ 2019-03-22 14:35 UTC (permalink / raw) To: Mark Brown, Marek Vasut, Boris Brezillon, Rob Herring Cc: devicetree, Alexandre Torgue, linux-kernel, linux-spi, linux-mtd, Ludovic Barre, Maxime Coquelin, linux-stm32, linux-arm-kernel From: Ludovic Barre <ludovic.barre@st.com> This patch adds spi_master_put in release function to drop the controller's refcount. Signed-off-by: Ludovic Barre <ludovic.barre@st.com> --- drivers/spi/spi-stm32-qspi.c | 48 +++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 7879a52..983584d 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -93,6 +93,7 @@ struct stm32_qspi_flash { struct stm32_qspi { struct device *dev; + struct spi_controller *ctrl; void __iomem *io_base; void __iomem *mm_base; resource_size_t mm_size; @@ -400,6 +401,7 @@ static void stm32_qspi_release(struct stm32_qspi *qspi) writel_relaxed(0, qspi->io_base + QSPI_CR); mutex_destroy(&qspi->lock); clk_disable_unprepare(qspi->clk); + spi_master_put(qspi->ctrl); } static int stm32_qspi_probe(struct platform_device *pdev) @@ -416,43 +418,56 @@ static int stm32_qspi_probe(struct platform_device *pdev) return -ENOMEM; qspi = spi_controller_get_devdata(ctrl); + qspi->ctrl = ctrl; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi"); qspi->io_base = devm_ioremap_resource(dev, res); - if (IS_ERR(qspi->io_base)) - return PTR_ERR(qspi->io_base); + if (IS_ERR(qspi->io_base)) { + ret = PTR_ERR(qspi->io_base); + goto err; + } + + qspi->phys_base = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm"); qspi->mm_base = devm_ioremap_resource(dev, res); - if (IS_ERR(qspi->mm_base)) - return PTR_ERR(qspi->mm_base); + if (IS_ERR(qspi->mm_base)) { + ret = PTR_ERR(qspi->mm_base); + goto err; + } qspi->mm_size = resource_size(res); - if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) - return -EINVAL; + if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) { + ret = -EINVAL; + goto err; + } irq = platform_get_irq(pdev, 0); ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0, dev_name(dev), qspi); if (ret) { dev_err(dev, "failed to request irq\n"); - return ret; + goto err; } init_completion(&qspi->data_completion); qspi->clk = devm_clk_get(dev, NULL); - if (IS_ERR(qspi->clk)) - return PTR_ERR(qspi->clk); + if (IS_ERR(qspi->clk)) { + ret = PTR_ERR(qspi->clk); + goto err; + } qspi->clk_rate = clk_get_rate(qspi->clk); - if (!qspi->clk_rate) - return -EINVAL; + if (!qspi->clk_rate) { + ret = -EINVAL; + goto err; + } ret = clk_prepare_enable(qspi->clk); if (ret) { dev_err(dev, "can not enable the clock\n"); - return ret; + goto err; } rstc = devm_reset_control_get_exclusive(dev, NULL); @@ -475,14 +490,11 @@ static int stm32_qspi_probe(struct platform_device *pdev) ctrl->dev.of_node = dev->of_node; ret = devm_spi_register_master(dev, ctrl); - if (ret) - goto err_spi_register; - - return 0; + if (!ret) + return 0; -err_spi_register: +err: stm32_qspi_release(qspi); - return ret; } -- 2.7.4 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 1/2] spi: stm32-qspi: add spi_master_put in release function @ 2019-03-22 14:35 ` Ludovic Barre 0 siblings, 0 replies; 19+ messages in thread From: Ludovic Barre @ 2019-03-22 14:35 UTC (permalink / raw) To: Mark Brown, Marek Vasut, Boris Brezillon, Rob Herring Cc: devicetree, Alexandre Torgue, linux-kernel, linux-spi, linux-mtd, Ludovic Barre, Maxime Coquelin, linux-stm32, linux-arm-kernel From: Ludovic Barre <ludovic.barre@st.com> This patch adds spi_master_put in release function to drop the controller's refcount. Signed-off-by: Ludovic Barre <ludovic.barre@st.com> --- drivers/spi/spi-stm32-qspi.c | 48 +++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 7879a52..983584d 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -93,6 +93,7 @@ struct stm32_qspi_flash { struct stm32_qspi { struct device *dev; + struct spi_controller *ctrl; void __iomem *io_base; void __iomem *mm_base; resource_size_t mm_size; @@ -400,6 +401,7 @@ static void stm32_qspi_release(struct stm32_qspi *qspi) writel_relaxed(0, qspi->io_base + QSPI_CR); mutex_destroy(&qspi->lock); clk_disable_unprepare(qspi->clk); + spi_master_put(qspi->ctrl); } static int stm32_qspi_probe(struct platform_device *pdev) @@ -416,43 +418,56 @@ static int stm32_qspi_probe(struct platform_device *pdev) return -ENOMEM; qspi = spi_controller_get_devdata(ctrl); + qspi->ctrl = ctrl; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi"); qspi->io_base = devm_ioremap_resource(dev, res); - if (IS_ERR(qspi->io_base)) - return PTR_ERR(qspi->io_base); + if (IS_ERR(qspi->io_base)) { + ret = PTR_ERR(qspi->io_base); + goto err; + } + + qspi->phys_base = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm"); qspi->mm_base = devm_ioremap_resource(dev, res); - if (IS_ERR(qspi->mm_base)) - return PTR_ERR(qspi->mm_base); + if (IS_ERR(qspi->mm_base)) { + ret = PTR_ERR(qspi->mm_base); + goto err; + } qspi->mm_size = resource_size(res); - if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) - return -EINVAL; + if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) { + ret = -EINVAL; + goto err; + } irq = platform_get_irq(pdev, 0); ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0, dev_name(dev), qspi); if (ret) { dev_err(dev, "failed to request irq\n"); - return ret; + goto err; } init_completion(&qspi->data_completion); qspi->clk = devm_clk_get(dev, NULL); - if (IS_ERR(qspi->clk)) - return PTR_ERR(qspi->clk); + if (IS_ERR(qspi->clk)) { + ret = PTR_ERR(qspi->clk); + goto err; + } qspi->clk_rate = clk_get_rate(qspi->clk); - if (!qspi->clk_rate) - return -EINVAL; + if (!qspi->clk_rate) { + ret = -EINVAL; + goto err; + } ret = clk_prepare_enable(qspi->clk); if (ret) { dev_err(dev, "can not enable the clock\n"); - return ret; + goto err; } rstc = devm_reset_control_get_exclusive(dev, NULL); @@ -475,14 +490,11 @@ static int stm32_qspi_probe(struct platform_device *pdev) ctrl->dev.of_node = dev->of_node; ret = devm_spi_register_master(dev, ctrl); - if (ret) - goto err_spi_register; - - return 0; + if (!ret) + return 0; -err_spi_register: +err: stm32_qspi_release(qspi); - return ret; } -- 2.7.4 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 1/2] spi: stm32-qspi: add spi_master_put in release function @ 2019-03-22 14:35 ` Ludovic Barre 0 siblings, 0 replies; 19+ messages in thread From: Ludovic Barre @ 2019-03-22 14:35 UTC (permalink / raw) To: Mark Brown, Marek Vasut, Boris Brezillon, Rob Herring Cc: Maxime Coquelin, Alexandre Torgue, linux-mtd, linux-spi, linux-arm-kernel, linux-kernel, linux-stm32, devicetree, Ludovic Barre From: Ludovic Barre <ludovic.barre@st.com> This patch adds spi_master_put in release function to drop the controller's refcount. Signed-off-by: Ludovic Barre <ludovic.barre@st.com> --- drivers/spi/spi-stm32-qspi.c | 48 +++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 7879a52..983584d 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -93,6 +93,7 @@ struct stm32_qspi_flash { struct stm32_qspi { struct device *dev; + struct spi_controller *ctrl; void __iomem *io_base; void __iomem *mm_base; resource_size_t mm_size; @@ -400,6 +401,7 @@ static void stm32_qspi_release(struct stm32_qspi *qspi) writel_relaxed(0, qspi->io_base + QSPI_CR); mutex_destroy(&qspi->lock); clk_disable_unprepare(qspi->clk); + spi_master_put(qspi->ctrl); } static int stm32_qspi_probe(struct platform_device *pdev) @@ -416,43 +418,56 @@ static int stm32_qspi_probe(struct platform_device *pdev) return -ENOMEM; qspi = spi_controller_get_devdata(ctrl); + qspi->ctrl = ctrl; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi"); qspi->io_base = devm_ioremap_resource(dev, res); - if (IS_ERR(qspi->io_base)) - return PTR_ERR(qspi->io_base); + if (IS_ERR(qspi->io_base)) { + ret = PTR_ERR(qspi->io_base); + goto err; + } + + qspi->phys_base = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm"); qspi->mm_base = devm_ioremap_resource(dev, res); - if (IS_ERR(qspi->mm_base)) - return PTR_ERR(qspi->mm_base); + if (IS_ERR(qspi->mm_base)) { + ret = PTR_ERR(qspi->mm_base); + goto err; + } qspi->mm_size = resource_size(res); - if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) - return -EINVAL; + if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) { + ret = -EINVAL; + goto err; + } irq = platform_get_irq(pdev, 0); ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0, dev_name(dev), qspi); if (ret) { dev_err(dev, "failed to request irq\n"); - return ret; + goto err; } init_completion(&qspi->data_completion); qspi->clk = devm_clk_get(dev, NULL); - if (IS_ERR(qspi->clk)) - return PTR_ERR(qspi->clk); + if (IS_ERR(qspi->clk)) { + ret = PTR_ERR(qspi->clk); + goto err; + } qspi->clk_rate = clk_get_rate(qspi->clk); - if (!qspi->clk_rate) - return -EINVAL; + if (!qspi->clk_rate) { + ret = -EINVAL; + goto err; + } ret = clk_prepare_enable(qspi->clk); if (ret) { dev_err(dev, "can not enable the clock\n"); - return ret; + goto err; } rstc = devm_reset_control_get_exclusive(dev, NULL); @@ -475,14 +490,11 @@ static int stm32_qspi_probe(struct platform_device *pdev) ctrl->dev.of_node = dev->of_node; ret = devm_spi_register_master(dev, ctrl); - if (ret) - goto err_spi_register; - - return 0; + if (!ret) + return 0; -err_spi_register: +err: stm32_qspi_release(qspi); - return ret; } -- 2.7.4 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH 1/2] spi: stm32-qspi: add spi_master_put in release function 2019-03-22 14:35 ` Ludovic Barre (?) @ 2019-03-25 16:03 ` Mark Brown -1 siblings, 0 replies; 19+ messages in thread From: Mark Brown @ 2019-03-25 16:03 UTC (permalink / raw) To: Ludovic Barre Cc: Marek Vasut, Boris Brezillon, Rob Herring, Maxime Coquelin, Alexandre Torgue, linux-mtd, linux-spi, linux-arm-kernel, linux-kernel, linux-stm32, devicetree [-- Attachment #1: Type: text/plain, Size: 556 bytes --] On Fri, Mar 22, 2019 at 03:35:53PM +0100, Ludovic Barre wrote: > From: Ludovic Barre <ludovic.barre@st.com> > > This patch adds spi_master_put in release function > to drop the controller's refcount. I'm getting build errors with this: CC drivers/spi/spi-stm32-qspi.o drivers/spi/spi-stm32-qspi.c: In function ‘stm32_qspi_probe’: drivers/spi/spi-stm32-qspi.c:430:8: error: ‘struct stm32_qspi’ has no member named ‘phys_base’; did you mean ‘io_base’? qspi->phys_base = res->start; ^~~~~~~~~ io_base [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/2] spi: stm32-qspi: add spi_master_put in release function @ 2019-03-25 16:03 ` Mark Brown 0 siblings, 0 replies; 19+ messages in thread From: Mark Brown @ 2019-03-25 16:03 UTC (permalink / raw) To: Ludovic Barre Cc: devicetree, Alexandre Torgue, Boris Brezillon, linux-kernel, linux-spi, Marek Vasut, Rob Herring, linux-mtd, Maxime Coquelin, linux-stm32, linux-arm-kernel [-- Attachment #1.1: Type: text/plain, Size: 556 bytes --] On Fri, Mar 22, 2019 at 03:35:53PM +0100, Ludovic Barre wrote: > From: Ludovic Barre <ludovic.barre@st.com> > > This patch adds spi_master_put in release function > to drop the controller's refcount. I'm getting build errors with this: CC drivers/spi/spi-stm32-qspi.o drivers/spi/spi-stm32-qspi.c: In function ‘stm32_qspi_probe’: drivers/spi/spi-stm32-qspi.c:430:8: error: ‘struct stm32_qspi’ has no member named ‘phys_base’; did you mean ‘io_base’? qspi->phys_base = res->start; ^~~~~~~~~ io_base [-- Attachment #1.2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] [-- Attachment #2: Type: text/plain, Size: 176 bytes --] _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/2] spi: stm32-qspi: add spi_master_put in release function @ 2019-03-25 16:03 ` Mark Brown 0 siblings, 0 replies; 19+ messages in thread From: Mark Brown @ 2019-03-25 16:03 UTC (permalink / raw) To: Ludovic Barre Cc: devicetree, Alexandre Torgue, Boris Brezillon, linux-kernel, linux-spi, Marek Vasut, Rob Herring, linux-mtd, Maxime Coquelin, linux-stm32, linux-arm-kernel [-- Attachment #1.1: Type: text/plain, Size: 556 bytes --] On Fri, Mar 22, 2019 at 03:35:53PM +0100, Ludovic Barre wrote: > From: Ludovic Barre <ludovic.barre@st.com> > > This patch adds spi_master_put in release function > to drop the controller's refcount. I'm getting build errors with this: CC drivers/spi/spi-stm32-qspi.o drivers/spi/spi-stm32-qspi.c: In function ‘stm32_qspi_probe’: drivers/spi/spi-stm32-qspi.c:430:8: error: ‘struct stm32_qspi’ has no member named ‘phys_base’; did you mean ‘io_base’? qspi->phys_base = res->start; ^~~~~~~~~ io_base [-- Attachment #1.2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] [-- Attachment #2: Type: text/plain, Size: 144 bytes --] ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/2] spi: stm32-qspi: add spi_master_put in release function 2019-03-25 16:03 ` Mark Brown (?) (?) @ 2019-03-25 16:19 ` Ludovic BARRE -1 siblings, 0 replies; 19+ messages in thread From: Ludovic BARRE @ 2019-03-25 16:19 UTC (permalink / raw) To: Mark Brown Cc: Marek Vasut, Boris Brezillon, Rob Herring, Maxime Coquelin, Alexandre Torgue, linux-mtd, linux-spi, linux-arm-kernel, linux-kernel, linux-stm32, devicetree hi Mark On 3/25/19 5:03 PM, Mark Brown wrote: > On Fri, Mar 22, 2019 at 03:35:53PM +0100, Ludovic Barre wrote: >> From: Ludovic Barre <ludovic.barre@st.com> >> >> This patch adds spi_master_put in release function >> to drop the controller's refcount. > > I'm getting build errors with this: > > CC drivers/spi/spi-stm32-qspi.o > drivers/spi/spi-stm32-qspi.c: In function ‘stm32_qspi_probe’: > drivers/spi/spi-stm32-qspi.c:430:8: error: ‘struct stm32_qspi’ has no member named ‘phys_base’; did you mean ‘io_base’? > qspi->phys_base = res->start; > ^~~~~~~~~ > io_base > I was sure I built each patch, but the fact is there an error :-( I resend a serie with this line in the second patch Regards Ludo ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/2] spi: stm32-qspi: add spi_master_put in release function @ 2019-03-25 16:19 ` Ludovic BARRE 0 siblings, 0 replies; 19+ messages in thread From: Ludovic BARRE @ 2019-03-25 16:19 UTC (permalink / raw) To: Mark Brown Cc: devicetree, Alexandre Torgue, Boris Brezillon, linux-kernel, linux-spi, Marek Vasut, Rob Herring, linux-mtd, Maxime Coquelin, linux-stm32, linux-arm-kernel hi Mark On 3/25/19 5:03 PM, Mark Brown wrote: > On Fri, Mar 22, 2019 at 03:35:53PM +0100, Ludovic Barre wrote: >> From: Ludovic Barre <ludovic.barre@st.com> >> >> This patch adds spi_master_put in release function >> to drop the controller's refcount. > > I'm getting build errors with this: > > CC drivers/spi/spi-stm32-qspi.o > drivers/spi/spi-stm32-qspi.c: In function ‘stm32_qspi_probe’: > drivers/spi/spi-stm32-qspi.c:430:8: error: ‘struct stm32_qspi’ has no member named ‘phys_base’; did you mean ‘io_base’? > qspi->phys_base = res->start; > ^~~~~~~~~ > io_base > I was sure I built each patch, but the fact is there an error :-( I resend a serie with this line in the second patch Regards Ludo _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/2] spi: stm32-qspi: add spi_master_put in release function @ 2019-03-25 16:19 ` Ludovic BARRE 0 siblings, 0 replies; 19+ messages in thread From: Ludovic BARRE @ 2019-03-25 16:19 UTC (permalink / raw) To: Mark Brown Cc: devicetree, Alexandre Torgue, Boris Brezillon, linux-kernel, linux-spi, Marek Vasut, Rob Herring, linux-mtd, Maxime Coquelin, linux-stm32, linux-arm-kernel hi Mark On 3/25/19 5:03 PM, Mark Brown wrote: > On Fri, Mar 22, 2019 at 03:35:53PM +0100, Ludovic Barre wrote: >> From: Ludovic Barre <ludovic.barre@st.com> >> >> This patch adds spi_master_put in release function >> to drop the controller's refcount. > > I'm getting build errors with this: > > CC drivers/spi/spi-stm32-qspi.o > drivers/spi/spi-stm32-qspi.c: In function ‘stm32_qspi_probe’: > drivers/spi/spi-stm32-qspi.c:430:8: error: ‘struct stm32_qspi’ has no member named ‘phys_base’; did you mean ‘io_base’? > qspi->phys_base = res->start; > ^~~~~~~~~ > io_base > I was sure I built each patch, but the fact is there an error :-( I resend a serie with this line in the second patch Regards Ludo ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/2] spi: stm32-qspi: add spi_master_put in release function @ 2019-03-25 16:19 ` Ludovic BARRE 0 siblings, 0 replies; 19+ messages in thread From: Ludovic BARRE @ 2019-03-25 16:19 UTC (permalink / raw) To: Mark Brown Cc: Marek Vasut, Boris Brezillon, Rob Herring, Maxime Coquelin, Alexandre Torgue, linux-mtd, linux-spi, linux-arm-kernel, linux-kernel, linux-stm32, devicetree hi Mark On 3/25/19 5:03 PM, Mark Brown wrote: > On Fri, Mar 22, 2019 at 03:35:53PM +0100, Ludovic Barre wrote: >> From: Ludovic Barre <ludovic.barre@st.com> >> >> This patch adds spi_master_put in release function >> to drop the controller's refcount. > > I'm getting build errors with this: > > CC drivers/spi/spi-stm32-qspi.o > drivers/spi/spi-stm32-qspi.c: In function ‘stm32_qspi_probe’: > drivers/spi/spi-stm32-qspi.c:430:8: error: ‘struct stm32_qspi’ has no member named ‘phys_base’; did you mean ‘io_base’? > qspi->phys_base = res->start; > ^~~~~~~~~ > io_base > I was sure I built each patch, but the fact is there an error :-( I resend a serie with this line in the second patch Regards Ludo ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 2/2] spi: stm32-qspi: add dma support 2019-03-22 14:35 ` Ludovic Barre (?) (?) @ 2019-03-22 14:35 ` Ludovic Barre -1 siblings, 0 replies; 19+ messages in thread From: Ludovic Barre @ 2019-03-22 14:35 UTC (permalink / raw) To: Mark Brown, Marek Vasut, Boris Brezillon, Rob Herring Cc: Maxime Coquelin, Alexandre Torgue, linux-mtd, linux-spi, linux-arm-kernel, linux-kernel, linux-stm32, devicetree, Ludovic Barre From: Ludovic Barre <ludovic.barre@st.com> This patch adds the dma support for the stm32-qspi hardware. The memory buffer constraints (lowmem, vmalloc, kmap) are taken into account by framework. In read mode, the memory map is preferred vs dma (due to better throughput). If the dma transfer fails the buffer is sent by polling. Signed-off-by: Ludovic Barre <ludovic.barre@st.com> --- drivers/spi/spi-stm32-qspi.c | 134 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 983584d..11a89aa 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -5,6 +5,8 @@ */ #include <linux/bitfield.h> #include <linux/clk.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> #include <linux/errno.h> #include <linux/io.h> #include <linux/iopoll.h> @@ -84,6 +86,7 @@ #define STM32_FIFO_TIMEOUT_US 30000 #define STM32_BUSY_TIMEOUT_US 100000 #define STM32_ABT_TIMEOUT_US 100000 +#define STM32_COMP_TIMEOUT_MS 1000 struct stm32_qspi_flash { struct stm32_qspi *qspi; @@ -94,6 +97,7 @@ struct stm32_qspi_flash { struct stm32_qspi { struct device *dev; struct spi_controller *ctrl; + phys_addr_t phys_base; void __iomem *io_base; void __iomem *mm_base; resource_size_t mm_size; @@ -103,6 +107,10 @@ struct stm32_qspi { struct completion data_completion; u32 fmode; + struct dma_chan *dma_chtx; + struct dma_chan *dma_chrx; + struct completion dma_completion; + u32 cr_reg; u32 dcr_reg; @@ -181,6 +189,81 @@ static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, return 0; } +static void stm32_qspi_dma_callback(void *arg) +{ + struct completion *dma_completion = arg; + + complete(dma_completion); +} + +static int stm32_qspi_tx_dma(struct stm32_qspi *qspi, + const struct spi_mem_op *op) +{ + struct dma_async_tx_descriptor *desc; + enum dma_transfer_direction dma_dir; + struct dma_chan *dma_ch; + struct sg_table sgt; + dma_cookie_t cookie; + u32 cr, t_out; + int err; + + if (op->data.dir == SPI_MEM_DATA_IN) { + dma_dir = DMA_DEV_TO_MEM; + dma_ch = qspi->dma_chrx; + } else { + dma_dir = DMA_MEM_TO_DEV; + dma_ch = qspi->dma_chtx; + } + + /* + * spi_map_buf return -EINVAL if the buffer is not DMA-able + * (DMA-able: in vmalloc | kmap | virt_addr_valid) + */ + err = spi_controller_dma_map_mem_op_data(qspi->ctrl, op, &sgt); + if (err) + return err; + + desc = dmaengine_prep_slave_sg(dma_ch, sgt.sgl, sgt.nents, + dma_dir, DMA_PREP_INTERRUPT); + if (!desc) { + err = -ENOMEM; + goto out_unmap; + } + + cr = readl_relaxed(qspi->io_base + QSPI_CR); + + reinit_completion(&qspi->dma_completion); + desc->callback = stm32_qspi_dma_callback; + desc->callback_param = &qspi->dma_completion; + cookie = dmaengine_submit(desc); + err = dma_submit_error(cookie); + if (err) + goto out; + + dma_async_issue_pending(dma_ch); + + writel_relaxed(cr | CR_DMAEN, qspi->io_base + QSPI_CR); + + t_out = sgt.nents * STM32_COMP_TIMEOUT_MS; + if (!wait_for_completion_interruptible_timeout(&qspi->dma_completion, + msecs_to_jiffies(t_out))) + err = -ETIMEDOUT; + + if (dma_async_is_tx_complete(dma_ch, cookie, + NULL, NULL) != DMA_COMPLETE) + err = -ETIMEDOUT; + + if (err) + dmaengine_terminate_all(dma_ch); + +out: + writel_relaxed(cr & ~CR_DMAEN, qspi->io_base + QSPI_CR); +out_unmap: + spi_controller_dma_unmap_mem_op_data(qspi->ctrl, op, &sgt); + + return err; +} + static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) { if (!op->data.nbytes) @@ -188,6 +271,10 @@ static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) if (qspi->fmode == CCR_FMODE_MM) return stm32_qspi_tx_mm(qspi, op); + else if ((op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) || + (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx)) + if (!stm32_qspi_tx_dma(qspi, op)) + return 0; return stm32_qspi_tx_poll(qspi, op); } @@ -218,7 +305,7 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR); if (!wait_for_completion_interruptible_timeout(&qspi->data_completion, - msecs_to_jiffies(1000))) { + msecs_to_jiffies(STM32_COMP_TIMEOUT_MS))) { err = -ETIMEDOUT; } else { sr = readl_relaxed(qspi->io_base + QSPI_SR); @@ -387,6 +474,49 @@ static int stm32_qspi_setup(struct spi_device *spi) return 0; } +static void stm32_qspi_dma_setup(struct stm32_qspi *qspi) +{ + struct dma_slave_config dma_cfg; + struct device *dev = qspi->dev; + + memset(&dma_cfg, 0, sizeof(dma_cfg)); + + dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_cfg.src_addr = qspi->phys_base + QSPI_DR; + dma_cfg.dst_addr = qspi->phys_base + QSPI_DR; + dma_cfg.src_maxburst = 4; + dma_cfg.dst_maxburst = 4; + + qspi->dma_chrx = dma_request_slave_channel(dev, "rx"); + if (qspi->dma_chrx) { + if (dmaengine_slave_config(qspi->dma_chrx, &dma_cfg)) { + dev_err(dev, "dma rx config failed\n"); + dma_release_channel(qspi->dma_chrx); + qspi->dma_chrx = NULL; + } + } + + qspi->dma_chtx = dma_request_slave_channel(dev, "tx"); + if (qspi->dma_chtx) { + if (dmaengine_slave_config(qspi->dma_chtx, &dma_cfg)) { + dev_err(dev, "dma tx config failed\n"); + dma_release_channel(qspi->dma_chtx); + qspi->dma_chtx = NULL; + } + } + + init_completion(&qspi->dma_completion); +} + +static void stm32_qspi_dma_free(struct stm32_qspi *qspi) +{ + if (qspi->dma_chtx) + dma_release_channel(qspi->dma_chtx); + if (qspi->dma_chrx) + dma_release_channel(qspi->dma_chrx); +} + /* * no special host constraint, so use default spi_mem_default_supports_op * to check supported mode. @@ -399,6 +529,7 @@ static void stm32_qspi_release(struct stm32_qspi *qspi) { /* disable qspi */ writel_relaxed(0, qspi->io_base + QSPI_CR); + stm32_qspi_dma_free(qspi); mutex_destroy(&qspi->lock); clk_disable_unprepare(qspi->clk); spi_master_put(qspi->ctrl); @@ -479,6 +610,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) qspi->dev = dev; platform_set_drvdata(pdev, qspi); + stm32_qspi_dma_setup(qspi); mutex_init(&qspi->lock); ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD -- 2.7.4 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 2/2] spi: stm32-qspi: add dma support @ 2019-03-22 14:35 ` Ludovic Barre 0 siblings, 0 replies; 19+ messages in thread From: Ludovic Barre @ 2019-03-22 14:35 UTC (permalink / raw) To: Mark Brown, Marek Vasut, Boris Brezillon, Rob Herring Cc: devicetree, Alexandre Torgue, linux-kernel, linux-spi, linux-mtd, Ludovic Barre, Maxime Coquelin, linux-stm32, linux-arm-kernel From: Ludovic Barre <ludovic.barre@st.com> This patch adds the dma support for the stm32-qspi hardware. The memory buffer constraints (lowmem, vmalloc, kmap) are taken into account by framework. In read mode, the memory map is preferred vs dma (due to better throughput). If the dma transfer fails the buffer is sent by polling. Signed-off-by: Ludovic Barre <ludovic.barre@st.com> --- drivers/spi/spi-stm32-qspi.c | 134 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 983584d..11a89aa 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -5,6 +5,8 @@ */ #include <linux/bitfield.h> #include <linux/clk.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> #include <linux/errno.h> #include <linux/io.h> #include <linux/iopoll.h> @@ -84,6 +86,7 @@ #define STM32_FIFO_TIMEOUT_US 30000 #define STM32_BUSY_TIMEOUT_US 100000 #define STM32_ABT_TIMEOUT_US 100000 +#define STM32_COMP_TIMEOUT_MS 1000 struct stm32_qspi_flash { struct stm32_qspi *qspi; @@ -94,6 +97,7 @@ struct stm32_qspi_flash { struct stm32_qspi { struct device *dev; struct spi_controller *ctrl; + phys_addr_t phys_base; void __iomem *io_base; void __iomem *mm_base; resource_size_t mm_size; @@ -103,6 +107,10 @@ struct stm32_qspi { struct completion data_completion; u32 fmode; + struct dma_chan *dma_chtx; + struct dma_chan *dma_chrx; + struct completion dma_completion; + u32 cr_reg; u32 dcr_reg; @@ -181,6 +189,81 @@ static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, return 0; } +static void stm32_qspi_dma_callback(void *arg) +{ + struct completion *dma_completion = arg; + + complete(dma_completion); +} + +static int stm32_qspi_tx_dma(struct stm32_qspi *qspi, + const struct spi_mem_op *op) +{ + struct dma_async_tx_descriptor *desc; + enum dma_transfer_direction dma_dir; + struct dma_chan *dma_ch; + struct sg_table sgt; + dma_cookie_t cookie; + u32 cr, t_out; + int err; + + if (op->data.dir == SPI_MEM_DATA_IN) { + dma_dir = DMA_DEV_TO_MEM; + dma_ch = qspi->dma_chrx; + } else { + dma_dir = DMA_MEM_TO_DEV; + dma_ch = qspi->dma_chtx; + } + + /* + * spi_map_buf return -EINVAL if the buffer is not DMA-able + * (DMA-able: in vmalloc | kmap | virt_addr_valid) + */ + err = spi_controller_dma_map_mem_op_data(qspi->ctrl, op, &sgt); + if (err) + return err; + + desc = dmaengine_prep_slave_sg(dma_ch, sgt.sgl, sgt.nents, + dma_dir, DMA_PREP_INTERRUPT); + if (!desc) { + err = -ENOMEM; + goto out_unmap; + } + + cr = readl_relaxed(qspi->io_base + QSPI_CR); + + reinit_completion(&qspi->dma_completion); + desc->callback = stm32_qspi_dma_callback; + desc->callback_param = &qspi->dma_completion; + cookie = dmaengine_submit(desc); + err = dma_submit_error(cookie); + if (err) + goto out; + + dma_async_issue_pending(dma_ch); + + writel_relaxed(cr | CR_DMAEN, qspi->io_base + QSPI_CR); + + t_out = sgt.nents * STM32_COMP_TIMEOUT_MS; + if (!wait_for_completion_interruptible_timeout(&qspi->dma_completion, + msecs_to_jiffies(t_out))) + err = -ETIMEDOUT; + + if (dma_async_is_tx_complete(dma_ch, cookie, + NULL, NULL) != DMA_COMPLETE) + err = -ETIMEDOUT; + + if (err) + dmaengine_terminate_all(dma_ch); + +out: + writel_relaxed(cr & ~CR_DMAEN, qspi->io_base + QSPI_CR); +out_unmap: + spi_controller_dma_unmap_mem_op_data(qspi->ctrl, op, &sgt); + + return err; +} + static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) { if (!op->data.nbytes) @@ -188,6 +271,10 @@ static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) if (qspi->fmode == CCR_FMODE_MM) return stm32_qspi_tx_mm(qspi, op); + else if ((op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) || + (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx)) + if (!stm32_qspi_tx_dma(qspi, op)) + return 0; return stm32_qspi_tx_poll(qspi, op); } @@ -218,7 +305,7 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR); if (!wait_for_completion_interruptible_timeout(&qspi->data_completion, - msecs_to_jiffies(1000))) { + msecs_to_jiffies(STM32_COMP_TIMEOUT_MS))) { err = -ETIMEDOUT; } else { sr = readl_relaxed(qspi->io_base + QSPI_SR); @@ -387,6 +474,49 @@ static int stm32_qspi_setup(struct spi_device *spi) return 0; } +static void stm32_qspi_dma_setup(struct stm32_qspi *qspi) +{ + struct dma_slave_config dma_cfg; + struct device *dev = qspi->dev; + + memset(&dma_cfg, 0, sizeof(dma_cfg)); + + dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_cfg.src_addr = qspi->phys_base + QSPI_DR; + dma_cfg.dst_addr = qspi->phys_base + QSPI_DR; + dma_cfg.src_maxburst = 4; + dma_cfg.dst_maxburst = 4; + + qspi->dma_chrx = dma_request_slave_channel(dev, "rx"); + if (qspi->dma_chrx) { + if (dmaengine_slave_config(qspi->dma_chrx, &dma_cfg)) { + dev_err(dev, "dma rx config failed\n"); + dma_release_channel(qspi->dma_chrx); + qspi->dma_chrx = NULL; + } + } + + qspi->dma_chtx = dma_request_slave_channel(dev, "tx"); + if (qspi->dma_chtx) { + if (dmaengine_slave_config(qspi->dma_chtx, &dma_cfg)) { + dev_err(dev, "dma tx config failed\n"); + dma_release_channel(qspi->dma_chtx); + qspi->dma_chtx = NULL; + } + } + + init_completion(&qspi->dma_completion); +} + +static void stm32_qspi_dma_free(struct stm32_qspi *qspi) +{ + if (qspi->dma_chtx) + dma_release_channel(qspi->dma_chtx); + if (qspi->dma_chrx) + dma_release_channel(qspi->dma_chrx); +} + /* * no special host constraint, so use default spi_mem_default_supports_op * to check supported mode. @@ -399,6 +529,7 @@ static void stm32_qspi_release(struct stm32_qspi *qspi) { /* disable qspi */ writel_relaxed(0, qspi->io_base + QSPI_CR); + stm32_qspi_dma_free(qspi); mutex_destroy(&qspi->lock); clk_disable_unprepare(qspi->clk); spi_master_put(qspi->ctrl); @@ -479,6 +610,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) qspi->dev = dev; platform_set_drvdata(pdev, qspi); + stm32_qspi_dma_setup(qspi); mutex_init(&qspi->lock); ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD -- 2.7.4 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 2/2] spi: stm32-qspi: add dma support @ 2019-03-22 14:35 ` Ludovic Barre 0 siblings, 0 replies; 19+ messages in thread From: Ludovic Barre @ 2019-03-22 14:35 UTC (permalink / raw) To: Mark Brown, Marek Vasut, Boris Brezillon, Rob Herring Cc: devicetree, Alexandre Torgue, linux-kernel, linux-spi, linux-mtd, Ludovic Barre, Maxime Coquelin, linux-stm32, linux-arm-kernel From: Ludovic Barre <ludovic.barre@st.com> This patch adds the dma support for the stm32-qspi hardware. The memory buffer constraints (lowmem, vmalloc, kmap) are taken into account by framework. In read mode, the memory map is preferred vs dma (due to better throughput). If the dma transfer fails the buffer is sent by polling. Signed-off-by: Ludovic Barre <ludovic.barre@st.com> --- drivers/spi/spi-stm32-qspi.c | 134 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 983584d..11a89aa 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -5,6 +5,8 @@ */ #include <linux/bitfield.h> #include <linux/clk.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> #include <linux/errno.h> #include <linux/io.h> #include <linux/iopoll.h> @@ -84,6 +86,7 @@ #define STM32_FIFO_TIMEOUT_US 30000 #define STM32_BUSY_TIMEOUT_US 100000 #define STM32_ABT_TIMEOUT_US 100000 +#define STM32_COMP_TIMEOUT_MS 1000 struct stm32_qspi_flash { struct stm32_qspi *qspi; @@ -94,6 +97,7 @@ struct stm32_qspi_flash { struct stm32_qspi { struct device *dev; struct spi_controller *ctrl; + phys_addr_t phys_base; void __iomem *io_base; void __iomem *mm_base; resource_size_t mm_size; @@ -103,6 +107,10 @@ struct stm32_qspi { struct completion data_completion; u32 fmode; + struct dma_chan *dma_chtx; + struct dma_chan *dma_chrx; + struct completion dma_completion; + u32 cr_reg; u32 dcr_reg; @@ -181,6 +189,81 @@ static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, return 0; } +static void stm32_qspi_dma_callback(void *arg) +{ + struct completion *dma_completion = arg; + + complete(dma_completion); +} + +static int stm32_qspi_tx_dma(struct stm32_qspi *qspi, + const struct spi_mem_op *op) +{ + struct dma_async_tx_descriptor *desc; + enum dma_transfer_direction dma_dir; + struct dma_chan *dma_ch; + struct sg_table sgt; + dma_cookie_t cookie; + u32 cr, t_out; + int err; + + if (op->data.dir == SPI_MEM_DATA_IN) { + dma_dir = DMA_DEV_TO_MEM; + dma_ch = qspi->dma_chrx; + } else { + dma_dir = DMA_MEM_TO_DEV; + dma_ch = qspi->dma_chtx; + } + + /* + * spi_map_buf return -EINVAL if the buffer is not DMA-able + * (DMA-able: in vmalloc | kmap | virt_addr_valid) + */ + err = spi_controller_dma_map_mem_op_data(qspi->ctrl, op, &sgt); + if (err) + return err; + + desc = dmaengine_prep_slave_sg(dma_ch, sgt.sgl, sgt.nents, + dma_dir, DMA_PREP_INTERRUPT); + if (!desc) { + err = -ENOMEM; + goto out_unmap; + } + + cr = readl_relaxed(qspi->io_base + QSPI_CR); + + reinit_completion(&qspi->dma_completion); + desc->callback = stm32_qspi_dma_callback; + desc->callback_param = &qspi->dma_completion; + cookie = dmaengine_submit(desc); + err = dma_submit_error(cookie); + if (err) + goto out; + + dma_async_issue_pending(dma_ch); + + writel_relaxed(cr | CR_DMAEN, qspi->io_base + QSPI_CR); + + t_out = sgt.nents * STM32_COMP_TIMEOUT_MS; + if (!wait_for_completion_interruptible_timeout(&qspi->dma_completion, + msecs_to_jiffies(t_out))) + err = -ETIMEDOUT; + + if (dma_async_is_tx_complete(dma_ch, cookie, + NULL, NULL) != DMA_COMPLETE) + err = -ETIMEDOUT; + + if (err) + dmaengine_terminate_all(dma_ch); + +out: + writel_relaxed(cr & ~CR_DMAEN, qspi->io_base + QSPI_CR); +out_unmap: + spi_controller_dma_unmap_mem_op_data(qspi->ctrl, op, &sgt); + + return err; +} + static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) { if (!op->data.nbytes) @@ -188,6 +271,10 @@ static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) if (qspi->fmode == CCR_FMODE_MM) return stm32_qspi_tx_mm(qspi, op); + else if ((op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) || + (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx)) + if (!stm32_qspi_tx_dma(qspi, op)) + return 0; return stm32_qspi_tx_poll(qspi, op); } @@ -218,7 +305,7 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR); if (!wait_for_completion_interruptible_timeout(&qspi->data_completion, - msecs_to_jiffies(1000))) { + msecs_to_jiffies(STM32_COMP_TIMEOUT_MS))) { err = -ETIMEDOUT; } else { sr = readl_relaxed(qspi->io_base + QSPI_SR); @@ -387,6 +474,49 @@ static int stm32_qspi_setup(struct spi_device *spi) return 0; } +static void stm32_qspi_dma_setup(struct stm32_qspi *qspi) +{ + struct dma_slave_config dma_cfg; + struct device *dev = qspi->dev; + + memset(&dma_cfg, 0, sizeof(dma_cfg)); + + dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_cfg.src_addr = qspi->phys_base + QSPI_DR; + dma_cfg.dst_addr = qspi->phys_base + QSPI_DR; + dma_cfg.src_maxburst = 4; + dma_cfg.dst_maxburst = 4; + + qspi->dma_chrx = dma_request_slave_channel(dev, "rx"); + if (qspi->dma_chrx) { + if (dmaengine_slave_config(qspi->dma_chrx, &dma_cfg)) { + dev_err(dev, "dma rx config failed\n"); + dma_release_channel(qspi->dma_chrx); + qspi->dma_chrx = NULL; + } + } + + qspi->dma_chtx = dma_request_slave_channel(dev, "tx"); + if (qspi->dma_chtx) { + if (dmaengine_slave_config(qspi->dma_chtx, &dma_cfg)) { + dev_err(dev, "dma tx config failed\n"); + dma_release_channel(qspi->dma_chtx); + qspi->dma_chtx = NULL; + } + } + + init_completion(&qspi->dma_completion); +} + +static void stm32_qspi_dma_free(struct stm32_qspi *qspi) +{ + if (qspi->dma_chtx) + dma_release_channel(qspi->dma_chtx); + if (qspi->dma_chrx) + dma_release_channel(qspi->dma_chrx); +} + /* * no special host constraint, so use default spi_mem_default_supports_op * to check supported mode. @@ -399,6 +529,7 @@ static void stm32_qspi_release(struct stm32_qspi *qspi) { /* disable qspi */ writel_relaxed(0, qspi->io_base + QSPI_CR); + stm32_qspi_dma_free(qspi); mutex_destroy(&qspi->lock); clk_disable_unprepare(qspi->clk); spi_master_put(qspi->ctrl); @@ -479,6 +610,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) qspi->dev = dev; platform_set_drvdata(pdev, qspi); + stm32_qspi_dma_setup(qspi); mutex_init(&qspi->lock); ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD -- 2.7.4 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 2/2] spi: stm32-qspi: add dma support @ 2019-03-22 14:35 ` Ludovic Barre 0 siblings, 0 replies; 19+ messages in thread From: Ludovic Barre @ 2019-03-22 14:35 UTC (permalink / raw) To: Mark Brown, Marek Vasut, Boris Brezillon, Rob Herring Cc: Maxime Coquelin, Alexandre Torgue, linux-mtd, linux-spi, linux-arm-kernel, linux-kernel, linux-stm32, devicetree, Ludovic Barre From: Ludovic Barre <ludovic.barre@st.com> This patch adds the dma support for the stm32-qspi hardware. The memory buffer constraints (lowmem, vmalloc, kmap) are taken into account by framework. In read mode, the memory map is preferred vs dma (due to better throughput). If the dma transfer fails the buffer is sent by polling. Signed-off-by: Ludovic Barre <ludovic.barre@st.com> --- drivers/spi/spi-stm32-qspi.c | 134 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 983584d..11a89aa 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -5,6 +5,8 @@ */ #include <linux/bitfield.h> #include <linux/clk.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> #include <linux/errno.h> #include <linux/io.h> #include <linux/iopoll.h> @@ -84,6 +86,7 @@ #define STM32_FIFO_TIMEOUT_US 30000 #define STM32_BUSY_TIMEOUT_US 100000 #define STM32_ABT_TIMEOUT_US 100000 +#define STM32_COMP_TIMEOUT_MS 1000 struct stm32_qspi_flash { struct stm32_qspi *qspi; @@ -94,6 +97,7 @@ struct stm32_qspi_flash { struct stm32_qspi { struct device *dev; struct spi_controller *ctrl; + phys_addr_t phys_base; void __iomem *io_base; void __iomem *mm_base; resource_size_t mm_size; @@ -103,6 +107,10 @@ struct stm32_qspi { struct completion data_completion; u32 fmode; + struct dma_chan *dma_chtx; + struct dma_chan *dma_chrx; + struct completion dma_completion; + u32 cr_reg; u32 dcr_reg; @@ -181,6 +189,81 @@ static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, return 0; } +static void stm32_qspi_dma_callback(void *arg) +{ + struct completion *dma_completion = arg; + + complete(dma_completion); +} + +static int stm32_qspi_tx_dma(struct stm32_qspi *qspi, + const struct spi_mem_op *op) +{ + struct dma_async_tx_descriptor *desc; + enum dma_transfer_direction dma_dir; + struct dma_chan *dma_ch; + struct sg_table sgt; + dma_cookie_t cookie; + u32 cr, t_out; + int err; + + if (op->data.dir == SPI_MEM_DATA_IN) { + dma_dir = DMA_DEV_TO_MEM; + dma_ch = qspi->dma_chrx; + } else { + dma_dir = DMA_MEM_TO_DEV; + dma_ch = qspi->dma_chtx; + } + + /* + * spi_map_buf return -EINVAL if the buffer is not DMA-able + * (DMA-able: in vmalloc | kmap | virt_addr_valid) + */ + err = spi_controller_dma_map_mem_op_data(qspi->ctrl, op, &sgt); + if (err) + return err; + + desc = dmaengine_prep_slave_sg(dma_ch, sgt.sgl, sgt.nents, + dma_dir, DMA_PREP_INTERRUPT); + if (!desc) { + err = -ENOMEM; + goto out_unmap; + } + + cr = readl_relaxed(qspi->io_base + QSPI_CR); + + reinit_completion(&qspi->dma_completion); + desc->callback = stm32_qspi_dma_callback; + desc->callback_param = &qspi->dma_completion; + cookie = dmaengine_submit(desc); + err = dma_submit_error(cookie); + if (err) + goto out; + + dma_async_issue_pending(dma_ch); + + writel_relaxed(cr | CR_DMAEN, qspi->io_base + QSPI_CR); + + t_out = sgt.nents * STM32_COMP_TIMEOUT_MS; + if (!wait_for_completion_interruptible_timeout(&qspi->dma_completion, + msecs_to_jiffies(t_out))) + err = -ETIMEDOUT; + + if (dma_async_is_tx_complete(dma_ch, cookie, + NULL, NULL) != DMA_COMPLETE) + err = -ETIMEDOUT; + + if (err) + dmaengine_terminate_all(dma_ch); + +out: + writel_relaxed(cr & ~CR_DMAEN, qspi->io_base + QSPI_CR); +out_unmap: + spi_controller_dma_unmap_mem_op_data(qspi->ctrl, op, &sgt); + + return err; +} + static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) { if (!op->data.nbytes) @@ -188,6 +271,10 @@ static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) if (qspi->fmode == CCR_FMODE_MM) return stm32_qspi_tx_mm(qspi, op); + else if ((op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) || + (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx)) + if (!stm32_qspi_tx_dma(qspi, op)) + return 0; return stm32_qspi_tx_poll(qspi, op); } @@ -218,7 +305,7 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR); if (!wait_for_completion_interruptible_timeout(&qspi->data_completion, - msecs_to_jiffies(1000))) { + msecs_to_jiffies(STM32_COMP_TIMEOUT_MS))) { err = -ETIMEDOUT; } else { sr = readl_relaxed(qspi->io_base + QSPI_SR); @@ -387,6 +474,49 @@ static int stm32_qspi_setup(struct spi_device *spi) return 0; } +static void stm32_qspi_dma_setup(struct stm32_qspi *qspi) +{ + struct dma_slave_config dma_cfg; + struct device *dev = qspi->dev; + + memset(&dma_cfg, 0, sizeof(dma_cfg)); + + dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_cfg.src_addr = qspi->phys_base + QSPI_DR; + dma_cfg.dst_addr = qspi->phys_base + QSPI_DR; + dma_cfg.src_maxburst = 4; + dma_cfg.dst_maxburst = 4; + + qspi->dma_chrx = dma_request_slave_channel(dev, "rx"); + if (qspi->dma_chrx) { + if (dmaengine_slave_config(qspi->dma_chrx, &dma_cfg)) { + dev_err(dev, "dma rx config failed\n"); + dma_release_channel(qspi->dma_chrx); + qspi->dma_chrx = NULL; + } + } + + qspi->dma_chtx = dma_request_slave_channel(dev, "tx"); + if (qspi->dma_chtx) { + if (dmaengine_slave_config(qspi->dma_chtx, &dma_cfg)) { + dev_err(dev, "dma tx config failed\n"); + dma_release_channel(qspi->dma_chtx); + qspi->dma_chtx = NULL; + } + } + + init_completion(&qspi->dma_completion); +} + +static void stm32_qspi_dma_free(struct stm32_qspi *qspi) +{ + if (qspi->dma_chtx) + dma_release_channel(qspi->dma_chtx); + if (qspi->dma_chrx) + dma_release_channel(qspi->dma_chrx); +} + /* * no special host constraint, so use default spi_mem_default_supports_op * to check supported mode. @@ -399,6 +529,7 @@ static void stm32_qspi_release(struct stm32_qspi *qspi) { /* disable qspi */ writel_relaxed(0, qspi->io_base + QSPI_CR); + stm32_qspi_dma_free(qspi); mutex_destroy(&qspi->lock); clk_disable_unprepare(qspi->clk); spi_master_put(qspi->ctrl); @@ -479,6 +610,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) qspi->dev = dev; platform_set_drvdata(pdev, qspi); + stm32_qspi_dma_setup(qspi); mutex_init(&qspi->lock); ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD -- 2.7.4 ^ permalink raw reply related [flat|nested] 19+ messages in thread
end of thread, other threads:[~2019-03-25 16:20 UTC | newest] Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2019-03-22 14:35 [PATCH 0/2] spi: stm32-qspi: add dma support Ludovic Barre 2019-03-22 14:35 ` Ludovic Barre 2019-03-22 14:35 ` Ludovic Barre 2019-03-22 14:35 ` Ludovic Barre 2019-03-22 14:35 ` [PATCH 1/2] spi: stm32-qspi: add spi_master_put in release function Ludovic Barre 2019-03-22 14:35 ` Ludovic Barre 2019-03-22 14:35 ` Ludovic Barre 2019-03-22 14:35 ` Ludovic Barre 2019-03-25 16:03 ` Mark Brown 2019-03-25 16:03 ` Mark Brown 2019-03-25 16:03 ` Mark Brown 2019-03-25 16:19 ` Ludovic BARRE 2019-03-25 16:19 ` Ludovic BARRE 2019-03-25 16:19 ` Ludovic BARRE 2019-03-25 16:19 ` Ludovic BARRE 2019-03-22 14:35 ` [PATCH 2/2] spi: stm32-qspi: add dma support Ludovic Barre 2019-03-22 14:35 ` Ludovic Barre 2019-03-22 14:35 ` Ludovic Barre 2019-03-22 14:35 ` Ludovic Barre
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.