ARM: sun8i: Add DMA controller support
Subsystems (3)
v2 cover ARM: sun8i: Add DMA controller support
Hi everyone,
This is v2 of my sun8i DMA controller support series. This series adds support for the DMA controller found in the Allwinner A23 SoC. It is the same hardware as found in the A31 (sun6i) SoC. In addition to reduced physical channels and endpoints, the controller in the A23 requires an undocumented register to be toggled. That seems to allow memory bus access.
This series is based on my earlier "clk: sun6i: Unify AHB1 clock and fix rate calculation" series, which removes the clock muxing calls from the sun6i-dma driver. The default PLL6 pre-divider for AHB1 on the A23 results in an exceedingly high clock rate for AHB1, and the system hangs. Also, on the A23, the dma controller happily works even when AHB1 is clocked from AXI.
Patch 1 changes the channel count macros into runtime data binded to the DT compatible strings. It also gets rid of some hardcoded values in the interrupt handler.
Patch 2 adds the channel number data for the A23 (sun8i), as well as the undocumented register quirk.
Patch 3 adds the dma controller node, and related dma resources, to the DT.
Changes since v1:
- Added Maxime's Acked-by for patch 1
- Added macros for sun8i specific dma gating registers, and updated comment to reflect its usage.
Cheers
ChenYu
Chen-Yu Tsai (3):
dmaengine: sun6i: support parameterized compatible strings
dmaengine: sun6i: Add support for Allwinner A23 (sun8i) variant
ARM: dts: sun8i: Add DMA controller node
.../devicetree/bindings/dma/sun6i-dma.txt | 2 +- arch/arm/boot/dts/sun8i-a23.dtsi | 19 ++++ drivers/dma/Kconfig | 4 +- drivers/dma/sun6i-dma.c | 123 +++++++++++++++------ 4 files changed, 110 insertions(+), 38 deletions(-)
Signature · 1 line
2.1.0
PATCH v2 1/3 dmaengine: sun6i: support parameterized compatible strings
This patch adds support for hardware parameters tied to compatible strings, so similar hardware can reuse the driver.
--- drivers/dma/sun6i-dma.c | 96 +++++++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 35 deletions(-)
drivers/dma/sun6i-dma.c +61 -35
@@ -18,6 +18,7 @@#include <linux/interrupt.h> #include <linux/module.h> #include <linux/of_dma.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/reset.h> #include <linux/slab.h>
@@ -26,24 +27,6 @@#include "virt-dma.h" /* -* There's 16 physical channels that can work in parallel. -* -* However we have 30 different endpoints for our requests. -* -* Since the channels are able to handle only an unidirectional -* transfer, we need to allocate more virtual channels so that -* everyone can grab one channel. -* -* Some devices can't work in both direction (mostly because it -* wouldn't make sense), so we have a bit fewer virtual channels than -* 2 channels per endpoints. -*/ - -#define NR_MAX_CHANNELS 16 -#define NR_MAX_REQUESTS 30 -#define NR_MAX_VCHANS 53 - -/* * Common registers */ #define DMA_IRQ_EN (x) ((x) * 0x04)
@@ -102,6 +85,19 @@#define DRQ_SDRAM 1/* +* Hardware channels / ports representation +* +* The hardware is used in several SoCs, with differing numbers +* of channels and endpoints. This structure ties those numbers +* to a certain compatible string. +*/ +struct sun6i_dma_config { +u32 nr_max_channels; +u32 nr_max_requests; +u32 nr_max_vchans; +}; + +/* * Hardware representation of the LLI * * The hardware will be fed the physical address of this structure,
@@ -159,6 +155,7 @@ struct sun6i_dma_dev {struct dma_pool *pool;struct sun6i_pchan *pchans;struct sun6i_vchan *vchans; +const struct sun6i_dma_config *cfg; };static struct device *chan2dev (struct dma_chan *chan)
@@ -432,6 +429,7 @@ static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)static void sun6i_dma_tasklet (unsigned long data) {struct sun6i_dma_dev *sdev = (struct sun6i_dma_dev *)data; +const struct sun6i_dma_config *cfg = sdev->cfg;struct sun6i_vchan *vchan;struct sun6i_pchan *pchan;unsigned int pchan_alloc =0 ;
@@ -459,7 +457,7 @@ static void sun6i_dma_tasklet(unsigned long data) }spin_lock_irq (&sdev->lock); -for (pchan_idx =0 ; pchan_idx <NR_MAX_CHANNELS ; pchan_idx++) { +for (pchan_idx =0 ; pchan_idx < cfg->nr_max_channels; pchan_idx++) { pchan = &sdev->pchans[pchan_idx];if (pchan->vchan ||list_empty (&sdev->pending))
@@ -480,7 +478,7 @@ static void sun6i_dma_tasklet(unsigned long data) }spin_unlock_irq (&sdev->lock); -for (pchan_idx =0 ; pchan_idx <NR_MAX_CHANNELS ; pchan_idx++) { +for (pchan_idx =0 ; pchan_idx < cfg->nr_max_channels; pchan_idx++) {if (!(pchan_alloc &BIT (pchan_idx)))continue ;
@@ -502,7 +500,7 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)int i, j, ret =IRQ_NONE ;u32 status; -for (i =0 ; i <2 ; i++) { +for (i =0 ; i < sdev->cfg->nr_max_channels /DMA_IRQ_CHAN_NR ; i++) { status =readl (sdev->base +DMA_IRQ_STAT (i));if (!status)continue ;
@@ -512,7 +510,7 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)writel (status, sdev->base +DMA_IRQ_STAT (i)); -for (j =0 ; (j <8 ) && status; j++) { +for (j =0 ; (j <DMA_IRQ_CHAN_NR ) && status; j++) {if (status &DMA_IRQ_QUEUE ) { pchan = sdev->pchans + j; vchan = pchan->vchan;
@@ -525,7 +523,7 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id) } } - status = status >>4 ; + status = status >>DMA_IRQ_CHAN_WIDTH ; }if (!atomic_read (&sdev->tasklet_shutdown))
@@ -817,7 +815,7 @@ static struct dma_chan *sun6i_dma_of_xlate(struct of_phandle_args *dma_spec,struct dma_chan *chan;u8 port = dma_spec->args[0 ]; -if (port >NR_MAX_REQUESTS ) +if (port > sdev->cfg->nr_max_requests)return NULL ; chan =dma_get_any_slave_channel (&sdev->slave);
@@ -850,7 +848,7 @@ static inline void sun6i_dma_free(struct sun6i_dma_dev *sdev) {int i; -for (i =0 ; i <NR_MAX_VCHANS ; i++) { +for (i =0 ; i < sdev->cfg->nr_max_vchans; i++) {struct sun6i_vchan *vchan = &sdev->vchans[i];list_del (&vchan->vc.chan.device_node);
@@ -858,8 +856,36 @@ static inline void sun6i_dma_free(struct sun6i_dma_dev *sdev) } } +/* +* For A31: +* +* There's 16 physical channels that can work in parallel. +* +* However we have 30 different endpoints for our requests. +* +* Since the channels are able to handle only an unidirectional +* transfer, we need to allocate more virtual channels so that +* everyone can grab one channel. +* +* Some devices can't work in both direction (mostly because it +* wouldn't make sense), so we have a bit fewer virtual channels than +* 2 channels per endpoints. +*/ + +static struct sun6i_dma_config sun6i_a31_dma_cfg = { + .nr_max_channels =16 , + .nr_max_requests =30 , + .nr_max_vchans =53 , +}; + +static struct of_device_id sun6i_dma_match[] = { + { .compatible ="allwinner,sun6i-a31-dma" , .data = &sun6i_a31_dma_cfg }, + {/* sentinel */ } +}; +static int sun6i_dma_probe (struct platform_device *pdev) { +const struct of_device_id *device;struct sun6i_dma_dev *sdc;struct resource *res;int ret, i;
@@ -868,6 +894,11 @@ static int sun6i_dma_probe(struct platform_device *pdev)if (!sdc)return -ENOMEM ; + device =of_match_device (sun6i_dma_match, &pdev->dev); +if (!device) +return -ENODEV ; + sdc->cfg = device->data; + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); sdc->base =devm_ioremap_resource (&pdev->dev, res);if (IS_ERR (sdc->base))
@@ -914,30 +945,30 @@ static int sun6i_dma_probe(struct platform_device *pdev) sdc->slave.device_prep_slave_sg = sun6i_dma_prep_slave_sg; sdc->slave.device_prep_dma_memcpy = sun6i_dma_prep_dma_memcpy; sdc->slave.device_control = sun6i_dma_control; - sdc->slave.chancnt =NR_MAX_VCHANS ; + sdc->slave.chancnt = sdc->cfg->nr_max_vchans; sdc->slave.dev = &pdev->dev; - sdc->pchans =devm_kcalloc (&pdev->dev,NR_MAX_CHANNELS , + sdc->pchans =devm_kcalloc (&pdev->dev, sdc->cfg->nr_max_channels,sizeof (struct sun6i_pchan ),GFP_KERNEL );if (!sdc->pchans)return -ENOMEM ; - sdc->vchans =devm_kcalloc (&pdev->dev,NR_MAX_VCHANS , + sdc->vchans =devm_kcalloc (&pdev->dev, sdc->cfg->nr_max_vchans,sizeof (struct sun6i_vchan ),GFP_KERNEL );if (!sdc->vchans)return -ENOMEM ;tasklet_init (&sdc->task, sun6i_dma_tasklet, (unsigned long )sdc); -for (i =0 ; i <NR_MAX_CHANNELS ; i++) { +for (i =0 ; i < sdc->cfg->nr_max_channels; i++) {struct sun6i_pchan *pchan = &sdc->pchans[i]; pchan->idx = i; pchan->base = sdc->base +0x100 + i *0x40 ; } -for (i =0 ; i <NR_MAX_VCHANS ; i++) { +for (i =0 ; i < sdc->cfg->nr_max_vchans; i++) {struct sun6i_vchan *vchan = &sdc->vchans[i];INIT_LIST_HEAD (&vchan->node);
@@ -1009,11 +1040,6 @@ static int sun6i_dma_remove(struct platform_device *pdev)return 0 ; } -static struct of_device_id sun6i_dma_match[] = { - { .compatible ="allwinner,sun6i-a31-dma" }, - {/* sentinel */ } -}; -static struct platform_driver sun6i_dma_driver = { .probe = sun6i_dma_probe, .remove = sun6i_dma_remove,
Signature · 1 line
2.1.0
PATCH v2 2/3 dmaengine: sun6i: Add support for Allwinner A23 (sun8i) variant
In reply to Chen-Yu TsaiThe A23 SoC has the same dma engine as the A31 (sun6i), with a reduced amount of endpoints and physical channels. Add the proper config data and compatible string to support it.
A slight difference in sun8i is an undocumented register needs to be toggled for dma to function.
--- .../devicetree/bindings/dma/sun6i-dma.txt | 2 +- drivers/dma/Kconfig | 4 ++-- drivers/dma/sun6i-dma.c | 27 ++++++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-)
Documentation/devicetree/bindings/dma/sun6i-dma.txt +1 -1
@@ -4,7 +4,7 @@ This driver follows the generic DMA bindings defined in dma.txt. Required properties: -- compatible: Must be "allwinner,sun6i-a31-dma" +- compatible: Must be "allwinner,sun6i-a31-dma" or "allwinner,sun8i-a23-dma" - reg: Should contain the registers base address and length - interrupts: Should contain a reference to the interrupt used by this device - clocks: Should contain a reference to the parent AHB clock
drivers/dma/Kconfig +2 -2
@@ -395,12 +395,12 @@ config XILINX_VDMA config DMA_SUN6I tristate "Allwinner A31 SoCs DMA support" - depends on MACH_SUN6I || COMPILE_TEST + depends on MACH_SUN6I || MACH_SUN8I || COMPILE_TEST depends on RESET_CONTROLLER select DMA_ENGINE select DMA_VIRTUAL_CHANNELS help - Support for the DMA engine for Allwinner A31 SoCs. + Support for the DMA engine first found in Allwinner A31 SoCs. config NBPFAXI_DMA tristate "Renesas Type-AXI NBPF DMA support"
drivers/dma/sun6i-dma.c +27 -0
@@ -43,6 +43,12 @@#define DMA_STAT 0x30/* +* sun8i specific registers +*/ +#define SUN8I_DMA_GATE 0x20 +#define SUN8I_DMA_GATE_ENABLE 0x4 + +/* * Channels specific registers */ #define DMA_CHAN_ENABLE 0x00
@@ -878,8 +884,20 @@ static struct sun6i_dma_config sun6i_a31_dma_cfg = { .nr_max_vchans = 53, }; +/* +* The A23 only has 8 physical channels, a maximum DRQ port id of 24, +* and a total of 37 usable source and destination endpoints. +*/ + +static struct sun6i_dma_config sun8i_a23_dma_cfg = { + .nr_max_channels =8 , + .nr_max_requests =24 , + .nr_max_vchans =37 , +}; +static struct of_device_id sun6i_dma_match[] = { { .compatible ="allwinner,sun6i-a31-dma" , .data = &sun6i_a31_dma_cfg }, + { .compatible ="allwinner,sun8i-a23-dma" , .data = &sun8i_a23_dma_cfg }, {/* sentinel */ } };
@@ -1008,6 +1026,15 @@ static int sun6i_dma_probe(struct platform_device *pdev) goto err_dma_unregister; } +/* +* sun8i variant requires us to toggle a dma gating register, +* as seen in Allwinner's SDK. This register is not documented +* in the A23 user manual. +*/ +if (of_device_is_compatible (pdev->dev.of_node, +"allwinner,sun8i-a23-dma" )) +writel (SUN8I_DMA_GATE_ENABLE , sdc->base +SUN8I_DMA_GATE ); +return 0 ; err_dma_unregister:
Signature · 1 line
2.1.0
PATCH v2 2/3 dmaengine: sun6i: Add support for Allwinner A23 (sun8i) variant
Quoted 8 lines · Chen-Yu Tsai
The A23 SoC has the same dma engine as the A31 (sun6i), with a reduced amount of endpoints and physical channels. Add the proper config data and compatible string to support it.
A slight difference in sun8i is an undocumented register needs to be toggled for dma to function.
Signed-off-by Chen-Yu Tsai <[email protected]>
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140920/9a28efe9/attachment.sig>
PATCH v2 3/3 ARM: dts: sun8i: Add DMA controller node
In reply to Chen-Yu TsaiAdd the DMA controller node and DMA bindings to the supported devices.
--- arch/arm/boot/dts/sun8i-a23.dtsi | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
arch/arm/boot/dts/sun8i-a23.dtsi +19 -0
@@ -203,6 +203,15 @@ #size-cells = <1>; ranges; + dma: dma-controller at 01c02000 { + compatible = "allwinner,sun8i-a23-dma"; + reg = <0x01c02000 0x1000>; + interrupts = <0 50 4>; + clocks = <&ahb1_gates 6>; + resets = <&ahb1_rst 6>; + #dma-cells = <1>; + }; + mmc0: mmc at 01c0f000 { compatible = "allwinner,sun5i-a13-mmc"; reg = <0x01c0f000 0x1000>;
@@ -332,6 +341,8 @@ reg-io-width = <4>; clocks = <&apb2_gates 16>; resets = <&apb2_rst 16>; + dmas = <&dma 6>, <&dma 6>; + dma-names = "rx", "tx"; status = "disabled"; };
@@ -343,6 +354,8 @@ reg-io-width = <4>; clocks = <&apb2_gates 17>; resets = <&apb2_rst 17>; + dmas = <&dma 7>, <&dma 7>; + dma-names = "rx", "tx"; status = "disabled"; };
@@ -354,6 +367,8 @@ reg-io-width = <4>; clocks = <&apb2_gates 18>; resets = <&apb2_rst 18>; + dmas = <&dma 8>, <&dma 8>; + dma-names = "rx", "tx"; status = "disabled"; };
@@ -365,6 +380,8 @@ reg-io-width = <4>; clocks = <&apb2_gates 19>; resets = <&apb2_rst 19>; + dmas = <&dma 9>, <&dma 9>; + dma-names = "rx", "tx"; status = "disabled"; };
@@ -376,6 +393,8 @@ reg-io-width = <4>; clocks = <&apb2_gates 20>; resets = <&apb2_rst 20>; + dmas = <&dma 10>, <&dma 10>; + dma-names = "rx", "tx"; status = "disabled"; };
Signature · 1 line
2.1.0
Maxime Ripard
AppliedPATCH v2 3/3 ARM: dts: sun8i: Add DMA controller node
Quoted 3 lines · Chen-Yu Tsai
Add the DMA controller node and DMA bindings to the supported devices.
Signed-off-by Chen-Yu Tsai <[email protected]>
Applied, thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140920/05d3cc2b/attachment.sig>
v2 cover ARM: sun8i: Add DMA controller support
In reply to Chen-Yu TsaiQuoted 17 lines · Chen-Yu Tsai
Hi everyone,
This is v2 of my sun8i DMA controller support series. This series adds support for the DMA controller found in the Allwinner A23 SoC. It is the same hardware as found in the A31 (sun6i) SoC. In addition to reduced physical channels and endpoints, the controller in the A23 requires an undocumented register to be toggled. That seems to allow memory bus access.
This series is based on my earlier "clk: sun6i: Unify AHB1 clock and fix rate calculation" series, which removes the clock muxing calls from the sun6i-dma driver. The default PLL6 pre-divider for AHB1 on the A23 results in an exceedingly high clock rate for AHB1, and the system hangs. Also, on the A23, the dma controller happily works even when AHB1 is clocked from AXI.
Quoted 6 lines
Patch 1 changes the channel count macros into runtime data binded to the DT compatible strings. It also gets rid of some hardcoded values in the interrupt handler.
Patch 2 adds the channel number data for the A23 (sun8i), as well as the undocumented register quirk.
Hi, Vinod,
Any chance we can get patches 1 & 2 merged? You've already merged the prerequisite patch "dmaengine: sun6i: Remove obsolete clk muxing code" a few days ago, and patch 3 is already in arm-soc.
Thanks!
ChenYu
Quoted 28 lines
Patch 3 adds the dma controller node, and related dma resources, to the DT.
Changes since v1:
- Added Maxime's Acked-by for patch 1
- Added macros for sun8i specific dma gating registers, and updated comment to reflect its usage.Cheers
ChenYuChen-Yu Tsai (3):
dmaengine: sun6i: support parameterized compatible strings
dmaengine: sun6i: Add support for Allwinner A23 (sun8i) variant
ARM: dts: sun8i: Add DMA controller node.../devicetree/bindings/dma/sun6i-dma.txt | 2 +- arch/arm/boot/dts/sun8i-a23.dtsi | 19 ++++ drivers/dma/Kconfig | 4 +- drivers/dma/sun6i-dma.c | 123 +++++++++++++++------ 4 files changed, 110 insertions(+), 38 deletions(-)--
2.1.0
v2 cover ARM: sun8i: Add DMA controller support
Quoted 22 lines · Chen-Yu Tsai
Quoted 21 lines · Chen-Yu Tsai
Hi everyone,
This is v2 of my sun8i DMA controller support series. This series adds support for the DMA controller found in the Allwinner A23 SoC. It is the same hardware as found in the A31 (sun6i) SoC. In addition to reduced physical channels and endpoints, the controller in the A23 requires an undocumented register to be toggled. That seems to allow memory bus access.
This series is based on my earlier "clk: sun6i: Unify AHB1 clock and fix rate calculation" series, which removes the clock muxing calls from the sun6i-dma driver. The default PLL6 pre-divider for AHB1 on the A23 results in an exceedingly high clock rate for AHB1, and the system hangs. Also, on the A23, the dma controller happily works even when AHB1 is clocked from AXI.
Patch 1 changes the channel count macros into runtime data binded to the DT compatible strings. It also gets rid of some hardcoded values in the interrupt handler.
Quoted 8 lines
Quoted 2 lines
Patch 2 adds the channel number data for the A23 (sun8i), as well as the undocumented register quirk.
Hi, Vinod,
Any chance we can get patches 1 & 2 merged? You've already merged the prerequisite patch "dmaengine: sun6i: Remove obsolete clk muxing code" a few days ago, and patch 3 is already in arm-soc.
Hi ChenYu,
The patches look fine to me so I tried applying them but they fail to apply, can you please rebase these two and resend
Thanks
Signature · 1 line
~Vinod
v2 cover ARM: sun8i: Add DMA controller support
Quoted 28 lines · Vinod Koul
Quoted 27 lines · Chen-Yu Tsai
Quoted 17 lines · Chen-Yu Tsai
Hi everyone,
This is v2 of my sun8i DMA controller support series. This series adds support for the DMA controller found in the Allwinner A23 SoC. It is the same hardware as found in the A31 (sun6i) SoC. In addition to reduced physical channels and endpoints, the controller in the A23 requires an undocumented register to be toggled. That seems to allow memory bus access.
This series is based on my earlier "clk: sun6i: Unify AHB1 clock and fix rate calculation" series, which removes the clock muxing calls from the sun6i-dma driver. The default PLL6 pre-divider for AHB1 on the A23 results in an exceedingly high clock rate for AHB1, and the system hangs. Also, on the A23, the dma controller happily works even when AHB1 is clocked from AXI.
Quoted 6 lines
Patch 1 changes the channel count macros into runtime data binded to the DT compatible strings. It also gets rid of some hardcoded values in the interrupt handler.
Patch 2 adds the channel number data for the A23 (sun8i), as well as the undocumented register quirk.
Hi, Vinod,
Quoted 8 lines
Quoted 3 lines
Any chance we can get patches 1 & 2 merged? You've already merged the prerequisite patch "dmaengine: sun6i: Remove obsolete clk muxing code" a few days ago, and patch 3 is already in arm-soc.
Hi ChenYu,
The patches look fine to me so I tried applying them but they fail to apply, can you please rebase these two and resend
Hi Vinod,
Could you publish an updated slave-dma/next branch? Currently I see it at v3.18-rc1. And the series rebases cleanly onto it with no differences.
I'm guessing some of Maxime's cleanup work is the source of conflict.
Thanks
ChenYu
v2 cover ARM: sun8i: Add DMA controller support
Quoted 9 lines · Chen-Yu Tsai
Quoted 2 lines
The patches look fine to me so I tried applying them but they fail to apply, can you please rebase these two and resend
Hi Vinod,
Could you publish an updated slave-dma/next branch? Currently I see it at v3.18-rc1. And the series rebases cleanly onto it with no differences.
I'm guessing some of Maxime's cleanup work is the source of conflict.
Its pushed now..
Signature · 1 line
~Vinod