DMA Engine development
 help / color / mirror / Atom feed
* [v2,1/4] dt-bindings: dma: Add binding for Actions Semi Owl SoCs
From: Manivannan Sadhasivam @ 2018-07-25 15:23 UTC (permalink / raw)
  To: Vinod
  Cc: dan.j.williams, afaerber, robh+dt, dmaengine, liuwei, 96boards,
	devicetree, daniel.thompson, amit.kucheria, linux-arm-kernel,
	linux-kernel, hzhang, bdong, manivannanece23, thomas.liau,
	jeff.chen, pn, edgar.righi

Hi Vinod,

On Tue, Jul 24, 2018 at 05:46:04PM +0530, Vinod wrote:
> Hi Mani,
> 
> Patch title should be dmaengine: ... Please always use the apt tags and
> one can find them using git log <subsystem>
> 

Did you mean, dt-bindings: dmaengine? If yes, then I will use it for the
future patches.

> On 23-07-18, 09:47, Manivannan Sadhasivam wrote:
> > Add devicetree binding for Actions Semi Owl SoCs DMA controller.
> 
> 
> It would help for review to describe the controller here
> 

Okay.

> > 
> > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > ---
> >  .../devicetree/bindings/dma/owl-dma.txt       | 46 +++++++++++++++++++
> >  1 file changed, 46 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/dma/owl-dma.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/dma/owl-dma.txt b/Documentation/devicetree/bindings/dma/owl-dma.txt
> > new file mode 100644
> > index 000000000000..dd6ce237b216
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/dma/owl-dma.txt
> > @@ -0,0 +1,46 @@
> > +* Actions Semi Owl SoCs DMA controller
> > +
> > +This binding follows the generic DMA bindings defined in dma.txt.
> > +
> > +Required properties:
> > +- compatible: Should be "actions,s900-dma".
> > +- reg: Should contain DMA registers location and length.
> > +- interrupts: Should contain 4 interrupts shared by all channel.
> > +- #dma-cells: Must be <1>. Used to represent the number of integer
> > +              cells in the dmas property of client device.
> > +- dma-channels: Physical channels supported.
> > +- dma-requests: Virtual channels supported.
> 
> not really, virtual channel is a software concepts. On the other hand
> you may have request lines in hw and you can describe that, if not skip
> this one
> 

Okay. Will change the property description to request signals.

Thanks,
Mani

> > +- clocks: Phandle and Specifier of the clock feeding the DMA controller.
> > +
> > +Example:
> > +
> > +Controller:
> > +                dma: dma-controller@e0260000 {
> > +                        compatible = "actions,s900-dma";
> > +                        reg = <0x0 0xe0260000 0x0 0x1000>;
> > +                        interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
> > +                                     <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
> > +                                     <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
> > +                                     <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
> > +                        #dma-cells = <1>;
> > +                        dma-channels = <12>;
> > +                        dma-requests = <46>;
> > +                        clocks = <&clock CLK_DMAC>;
> > +                };
> > +
> > +Client:
> > +
> > +DMA clients connected to the Actions Semi Owl SoCs DMA controller must
> > +use the format described in the dma.txt file, using a two-cell specifier
> > +for each channel.
> > +
> > +The two cells in order are:
> > +1. A phandle pointing to the DMA controller.
> > +2. The channel id.
> > +
> > +uart5: serial@e012a000 {
> > +        ...
> > +        dma-names = "tx", "rx";
> > +        dmas = <&dma 26>, <&dma 27>;
> > +        ...
> > +};
> > -- 
> > 2.17.1
> 
> -- 
> ~Vinod
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [v7,4/7] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA controller bindings
From: Li Yang @ 2018-07-25 21:19 UTC (permalink / raw)
  To: Wen He
  Cc: Vinod, dmaengine, Rob Herring,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Jiafei Pan, Jiaheng Fan

On Wed, Jul 25, 2018 at 6:29 AM, Wen He <wen.he_1@nxp.com> wrote:
> Document the devicetree bindings for NXP Layerscape qDMA controller
> which could be found on NXP QorIQ Layerscape SoCs.
>
> Signed-off-by: Wen He <wen.he_1@nxp.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---
>  Documentation/devicetree/bindings/dma/fsl-qdma.txt |   41 ++++++++++++++++++++
>  1 files changed, 41 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/dma/fsl-qdma.txt
>
> diff --git a/Documentation/devicetree/bindings/dma/fsl-qdma.txt b/Documentation/devicetree/bindings/dma/fsl-qdma.txt
> new file mode 100644
> index 0000000..99b3d74
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/fsl-qdma.txt
> @@ -0,0 +1,41 @@
> +NXP Layerscape SoC qDMA Controller
> +==================================
> +
> +This device follows the generic DMA bindings defined in dma/dma.txt.
> +
> +Required properties:
> +
> +- compatible:          Must be one of
> +                        "fsl,ls1021a-qdma": for LS1021A Board
> +                        "fsl,ls1043a-qdma": for ls1043A Board
> +                        "fsl,ls1046a-qdma": for ls1046A Board

Can you align on the case of "ls"?

> +- reg:                 Should contain the register's base address and length.
> +- interrupts:          Should contain a reference to the interrupt used by this
> +                       device.
> +- interrupt-names:     Should contain interrupt names:
> +                        "qdma-error": the error interrupt
> +                        "qdma-queue": the queue interrupt
> +- fsl,queues:          Should contain number of queues supported.

This property name looks very general.  Not sure if making it a little
bit more specific will be better such as "fsl,dma-queues".

> +
> +Optional properties:
> +
> +- dma-channels:                Number of DMA channels supported by the controller.
> +- big-endian:          If present registers and hardware scatter/gather descriptors
> +                       of the qDMA are implemented in big endian mode, otherwise in little
> +                       mode.
> +
> +Examples:
> +
> +       qdma: dma-controller@8390000 {
> +               compatible = "fsl,ls1021a-qdma";
> +               reg = <0x0 0x8398000 0x0 0x2000 /* Controller registers */
> +                      0x0 0x839a000 0x0 0x2000>; /* Block registers */
> +               interrupts = <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>,
> +                               <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
> +               interrupt-names = "qdma-error", "qdma-queue";
> +               dma-channels = <8>;
> +               queues = <2>;

Not updated after the binding is updated.

> +               big-endian;
> +       };
> +
> +DMA clients must use the format described in dma/dma.txt file.
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* dmaengine: add a new helper dmam_async_device_register
From: Huang Shijie @ 2018-07-26  1:21 UTC (permalink / raw)
  To: Vinod; +Cc: corbet, dan.j.williams, robh, linux-doc, dmaengine, linux-kernel

Hi Vinod,


在 2018年07月25日 20:38, Vinod 写道:
> On 25-07-18, 13:46, Huang Shijie wrote:
>> This patch adds the dmam_async_device_register for DMA code.
>> Use the Devres to call the release for the DMA engine driver.
> no users?
I can add some new users if you want.
I will add an extra patch for it.

>
>> Signed-off-by: Huang Shijie <sjhuang@iluvatar.ai>
>> ---
>>   Documentation/driver-model/devres.txt |  1 +
>>   drivers/dma/dmaengine.c               | 35 +++++++++++++++++++++++++++
>>   include/linux/dmaengine.h             |  1 +
>>   3 files changed, 37 insertions(+)
>>
>> diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
>> index a3e8bceb5f19..26c6de621446 100644
>> --- a/Documentation/driver-model/devres.txt
>> +++ b/Documentation/driver-model/devres.txt
>> @@ -240,6 +240,7 @@ CLOCK
>>     devm_of_clk_add_hw_provider()
>>   
>>   DMA
>> +  dmam_async_device_register()
> can we name it dmaengine_async_device_register, not to confuse with dma APIs
ok.
If no one objects the dmaengine_async_device_register().
I will use it in the next version.

Thanks
Huang Shijie
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* dmaengine: add a new helper dmam_async_device_register
From: Vinod Koul @ 2018-07-26  4:10 UTC (permalink / raw)
  To: Huang Shijie
  Cc: corbet, dan.j.williams, robh, linux-doc, dmaengine, linux-kernel

On 26-07-18, 09:21, Huang Shijie wrote:
> > > @@ -240,6 +240,7 @@ CLOCK
> > >     devm_of_clk_add_hw_provider()
> > >   DMA
> > > +  dmam_async_device_register()
> > can we name it dmaengine_async_device_register, not to confuse with dma APIs
> ok.
> If no one objects the dmaengine_async_device_register().
> I will use it in the next version.

Relooking at it, we also need to suggest that it is devm api, so:

dmaenginem_async_device_register() would be better IMO

^ permalink raw reply

* [v7,4/7] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA controller bindings
From: Wen He @ 2018-07-26  4:28 UTC (permalink / raw)
  To: Leo Li
  Cc: Vinod, dmaengine@vger.kernel.org, Rob Herring,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Jiafei Pan, Jiaheng Fan

DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogTGkgWWFuZyBbbWFpbHRv
Omxlb3lhbmcubGlAbnhwLmNvbV0NCj4gU2VudDogMjAxOOW5tDfmnIgyNuaXpSA1OjE5DQo+IFRv
OiBXZW4gSGUgPHdlbi5oZV8xQG54cC5jb20+DQo+IENjOiBWaW5vZCA8dmtvdWxAa2VybmVsLm9y
Zz47IGRtYWVuZ2luZUB2Z2VyLmtlcm5lbC5vcmc7IFJvYiBIZXJyaW5nDQo+IDxyb2JoK2R0QGtl
cm5lbC5vcmc+OyBvcGVuIGxpc3Q6T1BFTiBGSVJNV0FSRSBBTkQgRkxBVFRFTkVEIERFVklDRQ0K
PiBUUkVFIEJJTkRJTkdTIDxkZXZpY2V0cmVlQHZnZXIua2VybmVsLm9yZz47IEppYWZlaSBQYW4N
Cj4gPGppYWZlaS5wYW5AbnhwLmNvbT47IEppYWhlbmcgRmFuIDxqaWFoZW5nLmZhbkBueHAuY29t
Pg0KPiBTdWJqZWN0OiBSZTogW3Y3IDQvN10gZHQtYmluZGluZ3M6IGZzbC1xZG1hOiBBZGQgTlhQ
IExheWVyc2NwYWUgcURNQQ0KPiBjb250cm9sbGVyIGJpbmRpbmdzDQo+IA0KPiBPbiBXZWQsIEp1
bCAyNSwgMjAxOCBhdCA2OjI5IEFNLCBXZW4gSGUgPHdlbi5oZV8xQG54cC5jb20+IHdyb3RlOg0K
PiA+IERvY3VtZW50IHRoZSBkZXZpY2V0cmVlIGJpbmRpbmdzIGZvciBOWFAgTGF5ZXJzY2FwZSBx
RE1BIGNvbnRyb2xsZXINCj4gPiB3aGljaCBjb3VsZCBiZSBmb3VuZCBvbiBOWFAgUW9ySVEgTGF5
ZXJzY2FwZSBTb0NzLg0KPiA+DQo+ID4gU2lnbmVkLW9mZi1ieTogV2VuIEhlIDx3ZW4uaGVfMUBu
eHAuY29tPg0KPiA+IFJldmlld2VkLWJ5OiBSb2IgSGVycmluZyA8cm9iaEBrZXJuZWwub3JnPg0K
PiA+IC0tLQ0KPiA+ICBEb2N1bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvZG1hL2ZzbC1x
ZG1hLnR4dCB8ICAgNDENCj4gKysrKysrKysrKysrKysrKysrKysNCj4gPiAgMSBmaWxlcyBjaGFu
Z2VkLCA0MSBpbnNlcnRpb25zKCspLCAwIGRlbGV0aW9ucygtKSAgY3JlYXRlIG1vZGUgMTAwNjQ0
DQo+ID4gRG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL2RtYS9mc2wtcWRtYS50eHQN
Cj4gPg0KPiA+IGRpZmYgLS1naXQgYS9Eb2N1bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3Mv
ZG1hL2ZzbC1xZG1hLnR4dA0KPiA+IGIvRG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdz
L2RtYS9mc2wtcWRtYS50eHQNCj4gPiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiA+IGluZGV4IDAw
MDAwMDAuLjk5YjNkNzQNCj4gPiAtLS0gL2Rldi9udWxsDQo+ID4gKysrIGIvRG9jdW1lbnRhdGlv
bi9kZXZpY2V0cmVlL2JpbmRpbmdzL2RtYS9mc2wtcWRtYS50eHQNCj4gPiBAQCAtMCwwICsxLDQx
IEBADQo+ID4gK05YUCBMYXllcnNjYXBlIFNvQyBxRE1BIENvbnRyb2xsZXINCj4gPiArPT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KPiA+ICsNCj4gPiArVGhpcyBkZXZpY2UgZm9s
bG93cyB0aGUgZ2VuZXJpYyBETUEgYmluZGluZ3MgZGVmaW5lZCBpbiBkbWEvZG1hLnR4dC4NCj4g
PiArDQo+ID4gK1JlcXVpcmVkIHByb3BlcnRpZXM6DQo+ID4gKw0KPiA+ICstIGNvbXBhdGlibGU6
ICAgICAgICAgIE11c3QgYmUgb25lIG9mDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICJm
c2wsbHMxMDIxYS1xZG1hIjogZm9yIExTMTAyMUEgQm9hcmQNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICAgImZzbCxsczEwNDNhLXFkbWEiOiBmb3IgbHMxMDQzQSBCb2FyZA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAiZnNsLGxzMTA0NmEtcWRtYSI6IGZvciBsczEwNDZBIEJvYXJk
DQo+IA0KPiBDYW4geW91IGFsaWduIG9uIHRoZSBjYXNlIG9mICJscyI/DQo+IA0KDQpPSw0KDQo+
ID4gKy0gcmVnOiAgICAgICAgICAgICAgICAgU2hvdWxkIGNvbnRhaW4gdGhlIHJlZ2lzdGVyJ3Mg
YmFzZSBhZGRyZXNzIGFuZA0KPiBsZW5ndGguDQo+ID4gKy0gaW50ZXJydXB0czogICAgICAgICAg
U2hvdWxkIGNvbnRhaW4gYSByZWZlcmVuY2UgdG8gdGhlIGludGVycnVwdCB1c2VkDQo+IGJ5IHRo
aXMNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBkZXZpY2UuDQo+ID4gKy0gaW50ZXJydXB0
LW5hbWVzOiAgICAgU2hvdWxkIGNvbnRhaW4gaW50ZXJydXB0IG5hbWVzOg0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAicWRtYS1lcnJvciI6IHRoZSBlcnJvciBpbnRlcnJ1cHQNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAgInFkbWEtcXVldWUiOiB0aGUgcXVldWUgaW50ZXJydXB0
DQo+ID4gKy0gZnNsLHF1ZXVlczogICAgICAgICAgU2hvdWxkIGNvbnRhaW4gbnVtYmVyIG9mIHF1
ZXVlcyBzdXBwb3J0ZWQuDQo+IA0KPiBUaGlzIHByb3BlcnR5IG5hbWUgbG9va3MgdmVyeSBnZW5l
cmFsLiAgTm90IHN1cmUgaWYgbWFraW5nIGl0IGEgbGl0dGxlIGJpdCBtb3JlDQo+IHNwZWNpZmlj
IHdpbGwgYmUgYmV0dGVyIHN1Y2ggYXMgImZzbCxkbWEtcXVldWVzIi4NCj4gDQoNCkdvb2QgaWRl
YSwgdGhhbmsgeW91ciBjb21tZW50cy4NCg0KPiA+ICsNCj4gPiArT3B0aW9uYWwgcHJvcGVydGll
czoNCj4gPiArDQo+ID4gKy0gZG1hLWNoYW5uZWxzOiAgICAgICAgICAgICAgICBOdW1iZXIgb2Yg
RE1BIGNoYW5uZWxzIHN1cHBvcnRlZA0KPiBieSB0aGUgY29udHJvbGxlci4NCj4gPiArLSBiaWct
ZW5kaWFuOiAgICAgICAgICBJZiBwcmVzZW50IHJlZ2lzdGVycyBhbmQgaGFyZHdhcmUgc2NhdHRl
ci9nYXRoZXINCj4gZGVzY3JpcHRvcnMNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBvZiB0
aGUgcURNQSBhcmUgaW1wbGVtZW50ZWQgaW4gYmlnIGVuZGlhbg0KPiBtb2RlLCBvdGhlcndpc2Ug
aW4gbGl0dGxlDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbW9kZS4NCj4gPiArDQo+ID4g
K0V4YW1wbGVzOg0KPiA+ICsNCj4gPiArICAgICAgIHFkbWE6IGRtYS1jb250cm9sbGVyQDgzOTAw
MDAgew0KPiA+ICsgICAgICAgICAgICAgICBjb21wYXRpYmxlID0gImZzbCxsczEwMjFhLXFkbWEi
Ow0KPiA+ICsgICAgICAgICAgICAgICByZWcgPSA8MHgwIDB4ODM5ODAwMCAweDAgMHgyMDAwIC8q
IENvbnRyb2xsZXINCj4gcmVnaXN0ZXJzICovDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAw
eDAgMHg4MzlhMDAwIDB4MCAweDIwMDA+OyAvKiBCbG9jayByZWdpc3RlcnMNCj4gKi8NCj4gPiAr
ICAgICAgICAgICAgICAgaW50ZXJydXB0cyA9IDxHSUNfU1BJIDE4NSBJUlFfVFlQRV9MRVZFTF9I
SUdIPiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxHSUNfU1BJIDc2DQo+
IElSUV9UWVBFX0xFVkVMX0hJR0g+Ow0KPiA+ICsgICAgICAgICAgICAgICBpbnRlcnJ1cHQtbmFt
ZXMgPSAicWRtYS1lcnJvciIsICJxZG1hLXF1ZXVlIjsNCj4gPiArICAgICAgICAgICAgICAgZG1h
LWNoYW5uZWxzID0gPDg+Ow0KPiA+ICsgICAgICAgICAgICAgICBxdWV1ZXMgPSA8Mj47DQo+IA0K
PiBOb3QgdXBkYXRlZCBhZnRlciB0aGUgYmluZGluZyBpcyB1cGRhdGVkLg0KPiANCg0KV2hhdCBk
b2VzIG1lYW5zPyBXaGljaCBvbmUgdXBkYXRlZCBhZnRlciB0aGUgYmluZGluZyBpcyB1cGRhdGU/
DQoNCkJlc3QgUmVnYXJkcywNCldlbg0KPiA+ICsgICAgICAgICAgICAgICBiaWctZW5kaWFuOw0K
PiA+ICsgICAgICAgfTsNCj4gPiArDQo+ID4gK0RNQSBjbGllbnRzIG11c3QgdXNlIHRoZSBmb3Jt
YXQgZGVzY3JpYmVkIGluIGRtYS9kbWEudHh0IGZpbGUuDQo+ID4gLS0NCj4gPiAxLjcuMQ0KPiA+
DQo+ID4gLS0NCj4gPiBUbyB1bnN1YnNjcmliZSBmcm9tIHRoaXMgbGlzdDogc2VuZCB0aGUgbGlu
ZSAidW5zdWJzY3JpYmUgZGV2aWNldHJlZSINCj4gPiBpbiB0aGUgYm9keSBvZiBhIG1lc3NhZ2Ug
dG8gbWFqb3Jkb21vQHZnZXIua2VybmVsLm9yZyBNb3JlIG1ham9yZG9tbw0KPiA+IGluZm8gYXQN
Cj4gPg0KPiBodHRwczovL2VtZWEwMS5zYWZlbGlua3MucHJvdGVjdGlvbi5vdXRsb29rLmNvbS8/
dXJsPWh0dHAlM0ElMkYlMkZ2Z2VyDQo+ID4gLmtlcm5lbC5vcmclMkZtYWpvcmRvbW8taW5mby5o
dG1sJmFtcDtkYXRhPTAyJTdDMDElN0N3ZW4uaGVfMSU0DQo+IDBueHAuY28NCj4gPg0KPiBtJTdD
ZjVjOTMxYTkxMGE1NDEwMjY4ZmMwOGQ1ZjI3NDNmYjIlN0M2ODZlYTFkM2JjMmI0YzZmYTkyY2Q5
OWMNCj4gNWMzMDE2Mw0KPiA+DQo+IDUlN0MwJTdDMCU3QzYzNjY4MTUwMzQ1NjkzOTkxOCZhbXA7
c2RhdGE9ekM1NyUyQmM5SmkycmpRWTBLdE5TDQo+IGQ4bWxLZ3BwDQo+ID4gSmcyR3FUZWNsd0Z5
OVhqcyUzRCZhbXA7cmVzZXJ2ZWQ9MA0K
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [v2,3/4] dma: Add Actions Semi Owl family S900 DMA driver
From: Manivannan Sadhasivam @ 2018-07-26  4:52 UTC (permalink / raw)
  To: Vinod
  Cc: dan.j.williams, afaerber, robh+dt, dmaengine, liuwei, 96boards,
	devicetree, daniel.thompson, amit.kucheria, linux-arm-kernel,
	linux-kernel, hzhang, bdong, manivannanece23, thomas.liau,
	jeff.chen, pn, edgar.righi

Hi Vinod,

On Tue, Jul 24, 2018 at 06:39:43PM +0530, Vinod wrote:
> somehow this got stuck so sending again...
> 
> On 24-07-18, 18:16, Vinod wrote:
> > On 23-07-18, 09:47, Manivannan Sadhasivam wrote:
> > 
> > > +#include <linux/bitops.h>
> > > +#include <linux/clk.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/dmaengine.h>
> > > +#include <linux/dma-mapping.h>
> > > +#include <linux/dmapool.h>
> > > +#include <linux/err.h>
> > > +#include <linux/init.h>
> > > +#include <linux/interrupt.h>
> > > +#include <linux/io.h>
> > > +#include <linux/mm.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of_device.h>
> > > +#include <linux/of_dma.h>
> > 
> > do you need this?
> > 

Not now ;-) will remove this.

> > > +/* OWL_DMAX_MODE Bits */
> > > +#define OWL_DMA_MODE_TS(x)			(((x) & 0x3f) << 0)
> > > +#define OWL_DMA_MODE_ST(x)			(((x) & 0x3) << 8)
> > > +#define	OWL_DMA_MODE_ST_DEV			OWL_DMA_MODE_ST(0)
> > > +#define	OWL_DMA_MODE_ST_DCU			OWL_DMA_MODE_ST(2)
> > > +#define	OWL_DMA_MODE_ST_SRAM			OWL_DMA_MODE_ST(3)
> > 
> > what are you trying to do with this? Generally we would define register
> > bits using BIT and GENMASK here..
> > 

Okay. Not sure about BIT() but I can use GENMASK() here.

> > > +/* Extract the bit field to new shift */
> > > +#define BIT_FIELD(val, width, shift, newshift)	\
> > > +		((((val) >> (shift)) & ((BIT(width)) - 1)) << (newshift))
> > 
> > why new shift? I guess you want to extract bits from a register here and
> > use those, right?
> > 

No. Here we are trying to pack two bit fields in a single word. So, the
`shift` is for the first Bit field and the `newshift` is for the second
one. Will modify the comment accordingly!

> > > +struct owl_dma_lli_hw {
> > > +	u32	next_lli;	/* physical address of the next link list */
> > > +	u32	saddr;		/* source physical address */
> > > +	u32	daddr;		/* destination physical address */
> > > +	u32	flen:20;	/* frame length */
> > > +	u32	fcnt:12;	/* frame count */
> > > +	u32	src_stride;	/* source stride */
> > > +	u32	dst_stride;	/* destination stride */
> > > +	u32	ctrla;		/* dma_mode and linklist ctrl */
> > > +	u32	ctrlb;		/* interrupt control */
> > > +	u32	const_num;	/* data for constant fill */
> > 
> > i think you can skip comment here or kernel-doc style, please pick one
> > and not both
> > 

Ack. Will remove the per member comment.

> > > +struct owl_dma_txd {
> > > +	struct virt_dma_desc	vd;
> > > +	struct list_head	lli_list;
> > 
> > why do you need this list. vd has its own list as well!
> > 

Yes, but vd's list is named as node and that will create ambiguity since we
will be using it as a list. So, I guess we would need lli_list.

> > > +static void pchan_update(void __iomem *reg, u32 val, bool state)
> > 
> > why does this not use pchan as arg as the name of API implies (you did
> > that on the other two)
> > 

I wanted to just update the reg without using too many arguments.
Anyway, I can modify it to use pchan as the argument.

> > > +static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan,
> > > +				  struct owl_dma_lli *lli,
> > > +				  dma_addr_t src, dma_addr_t dst,
> > > +				  u32 len, enum dma_transfer_direction dir)
> > > +{
> > > +	struct owl_dma_lli_hw *hw = &lli->hw;
> > > +	u32 mode;
> > > +
> > > +	mode = OWL_DMA_MODE_PW(0);
> > > +
> > > +	switch (dir) {
> > > +	case DMA_MEM_TO_MEM:
> > > +		mode |= OWL_DMA_MODE_TS(0) | OWL_DMA_MODE_ST_DCU |
> > > +			OWL_DMA_MODE_DT_DCU | OWL_DMA_MODE_SAM_INC |
> > > +			OWL_DMA_MODE_DAM_INC;
> > > +
> > > +		break;
> > > +	default:
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	hw->next_lli = 0; /* One link list by default */
> > > +	hw->saddr = src;
> > > +	hw->daddr = dst;
> > > +
> > > +	hw->fcnt = 1; /* Frame count fixed as 1 */
> > > +	hw->flen = len; /* Max frame length is 1MB */
> > 
> > are you checking that somewhere?
> > 

No need to check since we allow only max size in the caller. The
following line does the job:

bytes = min_t(size_t, (len - offset), OWL_DMA_FRAME_MAX_LENGTH);

> > > +static struct owl_dma_pchan *owl_dma_get_pchan(struct owl_dma *od,
> > > +					       struct owl_dma_vchan *vchan)
> > > +{
> > > +	struct owl_dma_pchan *pchan;
> > > +	unsigned long flags;
> > > +	int i;
> > > +
> > > +	for (i = 0; i < od->nr_pchans; i++) {
> > > +		pchan = &od->pchans[i];
> > > +
> > > +		spin_lock_irqsave(&pchan->lock, flags);
> > > +		if (!pchan->vchan) {
> > > +			pchan->vchan = vchan;
> > > +			spin_unlock_irqrestore(&pchan->lock, flags);
> > > +			break;
> > > +		}
> > > +
> > > +		spin_unlock_irqrestore(&pchan->lock, flags);
> > > +	}
> > > +
> > > +	if (i == od->nr_pchans) {
> > > +		/* No physical channel available, cope with it */
> > > +		dev_dbg(od->dma.dev, "no physical channel available\n");
> > 
> > not sure about this. The concept of virt-chan is that you would submit a
> > transaction to controller for different channels. If channel is busy the
> > txn is simply queued up. You do not need a _free_ channel
> > 

Okay. I guess I should remove the error message here. We are bailing out
if all of the channels are busy otherwise we will start the transactions
one by one with the help of ISR.

> > > +static void owl_dma_pause_pchan(struct owl_dma_pchan *pchan)
> > > +{
> > > +	pchan_writel(pchan, 1, OWL_DMAX_PAUSE);
> > > +}
> > > +
> > > +static void owl_dma_resume_pchan(struct owl_dma_pchan *pchan)
> > > +{
> > > +	pchan_writel(pchan, 0, OWL_DMAX_PAUSE);
> > > +}
> > 
> > mempcy and pause/resume dont make much sense, are you sure you want that
> > here and not later on slave copy
> > 

Okay, will remove these for now and add it in slave support.

> > > +static void owl_dma_free_txd(struct owl_dma *od, struct owl_dma_txd *txd)
> > > +{
> > > +	struct owl_dma_lli *lli, *_lli;
> > > +
> > > +	if (unlikely(!txd))
> > > +		return;
> > > +
> > > +	list_for_each_entry_safe(lli, _lli, &txd->lli_list, node) {
> > > +		owl_dma_free_lli(od, lli);
> > > +	}
> > 
> > braces not required here
> > 

Ack.

> > > +static int owl_dma_remove(struct platform_device *pdev)
> > > +{
> > > +	struct owl_dma *od = platform_get_drvdata(pdev);
> > > +
> > > +	of_dma_controller_free(pdev->dev.of_node);

Oops. This is not needed here.

> > > +	dma_async_device_unregister(&od->dma);
> > > +
> > > +	/* Mask all interrupts for this execution environment */
> > > +	dma_writel(od, 0x0, OWL_DMA_IRQ_EN0);
> > > +	owl_dma_free(od);
> > 
> > the tasklets are killed but irqs can still run and trigger the irqs :)

Okay, will add devm_free_irq.

Thanks,
Mani

> > -- 
> > ~Vinod
> 
> -- 
> ~Vinod
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [v3,1/4] dt-bindings: dmaengine: Add binding for Actions Semi Owl SoCs
From: Manivannan Sadhasivam @ 2018-07-26  5:06 UTC (permalink / raw)
  To: vkoul, dan.j.williams, afaerber, robh+dt, dmaengine, liuwei,
	96boards, devicetree, daniel.thompson, amit.kucheria,
	linux-arm-kernel, linux-kernel, hzhang, bdong, manivannanece23,
	thomas.liau, jeff.chen, pn, edgar.righi
  Cc: Manivannan Sadhasivam

Add devicetree binding for Actions Semi Owl SoCs DMA controller.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 .../devicetree/bindings/dma/owl-dma.txt       | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/dma/owl-dma.txt

diff --git a/Documentation/devicetree/bindings/dma/owl-dma.txt b/Documentation/devicetree/bindings/dma/owl-dma.txt
new file mode 100644
index 000000000000..03e9bb12b75f
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/owl-dma.txt
@@ -0,0 +1,47 @@
+* Actions Semi Owl SoCs DMA controller
+
+This binding follows the generic DMA bindings defined in dma.txt.
+
+Required properties:
+- compatible: Should be "actions,s900-dma".
+- reg: Should contain DMA registers location and length.
+- interrupts: Should contain 4 interrupts shared by all channel.
+- #dma-cells: Must be <1>. Used to represent the number of integer
+              cells in the dmas property of client device.
+- dma-channels: Physical channels supported.
+- dma-requests: Number of DMA request signals supported by the controller.
+                Refer to Documentation/devicetree/bindings/dma/dma.txt
+- clocks: Phandle and Specifier of the clock feeding the DMA controller.
+
+Example:
+
+Controller:
+                dma: dma-controller@e0260000 {
+                        compatible = "actions,s900-dma";
+                        reg = <0x0 0xe0260000 0x0 0x1000>;
+                        interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+                        #dma-cells = <1>;
+                        dma-channels = <12>;
+                        dma-requests = <46>;
+                        clocks = <&clock CLK_DMAC>;
+                };
+
+Client:
+
+DMA clients connected to the Actions Semi Owl SoCs DMA controller must
+use the format described in the dma.txt file, using a two-cell specifier
+for each channel.
+
+The two cells in order are:
+1. A phandle pointing to the DMA controller.
+2. The channel id.
+
+uart5: serial@e012a000 {
+        ...
+        dma-names = "tx", "rx";
+        dmas = <&dma 26>, <&dma 27>;
+        ...
+};

^ permalink raw reply related

* [v3,2/4] arm64: dts: actions: Add Actions Semi S900 DMA Controller
From: Manivannan Sadhasivam @ 2018-07-26  5:06 UTC (permalink / raw)
  To: vkoul, dan.j.williams, afaerber, robh+dt, dmaengine, liuwei,
	96boards, devicetree, daniel.thompson, amit.kucheria,
	linux-arm-kernel, linux-kernel, hzhang, bdong, manivannanece23,
	thomas.liau, jeff.chen, pn, edgar.righi
  Cc: Manivannan Sadhasivam

Add DMA controller node for Actions Semi S900 SoC.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 arch/arm64/boot/dts/actions/s900.dtsi | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm64/boot/dts/actions/s900.dtsi b/arch/arm64/boot/dts/actions/s900.dtsi
index 7ae8b931f000..2e8178e50832 100644
--- a/arch/arm64/boot/dts/actions/s900.dtsi
+++ b/arch/arm64/boot/dts/actions/s900.dtsi
@@ -191,6 +191,19 @@
 				     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
+		dma: dma-controller@e0260000 {
+			compatible = "actions,s900-dma";
+			reg = <0x0 0xe0260000 0x0 0x1000>;
+			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+			#dma-cells = <1>;
+			dma-channels = <12>;
+			dma-requests = <46>;
+			clocks = <&cmu CLK_DMAC>;
+		};
+
 		timer: timer@e0228000 {
 			compatible = "actions,s900-timer";
 			reg = <0x0 0xe0228000 0x0 0x8000>;

^ permalink raw reply related

* [v3,3/4] dmaengine: Add Actions Semi Owl family S900 DMA driver
From: Manivannan Sadhasivam @ 2018-07-26  5:06 UTC (permalink / raw)
  To: vkoul, dan.j.williams, afaerber, robh+dt, dmaengine, liuwei,
	96boards, devicetree, daniel.thompson, amit.kucheria,
	linux-arm-kernel, linux-kernel, hzhang, bdong, manivannanece23,
	thomas.liau, jeff.chen, pn, edgar.righi
  Cc: Manivannan Sadhasivam

Add Actions Semi Owl family S900 DMA driver.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 drivers/dma/Kconfig   |   8 +
 drivers/dma/Makefile  |   1 +
 drivers/dma/owl-dma.c | 971 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 980 insertions(+)
 create mode 100644 drivers/dma/owl-dma.c

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index ca1680afa20a..92a278e6618c 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -413,6 +413,14 @@ config NBPFAXI_DMA
 	help
 	  Support for "Type-AXI" NBPF DMA IPs from Renesas
 
+config OWL_DMA
+	tristate "Actions Semi Owl SoCs DMA support"
+	depends on ARCH_ACTIONS
+	select DMA_ENGINE
+	select DMA_VIRTUAL_CHANNELS
+	help
+	  Enable support for the Actions Semi Owl SoCs DMA controller.
+
 config PCH_DMA
 	tristate "Intel EG20T PCH / LAPIS Semicon IOH(ML7213/ML7223/ML7831) DMA"
 	depends on PCI && (X86_32 || COMPILE_TEST)
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 203a99d68315..c91702d88b95 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_MV_XOR_V2) += mv_xor_v2.o
 obj-$(CONFIG_MXS_DMA) += mxs-dma.o
 obj-$(CONFIG_MX3_IPU) += ipu/
 obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o
+obj-$(CONFIG_OWL_DMA) += owl-dma.o
 obj-$(CONFIG_PCH_DMA) += pch_dma.o
 obj-$(CONFIG_PL330_DMA) += pl330.o
 obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
diff --git a/drivers/dma/owl-dma.c b/drivers/dma/owl-dma.c
new file mode 100644
index 000000000000..7812a6338acd
--- /dev/null
+++ b/drivers/dma/owl-dma.c
@@ -0,0 +1,971 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Actions Semi Owl SoCs DMA driver
+//
+// Copyright (c) 2014 Actions Semi Inc.
+// Author: David Liu <liuwei@actions-semi.com>
+//
+// Copyright (c) 2018 Linaro Ltd.
+// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include "virt-dma.h"
+
+#define OWL_DMA_FRAME_MAX_LENGTH		0xfffff
+
+/* Global DMA Controller Registers */
+#define OWL_DMA_IRQ_PD0				0x00
+#define OWL_DMA_IRQ_PD1				0x04
+#define OWL_DMA_IRQ_PD2				0x08
+#define OWL_DMA_IRQ_PD3				0x0C
+#define OWL_DMA_IRQ_EN0				0x10
+#define OWL_DMA_IRQ_EN1				0x14
+#define OWL_DMA_IRQ_EN2				0x18
+#define OWL_DMA_IRQ_EN3				0x1C
+#define OWL_DMA_SECURE_ACCESS_CTL		0x20
+#define OWL_DMA_NIC_QOS				0x24
+#define OWL_DMA_DBGSEL				0x28
+#define OWL_DMA_IDLE_STAT			0x2C
+
+/* Channel Registers */
+#define OWL_DMA_CHAN_BASE(i)			(0x100 + (i) * 0x100)
+#define OWL_DMAX_MODE				0x00
+#define OWL_DMAX_SOURCE				0x04
+#define OWL_DMAX_DESTINATION			0x08
+#define OWL_DMAX_FRAME_LEN			0x0C
+#define OWL_DMAX_FRAME_CNT			0x10
+#define OWL_DMAX_REMAIN_FRAME_CNT		0x14
+#define OWL_DMAX_REMAIN_CNT			0x18
+#define OWL_DMAX_SOURCE_STRIDE			0x1C
+#define OWL_DMAX_DESTINATION_STRIDE		0x20
+#define OWL_DMAX_START				0x24
+#define OWL_DMAX_PAUSE				0x28
+#define OWL_DMAX_CHAINED_CTL			0x2C
+#define OWL_DMAX_CONSTANT			0x30
+#define OWL_DMAX_LINKLIST_CTL			0x34
+#define OWL_DMAX_NEXT_DESCRIPTOR		0x38
+#define OWL_DMAX_CURRENT_DESCRIPTOR_NUM		0x3C
+#define OWL_DMAX_INT_CTL			0x40
+#define OWL_DMAX_INT_STATUS			0x44
+#define OWL_DMAX_CURRENT_SOURCE_POINTER		0x48
+#define OWL_DMAX_CURRENT_DESTINATION_POINTER	0x4C
+
+/* OWL_DMAX_MODE Bits */
+#define OWL_DMA_MODE_TS(x)			(((x) & GENMASK(5, 0)) << 0)
+#define OWL_DMA_MODE_ST(x)			(((x) & GENMASK(1, 0)) << 8)
+#define	OWL_DMA_MODE_ST_DEV			OWL_DMA_MODE_ST(0)
+#define	OWL_DMA_MODE_ST_DCU			OWL_DMA_MODE_ST(2)
+#define	OWL_DMA_MODE_ST_SRAM			OWL_DMA_MODE_ST(3)
+#define OWL_DMA_MODE_DT(x)			(((x) & GENMASK(1, 0)) << 10)
+#define	OWL_DMA_MODE_DT_DEV			OWL_DMA_MODE_DT(0)
+#define	OWL_DMA_MODE_DT_DCU			OWL_DMA_MODE_DT(2)
+#define	OWL_DMA_MODE_DT_SRAM			OWL_DMA_MODE_DT(3)
+#define OWL_DMA_MODE_SAM(x)			(((x) & GENMASK(1, 0)) << 16)
+#define	OWL_DMA_MODE_SAM_CONST			OWL_DMA_MODE_SAM(0)
+#define	OWL_DMA_MODE_SAM_INC			OWL_DMA_MODE_SAM(1)
+#define	OWL_DMA_MODE_SAM_STRIDE			OWL_DMA_MODE_SAM(2)
+#define OWL_DMA_MODE_DAM(x)			(((x) & GENMASK(1, 0)) << 18)
+#define	OWL_DMA_MODE_DAM_CONST			OWL_DMA_MODE_DAM(0)
+#define	OWL_DMA_MODE_DAM_INC			OWL_DMA_MODE_DAM(1)
+#define	OWL_DMA_MODE_DAM_STRIDE			OWL_DMA_MODE_DAM(2)
+#define OWL_DMA_MODE_PW(x)			(((x) & GENMASK(2, 0)) << 20)
+#define OWL_DMA_MODE_CB				BIT(23)
+#define OWL_DMA_MODE_NDDBW(x)			(((x) & 0x1) << 28)
+#define	OWL_DMA_MODE_NDDBW_32BIT		OWL_DMA_MODE_NDDBW(0)
+#define	OWL_DMA_MODE_NDDBW_8BIT			OWL_DMA_MODE_NDDBW(1)
+#define OWL_DMA_MODE_CFE			BIT(29)
+#define OWL_DMA_MODE_LME			BIT(30)
+#define OWL_DMA_MODE_CME			BIT(31)
+
+/* OWL_DMAX_LINKLIST_CTL Bits */
+#define OWL_DMA_LLC_SAV(x)			(((x) & GENMASK(1, 0)) << 8)
+#define	OWL_DMA_LLC_SAV_INC			OWL_DMA_LLC_SAV(0)
+#define	OWL_DMA_LLC_SAV_LOAD_NEXT		OWL_DMA_LLC_SAV(1)
+#define	OWL_DMA_LLC_SAV_LOAD_PREV		OWL_DMA_LLC_SAV(2)
+#define OWL_DMA_LLC_DAV(x)			(((x) & GENMASK(1, 0)) << 10)
+#define	OWL_DMA_LLC_DAV_INC			OWL_DMA_LLC_DAV(0)
+#define	OWL_DMA_LLC_DAV_LOAD_NEXT		OWL_DMA_LLC_DAV(1)
+#define	OWL_DMA_LLC_DAV_LOAD_PREV		OWL_DMA_LLC_DAV(2)
+#define OWL_DMA_LLC_SUSPEND			BIT(16)
+
+/* OWL_DMAX_INT_CTL Bits */
+#define OWL_DMA_INTCTL_BLOCK			BIT(0)
+#define OWL_DMA_INTCTL_SUPER_BLOCK		BIT(1)
+#define OWL_DMA_INTCTL_FRAME			BIT(2)
+#define OWL_DMA_INTCTL_HALF_FRAME		BIT(3)
+#define OWL_DMA_INTCTL_LAST_FRAME		BIT(4)
+
+/* OWL_DMAX_INT_STATUS Bits */
+#define OWL_DMA_INTSTAT_BLOCK			BIT(0)
+#define OWL_DMA_INTSTAT_SUPER_BLOCK		BIT(1)
+#define OWL_DMA_INTSTAT_FRAME			BIT(2)
+#define OWL_DMA_INTSTAT_HALF_FRAME		BIT(3)
+#define OWL_DMA_INTSTAT_LAST_FRAME		BIT(4)
+
+/* Pack shift and newshift in a single word */
+#define BIT_FIELD(val, width, shift, newshift)	\
+		((((val) >> (shift)) & ((BIT(width)) - 1)) << (newshift))
+
+/**
+ * struct owl_dma_lli_hw - Hardware link list for dma transfer
+ * @next_lli: physical address of the next link list
+ * @saddr: source physical address
+ * @daddr: destination physical address
+ * @flen: frame length
+ * @fcnt: frame count
+ * @src_stride: source stride
+ * @dst_stride: destination stride
+ * @ctrla: dma_mode and linklist ctrl config
+ * @ctrlb: interrupt config
+ * @const_num: data for constant fill
+ */
+struct owl_dma_lli_hw {
+	u32	next_lli;
+	u32	saddr;
+	u32	daddr;
+	u32	flen:20;
+	u32	fcnt:12;
+	u32	src_stride;
+	u32	dst_stride;
+	u32	ctrla;
+	u32	ctrlb;
+	u32	const_num;
+};
+
+/**
+ * struct owl_dma_lli - Link list for dma transfer
+ * @hw: hardware link list
+ * @phys: physical address of hardware link list
+ * @node: node for txd's lli_list
+ */
+struct owl_dma_lli {
+	struct  owl_dma_lli_hw	hw;
+	dma_addr_t		phys;
+	struct list_head	node;
+};
+
+/**
+ * struct owl_dma_txd - Wrapper for struct dma_async_tx_descriptor
+ * @vd: virtual DMA descriptor
+ * @lli_list: link list of lli nodes
+ */
+struct owl_dma_txd {
+	struct virt_dma_desc	vd;
+	struct list_head	lli_list;
+};
+
+/**
+ * struct owl_dma_pchan - Holder for the physical channels
+ * @id: physical index to this channel
+ * @base: virtual memory base for the dma channel
+ * @vchan: the virtual channel currently being served by this physical channel
+ * @lock: a lock to use when altering an instance of this struct
+ */
+struct owl_dma_pchan {
+	u32			id;
+	void __iomem		*base;
+	struct owl_dma_vchan	*vchan;
+	spinlock_t		lock;
+};
+
+/**
+ * struct owl_dma_pchan - Wrapper for DMA ENGINE channel
+ * @vc: wrappped virtual channel
+ * @pchan: the physical channel utilized by this channel
+ * @txd: active transaction on this channel
+ */
+struct owl_dma_vchan {
+	struct virt_dma_chan	vc;
+	struct owl_dma_pchan	*pchan;
+	struct owl_dma_txd	*txd;
+};
+
+/**
+ * struct owl_dma - Holder for the Owl DMA controller
+ * @dma: dma engine for this instance
+ * @base: virtual memory base for the DMA controller
+ * @clk: clock for the DMA controller
+ * @lock: a lock to use when change DMA controller global register
+ * @lli_pool: a pool for the LLI descriptors
+ * @nr_pchans: the number of physical channels
+ * @pchans: array of data for the physical channels
+ * @nr_vchans: the number of physical channels
+ * @vchans: array of data for the physical channels
+ */
+struct owl_dma {
+	struct dma_device	dma;
+	void __iomem		*base;
+	struct clk		*clk;
+	spinlock_t		lock;
+	struct dma_pool		*lli_pool;
+	int			irq;
+
+	unsigned int		nr_pchans;
+	struct owl_dma_pchan	*pchans;
+
+	unsigned int		nr_vchans;
+	struct owl_dma_vchan	*vchans;
+};
+
+static void pchan_update(struct owl_dma_pchan *pchan, u32 reg,
+			 u32 val, bool state)
+{
+	u32 regval;
+
+	regval = readl(pchan->base + reg);
+
+	if (state)
+		regval |= val;
+	else
+		regval &= ~val;
+
+	writel(val, pchan->base + reg);
+}
+
+static void pchan_writel(struct owl_dma_pchan *pchan, u32 reg, u32 data)
+{
+	writel(data, pchan->base + reg);
+}
+
+static u32 pchan_readl(struct owl_dma_pchan *pchan, u32 reg)
+{
+	return readl(pchan->base + reg);
+}
+
+static void dma_update(struct owl_dma *od, u32 reg, u32 val, bool state)
+{
+	u32 regval;
+
+	regval = readl(od->base + reg);
+
+	if (state)
+		regval |= val;
+	else
+		regval &= ~val;
+
+	writel(val, od->base + reg);
+}
+
+static void dma_writel(struct owl_dma *od, u32 reg, u32 data)
+{
+	writel(data, od->base + reg);
+}
+
+static u32 dma_readl(struct owl_dma *od, u32 reg)
+{
+	return readl(od->base + reg);
+}
+
+static inline struct owl_dma *to_owl_dma(struct dma_device *dd)
+{
+	return container_of(dd, struct owl_dma, dma);
+}
+
+static struct device *chan2dev(struct dma_chan *chan)
+{
+	return &chan->dev->device;
+}
+
+static inline struct owl_dma_vchan *to_owl_vchan(struct dma_chan *chan)
+{
+	return container_of(chan, struct owl_dma_vchan, vc.chan);
+}
+
+static inline struct owl_dma_txd *to_owl_txd(struct dma_async_tx_descriptor *tx)
+{
+	return container_of(tx, struct owl_dma_txd, vd.tx);
+}
+
+static inline u32 llc_hw_ctrla(u32 mode, u32 llc_ctl)
+{
+	u32 ctl;
+
+	ctl = BIT_FIELD(mode, 4, 28, 28) |
+	      BIT_FIELD(mode, 8, 16, 20) |
+	      BIT_FIELD(mode, 4, 8, 16) |
+	      BIT_FIELD(mode, 6, 0, 10) |
+	      BIT_FIELD(llc_ctl, 2, 10, 8) |
+	      BIT_FIELD(llc_ctl, 2, 8, 6);
+
+	return ctl;
+}
+
+static inline u32 llc_hw_ctrlb(u32 int_ctl)
+{
+	u32 ctl;
+
+	ctl = BIT_FIELD(int_ctl, 7, 0, 18);
+
+	return ctl;
+}
+
+static void owl_dma_free_lli(struct owl_dma *od,
+			     struct owl_dma_lli *lli)
+{
+	list_del(&lli->node);
+	dma_pool_free(od->lli_pool, lli, lli->phys);
+}
+
+static struct owl_dma_lli *owl_dma_alloc_lli(struct owl_dma *od)
+{
+	struct owl_dma_lli *lli;
+	dma_addr_t phys;
+
+	lli = dma_pool_alloc(od->lli_pool, GFP_NOWAIT, &phys);
+	if (!lli)
+		return NULL;
+
+	INIT_LIST_HEAD(&lli->node);
+	lli->phys = phys;
+
+	return lli;
+}
+
+static struct owl_dma_lli *owl_dma_add_lli(struct owl_dma_txd *txd,
+					   struct owl_dma_lli *prev,
+					   struct owl_dma_lli *next)
+{
+	list_add_tail(&next->node, &txd->lli_list);
+
+	if (prev) {
+		prev->hw.next_lli = next->phys;
+		prev->hw.ctrla |= llc_hw_ctrla(OWL_DMA_MODE_LME, 0);
+	}
+
+	return next;
+}
+
+static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan,
+				  struct owl_dma_lli *lli,
+				  dma_addr_t src, dma_addr_t dst,
+				  u32 len, enum dma_transfer_direction dir)
+{
+	struct owl_dma_lli_hw *hw = &lli->hw;
+	u32 mode;
+
+	mode = OWL_DMA_MODE_PW(0);
+
+	switch (dir) {
+	case DMA_MEM_TO_MEM:
+		mode |= OWL_DMA_MODE_TS(0) | OWL_DMA_MODE_ST_DCU |
+			OWL_DMA_MODE_DT_DCU | OWL_DMA_MODE_SAM_INC |
+			OWL_DMA_MODE_DAM_INC;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	hw->next_lli = 0; /* One link list by default */
+	hw->saddr = src;
+	hw->daddr = dst;
+
+	hw->fcnt = 1; /* Frame count fixed as 1 */
+	hw->flen = len; /* Max frame length is 1MB */
+	hw->src_stride = 0;
+	hw->dst_stride = 0;
+	hw->ctrla = llc_hw_ctrla(mode,
+				 OWL_DMA_LLC_SAV_LOAD_NEXT |
+				 OWL_DMA_LLC_DAV_LOAD_NEXT);
+
+	hw->ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_SUPER_BLOCK);
+
+	return 0;
+}
+
+static struct owl_dma_pchan *owl_dma_get_pchan(struct owl_dma *od,
+					       struct owl_dma_vchan *vchan)
+{
+	struct owl_dma_pchan *pchan = NULL;
+	unsigned long flags;
+	int i;
+
+	for (i = 0; i < od->nr_pchans; i++) {
+		pchan = &od->pchans[i];
+
+		spin_lock_irqsave(&pchan->lock, flags);
+		if (!pchan->vchan) {
+			pchan->vchan = vchan;
+			spin_unlock_irqrestore(&pchan->lock, flags);
+			break;
+		}
+
+		spin_unlock_irqrestore(&pchan->lock, flags);
+	}
+
+	return pchan;
+}
+
+static int owl_dma_pchan_busy(struct owl_dma *od, struct owl_dma_pchan *pchan)
+{
+	unsigned int val;
+
+	val = dma_readl(od, OWL_DMA_IDLE_STAT);
+
+	return !(val & (1 << pchan->id));
+}
+
+static void owl_dma_terminate_pchan(struct owl_dma *od,
+				    struct owl_dma_pchan *pchan)
+{
+	unsigned long flags;
+	u32 irq_pd;
+
+	pchan_writel(pchan, OWL_DMAX_START, 0);
+	pchan_update(pchan, OWL_DMAX_INT_STATUS, 0xff, false);
+
+	spin_lock_irqsave(&od->lock, flags);
+	dma_update(od, OWL_DMA_IRQ_EN0, (1 << pchan->id), false);
+
+	irq_pd = dma_readl(od, OWL_DMA_IRQ_PD0);
+	if (irq_pd & (1 << pchan->id)) {
+		dev_warn(od->dma.dev,
+			 "terminating pchan %d that still has pending irq\n",
+			 pchan->id);
+		dma_writel(od, OWL_DMA_IRQ_PD0, (1 << pchan->id));
+	}
+
+	pchan->vchan = NULL;
+
+	spin_unlock_irqrestore(&od->lock, flags);
+}
+
+static int owl_dma_start_next_txd(struct owl_dma_vchan *vchan)
+{
+	struct owl_dma *od = to_owl_dma(vchan->vc.chan.device);
+	struct virt_dma_desc *vd = vchan_next_desc(&vchan->vc);
+	struct owl_dma_pchan *pchan = vchan->pchan;
+	struct owl_dma_txd *txd = to_owl_txd(&vd->tx);
+	struct owl_dma_lli *lli;
+	unsigned long flags;
+	u32 int_ctl;
+
+	list_del(&vd->node);
+
+	vchan->txd = txd;
+
+	/* Wait for channel inactive */
+	while (owl_dma_pchan_busy(od, pchan))
+		cpu_relax();
+
+	lli = list_first_entry(&txd->lli_list,
+			       struct owl_dma_lli, node);
+
+	int_ctl = OWL_DMA_INTCTL_SUPER_BLOCK;
+
+	pchan_writel(pchan, OWL_DMAX_MODE, OWL_DMA_MODE_LME);
+	pchan_writel(pchan, OWL_DMAX_LINKLIST_CTL,
+		     OWL_DMA_LLC_SAV_LOAD_NEXT | OWL_DMA_LLC_DAV_LOAD_NEXT);
+	pchan_writel(pchan, OWL_DMAX_NEXT_DESCRIPTOR, lli->phys);
+	pchan_writel(pchan, OWL_DMAX_INT_CTL, int_ctl);
+
+	/* Clear IRQ status for this pchan */
+	pchan_update(pchan, OWL_DMAX_INT_STATUS, 0xff, false);
+
+	spin_lock_irqsave(&od->lock, flags);
+
+	dma_update(od, OWL_DMA_IRQ_EN0, (1 << pchan->id), true);
+
+	spin_unlock_irqrestore(&od->lock, flags);
+
+	dev_dbg(chan2dev(&vchan->vc.chan), "starting pchan %d\n", pchan->id);
+
+	/* Start DMA transfer for this pchan */
+	pchan_writel(pchan, OWL_DMAX_START, 0x1);
+
+	return 0;
+}
+
+static void owl_dma_phy_free(struct owl_dma *od, struct owl_dma_vchan *vchan)
+{
+	/* Ensure that the physical channel is stopped */
+	owl_dma_terminate_pchan(od, vchan->pchan);
+
+	vchan->pchan = NULL;
+}
+
+static irqreturn_t owl_dma_interrupt(int irq, void *dev_id)
+{
+	struct owl_dma *od = dev_id;
+	struct owl_dma_vchan *vchan;
+	struct owl_dma_pchan *pchan;
+	unsigned long pending;
+	int i;
+	unsigned int global_irq_pending, chan_irq_pending;
+
+	spin_lock(&od->lock);
+
+	pending = dma_readl(od, OWL_DMA_IRQ_PD0);
+
+	/* Clear IRQ status for each pchan */
+	for_each_set_bit(i, &pending, od->nr_pchans) {
+		pchan = &od->pchans[i];
+		pchan_update(pchan, OWL_DMAX_INT_STATUS, 0xff, false);
+	}
+
+	/* Clear pending IRQ */
+	dma_writel(od, OWL_DMA_IRQ_PD0, pending);
+
+	/* Check missed pending IRQ */
+	for (i = 0; i < od->nr_pchans; i++) {
+		pchan = &od->pchans[i];
+		chan_irq_pending = pchan_readl(pchan, OWL_DMAX_INT_CTL) &
+				   pchan_readl(pchan, OWL_DMAX_INT_STATUS);
+
+		/* Dummy read to ensure OWL_DMA_IRQ_PD0 value is updated */
+		dma_readl(od, OWL_DMA_IRQ_PD0);
+
+		global_irq_pending = dma_readl(od, OWL_DMA_IRQ_PD0);
+
+		if (chan_irq_pending && !(global_irq_pending & BIT(i)))	{
+			dev_dbg(od->dma.dev,
+				"global and channel IRQ pending match err\n");
+
+			/* Clear IRQ status for this pchan */
+			pchan_update(pchan, OWL_DMAX_INT_STATUS,
+				     0xff, false);
+
+			/* Update global IRQ pending */
+			pending |= BIT(i);
+		}
+	}
+
+	spin_unlock(&od->lock);
+
+	for_each_set_bit(i, &pending, od->nr_pchans) {
+		struct owl_dma_txd *txd;
+
+		pchan = &od->pchans[i];
+
+		vchan = pchan->vchan;
+		if (!vchan) {
+			dev_warn(od->dma.dev, "no vchan attached on pchan %d\n",
+				 pchan->id);
+			continue;
+		}
+
+		spin_lock(&vchan->vc.lock);
+
+		txd = vchan->txd;
+		if (txd) {
+			vchan->txd = NULL;
+
+			vchan_cookie_complete(&txd->vd);
+
+			/*
+			 * Start the next descriptor (if any),
+			 * otherwise free this channel.
+			 */
+			if (vchan_next_desc(&vchan->vc))
+				owl_dma_start_next_txd(vchan);
+			else
+				owl_dma_phy_free(od, vchan);
+		}
+
+		spin_unlock(&vchan->vc.lock);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void owl_dma_free_txd(struct owl_dma *od, struct owl_dma_txd *txd)
+{
+	struct owl_dma_lli *lli, *_lli;
+
+	if (unlikely(!txd))
+		return;
+
+	list_for_each_entry_safe(lli, _lli, &txd->lli_list, node)
+		owl_dma_free_lli(od, lli);
+
+	kfree(txd);
+}
+
+static void owl_dma_desc_free(struct virt_dma_desc *vd)
+{
+	struct owl_dma *od = to_owl_dma(vd->tx.chan->device);
+	struct owl_dma_txd *txd = to_owl_txd(&vd->tx);
+
+	owl_dma_free_txd(od, txd);
+}
+
+static int owl_dma_terminate_all(struct dma_chan *chan)
+{
+	struct owl_dma *od = to_owl_dma(chan->device);
+	struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+	unsigned long flags;
+	LIST_HEAD(head);
+
+	spin_lock_irqsave(&vchan->vc.lock, flags);
+
+	if (vchan->pchan)
+		owl_dma_phy_free(od, vchan);
+
+	if (vchan->txd) {
+		owl_dma_desc_free(&vchan->txd->vd);
+		vchan->txd = NULL;
+	}
+
+	vchan_get_all_descriptors(&vchan->vc, &head);
+	vchan_dma_desc_free_list(&vchan->vc, &head);
+
+	spin_unlock_irqrestore(&vchan->vc.lock, flags);
+
+	return 0;
+}
+
+static u32 owl_dma_getbytes_chan(struct owl_dma_vchan *vchan)
+{
+	struct owl_dma_pchan *pchan;
+	struct owl_dma_txd *txd;
+	struct owl_dma_lli *lli;
+	unsigned int next_lli_phy;
+	size_t bytes;
+
+	pchan = vchan->pchan;
+	txd = vchan->txd;
+
+	if (!pchan || !txd)
+		return 0;
+
+	/* Get remain count of current node in link list */
+	bytes = pchan_readl(pchan, OWL_DMAX_REMAIN_CNT);
+
+	/* Loop through the preceding nodes to get total remaining bytes */
+	if (pchan_readl(pchan, OWL_DMAX_MODE) & OWL_DMA_MODE_LME) {
+		next_lli_phy = pchan_readl(pchan, OWL_DMAX_NEXT_DESCRIPTOR);
+		list_for_each_entry(lli, &txd->lli_list, node) {
+			/* Start from the next active node */
+			if (lli->phys == next_lli_phy) {
+				list_for_each_entry(lli, &txd->lli_list, node)
+					bytes += lli->hw.flen;
+				break;
+			}
+		}
+	}
+
+	return bytes;
+}
+
+static enum dma_status owl_dma_tx_status(struct dma_chan *chan,
+					 dma_cookie_t cookie,
+					 struct dma_tx_state *state)
+{
+	struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+	struct owl_dma_lli *lli;
+	struct virt_dma_desc *vd;
+	struct owl_dma_txd *txd;
+	enum dma_status ret;
+	unsigned long flags;
+	size_t bytes = 0;
+
+	ret = dma_cookie_status(chan, cookie, state);
+	if (ret == DMA_COMPLETE || !state)
+		return ret;
+
+	spin_lock_irqsave(&vchan->vc.lock, flags);
+
+	vd = vchan_find_desc(&vchan->vc, cookie);
+	if (vd) {
+		txd = to_owl_txd(&vd->tx);
+		list_for_each_entry(lli, &txd->lli_list, node)
+			bytes += lli->hw.flen;
+	} else {
+		bytes = owl_dma_getbytes_chan(vchan);
+	}
+
+	spin_unlock_irqrestore(&vchan->vc.lock, flags);
+
+	dma_set_residue(state, bytes);
+
+	return ret;
+}
+
+static void owl_dma_phy_alloc_and_start(struct owl_dma_vchan *vchan)
+{
+	struct owl_dma *od = to_owl_dma(vchan->vc.chan.device);
+	struct owl_dma_pchan *pchan;
+
+	pchan = owl_dma_get_pchan(od, vchan);
+	if (!pchan)
+		return;
+
+	dev_dbg(od->dma.dev, "allocated pchan %d\n", pchan->id);
+
+	vchan->pchan = pchan;
+	owl_dma_start_next_txd(vchan);
+}
+
+static void owl_dma_issue_pending(struct dma_chan *chan)
+{
+	struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+	unsigned long flags;
+
+	spin_lock_irqsave(&vchan->vc.lock, flags);
+	if (vchan_issue_pending(&vchan->vc)) {
+		if (!vchan->pchan)
+			owl_dma_phy_alloc_and_start(vchan);
+	}
+	spin_unlock_irqrestore(&vchan->vc.lock, flags);
+}
+
+static struct dma_async_tx_descriptor
+		*owl_dma_prep_memcpy(struct dma_chan *chan,
+				     dma_addr_t dst, dma_addr_t src,
+				     size_t len, unsigned long flags)
+{
+	struct owl_dma *od = to_owl_dma(chan->device);
+	struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+	struct owl_dma_txd *txd;
+	struct owl_dma_lli *lli, *prev = NULL;
+	size_t offset, bytes;
+	int ret;
+
+	if (!len)
+		return NULL;
+
+	txd = kzalloc(sizeof(*txd), GFP_NOWAIT);
+	if (!txd)
+		return NULL;
+
+	INIT_LIST_HEAD(&txd->lli_list);
+
+	/* Process the transfer as frame by frame */
+	for (offset = 0; offset < len; offset += bytes) {
+		lli = owl_dma_alloc_lli(od);
+		if (!lli) {
+			dev_warn(chan2dev(chan), "failed to allocate lli\n");
+			goto err_txd_free;
+		}
+
+		bytes = min_t(size_t, (len - offset), OWL_DMA_FRAME_MAX_LENGTH);
+
+		ret = owl_dma_cfg_lli(vchan, lli, src + offset, dst + offset,
+				      bytes, DMA_MEM_TO_MEM);
+		if (ret) {
+			dev_warn(chan2dev(chan), "failed to config lli\n");
+			goto err_txd_free;
+		}
+
+		prev = owl_dma_add_lli(txd, prev, lli);
+	}
+
+	return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
+
+err_txd_free:
+	owl_dma_free_txd(od, txd);
+	return NULL;
+}
+
+static void owl_dma_free_chan_resources(struct dma_chan *chan)
+{
+	struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+
+	/* Ensure all queued descriptors are freed */
+	vchan_free_chan_resources(&vchan->vc);
+}
+
+static inline void owl_dma_free(struct owl_dma *od)
+{
+	struct owl_dma_vchan *vchan = NULL;
+	struct owl_dma_vchan *next;
+
+	list_for_each_entry_safe(vchan,
+				 next, &od->dma.channels, vc.chan.device_node) {
+		list_del(&vchan->vc.chan.device_node);
+		tasklet_kill(&vchan->vc.task);
+	}
+}
+
+static int owl_dma_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct owl_dma *od;
+	struct resource *res;
+	int ret, i, nr_channels, nr_requests;
+
+	od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL);
+	if (!od)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	od->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(od->base))
+		return PTR_ERR(od->base);
+
+	ret = of_property_read_u32(np, "dma-channels", &nr_channels);
+	if (ret) {
+		dev_err(&pdev->dev, "can't get dma-channels\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "dma-requests", &nr_requests);
+	if (ret) {
+		dev_err(&pdev->dev, "can't get dma-requests\n");
+		return ret;
+	}
+
+	dev_info(&pdev->dev, "dma-channels %d, dma-requests %d\n",
+		 nr_channels, nr_requests);
+
+	od->nr_pchans = nr_channels;
+	od->nr_vchans = nr_requests;
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	platform_set_drvdata(pdev, od);
+	spin_lock_init(&od->lock);
+
+	dma_cap_set(DMA_MEMCPY, od->dma.cap_mask);
+
+	od->dma.dev = &pdev->dev;
+	od->dma.device_free_chan_resources = owl_dma_free_chan_resources;
+	od->dma.device_tx_status = owl_dma_tx_status;
+	od->dma.device_issue_pending = owl_dma_issue_pending;
+	od->dma.device_prep_dma_memcpy = owl_dma_prep_memcpy;
+	od->dma.device_terminate_all = owl_dma_terminate_all;
+	od->dma.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+	od->dma.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+	od->dma.directions = BIT(DMA_MEM_TO_MEM);
+	od->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+
+	INIT_LIST_HEAD(&od->dma.channels);
+
+	od->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(od->clk)) {
+		dev_err(&pdev->dev, "unable to get clock\n");
+		return PTR_ERR(od->clk);
+	}
+
+	/*
+	 * Eventhough the DMA controller is capable of generating 4
+	 * IRQ's for DMA priority feature, we only use 1 IRQ for
+	 * simplification.
+	 */
+	od->irq = platform_get_irq(pdev, 0);
+	ret = devm_request_irq(&pdev->dev, od->irq, owl_dma_interrupt, 0,
+			       dev_name(&pdev->dev), od);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to request IRQ\n");
+		return ret;
+	}
+
+	/* Init physical channel */
+	od->pchans = devm_kcalloc(&pdev->dev, od->nr_pchans,
+				  sizeof(struct owl_dma_pchan), GFP_KERNEL);
+	if (!od->pchans)
+		return -ENOMEM;
+
+	for (i = 0; i < od->nr_pchans; i++) {
+		struct owl_dma_pchan *pchan = &od->pchans[i];
+
+		pchan->id = i;
+		pchan->base = od->base + OWL_DMA_CHAN_BASE(i);
+	}
+
+	/* Init virtual channel */
+	od->vchans = devm_kcalloc(&pdev->dev, od->nr_vchans,
+				  sizeof(struct owl_dma_vchan), GFP_KERNEL);
+	if (!od->vchans)
+		return -ENOMEM;
+
+	for (i = 0; i < od->nr_vchans; i++) {
+		struct owl_dma_vchan *vchan = &od->vchans[i];
+
+		vchan->vc.desc_free = owl_dma_desc_free;
+		vchan_init(&vchan->vc, &od->dma);
+	}
+
+	/* Create a pool of consistent memory blocks for hardware descriptors */
+	od->lli_pool = dma_pool_create(dev_name(od->dma.dev), od->dma.dev,
+				       sizeof(struct owl_dma_lli),
+				       __alignof__(struct owl_dma_lli),
+				       0);
+	if (!od->lli_pool) {
+		dev_err(&pdev->dev, "unable to allocate DMA descriptor pool\n");
+		return -ENOMEM;
+	}
+
+	clk_prepare_enable(od->clk);
+
+	ret = dma_async_device_register(&od->dma);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register DMA engine device\n");
+		goto err_pool_free;
+	}
+
+	return 0;
+
+err_pool_free:
+	clk_disable_unprepare(od->clk);
+	dma_pool_destroy(od->lli_pool);
+
+	return ret;
+}
+
+static int owl_dma_remove(struct platform_device *pdev)
+{
+	struct owl_dma *od = platform_get_drvdata(pdev);
+
+	dma_async_device_unregister(&od->dma);
+
+	/* Mask all interrupts for this execution environment */
+	dma_writel(od, OWL_DMA_IRQ_EN0, 0x0);
+
+	/* Make sure we won't have any further interrupts */
+	devm_free_irq(od->dma.dev, od->irq, od);
+
+	owl_dma_free(od);
+
+	clk_disable_unprepare(od->clk);
+
+	return 0;
+}
+
+static const struct of_device_id owl_dma_match[] = {
+	{ .compatible = "actions,s900-dma", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, owl_dma_match);
+
+static struct platform_driver owl_dma_driver = {
+	.probe	= owl_dma_probe,
+	.remove	= owl_dma_remove,
+	.driver = {
+		.name = "dma-owl",
+		.of_match_table = of_match_ptr(owl_dma_match),
+	},
+};
+
+static int owl_dma_init(void)
+{
+	return platform_driver_register(&owl_dma_driver);
+}
+subsys_initcall(owl_dma_init);
+
+static void __exit owl_dma_exit(void)
+{
+	platform_driver_unregister(&owl_dma_driver);
+}
+module_exit(owl_dma_exit);
+
+MODULE_AUTHOR("David Liu <liuwei@actions-semi.com>");
+MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
+MODULE_DESCRIPTION("Actions Semi Owl SoCs DMA driver");
+MODULE_LICENSE("GPL");

^ permalink raw reply related

* [v3,4/4] MAINTAINERS: Add entry for Actions Semi Owl SoCs DMA driver
From: Manivannan Sadhasivam @ 2018-07-26  5:06 UTC (permalink / raw)
  To: vkoul, dan.j.williams, afaerber, robh+dt, dmaengine, liuwei,
	96boards, devicetree, daniel.thompson, amit.kucheria,
	linux-arm-kernel, linux-kernel, hzhang, bdong, manivannanece23,
	thomas.liau, jeff.chen, pn, edgar.righi
  Cc: Manivannan Sadhasivam

Add entry for Actions Semi Owl SoCs DMA driver under ARM/ACTIONS.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 09b54e9ebc6f..56d9c7715c2a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1145,12 +1145,14 @@ F:	arch/arm/boot/dts/owl-*
 F:	arch/arm64/boot/dts/actions/
 F:	drivers/clk/actions/
 F:	drivers/clocksource/owl-*
+F:	drivers/dma/owl-dma.c
 F:	drivers/pinctrl/actions/*
 F:	drivers/soc/actions/
 F:	include/dt-bindings/power/owl-*
 F:	include/linux/soc/actions/
 F:	Documentation/devicetree/bindings/arm/actions.txt
 F:	Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
+F:	Documentation/devicetree/bindings/dma/owl-dma.txt
 F:	Documentation/devicetree/bindings/pinctrl/actions,s900-pinctrl.txt
 F:	Documentation/devicetree/bindings/power/actions,owl-sps.txt
 F:	Documentation/devicetree/bindings/timer/actions,owl-timer.txt

^ permalink raw reply related

* [v2,1/2] dmaengine: add a new helper dmaenginem_async_device_register
From: Huang Shijie @ 2018-07-26  6:45 UTC (permalink / raw)
  To: vkoul
  Cc: corbet, dan.j.williams, robh, linux-doc, dmaengine, linux-kernel,
	ashutosh.dixit, Huang Shijie

This patch adds the dmaenginem_async_device_register for DMA code.
Use the Devres to call the release for the DMA engine driver.

Signed-off-by: Huang Shijie <sjhuang@iluvatar.ai>
---
v1 --> v2:
    change the name to dmaenginem_async_device_register().
---
 Documentation/driver-model/devres.txt |  1 +
 drivers/dma/dmaengine.c               | 35 +++++++++++++++++++++++++++
 include/linux/dmaengine.h             |  1 +
 3 files changed, 37 insertions(+)

diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index a3e8bceb5f19..15720cd17958 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -240,6 +240,7 @@ CLOCK
   devm_of_clk_add_hw_provider()
 
 DMA
+  dmaenginem_async_device_register()
   dmam_alloc_coherent()
   dmam_alloc_attrs()
   dmam_declare_coherent_memory()
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 84ac38dbdb65..fa6fdc5f2a04 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -1135,6 +1135,41 @@ void dma_async_device_unregister(struct dma_device *device)
 }
 EXPORT_SYMBOL(dma_async_device_unregister);
 
+static void dmam_device_release(struct device *dev, void *res)
+{
+	struct dma_device *device;
+
+	device = *(struct dma_device **)res;
+	dma_async_device_unregister(device);
+}
+
+/**
+ * dmaenginem_async_device_register - registers DMA devices found
+ * @device: &dma_device
+ *
+ * The operation is managed and will be undone on driver detach.
+ */
+int dmaenginem_async_device_register(struct dma_device *device)
+{
+	void *p;
+	int ret;
+
+	p = devres_alloc(dmam_device_release, sizeof(void *), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	ret = dma_async_device_register(device);
+	if (!ret) {
+		*(struct dma_device **)p = device;
+		devres_add(device->dev, p);
+	} else {
+		devres_free(p);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(dmaenginem_async_device_register);
+
 struct dmaengine_unmap_pool {
 	struct kmem_cache *cache;
 	const char *name;
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index c8c3a7a93802..d49ec5c31944 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -1406,6 +1406,7 @@ static inline int dmaengine_desc_free(struct dma_async_tx_descriptor *desc)
 /* --- DMA device --- */
 
 int dma_async_device_register(struct dma_device *device);
+int dmaenginem_async_device_register(struct dma_device *device);
 void dma_async_device_unregister(struct dma_device *device);
 void dma_run_dependencies(struct dma_async_tx_descriptor *tx);
 struct dma_chan *dma_get_slave_channel(struct dma_chan *chan);

^ permalink raw reply related

* [v2,2/2] dmaengine: mic_x100_dma: use the new helper to simplify the code
From: Huang Shijie @ 2018-07-26  6:45 UTC (permalink / raw)
  To: vkoul
  Cc: corbet, dan.j.williams, robh, linux-doc, dmaengine, linux-kernel,
	ashutosh.dixit, Huang Shijie

Use dmaenginem_async_device_register() to simplify the code:
    remove the mic_dma_unregister_dma_device()

Signed-off-by: Huang Shijie <sjhuang@iluvatar.ai>
---
    Just add a user for the new helper.
---
 drivers/dma/mic_x100_dma.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/drivers/dma/mic_x100_dma.c b/drivers/dma/mic_x100_dma.c
index 68dd79783b54..b76cb17d879c 100644
--- a/drivers/dma/mic_x100_dma.c
+++ b/drivers/dma/mic_x100_dma.c
@@ -470,11 +470,6 @@ static void mic_dma_chan_destroy(struct mic_dma_chan *ch)
 	mic_dma_chan_mask_intr(ch);
 }
 
-static void mic_dma_unregister_dma_device(struct mic_dma_device *mic_dma_dev)
-{
-	dma_async_device_unregister(&mic_dma_dev->dma_dev);
-}
-
 static int mic_dma_setup_irq(struct mic_dma_chan *ch)
 {
 	ch->cookie =
@@ -630,7 +625,7 @@ static int mic_dma_register_dma_device(struct mic_dma_device *mic_dma_dev,
 		list_add_tail(&mic_dma_dev->mic_ch[i].api_ch.device_node,
 			      &mic_dma_dev->dma_dev.channels);
 	}
-	return dma_async_device_register(&mic_dma_dev->dma_dev);
+	return dmaenginem_async_device_register(&mic_dma_dev->dma_dev);
 }
 
 /*
@@ -678,7 +673,6 @@ static struct mic_dma_device *mic_dma_dev_reg(struct mbus_device *mbdev,
 
 static void mic_dma_dev_unreg(struct mic_dma_device *mic_dma_dev)
 {
-	mic_dma_unregister_dma_device(mic_dma_dev);
 	mic_dma_uninit(mic_dma_dev);
 	kfree(mic_dma_dev);
 }

^ permalink raw reply related

* [v7,4/7] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA controller bindings
From: Li Yang @ 2018-07-26  7:06 UTC (permalink / raw)
  To: Wen He
  Cc: Leo Li, Vinod, dmaengine@vger.kernel.org, Rob Herring,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Jiafei Pan, Jiaheng Fan

Sent from my iPhone
> On Jul 25, 2018, at 11:28 PM, Wen He <wen.he_1@nxp.com> wrote:
> 
> 
> 
>> -----Original Message-----
>> From: Li Yang [mailto:leoyang.li@nxp.com]
>> Sent: 2018年7月26日 5:19
>> To: Wen He <wen.he_1@nxp.com>
>> Cc: Vinod <vkoul@kernel.org>; dmaengine@vger.kernel.org; Rob Herring
>> <robh+dt@kernel.org>; open list:OPEN FIRMWARE AND FLATTENED DEVICE
>> TREE BINDINGS <devicetree@vger.kernel.org>; Jiafei Pan
>> <jiafei.pan@nxp.com>; Jiaheng Fan <jiaheng.fan@nxp.com>
>> Subject: Re: [v7 4/7] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA
>> controller bindings
>> 
>>> On Wed, Jul 25, 2018 at 6:29 AM, Wen He <wen.he_1@nxp.com> wrote:
>>> Document the devicetree bindings for NXP Layerscape qDMA controller
>>> which could be found on NXP QorIQ Layerscape SoCs.
>>> 
>>> Signed-off-by: Wen He <wen.he_1@nxp.com>
>>> Reviewed-by: Rob Herring <robh@kernel.org>
>>> ---
>>> Documentation/devicetree/bindings/dma/fsl-qdma.txt |   41
>> ++++++++++++++++++++
>>> 1 files changed, 41 insertions(+), 0 deletions(-)  create mode 100644
>>> Documentation/devicetree/bindings/dma/fsl-qdma.txt
>>> 
>>> diff --git a/Documentation/devicetree/bindings/dma/fsl-qdma.txt
>>> b/Documentation/devicetree/bindings/dma/fsl-qdma.txt
>>> new file mode 100644
>>> index 0000000..99b3d74
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/dma/fsl-qdma.txt
>>> @@ -0,0 +1,41 @@
>>> +NXP Layerscape SoC qDMA Controller
>>> +==================================
>>> +
>>> +This device follows the generic DMA bindings defined in dma/dma.txt.
>>> +
>>> +Required properties:
>>> +
>>> +- compatible:          Must be one of
>>> +                        "fsl,ls1021a-qdma": for LS1021A Board
>>> +                        "fsl,ls1043a-qdma": for ls1043A Board
>>> +                        "fsl,ls1046a-qdma": for ls1046A Board
>> 
>> Can you align on the case of "ls"?
>> 
> 
> OK
> 
>>> +- reg:                 Should contain the register's base address and
>> length.
>>> +- interrupts:          Should contain a reference to the interrupt used
>> by this
>>> +                       device.
>>> +- interrupt-names:     Should contain interrupt names:
>>> +                        "qdma-error": the error interrupt
>>> +                        "qdma-queue": the queue interrupt
>>> +- fsl,queues:          Should contain number of queues supported.
>> 
>> This property name looks very general.  Not sure if making it a little bit more
>> specific will be better such as "fsl,dma-queues".
>> 
> 
> Good idea, thank your comments.
> 
>>> +
>>> +Optional properties:
>>> +
>>> +- dma-channels:                Number of DMA channels supported
>> by the controller.
>>> +- big-endian:          If present registers and hardware scatter/gather
>> descriptors
>>> +                       of the qDMA are implemented in big endian
>> mode, otherwise in little
>>> +                       mode.
>>> +
>>> +Examples:
>>> +
>>> +       qdma: dma-controller@8390000 {
>>> +               compatible = "fsl,ls1021a-qdma";
>>> +               reg = <0x0 0x8398000 0x0 0x2000 /* Controller
>> registers */
>>> +                      0x0 0x839a000 0x0 0x2000>; /* Block registers
>> */
>>> +               interrupts = <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>,
>>> +                               <GIC_SPI 76
>> IRQ_TYPE_LEVEL_HIGH>;
>>> +               interrupt-names = "qdma-error", "qdma-queue";
>>> +               dma-channels = <8>;
>>> +               queues = <2>;
>> 
>> Not updated after the binding is updated.
>> 
> 
> What does means? Which one updated after the binding is update?

You are still using “queues” in the example...

> 
> Best Regards,
> Wen
>>> +               big-endian;
>>> +       };
>>> +
>>> +DMA clients must use the format described in dma/dma.txt file.
>>> --
>>> 1.7.1
>>> 
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe devicetree"
>>> in the body of a message to majordomo@vger.kernel.org More majordomo
>>> info at
>>> 
>> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvger
>>> .kernel.org%2Fmajordomo-info.html&amp;data=02%7C01%7Cwen.he_1%4
>> 0nxp.co
>>> 
>> m%7Cf5c931a910a5410268fc08d5f2743fb2%7C686ea1d3bc2b4c6fa92cd99c
>> 5c30163
>>> 
>> 5%7C0%7C0%7C636681503456939918&amp;sdata=zC57%2Bc9Ji2rjQY0KtNS
>> d8mlKgpp
>>> Jg2GqTeclwFy9Xjs%3D&amp;reserved=0
> N‹§²æìr¸›yúèšØb²X¬¶Ç§vØ^–)Þº{.nÇ+‰·zøœzÚÞz)í…æèw*\x1fjg¬±¨\x1e¶‰šŽŠÝ¢j/êäz¹Þ–Šà2ŠÞ™¨è­Ú&¢)ß¡«a¶Ú\x7fþø\x1e®G«éh®\x0fæj:+v‰¨Šwè†Ù¥

^ permalink raw reply

* dmaengine: sprd: Support DMA link-list mode
From: Baolin Wang @ 2018-07-26  8:00 UTC (permalink / raw)
  To: dan.j.williams, vkoul
  Cc: eric.long, broonie, baolin.wang, dmaengine, linux-kernel

From: Eric Long <eric.long@spreadtrum.com>

The Spreadtrum DMA can support the link-list transaction mode, which means
DMA controller can do transaction one by one automatically once we linked
these transaction by link-list register.

Signed-off-by: Eric Long <eric.long@spreadtrum.com>
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
 drivers/dma/sprd-dma.c       |   82 ++++++++++++++++++++++++++++++++++++++----
 include/linux/dma/sprd-dma.h |   69 +++++++++++++++++++++++++++++++++++
 2 files changed, 144 insertions(+), 7 deletions(-)

diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c
index 55df0d4..649bd2c 100644
--- a/drivers/dma/sprd-dma.c
+++ b/drivers/dma/sprd-dma.c
@@ -68,6 +68,7 @@
 
 /* SPRD_DMA_CHN_CFG register definition */
 #define SPRD_DMA_CHN_EN			BIT(0)
+#define SPRD_DMA_LINKLIST_EN		BIT(4)
 #define SPRD_DMA_WAIT_BDONE_OFFSET	24
 #define SPRD_DMA_DONOT_WAIT_BDONE	1
 
@@ -103,7 +104,7 @@
 #define SPRD_DMA_REQ_MODE_MASK		GENMASK(1, 0)
 #define SPRD_DMA_FIX_SEL_OFFSET		21
 #define SPRD_DMA_FIX_EN_OFFSET		20
-#define SPRD_DMA_LLIST_END_OFFSET	19
+#define SPRD_DMA_LLIST_END		BIT(19)
 #define SPRD_DMA_FRG_LEN_MASK		GENMASK(16, 0)
 
 /* SPRD_DMA_CHN_BLK_LEN register definition */
@@ -164,6 +165,7 @@ struct sprd_dma_desc {
 struct sprd_dma_chn {
 	struct virt_dma_chan	vc;
 	void __iomem		*chn_base;
+	struct sprd_dma_linklist	linklist;
 	struct dma_slave_config	slave_cfg;
 	u32			chn_num;
 	u32			dev_id;
@@ -582,7 +584,8 @@ static int sprd_dma_get_step(enum dma_slave_buswidth buswidth)
 }
 
 static int sprd_dma_fill_desc(struct dma_chan *chan,
-			      struct sprd_dma_desc *sdesc,
+			      struct sprd_dma_chn_hw *hw,
+			      unsigned int sglen, int sg_index,
 			      dma_addr_t src, dma_addr_t dst, u32 len,
 			      enum dma_transfer_direction dir,
 			      unsigned long flags,
@@ -590,7 +593,6 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
 {
 	struct sprd_dma_dev *sdev = to_sprd_dma_dev(chan);
 	struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
-	struct sprd_dma_chn_hw *hw = &sdesc->chn_hw;
 	u32 req_mode = (flags >> SPRD_DMA_REQ_SHIFT) & SPRD_DMA_REQ_MODE_MASK;
 	u32 int_mode = flags & SPRD_DMA_INT_MASK;
 	int src_datawidth, dst_datawidth, src_step, dst_step;
@@ -670,12 +672,58 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
 	temp |= (src_step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_SRC_TRSF_STEP_OFFSET;
 	hw->trsf_step = temp;
 
+	/* link-list configuration */
+	if (schan->linklist.phy_addr) {
+		if (sg_index == sglen - 1)
+			hw->frg_len |= SPRD_DMA_LLIST_END;
+
+		hw->cfg |= SPRD_DMA_LINKLIST_EN;
+		hw->llist_ptr = schan->linklist.phy_addr +
+			((sg_index + 1) % sglen) * sizeof(*hw) +
+			SPRD_DMA_CHN_SRC_ADDR;
+	} else {
+		hw->llist_ptr = 0;
+	}
+
 	hw->frg_step = 0;
 	hw->src_blk_step = 0;
 	hw->des_blk_step = 0;
 	return 0;
 }
 
+static int sprd_dma_fill_linklist_desc(struct dma_chan *chan,
+				       unsigned int sglen, int sg_index,
+				       dma_addr_t src, dma_addr_t dst, u32 len,
+				       enum dma_transfer_direction dir,
+				       unsigned long flags,
+				       struct dma_slave_config *slave_cfg)
+{
+	struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
+	struct sprd_dma_chn_hw *hw;
+
+	if (sglen < 2 || !schan->linklist.virt_addr)
+		return -EINVAL;
+
+	hw = (struct sprd_dma_chn_hw *)(schan->linklist.virt_addr +
+					sg_index * sizeof(*hw));
+
+	return sprd_dma_fill_desc(chan, hw, sglen, sg_index, src, dst, len, dir,
+				  flags, slave_cfg);
+}
+
+static int sprd_dma_fill_chn_desc(struct dma_chan *chan,
+				  struct sprd_dma_desc *sdesc,
+				  dma_addr_t src, dma_addr_t dst, u32 len,
+				  enum dma_transfer_direction dir,
+				  unsigned long flags,
+				  struct dma_slave_config *slave_cfg)
+{
+	struct sprd_dma_chn_hw *hw = &sdesc->chn_hw;
+
+	return sprd_dma_fill_desc(chan, hw, 0, 0, src, dst, len, dir,
+				  flags, slave_cfg);
+}
+
 static struct dma_async_tx_descriptor *
 sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 			 size_t len, unsigned long flags)
@@ -744,10 +792,20 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
 	u32 len = 0;
 	int ret, i;
 
-	/* TODO: now we only support one sg for each DMA configuration. */
-	if (!is_slave_direction(dir) || sglen > 1)
+	if (!is_slave_direction(dir))
 		return NULL;
 
+	if (context) {
+		struct sprd_dma_linklist *ll_cfg =
+			(struct sprd_dma_linklist *)context;
+
+		schan->linklist.phy_addr = ll_cfg->phy_addr;
+		schan->linklist.virt_addr = ll_cfg->virt_addr;
+	} else {
+		schan->linklist.phy_addr = 0;
+		schan->linklist.virt_addr = 0;
+	}
+
 	sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT);
 	if (!sdesc)
 		return NULL;
@@ -762,10 +820,20 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
 			src = slave_cfg->src_addr;
 			dst = sg_dma_address(sg);
 		}
+
+		if (sglen < 2)
+			break;
+
+		ret = sprd_dma_fill_linklist_desc(chan, sglen, i, src, dst, len,
+						  dir, flags, slave_cfg);
+		if (ret) {
+			kfree(sdesc);
+			return NULL;
+		}
 	}
 
-	ret = sprd_dma_fill_desc(chan, sdesc, src, dst, len, dir, flags,
-				 slave_cfg);
+	ret = sprd_dma_fill_chn_desc(chan, sdesc, src, dst, len, dir, flags,
+				     slave_cfg);
 	if (ret) {
 		kfree(sdesc);
 		return NULL;
diff --git a/include/linux/dma/sprd-dma.h b/include/linux/dma/sprd-dma.h
index b0115e3..c51c705 100644
--- a/include/linux/dma/sprd-dma.h
+++ b/include/linux/dma/sprd-dma.h
@@ -58,4 +58,73 @@ enum sprd_dma_int_type {
 	SPRD_DMA_CFGERR_INT,
 };
 
+/*
+ * struct sprd_dma_linklist - DMA link-list address structure
+ * @virt_addr: link-list virtual address to configure link-list node
+ * @phy_addr: link-list physical address to link DMA transfer
+ *
+ * The Spreadtrum DMA controller supports the link-list mode, that means slaves
+ * can supply several groups configurations (each configuration represents one
+ * DMA transfer) saved in memory, and DMA controller will link these groups
+ * configurations by writing the physical address of each configuration into the
+ * link-list register.
+ *
+ * Just as shown below, the link-list pointer register will be pointed to the
+ * phycial address of 'configuration 1', and the 'configuration 1' link-list
+ * pointer will be pointed to 'configuration 2', and so on.
+ * Once trigger the DMA transfer, the DMA controller will load 'configureation
+ * 1' to its registers automatically, after 'configuration 1' transation is
+ * done, DMA controller will load 'configuration 2' automatically, until all
+ * DMA transactions are done.
+ *
+ * Note: The last link-list pointer should point to the physical address
+ * of 'configuration 1', which can avoid DMA controller loads incorrect
+ * configuration when the last configuration transaction is done.
+ *
+ *     DMA controller                    linklist memory
+ * ======================             -----------------------
+ *|                      |           |    configuration 1    |<---
+ *|   DMA controller     |   ------->|                       |   |
+ *|                      |   |       |                       |   |
+ *|                      |   |       |                       |   |
+ *|                      |   |       |                       |   |
+ *| linklist pointer reg |----   ----|    linklist pointer   |   |
+ * ======================        |    -----------------------    |
+ *                               |                               |
+ *                               |    -----------------------    |
+ *                               |   |    configuration 2    |   |
+ *                               --->|                       |   |
+ *                                   |                       |   |
+ *                                   |                       |   |
+ *                                   |                       |   |
+ *                               ----|    linklist pointer   |   |
+ *                               |    -----------------------    |
+ *                               |                               |
+ *                               |    -----------------------    |
+ *                               |   |    configuration 3    |   |
+ *                               --->|                       |   |
+ *                                   |                       |   |
+ *                                   |           .           |   |
+ *                                               .               |
+ *                                               .               |
+ *                                               .               |
+ *                               |               .               |
+ *                               |    -----------------------    |
+ *                               |   |    configuration n    |   |
+ *                               --->|                       |   |
+ *                                   |                       |   |
+ *                                   |                       |   |
+ *                                   |                       |   |
+ *                                   |    linklist pointer   |----
+ *                                    -----------------------
+ *
+ * To support the link-list mode, DMA slaves should allocate one segment memory
+ * from always-on IRAM or dma coherent memory to store these groups of DMA
+ * configuration, and pass the virtual and physical addess to DMA controller.
+ */
+struct sprd_dma_linklist {
+	unsigned long virt_addr;
+	phys_addr_t phy_addr;
+};
+
 #endif

^ permalink raw reply related

* [v7,4/7] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA controller bindings
From: Wen He @ 2018-07-26 10:40 UTC (permalink / raw)
  To: Leo Li
  Cc: Vinod, dmaengine@vger.kernel.org, Rob Herring,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Jiafei Pan, Jiaheng Fan

> -----Original Message-----
> From: Leo Li
> Sent: 2018年7月26日 15:07
> To: Wen He <wen.he_1@nxp.com>
> Cc: Leo Li <leoyang.li@nxp.com>; Vinod <vkoul@kernel.org>;
> dmaengine@vger.kernel.org; Rob Herring <robh+dt@kernel.org>; open
> list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
> <devicetree@vger.kernel.org>; Jiafei Pan <jiafei.pan@nxp.com>; Jiaheng Fan
> <jiaheng.fan@nxp.com>
> Subject: Re: [v7 4/7] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA
> controller bindings
> 
> 
> 
> 
> 
> Sent from my iPhone
> > On Jul 25, 2018, at 11:28 PM, Wen He <wen.he_1@nxp.com> wrote:
> >
> >
> >
> >> -----Original Message-----
> >> From: Li Yang [mailto:leoyang.li@nxp.com]
> >> Sent: 2018年7月26日 5:19
> >> To: Wen He <wen.he_1@nxp.com>
> >> Cc: Vinod <vkoul@kernel.org>; dmaengine@vger.kernel.org; Rob Herring
> >> <robh+dt@kernel.org>; open list:OPEN FIRMWARE AND FLATTENED
> DEVICE
> >> TREE BINDINGS <devicetree@vger.kernel.org>; Jiafei Pan
> >> <jiafei.pan@nxp.com>; Jiaheng Fan <jiaheng.fan@nxp.com>
> >> Subject: Re: [v7 4/7] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA
> >> controller bindings
> >>
> >>> On Wed, Jul 25, 2018 at 6:29 AM, Wen He <wen.he_1@nxp.com> wrote:
> >>> Document the devicetree bindings for NXP Layerscape qDMA controller
> >>> which could be found on NXP QorIQ Layerscape SoCs.
> >>>
> >>> Signed-off-by: Wen He <wen.he_1@nxp.com>
> >>> Reviewed-by: Rob Herring <robh@kernel.org>
> >>> ---
> >>> Documentation/devicetree/bindings/dma/fsl-qdma.txt |   41
> >> ++++++++++++++++++++
> >>> 1 files changed, 41 insertions(+), 0 deletions(-)  create mode
> >>> 100644 Documentation/devicetree/bindings/dma/fsl-qdma.txt
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/dma/fsl-qdma.txt
> >>> b/Documentation/devicetree/bindings/dma/fsl-qdma.txt
> >>> new file mode 100644
> >>> index 0000000..99b3d74
> >>> --- /dev/null
> >>> +++ b/Documentation/devicetree/bindings/dma/fsl-qdma.txt
> >>> @@ -0,0 +1,41 @@
> >>> +NXP Layerscape SoC qDMA Controller
> >>> +==================================
> >>> +
> >>> +This device follows the generic DMA bindings defined in dma/dma.txt.
> >>> +
> >>> +Required properties:
> >>> +
> >>> +- compatible:          Must be one of
> >>> +                        "fsl,ls1021a-qdma": for LS1021A Board
> >>> +                        "fsl,ls1043a-qdma": for ls1043A Board
> >>> +                        "fsl,ls1046a-qdma": for ls1046A Board
> >>
> >> Can you align on the case of "ls"?
> >>
> >
> > OK
> >
> >>> +- reg:                 Should contain the register's base address
> and
> >> length.
> >>> +- interrupts:          Should contain a reference to the interrupt used
> >> by this
> >>> +                       device.
> >>> +- interrupt-names:     Should contain interrupt names:
> >>> +                        "qdma-error": the error interrupt
> >>> +                        "qdma-queue": the queue interrupt
> >>> +- fsl,queues:          Should contain number of queues supported.
> >>
> >> This property name looks very general.  Not sure if making it a
> >> little bit more specific will be better such as "fsl,dma-queues".
> >>
> >
> > Good idea, thank your comments.
> >
> >>> +
> >>> +Optional properties:
> >>> +
> >>> +- dma-channels:                Number of DMA channels
> supported
> >> by the controller.
> >>> +- big-endian:          If present registers and hardware
> scatter/gather
> >> descriptors
> >>> +                       of the qDMA are implemented in big endian
> >> mode, otherwise in little
> >>> +                       mode.
> >>> +
> >>> +Examples:
> >>> +
> >>> +       qdma: dma-controller@8390000 {
> >>> +               compatible = "fsl,ls1021a-qdma";
> >>> +               reg = <0x0 0x8398000 0x0 0x2000 /* Controller
> >> registers */
> >>> +                      0x0 0x839a000 0x0 0x2000>; /* Block
> registers
> >> */
> >>> +               interrupts = <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>,
> >>> +                               <GIC_SPI 76
> >> IRQ_TYPE_LEVEL_HIGH>;
> >>> +               interrupt-names = "qdma-error", "qdma-queue";
> >>> +               dma-channels = <8>;
> >>> +               queues = <2>;
> >>
> >> Not updated after the binding is updated.
> >>
> >
> > What does means? Which one updated after the binding is update?
> 
> You are still using “queues” in the example...
> 

	OK, Thank you.
Best Regards,
Wen
> >
> > Best Regards,
> > Wen
> >>> +               big-endian;
> >>> +       };
> >>> +
> >>> +DMA clients must use the format described in dma/dma.txt file.
> >>> --
> >>> 1.7.1
> >>>
> >>> --
> >>> To unsubscribe from this list: send the line "unsubscribe devicetree"
> >>> in the body of a message to majordomo@vger.kernel.org More
> majordomo
> >>> info at
> >>>
> >>
> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvge
> >> r
> >>> .kernel.org%2Fmajordomo-info.html&amp;data=02%7C01%7Cwen.he_1
> %4
> >> 0nxp.co
> >>>
> >>
> m%7Cf5c931a910a5410268fc08d5f2743fb2%7C686ea1d3bc2b4c6fa92cd99c
> >> 5c30163
> >>>
> >>
> 5%7C0%7C0%7C636681503456939918&amp;sdata=zC57%2Bc9Ji2rjQY0KtNS
> >> d8mlKgpp
> >>> Jg2GqTeclwFy9Xjs%3D&amp;reserved=0
> > N‹§²æìr¸›yúèšØb²X¬¶Ç§vØ^–)Þº{.nÇ+‰·zøœzÚÞz)í…æèw*
> jg¬±¨\x1e¶‰šŽŠÝ¢j/êäz
> > ¹Þ–Šà2ŠÞ™¨è­Ú&¢)ß¡«a¶Ú\x7fþø\x1e®G«éh®\x0fæj:+v‰¨Šwè†Ù¥

^ permalink raw reply

* dmaengine: rcar-dmac: Make rcar_dmac_of_xlate() more robust
From: Geert Uytterhoeven @ 2018-07-27  8:44 UTC (permalink / raw)
  To: Dan Williams, Vinod Koul
  Cc: Laurent Pinchart, Yoshihiro Shimoda, dmaengine, linux-renesas-soc,
	Geert Uytterhoeven

Add an upper bound check for the MID/RID value passed from DT via the
DMA spec.

This avoids writing to reserved bits in the DMARS registers in case of
an out-of-range value in DT.

Suggested-by: Renesas BSP team via Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/dma/sh/rcar-dmac.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index 72572320208dbb9a..73cf1053bed90244 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -1644,8 +1644,11 @@ static struct dma_chan *rcar_dmac_of_xlate(struct of_phandle_args *dma_spec,
 	struct dma_chan *chan;
 	dma_cap_mask_t mask;
 
-	if (dma_spec->args_count != 1)
+	if (dma_spec->args_count != 1 || dma_spec->args[0] > 0xff) {
+		pr_info("%s: invalid MID/RID 0x%x... for %pOF\n", __func__,
+			dma_spec->args[0], dma_spec->np);
 		return NULL;
+	}
 
 	/* Only slave DMA channels can be allocated via DT */
 	dma_cap_zero(mask);

^ permalink raw reply related

* dmaengine: rcar-dmac: Make rcar_dmac_of_xlate() more robust
From: Laurent Pinchart @ 2018-07-27  8:53 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Dan Williams, Vinod Koul, Yoshihiro Shimoda, dmaengine,
	linux-renesas-soc

Hi Geert,

Thank you for the patch.

On Friday, 27 July 2018 11:44:47 EEST Geert Uytterhoeven wrote:
> Add an upper bound check for the MID/RID value passed from DT via the
> DMA spec.
> 
> This avoids writing to reserved bits in the DMARS registers in case of
> an out-of-range value in DT.

Is this really useful ? In the normal case, when information in DT is correct, 
this will just add overhead. What do we really want to guard against ? If we 
merge this change, how much further do we need to go ? What other values 
provided in DT, such as reg addresses, do we need to validate them too ? 
Functionally speaking this change does no harm, but it increases the kernel 
size, add overhead at runtime, and only addresses a very limited range of 
invalid DT issues.

> Suggested-by: Renesas BSP team via Yoshihiro Shimoda
> <yoshihiro.shimoda.uh@renesas.com> Signed-off-by: Geert Uytterhoeven
> <geert+renesas@glider.be>
> ---
>  drivers/dma/sh/rcar-dmac.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
> index 72572320208dbb9a..73cf1053bed90244 100644
> --- a/drivers/dma/sh/rcar-dmac.c
> +++ b/drivers/dma/sh/rcar-dmac.c
> @@ -1644,8 +1644,11 @@ static struct dma_chan *rcar_dmac_of_xlate(struct
> of_phandle_args *dma_spec, struct dma_chan *chan;
>  	dma_cap_mask_t mask;
> 
> -	if (dma_spec->args_count != 1)
> +	if (dma_spec->args_count != 1 || dma_spec->args[0] > 0xff) {
> +		pr_info("%s: invalid MID/RID 0x%x... for %pOF\n", __func__,
> +			dma_spec->args[0], dma_spec->np);
>  		return NULL;
> +	}
> 
>  	/* Only slave DMA channels can be allocated via DT */
>  	dma_cap_zero(mask);

^ permalink raw reply

* [1/3] dmaengine: xilinx_dma: Refactor axidma channel allocation
From: Radhey Shyam Pandey @ 2018-07-27 10:50 UTC (permalink / raw)
  To: dan.j.williams, vkoul, michal.simek, appana.durga.rao, lars,
	radhey.shyam.pandey
  Cc: dmaengine, linux-arm-kernel, linux-kernel

In axidma alloc_chan_resources merge BD and cyclic BD allocation.

Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---
 drivers/dma/xilinx/xilinx_dma.c |   36 ++++++++++++++++++------------------
 1 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index c124423..06d1632 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -887,6 +887,24 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan)
 				chan->id);
 			return -ENOMEM;
 		}
+		/*
+		 * For cyclic DMA mode we need to program the tail Descriptor
+		 * register with a value which is not a part of the BD chain
+		 * so allocating a desc segment during channel allocation for
+		 * programming tail descriptor.
+		 */
+		chan->cyclic_seg_v = dma_zalloc_coherent(chan->dev,
+					sizeof(*chan->cyclic_seg_v),
+					&chan->cyclic_seg_p, GFP_KERNEL);
+		if (!chan->cyclic_seg_v) {
+			dev_err(chan->dev,
+				"unable to allocate desc segment for cyclic DMA\n");
+			dma_free_coherent(chan->dev, sizeof(*chan->seg_v) *
+				XILINX_DMA_NUM_DESCS, chan->seg_v,
+				chan->seg_p);
+			return -ENOMEM;
+		}
+		chan->cyclic_seg_v->phys = chan->cyclic_seg_p;
 
 		for (i = 0; i < XILINX_DMA_NUM_DESCS; i++) {
 			chan->seg_v[i].hw.next_desc =
@@ -922,24 +940,6 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan)
 		return -ENOMEM;
 	}
 
-	if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
-		/*
-		 * For cyclic DMA mode we need to program the tail Descriptor
-		 * register with a value which is not a part of the BD chain
-		 * so allocating a desc segment during channel allocation for
-		 * programming tail descriptor.
-		 */
-		chan->cyclic_seg_v = dma_zalloc_coherent(chan->dev,
-					sizeof(*chan->cyclic_seg_v),
-					&chan->cyclic_seg_p, GFP_KERNEL);
-		if (!chan->cyclic_seg_v) {
-			dev_err(chan->dev,
-				"unable to allocate desc segment for cyclic DMA\n");
-			return -ENOMEM;
-		}
-		chan->cyclic_seg_v->phys = chan->cyclic_seg_p;
-	}
-
 	dma_cookie_init(dchan);
 
 	if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {

^ permalink raw reply related

* [2/3] dmaengine: xilinx_dma: Refactor axidma channel validation
From: Radhey Shyam Pandey @ 2018-07-27 10:50 UTC (permalink / raw)
  To: dan.j.williams, vkoul, michal.simek, appana.durga.rao, lars,
	radhey.shyam.pandey
  Cc: dmaengine, linux-arm-kernel, linux-kernel

In axidma start_transfer, prefer checking channel states before
other params i.e pending_list.

Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
---
 drivers/dma/xilinx/xilinx_dma.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 06d1632..a37871e 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -1271,10 +1271,10 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
 	if (chan->err)
 		return;
 
-	if (list_empty(&chan->pending_list))
+	if (!chan->idle)
 		return;
 
-	if (!chan->idle)
+	if (list_empty(&chan->pending_list))
 		return;
 
 	head_desc = list_first_entry(&chan->pending_list,

^ permalink raw reply related

* [3/3] dmaengine: xilinx_dma: Fix 64-bit simple CDMA transfer
From: Radhey Shyam Pandey @ 2018-07-27 10:50 UTC (permalink / raw)
  To: dan.j.williams, vkoul, michal.simek, appana.durga.rao, lars,
	radhey.shyam.pandey
  Cc: dmaengine, linux-arm-kernel, linux-kernel

In AXI CDMA simple mode also pass MSB bits of source and destination
address to xilinx_write function. This fixes simple CDMA operation
mode using 64-bit addressing.

Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---
 drivers/dma/xilinx/xilinx_dma.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index a37871e..2e15d86 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -1245,8 +1245,10 @@ static void xilinx_cdma_start_transfer(struct xilinx_dma_chan *chan)
 
 		hw = &segment->hw;
 
-		xilinx_write(chan, XILINX_CDMA_REG_SRCADDR, hw->src_addr);
-		xilinx_write(chan, XILINX_CDMA_REG_DSTADDR, hw->dest_addr);
+		xilinx_write(chan, XILINX_CDMA_REG_SRCADDR, (dma_addr_t)
+			     ((u64)hw->src_addr_msb << 32 | hw->src_addr));
+		xilinx_write(chan, XILINX_CDMA_REG_DSTADDR, (dma_addr_t)
+			     ((u64)hw->dest_addr_msb << 32 | hw->dest_addr));
 
 		/* Start the transfer */
 		dma_ctrl_write(chan, XILINX_DMA_REG_BTT,

^ permalink raw reply related

* [v3,1/3] dmaengine: imx-sdma: add SDMA_BD_MAX_CNT to replace '0xffff'
From: Vinod Koul @ 2018-07-30  5:04 UTC (permalink / raw)
  To: Robin Gong
  Cc: dan.j.williams, s.hauer, linux, linux-arm-kernel, kernel,
	dmaengine, linux-kernel, linux-imx

On 24-07-18, 01:46, Robin Gong wrote:
> Add macro SDMA_BD_MAX_CNT to replace '0xffff'.

Applied, thanks

^ permalink raw reply

* [v3,2/3] dmaengine: imx-sdma: add memcpy interface
From: Vinod Koul @ 2018-07-30  5:04 UTC (permalink / raw)
  To: Robin Gong
  Cc: dan.j.williams, s.hauer, linux, linux-arm-kernel, kernel,
	dmaengine, linux-kernel, linux-imx

On 24-07-18, 01:46, Robin Gong wrote:
> Add MEMCPY capability for imx-sdma driver.

Applied, thanks

^ permalink raw reply

* [v2,1/2] dmaengine: add a new helper dmaenginem_async_device_register
From: Vinod Koul @ 2018-07-30  5:20 UTC (permalink / raw)
  To: Huang Shijie
  Cc: corbet, dan.j.williams, robh, linux-doc, dmaengine, linux-kernel,
	ashutosh.dixit

On 26-07-18, 14:45, Huang Shijie wrote:
> This patch adds the dmaenginem_async_device_register for DMA code.
> Use the Devres to call the release for the DMA engine driver.

Applied both, thanks

^ permalink raw reply

* dmaengine: sh: rcar-dmac: Should not stop the DMAC by rcar_dmac_sync_tcr()
From: Geert Uytterhoeven @ 2018-07-30  9:10 UTC (permalink / raw)
  To: Yoshihiro Shimoda; +Cc: Vinod Koul, dmaengine, Linux-Renesas

On Wed, Jul 25, 2018 at 10:29 AM Yoshihiro Shimoda
<yoshihiro.shimoda.uh@renesas.com> wrote:
> rcar_dmac_chan_get_residue() should not stop the DMAC, because
> the commit 538603c6026c ("dmaengine: sh: rcar-dmac: avoid to write
> CHCR.TE to 1 if TCR is set to 0") had fixed unexpected re-transferring
> issue. But it had caused the next issue which might stop the cyclic
> mode transferring. Thus, for example R-Car sound might be stopped
> suddenly.
>
> According to the commit 73a47bd0da66 ("dmaengine: rcar-dmac: use TCRB
> instead of TCR for residue"), the purpose of clearing CHCR.DE bit is
> flushing buffered data to calculate the exact residue.
>
> Such the "exact" residue had been required by sh-sci driver. sh-sci
> driver is calling dmaengine_pause() to stop transferring, and get
> "exact" residue. Otherwise, it might receive extra data during
> getting residue without pausing.
>
> In rx_timer_fn() of sh-sci driver:
>         dmaengine_tx_status();          /* For checking roughly */
>         dmaengine_pause();
>         dmaengine_tx_status();          /* For getting residue */
>         dmaengine_terminate_all();
>
> But, unfortunately the rcar-dmac driver didn't support dmaengine_pause()
> at that time. So, the sh-sci driver cannot get the "exact" residue
> without stopping the transferring, because rcar-dmac is buffering data
> inside.
>
> Because of these backgrounds, rcar-dmac had been cleared/set CHCR.DE
> bit in rcar_dmac_chan_get_residue() to synchronizing data and getting
> "exact" residue.
>
> However, rcar-dmac driver has rcar_dmac_chan_pause() now, and clearing
> CHCR.DE bit in rcar_dmac_chan_get_residue() doesn't need anymore.
> So, this patch removes the rcar_dmac_sync_tcr().
>
> Fixes: 73a47bd0da66 ("dmaengine: rcar-dmac: use TCRB instead of TCR for residue")
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> Tested-by: Hiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com>

Makes sense, so
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

^ permalink raw reply

* [RFC] dmaengine: Add metadat_ops for dma_async_tx_descriptor
From: Peter Ujfalusi @ 2018-07-30  9:46 UTC (permalink / raw)
  To: Vinod
  Cc: radheys, vinod.koul, lars, michal.simek, linux-kernel, dmaengine,
	dan.j.williams, appanad, linux-arm-kernel

Vinod,

On 2018-07-24 14:14, Vinod wrote:
>>>> Clients must not mix the two way of handling the metadata.
>>>> The set_len() is intended to tell the DMA driver the client provided
>>>> metadata size (in MEM_TO_DEV case mostly).
>>>>
>>>> MEM_TO_DEV flow on client side:
>>>> get_ptr()
>>>> fill in the metadata to the pointer (not exceeding max_len)
>>>> set_len() to tell the DMA driver the amount of valid bytes written
>>>>
>>>> DEV_TO_MEM flow on client side:
>>>> In the completion callback, get_ptr()
>>>> the metadata is payload_len bytes and can be accessed in the return pointer.
>>>
>>> I would think to unify this..
>>
>> I have tried it, but the attach mode and the pointer mode is hard to
>> handle with a generic API.
>> I will try to find a way to unify things in a sane way.
> 
> Hmmm, looking from the description they will be for different methods,
> so lets make them orthogonal and not allow driver to register both.

I would allow DMA drivers to register both, but somehow enforce that
clients are not mixing the two distinct way of dealing with the metadata.

The reason for that is for example the attach mode is the simplest (I
implemented it first and I have a client using it), but if the pointer
mode is found to be more efficient and feasible for the DMA then the DMA
driver can implement that mode and the client can move as well w/o
breaking anything.

> 
>>
>> I have moved the metadata_ops to dma_async_tx_descriptor to emphasize
>> that it is per descriptor setting:
>> https://github.com/omap-audio/linux-audio/commit/02e095d1320a4bb3ae281ddb208ce82ead746f00#diff-92c0a79f414dc3be9dfc67a969c0dd71
>>
>>
>>>> BTW: The driver which is going to need this is now accessible in public:
>>>> https://git.ti.com/ti-linux-kernel/ti-linux-kernel/trees/ti-linux-4.14.y/drivers/dma/ti
>>>>
>>>> or in my wip tree:
>>>> https://github.com/omap-audio/linux-audio/tree/peter/ti-linux-4.14.y/wip/drivers/dma/ti
>>>>
>>>> prefixed with k3-*
>>>>
>>
>> - Péter
>>
>> Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
>> Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
> 

- Péter

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox