Date   

Re: [PATCH 5.10.y-cip 00/22] RZ/G2L: Add support for pinctrl/dmac/iic

Pavel Machek
 

Hi!

This patch series adds Pinctrl/DMAC/IIC support for Renesas RZ/G2L SoC.

All the patches have been cherry picked from v5.16-rc5.

I have created a MR [0] for cip-kernel-config (for testing purpose),
which can later be merged once this patches have been merged.
And these are various minor nits I noticed while reviewing the code.
Thank you for the review. Do you want me to collate the changes and
submit or do you plan to submit them?
I'd preffer you to submit them.

Thank you,
Pavel


--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: [PATCH 5.10.y-cip 00/22] RZ/G2L: Add support for pinctrl/dmac/iic

Lad Prabhakar
 

Hi Pavel,

-----Original Message-----
From: Pavel Machek <pavel@...>
Sent: 22 December 2021 10:06
To: Prabhakar Mahadev Lad <prabhakar.mahadev-lad.rj@...>
Cc: cip-dev@...; Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@...>; Pavel Machek
<pavel@...>; Biju Das <biju.das.jz@...>
Subject: Re: [PATCH 5.10.y-cip 00/22] RZ/G2L: Add support for pinctrl/dmac/iic

Hi!

This patch series adds Pinctrl/DMAC/IIC support for Renesas RZ/G2L SoC.

All the patches have been cherry picked from v5.16-rc5.

I have created a MR [0] for cip-kernel-config (for testing purpose),
which can later be merged once this patches have been merged.
And these are various minor nits I noticed while reviewing the code.
Thank you for the review. Do you want me to collate the changes and submit or do you plan to submit them?

Cheers,
Prabhakar

Best regards,
Pavel

diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml
b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml
index ef68dabcf4dc3..dacf43ed6d040 100644
--- a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.ya
+++ ml
@@ -4,14 +4,14 @@
$id: http://devicetree.org/schemas/pinctrl/renesas,rzg2l-pinctrl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

-title: Renesas RZ/G2L combined Pin and GPIO controller
+title: Renesas RZ/G2L combined pin and GPIO controller

maintainers:
- Geert Uytterhoeven <geert+renesas@...>
- Lad Prabhakar <prabhakar.mahadev-lad.rj@...>

description:
- The Renesas SoCs of the RZ/G2L series feature a combined Pin and GPIO
+ The Renesas SoCs of the RZ/G2L series feature a combined pin and GPIO
controller.
Pin multiplexing and GPIO configuration is performed on a per-pin basis.
Each port features up to 8 pins, each of them configurable for GPIO function diff --git
a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c index ee2872e7d64c6..6946dd0d0485d 100644
--- a/drivers/dma/sh/rz-dmac.c
+++ b/drivers/dma/sh/rz-dmac.c
@@ -25,7 +25,7 @@
#include "../dmaengine.h"
#include "../virt-dma.h"

-enum rz_dmac_prep_type {
+enum rz_dmac_prep_type {
RZ_DMAC_DESC_MEMCPY,
RZ_DMAC_DESC_SLAVE_SG,
};
diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index 20b2af889ca96..08d0bf139ba3a 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -328,7 +328,7 @@ static int rzg2l_dt_subnode_to_map(struct pinctrl_dev *pctldev,
psel_val[i] = MUX_FUNC(value);
}

- /* Register a single pin group listing all the pins we read from DT */
+ /* Register a single pin group, listing all the pins we read from DT
+*/
gsel = pinctrl_generic_add_group(pctldev, np->name, pins, num_pinmux, NULL);
if (gsel < 0) {
ret = gsel;
@@ -612,7 +612,7 @@ static int rzg2l_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev,
if (ret)
return ret;

- /* Check config matching between to pin */
+ /* Check config matching between the pins */
if (i && prev_config != *config)
return -EOPNOTSUPP;

@@ -886,7 +886,7 @@ static const u32 rzg2l_gpio_configs[] = {
RZG2L_GPIO_PORT_PACK(5, 0x40, RZG2L_MPXED_PIN_FUNCS), };

-static struct rzg2l_dedicated_configs rzg2l_dedicated_pins[] = {
+static struct rzg2l_dedicated_configs rzg2l_dedicated_pins[] = {
{ "NMI", RZG2L_SINGLE_PIN_PACK(0x1, 0,
(PIN_CFG_FILONOFF | PIN_CFG_FILNUM | PIN_CFG_FILCLKSEL)) },
{ "TMS/SWDIO", RZG2L_SINGLE_PIN_PACK(0x2, 0, @@ -1109,7 +1109,7 @@ static int
rzg2l_pinctrl_probe(struct platform_device *pdev)
pctrl->clk = devm_clk_get(pctrl->dev, NULL);
if (IS_ERR(pctrl->clk)) {
ret = PTR_ERR(pctrl->clk);
- dev_err(pctrl->dev, "failed to get GPIO clk : %i\n", ret);
+ dev_err(pctrl->dev, "failed to get GPIO clk: %i\n", ret);
return ret;
}

@@ -1127,7 +1127,7 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev)
pctrl->clk);
if (ret) {
dev_err(pctrl->dev,
- "failed to register GPIO clk disable action, %i\n",
+ "failed to register GPIO clk disable action: %i\n",
ret);
return ret;
}
@@ -1171,5 +1171,5 @@ static int __init rzg2l_pinctrl_init(void) core_initcall(rzg2l_pinctrl_init);

MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@...>");
-MODULE_DESCRIPTION("Pin and gpio controller driver for RZ/G2L family");
+MODULE_DESCRIPTION("Pin and GPIO controller driver for RZ/G2L family");
MODULE_LICENSE("GPL v2");


--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: [PATCH 5.10.y-cip 00/22] RZ/G2L: Add support for pinctrl/dmac/iic

Pavel Machek
 

Hi!

This patch series adds Pinctrl/DMAC/IIC support for Renesas RZ/G2L SoC.

All the patches have been cherry picked from v5.16-rc5.

I have created a MR [0] for cip-kernel-config (for testing purpose), which
can later be merged once this patches have been merged.
And these are various minor nits I noticed while reviewing the code.

Best regards,
Pavel

diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml
index ef68dabcf4dc3..dacf43ed6d040 100644
--- a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml
@@ -4,14 +4,14 @@
$id: http://devicetree.org/schemas/pinctrl/renesas,rzg2l-pinctrl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

-title: Renesas RZ/G2L combined Pin and GPIO controller
+title: Renesas RZ/G2L combined pin and GPIO controller

maintainers:
- Geert Uytterhoeven <geert+renesas@...>
- Lad Prabhakar <prabhakar.mahadev-lad.rj@...>

description:
- The Renesas SoCs of the RZ/G2L series feature a combined Pin and GPIO
+ The Renesas SoCs of the RZ/G2L series feature a combined pin and GPIO
controller.
Pin multiplexing and GPIO configuration is performed on a per-pin basis.
Each port features up to 8 pins, each of them configurable for GPIO function
diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c
index ee2872e7d64c6..6946dd0d0485d 100644
--- a/drivers/dma/sh/rz-dmac.c
+++ b/drivers/dma/sh/rz-dmac.c
@@ -25,7 +25,7 @@
#include "../dmaengine.h"
#include "../virt-dma.h"

-enum rz_dmac_prep_type {
+enum rz_dmac_prep_type {
RZ_DMAC_DESC_MEMCPY,
RZ_DMAC_DESC_SLAVE_SG,
};
diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index 20b2af889ca96..08d0bf139ba3a 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -328,7 +328,7 @@ static int rzg2l_dt_subnode_to_map(struct pinctrl_dev *pctldev,
psel_val[i] = MUX_FUNC(value);
}

- /* Register a single pin group listing all the pins we read from DT */
+ /* Register a single pin group, listing all the pins we read from DT */
gsel = pinctrl_generic_add_group(pctldev, np->name, pins, num_pinmux, NULL);
if (gsel < 0) {
ret = gsel;
@@ -612,7 +612,7 @@ static int rzg2l_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev,
if (ret)
return ret;

- /* Check config matching between to pin */
+ /* Check config matching between the pins */
if (i && prev_config != *config)
return -EOPNOTSUPP;

@@ -886,7 +886,7 @@ static const u32 rzg2l_gpio_configs[] = {
RZG2L_GPIO_PORT_PACK(5, 0x40, RZG2L_MPXED_PIN_FUNCS),
};

-static struct rzg2l_dedicated_configs rzg2l_dedicated_pins[] = {
+static struct rzg2l_dedicated_configs rzg2l_dedicated_pins[] = {
{ "NMI", RZG2L_SINGLE_PIN_PACK(0x1, 0,
(PIN_CFG_FILONOFF | PIN_CFG_FILNUM | PIN_CFG_FILCLKSEL)) },
{ "TMS/SWDIO", RZG2L_SINGLE_PIN_PACK(0x2, 0,
@@ -1109,7 +1109,7 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev)
pctrl->clk = devm_clk_get(pctrl->dev, NULL);
if (IS_ERR(pctrl->clk)) {
ret = PTR_ERR(pctrl->clk);
- dev_err(pctrl->dev, "failed to get GPIO clk : %i\n", ret);
+ dev_err(pctrl->dev, "failed to get GPIO clk: %i\n", ret);
return ret;
}

@@ -1127,7 +1127,7 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev)
pctrl->clk);
if (ret) {
dev_err(pctrl->dev,
- "failed to register GPIO clk disable action, %i\n",
+ "failed to register GPIO clk disable action: %i\n",
ret);
return ret;
}
@@ -1171,5 +1171,5 @@ static int __init rzg2l_pinctrl_init(void)
core_initcall(rzg2l_pinctrl_init);

MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@...>");
-MODULE_DESCRIPTION("Pin and gpio controller driver for RZ/G2L family");
+MODULE_DESCRIPTION("Pin and GPIO controller driver for RZ/G2L family");
MODULE_LICENSE("GPL v2");


--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: [PATCH 5.10.y-cip 20/22] dmaengine: sh: make array ds_lut static

Pavel Machek
 

Hi!

commit 4c0eee50658746b0333d35a75d3db6e0aac08ef9 upstream.

Don't populate the read-only array ds_lut on the stack but instead it
static. Also makes the object code smaller by 163 bytes:

Before:
text data bss dec hex filename
23508 4796 0 28304 6e90 ./drivers/dma/sh/rz-dmac.o

After:
text data bss dec hex filename
23281 4860 0 28141 6ded ./drivers/dma/sh/rz-dmac.o
Heh.

@@ -574,7 +574,7 @@ static void rz_dmac_issue_pending(struct dma_chan *chan)
static u8 rz_dmac_ds_to_val_mapping(enum dma_slave_buswidth ds)
{
u8 i;
- const enum dma_slave_buswidth ds_lut[] = {
+ static const enum dma_slave_buswidth ds_lut[] = {
DMA_SLAVE_BUSWIDTH_1_BYTE,
DMA_SLAVE_BUSWIDTH_2_BYTES,
DMA_SLAVE_BUSWIDTH_4_BYTES,
Array could be avoided altogether; you could check for power of two
and then count bits. That would give even shorter code, but I'm not
sure about readability.

I'd also not mind using usual convention here: return int, >= 0
success, < 0 errno.

Best regards,
Pavel
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: [PATCH 5.10.y-cip 04/22] pinctrl: renesas: Add RZ/G2L pin and gpio controller driver

Pavel Machek
 

Hi!

Add support for pin and gpio controller driver for RZ/G2L SoC.

Based on a patch in the BSP by Hien Huynh <hien.huynh.px@...>.
+static int rzg2l_map_add_config(struct pinctrl_map *map,
+ const char *group_or_pin,
+ enum pinctrl_map_type type,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ unsigned long *cfgs;
+
+ cfgs = kmemdup(configs, num_configs * sizeof(*cfgs),
+ GFP_KERNEL);
Should we check for overflows here, too?

Best regards,
Pavel
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: [PATCH 5.10.y-cip 03/22] dt-bindings: pinctrl: renesas: Add DT bindings for RZ/G2L pinctrl

Pavel Machek
 

Hi!

commit 7958f88aa6636f1927513c887a00e83168f12e35 upstream.

Add device tree binding documentation and header file for Renesas
RZ/G2L pinctrl.

+ drive-strength:
+ enum: [ 2, 4, 8, 12 ]
+ power-source:
+ enum: [ 1800, 2500, 3300 ]
These are likely milliamps and millivolts, right? Elsewhere in device
trees microvolts and microamps are used, so that is not too
consistent.

Is the unit mentioned somewhere / should it be?

Best regards,
Pavel
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: [PATCH 5.10.y-cip 00/22] RZ/G2L: Add support for pinctrl/dmac/iic

Pavel Machek
 

On Wed 2021-12-22 01:22:09, nobuhiro1.iwamatsu@... wrote:
Hi all,

Hi!

This patch series adds Pinctrl/DMAC/IIC support for Renesas RZ/G2L SoC.

All the patches have been cherry picked from v5.16-rc5.

I have created a MR [0] for cip-kernel-config (for testing purpose), which
can later be merged once this patches have been merged.
Series looks okay to me. All I could find are
whitespaces/comments/documentation issues.

I'll proceed with testing; I can apply it if it passes and there are
no other comments.
I reviewed this series, there was no issue.
And build test was all green.
https://gitlab.com/cip-project/cip-kernel/linux-cip/-/pipelines/433945722
Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@...>
Thank you, applied.

Best regards,
Pavel
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: [PATCH 5.10.y-cip 00/22] RZ/G2L: Add support for pinctrl/dmac/iic

Nobuhiro Iwamatsu
 

Hi all,

Hi!

This patch series adds Pinctrl/DMAC/IIC support for Renesas RZ/G2L SoC.

All the patches have been cherry picked from v5.16-rc5.

I have created a MR [0] for cip-kernel-config (for testing purpose), which
can later be merged once this patches have been merged.
Series looks okay to me. All I could find are
whitespaces/comments/documentation issues.

I'll proceed with testing; I can apply it if it passes and there are
no other comments.
I reviewed this series, there was no issue.
And build test was all green.
https://gitlab.com/cip-project/cip-kernel/linux-cip/-/pipelines/433945722
Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@...>

Best regards,
Nobuhiro

________________________________________
差出人: Pavel Machek
送信: 2021 12 月 21 日 (火曜日) 18:42
宛先: Lad Prabhakar
Cc: cip-dev@...; iwamatsu nobuhiro(岩松 信洋 □SWC◯ACT); Pavel Machek; Biju Das
件名: Re: [PATCH 5.10.y-cip 00/22] RZ/G2L: Add support for pinctrl/dmac/iic


Hi!

This patch series adds Pinctrl/DMAC/IIC support for Renesas RZ/G2L SoC.

All the patches have been cherry picked from v5.16-rc5.

I have created a MR [0] for cip-kernel-config (for testing purpose), which
can later be merged once this patches have been merged.
Series looks okay to me. All I could find are
whitespaces/comments/documentation issues.

I'll proceed with testing; I can apply it if it passes and there are
no other comments.

Best regards,
                                                                Pavel
--
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: 5.10.85 breaks CIP testing Re: [PATCH 5.10 00/33] 5.10.86-rc1 review

Nobuhiro Iwamatsu
 

Hi,

We should do what our users are likely to do... they want stable
kernel, and will not update toolchain in middle of product
maintainance. [Updating toolchain when starting new product with given
-cip kernel is more likely].

I believe that means we should stick to specific version, but I'm not
sure what version it is. We support Debian distro, likely gcc version
from that distro would be a good option? Perhaps we should ask on TSC
meeting tommorow?
Yes, we recommend using GCC with the rootfs environment.
And weare using the same container at compile time.


5.10 kernel was released in Dec 2020. At that time, gcc 8 and 9 were
maintained, and gcc 10 was new (https://gcc.gnu.org/releases.html).

To get some results for -stable testing, easiest options might be to
disable gcc plugin support in Kconfig.
+1.
Also, I think that this will not be necessary by preparing a build container
that matches the kernel.

Best regards,
Nobuhiro
________________________________________
差出人: cip-dev@... <cip-dev@...> が Pavel Machek <pavel@...> の代理で送信
送信日時: 2021年12月20日 18:58
宛先: Chris Paterson
CC: Pavel Machek; cip-dev@...
件名: Re: [cip-dev] 5.10.85 breaks CIP testing Re: [PATCH 5.10 00/33] 5.10.86-rc1 review

Hi!

I believe we should not change build requirements in the middle of
stable series.

To our testing team: 5.10.85 introduced new requirements for the
build. gmp.h is now required in our configs, and maybe something else.
Hi Pavel, sorry for missing this email before now.
I can look into supporting this, depending on the answers to the comments below...
Thank you.

Easiest fix might be to add

# CONFIG_GCC_PLUGINS is not set

to our configs. Alternatively I know which patch to revert.

But I believe -stable should be the one doing the revert, as the patch
does not fix serious bug and introduces problem. Faster compile is
nice but let mainline have those kind of changes.
But that commit is needed to get gcc11 plugins to work with the 5.10.y
kernel tree. So either we "break" it for old and obsolete gcc versions
(i.e. gcc7), or newer supported versions break.
Well this leads us to an interesting point.
At the moment we use GCC v8.1.0 for building all of our kernel trees (cip & stable).
What does CIP want to do mid/long term? Keep upgrading the version we use? Or try and support a specific version of GCC for 10 years?
If the former, when do we want to upgrade?
If the latter, which version?
We should do what our users are likely to do... they want stable
kernel, and will not update toolchain in middle of product
maintainance. [Updating toolchain when starting new product with given
-cip kernel is more likely].

I believe that means we should stick to specific version, but I'm not
sure what version it is. We support Debian distro, likely gcc version
from that distro would be a good option? Perhaps we should ask on TSC
meeting tommorow?

5.10 kernel was released in Dec 2020. At that time, gcc 8 and 9 were
maintained, and gcc 10 was new (https://gcc.gnu.org/releases.html).

To get some results for -stable testing, easiest options might be to
disable gcc plugin support in Kconfig.

Best regards,
Pavel
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: [PATCH 5.10.y-cip 00/22] RZ/G2L: Add support for pinctrl/dmac/iic

Pavel Machek
 

Hi!

This patch series adds Pinctrl/DMAC/IIC support for Renesas RZ/G2L SoC.

All the patches have been cherry picked from v5.16-rc5.

I have created a MR [0] for cip-kernel-config (for testing purpose), which
can later be merged once this patches have been merged.
Series looks okay to me. All I could find are
whitespaces/comments/documentation issues.

I'll proceed with testing; I can apply it if it passes and there are
no other comments.

Best regards,
Pavel
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: 5.10.85 breaks CIP testing Re: [PATCH 5.10 00/33] 5.10.86-rc1 review

Jan Kiszka
 

On 20.12.21 10:58, Pavel Machek wrote:
Hi!

I believe we should not change build requirements in the middle of
stable series.

To our testing team: 5.10.85 introduced new requirements for the
build. gmp.h is now required in our configs, and maybe something else.
Hi Pavel, sorry for missing this email before now.
I can look into supporting this, depending on the answers to the comments below...
Thank you.

Easiest fix might be to add

# CONFIG_GCC_PLUGINS is not set

to our configs. Alternatively I know which patch to revert.

But I believe -stable should be the one doing the revert, as the patch
does not fix serious bug and introduces problem. Faster compile is
nice but let mainline have those kind of changes.
But that commit is needed to get gcc11 plugins to work with the 5.10.y
kernel tree. So either we "break" it for old and obsolete gcc versions
(i.e. gcc7), or newer supported versions break.
Well this leads us to an interesting point.
At the moment we use GCC v8.1.0 for building all of our kernel trees (cip & stable).
What does CIP want to do mid/long term? Keep upgrading the version we use? Or try and support a specific version of GCC for 10 years?
If the former, when do we want to upgrade?
If the latter, which version?
We should do what our users are likely to do... they want stable
kernel, and will not update toolchain in middle of product
maintainance. [Updating toolchain when starting new product with given
-cip kernel is more likely].

I believe that means we should stick to specific version, but I'm not
sure what version it is. We support Debian distro, likely gcc version
from that distro would be a good option? Perhaps we should ask on TSC
meeting tommorow?

5.10 kernel was released in Dec 2020. At that time, gcc 8 and 9 were
maintained, and gcc 10 was new (https://gcc.gnu.org/releases.html).

To get some results for -stable testing, easiest options might be to
disable gcc plugin support in Kconfig.

Best regards,
Pavel
The natural pairing would be "buster/kernel 4.19/gcc-8" and
"bullseye/kernel 5.10/gcc-10", indeed.

I'm definitely not able to attend the TSC call tomorrow. If you want to
discuss this topic, someone would have to pick up the kernel WG
representation.

Jan


[PATCH 5.10.y-cip 22/22] arm64: defconfig: Enable RZ_DMAC

Lad Prabhakar
 

From: Biju Das <biju.das.jz@...>

commit 7e2aa15f5ec3a8294127673f186c83b4d87cde13 upstream.

Enable DMAC driver support for Renesas RZ/G2L based platforms.

Signed-off-by: Biju Das <biju.das.jz@...>
Link: https://lore.kernel.org/r/20210920093605.8906-1-biju.das.jz@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index e022d807c6d8..2604bcd75baa 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -850,6 +850,7 @@ CONFIG_QCOM_HIDMA_MGMT=y
CONFIG_QCOM_HIDMA=y
CONFIG_RCAR_DMAC=y
CONFIG_RENESAS_USB_DMAC=m
+CONFIG_RZ_DMAC=y
CONFIG_TI_K3_UDMA=y
CONFIG_TI_K3_UDMA_GLUE_LAYER=y
CONFIG_VFIO=y
--
2.17.1


[PATCH 5.10.y-cip 21/22] arm64: dts: renesas: r9a07g044: Add DMAC support

Lad Prabhakar
 

From: Biju Das <biju.das.jz@...>

commit bcd5e5173740087515bf3a05894917d0d8f5779f upstream.

Add DMAC support to RZ/G2L SoC DT.

Signed-off-by: Biju Das <biju.das.jz@...>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Link: https://lore.kernel.org/r/20210719092535.4474-4-biju.das.jz@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
arch/arm64/boot/dts/renesas/r9a07g044.dtsi | 36 ++++++++++++++++++++++
1 file changed, 36 insertions(+)

diff --git a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi
index 6e9643c36229..7c83a8d39351 100644
--- a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi
@@ -212,6 +212,42 @@
<&cpg R9A07G044_GPIO_SPARE_RESETN>;
};

+ dmac: dma-controller@11820000 {
+ compatible = "renesas,r9a07g044-dmac",
+ "renesas,rz-dmac";
+ reg = <0 0x11820000 0 0x10000>,
+ <0 0x11830000 0 0x10000>;
+ interrupts = <GIC_SPI 141 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 125 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 126 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 127 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 128 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 129 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 130 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 131 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 132 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 133 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 134 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 135 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 136 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 137 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 138 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 139 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 140 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3",
+ "ch4", "ch5", "ch6", "ch7",
+ "ch8", "ch9", "ch10", "ch11",
+ "ch12", "ch13", "ch14", "ch15";
+ clocks = <&cpg CPG_MOD R9A07G044_DMAC_ACLK>,
+ <&cpg CPG_MOD R9A07G044_DMAC_PCLK>;
+ power-domains = <&cpg>;
+ resets = <&cpg R9A07G044_DMAC_ARESETN>,
+ <&cpg R9A07G044_DMAC_RST_ASYNC>;
+ #dma-cells = <1>;
+ dma-channels = <16>;
+ };
+
gic: interrupt-controller@11900000 {
compatible = "arm,gic-v3";
#interrupt-cells = <3>;
--
2.17.1


[PATCH 5.10.y-cip 20/22] dmaengine: sh: make array ds_lut static

Lad Prabhakar
 

From: Colin Ian King <colin.king@...>

commit 4c0eee50658746b0333d35a75d3db6e0aac08ef9 upstream.

Don't populate the read-only array ds_lut on the stack but instead it
static. Also makes the object code smaller by 163 bytes:

Before:
text data bss dec hex filename
23508 4796 0 28304 6e90 ./drivers/dma/sh/rz-dmac.o

After:
text data bss dec hex filename
23281 4860 0 28141 6ded ./drivers/dma/sh/rz-dmac.o

(gcc version 11.2.0)

Signed-off-by: Colin Ian King <colin.king@...>
Link: https://lore.kernel.org/r/20210915112038.12407-1-colin.king@canonical.com
Signed-off-by: Vinod Koul <vkoul@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/dma/sh/rz-dmac.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c
index d9f2cfef878e..ee2872e7d64c 100644
--- a/drivers/dma/sh/rz-dmac.c
+++ b/drivers/dma/sh/rz-dmac.c
@@ -574,7 +574,7 @@ static void rz_dmac_issue_pending(struct dma_chan *chan)
static u8 rz_dmac_ds_to_val_mapping(enum dma_slave_buswidth ds)
{
u8 i;
- const enum dma_slave_buswidth ds_lut[] = {
+ static const enum dma_slave_buswidth ds_lut[] = {
DMA_SLAVE_BUSWIDTH_1_BYTE,
DMA_SLAVE_BUSWIDTH_2_BYTES,
DMA_SLAVE_BUSWIDTH_4_BYTES,
--
2.17.1


[PATCH 5.10.y-cip 19/22] dmaengine: sh: rz-dmac: Add DMA clock handling

Lad Prabhakar
 

From: Biju Das <biju.das.jz@...>

commit 161596fd776a54df922158175ed844804a861c37 upstream.

Currently, DMA clocks are turned on by the bootloader.
This patch adds support for DMA clock handling so that
the driver manages the DMA clocks.

Fixes: 5000d37042a6 ("dmaengine: sh: Add DMAC driver for RZ/G2L SoC")
Signed-off-by: Biju Das <biju.das.jz@...>
Reviewed-by: Geert Uytterhoeven <geert+renesas@...>
Link: https://lore.kernel.org/r/20210923102451.11403-1-biju.das.jz@bp.renesas.com
Signed-off-by: Vinod Koul <vkoul@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/dma/sh/rz-dmac.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c
index f9f30cbeccbe..d9f2cfef878e 100644
--- a/drivers/dma/sh/rz-dmac.c
+++ b/drivers/dma/sh/rz-dmac.c
@@ -18,6 +18,7 @@
#include <linux/of_dma.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spinlock.h>

@@ -872,6 +873,13 @@ static int rz_dmac_probe(struct platform_device *pdev)
/* Initialize the channels. */
INIT_LIST_HEAD(&dmac->engine.channels);

+ pm_runtime_enable(&pdev->dev);
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "pm_runtime_resume_and_get failed\n");
+ goto err_pm_disable;
+ }
+
for (i = 0; i < dmac->n_channels; i++) {
ret = rz_dmac_chan_probe(dmac, &dmac->channels[i], i);
if (ret < 0)
@@ -925,6 +933,10 @@ static int rz_dmac_probe(struct platform_device *pdev)
channel->lmdesc.base_dma);
}

+ pm_runtime_put(&pdev->dev);
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+
return ret;
}

@@ -943,6 +955,8 @@ static int rz_dmac_remove(struct platform_device *pdev)
}
of_dma_controller_free(pdev->dev.of_node);
dma_async_device_unregister(&dmac->engine);
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);

return 0;
}
--
2.17.1


[PATCH 5.10.y-cip 18/22] dmaengine: sh: fix some NULL dereferences

Lad Prabhakar
 

From: Dan Carpenter <dan.carpenter@...>

commit 11a427be2c4749954e8b868ef5301dc65ca5a14b upstream.

The dma_free_coherent() function needs a valid device pointer or it will
crash.

Fixes: 550c591a89a1 ("dmaengine: sh: Add DMAC driver for RZ/G2L SoC")
Signed-off-by: Dan Carpenter <dan.carpenter@...>
Link: https://lore.kernel.org/r/20210827085410.GA9183@kili
Signed-off-by: Vinod Koul <vkoul@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/dma/sh/rz-dmac.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c
index 3d1c239de306..f9f30cbeccbe 100644
--- a/drivers/dma/sh/rz-dmac.c
+++ b/drivers/dma/sh/rz-dmac.c
@@ -919,7 +919,7 @@ static int rz_dmac_probe(struct platform_device *pdev)
for (i = 0; i < channel_num; i++) {
struct rz_dmac_chan *channel = &dmac->channels[i];

- dma_free_coherent(NULL,
+ dma_free_coherent(&pdev->dev,
sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC,
channel->lmdesc.base,
channel->lmdesc.base_dma);
@@ -936,7 +936,7 @@ static int rz_dmac_remove(struct platform_device *pdev)
for (i = 0; i < dmac->n_channels; i++) {
struct rz_dmac_chan *channel = &dmac->channels[i];

- dma_free_coherent(NULL,
+ dma_free_coherent(&pdev->dev,
sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC,
channel->lmdesc.base,
channel->lmdesc.base_dma);
--
2.17.1


[PATCH 5.10.y-cip 17/22] dmaengine: sh: Fix unused initialization of pointer lmdesc

Lad Prabhakar
 

From: Colin Ian King <colin.king@...>

commit 1e008336b9f590eb749ac96ccef4ea0301f79619 upstream.

Pointer lmdesc is being inintialized with a value that is never read,
it is later being re-assigned a new value. Fix this by initializing
it with the latter value.

Addresses-Coverity: ("Unused value")
Fixes: 550c591a89a1 ("dmaengine: sh: Add DMAC driver for RZ/G2L SoC")
Signed-off-by: Colin Ian King <colin.king@...>
Link: https://lore.kernel.org/r/20210829152811.529766-1-colin.king@canonical.com
Signed-off-by: Vinod Koul <vkoul@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/dma/sh/rz-dmac.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c
index 11986a8d22fc..3d1c239de306 100644
--- a/drivers/dma/sh/rz-dmac.c
+++ b/drivers/dma/sh/rz-dmac.c
@@ -308,12 +308,10 @@ static void rz_dmac_prepare_desc_for_memcpy(struct rz_dmac_chan *channel)
{
struct dma_chan *chan = &channel->vc.chan;
struct rz_dmac *dmac = to_rz_dmac(chan->device);
- struct rz_lmdesc *lmdesc = channel->lmdesc.base;
+ struct rz_lmdesc *lmdesc = channel->lmdesc.tail;
struct rz_dmac_desc *d = channel->desc;
u32 chcfg = CHCFG_MEM_COPY;

- lmdesc = channel->lmdesc.tail;
-
/* prepare descriptor */
lmdesc->sa = d->src;
lmdesc->da = d->dest;
--
2.17.1


[PATCH 5.10.y-cip 16/22] dmaengine: sh: Add DMAC driver for RZ/G2L SoC

Lad Prabhakar
 

From: Biju Das <biju.das.jz@...>

commit 5000d37042a61ca556fde2782ca40dbfa802ea16 upstream.

Add DMA Controller driver for RZ/G2L SoC.

Based on the work done by Chris Brandt for RZ/A DMA driver.

Signed-off-by: Biju Das <biju.das.jz@...>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Link: https://lore.kernel.org/r/20210806095322.2326-4-biju.das.jz@bp.renesas.com
Signed-off-by: Vinod Koul <vkoul@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/dma/sh/Kconfig | 9 +
drivers/dma/sh/Makefile | 1 +
drivers/dma/sh/rz-dmac.c | 971 +++++++++++++++++++++++++++++++++++++++
3 files changed, 981 insertions(+)
create mode 100644 drivers/dma/sh/rz-dmac.c

diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
index 13437323a85b..a46296285307 100644
--- a/drivers/dma/sh/Kconfig
+++ b/drivers/dma/sh/Kconfig
@@ -47,3 +47,12 @@ config RENESAS_USB_DMAC
help
This driver supports the USB-DMA controller found in the Renesas
SoCs.
+
+config RZ_DMAC
+ tristate "Renesas RZ/G2L DMA Controller"
+ depends on ARCH_R9A07G044 || COMPILE_TEST
+ select RENESAS_DMA
+ select DMA_VIRTUAL_CHANNELS
+ help
+ This driver supports the general purpose DMA controller found in the
+ Renesas RZ/G2L SoC variants.
diff --git a/drivers/dma/sh/Makefile b/drivers/dma/sh/Makefile
index 112fbd22bb3f..9b2927f543bf 100644
--- a/drivers/dma/sh/Makefile
+++ b/drivers/dma/sh/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_SH_DMAE) += shdma.o

obj-$(CONFIG_RCAR_DMAC) += rcar-dmac.o
obj-$(CONFIG_RENESAS_USB_DMAC) += usb-dmac.o
+obj-$(CONFIG_RZ_DMAC) += rz-dmac.o
diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c
new file mode 100644
index 000000000000..11986a8d22fc
--- /dev/null
+++ b/drivers/dma/sh/rz-dmac.c
@@ -0,0 +1,971 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/G2L DMA Controller Driver
+ *
+ * Based on imx-dma.c
+ *
+ * Copyright (C) 2021 Renesas Electronics Corp.
+ * Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@...>
+ * Copyright 2012 Javier Martin, Vista Silicon <javier.martin@...>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "../dmaengine.h"
+#include "../virt-dma.h"
+
+enum rz_dmac_prep_type {
+ RZ_DMAC_DESC_MEMCPY,
+ RZ_DMAC_DESC_SLAVE_SG,
+};
+
+struct rz_lmdesc {
+ u32 header;
+ u32 sa;
+ u32 da;
+ u32 tb;
+ u32 chcfg;
+ u32 chitvl;
+ u32 chext;
+ u32 nxla;
+};
+
+struct rz_dmac_desc {
+ struct virt_dma_desc vd;
+ dma_addr_t src;
+ dma_addr_t dest;
+ size_t len;
+ struct list_head node;
+ enum dma_transfer_direction direction;
+ enum rz_dmac_prep_type type;
+ /* For slave sg */
+ struct scatterlist *sg;
+ unsigned int sgcount;
+};
+
+#define to_rz_dmac_desc(d) container_of(d, struct rz_dmac_desc, vd)
+
+struct rz_dmac_chan {
+ struct virt_dma_chan vc;
+ void __iomem *ch_base;
+ void __iomem *ch_cmn_base;
+ unsigned int index;
+ int irq;
+ struct rz_dmac_desc *desc;
+ int descs_allocated;
+
+ enum dma_slave_buswidth src_word_size;
+ enum dma_slave_buswidth dst_word_size;
+ dma_addr_t src_per_address;
+ dma_addr_t dst_per_address;
+
+ u32 chcfg;
+ u32 chctrl;
+ int mid_rid;
+
+ struct list_head ld_free;
+ struct list_head ld_queue;
+ struct list_head ld_active;
+
+ struct {
+ struct rz_lmdesc *base;
+ struct rz_lmdesc *head;
+ struct rz_lmdesc *tail;
+ dma_addr_t base_dma;
+ } lmdesc;
+};
+
+#define to_rz_dmac_chan(c) container_of(c, struct rz_dmac_chan, vc.chan)
+
+struct rz_dmac {
+ struct dma_device engine;
+ struct device *dev;
+ void __iomem *base;
+ void __iomem *ext_base;
+
+ unsigned int n_channels;
+ struct rz_dmac_chan *channels;
+
+ DECLARE_BITMAP(modules, 1024);
+};
+
+#define to_rz_dmac(d) container_of(d, struct rz_dmac, engine)
+
+/*
+ * -----------------------------------------------------------------------------
+ * Registers
+ */
+
+#define CHSTAT 0x0024
+#define CHCTRL 0x0028
+#define CHCFG 0x002c
+#define NXLA 0x0038
+
+#define DCTRL 0x0000
+
+#define EACH_CHANNEL_OFFSET 0x0040
+#define CHANNEL_0_7_OFFSET 0x0000
+#define CHANNEL_0_7_COMMON_BASE 0x0300
+#define CHANNEL_8_15_OFFSET 0x0400
+#define CHANNEL_8_15_COMMON_BASE 0x0700
+
+#define CHSTAT_ER BIT(4)
+#define CHSTAT_EN BIT(0)
+
+#define CHCTRL_CLRINTMSK BIT(17)
+#define CHCTRL_CLRSUS BIT(9)
+#define CHCTRL_CLRTC BIT(6)
+#define CHCTRL_CLREND BIT(5)
+#define CHCTRL_CLRRQ BIT(4)
+#define CHCTRL_SWRST BIT(3)
+#define CHCTRL_STG BIT(2)
+#define CHCTRL_CLREN BIT(1)
+#define CHCTRL_SETEN BIT(0)
+#define CHCTRL_DEFAULT (CHCTRL_CLRINTMSK | CHCTRL_CLRSUS | \
+ CHCTRL_CLRTC | CHCTRL_CLREND | \
+ CHCTRL_CLRRQ | CHCTRL_SWRST | \
+ CHCTRL_CLREN)
+
+#define CHCFG_DMS BIT(31)
+#define CHCFG_DEM BIT(24)
+#define CHCFG_DAD BIT(21)
+#define CHCFG_SAD BIT(20)
+#define CHCFG_REQD BIT(3)
+#define CHCFG_SEL(bits) ((bits) & 0x07)
+#define CHCFG_MEM_COPY (0x80400008)
+#define CHCFG_FILL_DDS(a) (((a) << 16) & GENMASK(19, 16))
+#define CHCFG_FILL_SDS(a) (((a) << 12) & GENMASK(15, 12))
+#define CHCFG_FILL_TM(a) (((a) & BIT(5)) << 22)
+#define CHCFG_FILL_AM(a) (((a) & GENMASK(4, 2)) << 6)
+#define CHCFG_FILL_LVL(a) (((a) & BIT(1)) << 5)
+#define CHCFG_FILL_HIEN(a) (((a) & BIT(0)) << 5)
+
+#define MID_RID_MASK GENMASK(9, 0)
+#define CHCFG_MASK GENMASK(15, 10)
+#define CHCFG_DS_INVALID 0xFF
+#define DCTRL_LVINT BIT(1)
+#define DCTRL_PR BIT(0)
+#define DCTRL_DEFAULT (DCTRL_LVINT | DCTRL_PR)
+
+/* LINK MODE DESCRIPTOR */
+#define HEADER_LV BIT(0)
+
+#define RZ_DMAC_MAX_CHAN_DESCRIPTORS 16
+#define RZ_DMAC_MAX_CHANNELS 16
+#define DMAC_NR_LMDESC 64
+
+/*
+ * -----------------------------------------------------------------------------
+ * Device access
+ */
+
+static void rz_dmac_writel(struct rz_dmac *dmac, unsigned int val,
+ unsigned int offset)
+{
+ writel(val, dmac->base + offset);
+}
+
+static void rz_dmac_ext_writel(struct rz_dmac *dmac, unsigned int val,
+ unsigned int offset)
+{
+ writel(val, dmac->ext_base + offset);
+}
+
+static u32 rz_dmac_ext_readl(struct rz_dmac *dmac, unsigned int offset)
+{
+ return readl(dmac->ext_base + offset);
+}
+
+static void rz_dmac_ch_writel(struct rz_dmac_chan *channel, unsigned int val,
+ unsigned int offset, int which)
+{
+ if (which)
+ writel(val, channel->ch_base + offset);
+ else
+ writel(val, channel->ch_cmn_base + offset);
+}
+
+static u32 rz_dmac_ch_readl(struct rz_dmac_chan *channel,
+ unsigned int offset, int which)
+{
+ if (which)
+ return readl(channel->ch_base + offset);
+ else
+ return readl(channel->ch_cmn_base + offset);
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Initialization
+ */
+
+static void rz_lmdesc_setup(struct rz_dmac_chan *channel,
+ struct rz_lmdesc *lmdesc)
+{
+ u32 nxla;
+
+ channel->lmdesc.base = lmdesc;
+ channel->lmdesc.head = lmdesc;
+ channel->lmdesc.tail = lmdesc;
+ nxla = channel->lmdesc.base_dma;
+ while (lmdesc < (channel->lmdesc.base + (DMAC_NR_LMDESC - 1))) {
+ lmdesc->header = 0;
+ nxla += sizeof(*lmdesc);
+ lmdesc->nxla = nxla;
+ lmdesc++;
+ }
+
+ lmdesc->header = 0;
+ lmdesc->nxla = channel->lmdesc.base_dma;
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Descriptors preparation
+ */
+
+static void rz_dmac_lmdesc_recycle(struct rz_dmac_chan *channel)
+{
+ struct rz_lmdesc *lmdesc = channel->lmdesc.head;
+
+ while (!(lmdesc->header & HEADER_LV)) {
+ lmdesc->header = 0;
+ lmdesc++;
+ if (lmdesc >= (channel->lmdesc.base + DMAC_NR_LMDESC))
+ lmdesc = channel->lmdesc.base;
+ }
+ channel->lmdesc.head = lmdesc;
+}
+
+static void rz_dmac_enable_hw(struct rz_dmac_chan *channel)
+{
+ struct dma_chan *chan = &channel->vc.chan;
+ struct rz_dmac *dmac = to_rz_dmac(chan->device);
+ unsigned long flags;
+ u32 nxla;
+ u32 chctrl;
+ u32 chstat;
+
+ dev_dbg(dmac->dev, "%s channel %d\n", __func__, channel->index);
+
+ local_irq_save(flags);
+
+ rz_dmac_lmdesc_recycle(channel);
+
+ nxla = channel->lmdesc.base_dma +
+ (sizeof(struct rz_lmdesc) * (channel->lmdesc.head -
+ channel->lmdesc.base));
+
+ chstat = rz_dmac_ch_readl(channel, CHSTAT, 1);
+ if (!(chstat & CHSTAT_EN)) {
+ chctrl = (channel->chctrl | CHCTRL_SETEN);
+ rz_dmac_ch_writel(channel, nxla, NXLA, 1);
+ rz_dmac_ch_writel(channel, channel->chcfg, CHCFG, 1);
+ rz_dmac_ch_writel(channel, CHCTRL_SWRST, CHCTRL, 1);
+ rz_dmac_ch_writel(channel, chctrl, CHCTRL, 1);
+ }
+
+ local_irq_restore(flags);
+}
+
+static void rz_dmac_disable_hw(struct rz_dmac_chan *channel)
+{
+ struct dma_chan *chan = &channel->vc.chan;
+ struct rz_dmac *dmac = to_rz_dmac(chan->device);
+ unsigned long flags;
+
+ dev_dbg(dmac->dev, "%s channel %d\n", __func__, channel->index);
+
+ local_irq_save(flags);
+ rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
+ local_irq_restore(flags);
+}
+
+static void rz_dmac_set_dmars_register(struct rz_dmac *dmac, int nr, u32 dmars)
+{
+ u32 dmars_offset = (nr / 2) * 4;
+ u32 shift = (nr % 2) * 16;
+ u32 dmars32;
+
+ dmars32 = rz_dmac_ext_readl(dmac, dmars_offset);
+ dmars32 &= ~(0xffff << shift);
+ dmars32 |= dmars << shift;
+
+ rz_dmac_ext_writel(dmac, dmars32, dmars_offset);
+}
+
+static void rz_dmac_prepare_desc_for_memcpy(struct rz_dmac_chan *channel)
+{
+ struct dma_chan *chan = &channel->vc.chan;
+ struct rz_dmac *dmac = to_rz_dmac(chan->device);
+ struct rz_lmdesc *lmdesc = channel->lmdesc.base;
+ struct rz_dmac_desc *d = channel->desc;
+ u32 chcfg = CHCFG_MEM_COPY;
+
+ lmdesc = channel->lmdesc.tail;
+
+ /* prepare descriptor */
+ lmdesc->sa = d->src;
+ lmdesc->da = d->dest;
+ lmdesc->tb = d->len;
+ lmdesc->chcfg = chcfg;
+ lmdesc->chitvl = 0;
+ lmdesc->chext = 0;
+ lmdesc->header = HEADER_LV;
+
+ rz_dmac_set_dmars_register(dmac, channel->index, 0);
+
+ channel->chcfg = chcfg;
+ channel->chctrl = CHCTRL_STG | CHCTRL_SETEN;
+}
+
+static void rz_dmac_prepare_descs_for_slave_sg(struct rz_dmac_chan *channel)
+{
+ struct dma_chan *chan = &channel->vc.chan;
+ struct rz_dmac *dmac = to_rz_dmac(chan->device);
+ struct rz_dmac_desc *d = channel->desc;
+ struct scatterlist *sg, *sgl = d->sg;
+ struct rz_lmdesc *lmdesc;
+ unsigned int i, sg_len = d->sgcount;
+
+ channel->chcfg |= CHCFG_SEL(channel->index) | CHCFG_DEM | CHCFG_DMS;
+
+ if (d->direction == DMA_DEV_TO_MEM) {
+ channel->chcfg |= CHCFG_SAD;
+ channel->chcfg &= ~CHCFG_REQD;
+ } else {
+ channel->chcfg |= CHCFG_DAD | CHCFG_REQD;
+ }
+
+ lmdesc = channel->lmdesc.tail;
+
+ for (i = 0, sg = sgl; i < sg_len; i++, sg = sg_next(sg)) {
+ if (d->direction == DMA_DEV_TO_MEM) {
+ lmdesc->sa = channel->src_per_address;
+ lmdesc->da = sg_dma_address(sg);
+ } else {
+ lmdesc->sa = sg_dma_address(sg);
+ lmdesc->da = channel->dst_per_address;
+ }
+
+ lmdesc->tb = sg_dma_len(sg);
+ lmdesc->chitvl = 0;
+ lmdesc->chext = 0;
+ if (i == (sg_len - 1)) {
+ lmdesc->chcfg = (channel->chcfg & ~CHCFG_DEM);
+ lmdesc->header = HEADER_LV;
+ } else {
+ lmdesc->chcfg = channel->chcfg;
+ lmdesc->header = HEADER_LV;
+ }
+ if (++lmdesc >= (channel->lmdesc.base + DMAC_NR_LMDESC))
+ lmdesc = channel->lmdesc.base;
+ }
+
+ channel->lmdesc.tail = lmdesc;
+
+ rz_dmac_set_dmars_register(dmac, channel->index, channel->mid_rid);
+ channel->chctrl = CHCTRL_SETEN;
+}
+
+static int rz_dmac_xfer_desc(struct rz_dmac_chan *chan)
+{
+ struct rz_dmac_desc *d = chan->desc;
+ struct virt_dma_desc *vd;
+
+ vd = vchan_next_desc(&chan->vc);
+ if (!vd)
+ return 0;
+
+ list_del(&vd->node);
+
+ switch (d->type) {
+ case RZ_DMAC_DESC_MEMCPY:
+ rz_dmac_prepare_desc_for_memcpy(chan);
+ break;
+
+ case RZ_DMAC_DESC_SLAVE_SG:
+ rz_dmac_prepare_descs_for_slave_sg(chan);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ rz_dmac_enable_hw(chan);
+
+ return 0;
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * DMA engine operations
+ */
+
+static int rz_dmac_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct rz_dmac_chan *channel = to_rz_dmac_chan(chan);
+
+ while (channel->descs_allocated < RZ_DMAC_MAX_CHAN_DESCRIPTORS) {
+ struct rz_dmac_desc *desc;
+
+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ break;
+
+ list_add_tail(&desc->node, &channel->ld_free);
+ channel->descs_allocated++;
+ }
+
+ if (!channel->descs_allocated)
+ return -ENOMEM;
+
+ return channel->descs_allocated;
+}
+
+static void rz_dmac_free_chan_resources(struct dma_chan *chan)
+{
+ struct rz_dmac_chan *channel = to_rz_dmac_chan(chan);
+ struct rz_dmac *dmac = to_rz_dmac(chan->device);
+ struct rz_lmdesc *lmdesc = channel->lmdesc.base;
+ struct rz_dmac_desc *desc, *_desc;
+ unsigned long flags;
+ unsigned int i;
+
+ spin_lock_irqsave(&channel->vc.lock, flags);
+
+ for (i = 0; i < DMAC_NR_LMDESC; i++)
+ lmdesc[i].header = 0;
+
+ rz_dmac_disable_hw(channel);
+ list_splice_tail_init(&channel->ld_active, &channel->ld_free);
+ list_splice_tail_init(&channel->ld_queue, &channel->ld_free);
+
+ if (channel->mid_rid >= 0) {
+ clear_bit(channel->mid_rid, dmac->modules);
+ channel->mid_rid = -EINVAL;
+ }
+
+ spin_unlock_irqrestore(&channel->vc.lock, flags);
+
+ list_for_each_entry_safe(desc, _desc, &channel->ld_free, node) {
+ kfree(desc);
+ channel->descs_allocated--;
+ }
+
+ INIT_LIST_HEAD(&channel->ld_free);
+ vchan_free_chan_resources(&channel->vc);
+}
+
+static struct dma_async_tx_descriptor *
+rz_dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+ size_t len, unsigned long flags)
+{
+ struct rz_dmac_chan *channel = to_rz_dmac_chan(chan);
+ struct rz_dmac *dmac = to_rz_dmac(chan->device);
+ struct rz_dmac_desc *desc;
+
+ dev_dbg(dmac->dev, "%s channel: %d src=0x%pad dst=0x%pad len=%zu\n",
+ __func__, channel->index, &src, &dest, len);
+
+ if (list_empty(&channel->ld_free))
+ return NULL;
+
+ desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
+
+ desc->type = RZ_DMAC_DESC_MEMCPY;
+ desc->src = src;
+ desc->dest = dest;
+ desc->len = len;
+ desc->direction = DMA_MEM_TO_MEM;
+
+ list_move_tail(channel->ld_free.next, &channel->ld_queue);
+ return vchan_tx_prep(&channel->vc, &desc->vd, flags);
+}
+
+static struct dma_async_tx_descriptor *
+rz_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len,
+ enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct rz_dmac_chan *channel = to_rz_dmac_chan(chan);
+ struct rz_dmac_desc *desc;
+ struct scatterlist *sg;
+ int dma_length = 0;
+ int i = 0;
+
+ if (list_empty(&channel->ld_free))
+ return NULL;
+
+ desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ dma_length += sg_dma_len(sg);
+ }
+
+ desc->type = RZ_DMAC_DESC_SLAVE_SG;
+ desc->sg = sgl;
+ desc->sgcount = sg_len;
+ desc->len = dma_length;
+ desc->direction = direction;
+
+ if (direction == DMA_DEV_TO_MEM)
+ desc->src = channel->src_per_address;
+ else
+ desc->dest = channel->dst_per_address;
+
+ list_move_tail(channel->ld_free.next, &channel->ld_queue);
+ return vchan_tx_prep(&channel->vc, &desc->vd, flags);
+}
+
+static int rz_dmac_terminate_all(struct dma_chan *chan)
+{
+ struct rz_dmac_chan *channel = to_rz_dmac_chan(chan);
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ rz_dmac_disable_hw(channel);
+ spin_lock_irqsave(&channel->vc.lock, flags);
+ list_splice_tail_init(&channel->ld_active, &channel->ld_free);
+ list_splice_tail_init(&channel->ld_queue, &channel->ld_free);
+ spin_unlock_irqrestore(&channel->vc.lock, flags);
+ vchan_get_all_descriptors(&channel->vc, &head);
+ vchan_dma_desc_free_list(&channel->vc, &head);
+
+ return 0;
+}
+
+static void rz_dmac_issue_pending(struct dma_chan *chan)
+{
+ struct rz_dmac_chan *channel = to_rz_dmac_chan(chan);
+ struct rz_dmac *dmac = to_rz_dmac(chan->device);
+ struct rz_dmac_desc *desc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->vc.lock, flags);
+
+ if (!list_empty(&channel->ld_queue)) {
+ desc = list_first_entry(&channel->ld_queue,
+ struct rz_dmac_desc, node);
+ channel->desc = desc;
+ if (vchan_issue_pending(&channel->vc)) {
+ if (rz_dmac_xfer_desc(channel) < 0)
+ dev_warn(dmac->dev, "ch: %d couldn't issue DMA xfer\n",
+ channel->index);
+ else
+ list_move_tail(channel->ld_queue.next,
+ &channel->ld_active);
+ }
+ }
+
+ spin_unlock_irqrestore(&channel->vc.lock, flags);
+}
+
+static u8 rz_dmac_ds_to_val_mapping(enum dma_slave_buswidth ds)
+{
+ u8 i;
+ const enum dma_slave_buswidth ds_lut[] = {
+ DMA_SLAVE_BUSWIDTH_1_BYTE,
+ DMA_SLAVE_BUSWIDTH_2_BYTES,
+ DMA_SLAVE_BUSWIDTH_4_BYTES,
+ DMA_SLAVE_BUSWIDTH_8_BYTES,
+ DMA_SLAVE_BUSWIDTH_16_BYTES,
+ DMA_SLAVE_BUSWIDTH_32_BYTES,
+ DMA_SLAVE_BUSWIDTH_64_BYTES,
+ DMA_SLAVE_BUSWIDTH_128_BYTES,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(ds_lut); i++) {
+ if (ds_lut[i] == ds)
+ return i;
+ }
+
+ return CHCFG_DS_INVALID;
+}
+
+static int rz_dmac_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct rz_dmac_chan *channel = to_rz_dmac_chan(chan);
+ u32 val;
+
+ channel->src_per_address = config->src_addr;
+ channel->src_word_size = config->src_addr_width;
+ channel->dst_per_address = config->dst_addr;
+ channel->dst_word_size = config->dst_addr_width;
+
+ val = rz_dmac_ds_to_val_mapping(config->dst_addr_width);
+ if (val == CHCFG_DS_INVALID)
+ return -EINVAL;
+
+ channel->chcfg |= CHCFG_FILL_DDS(val);
+
+ val = rz_dmac_ds_to_val_mapping(config->src_addr_width);
+ if (val == CHCFG_DS_INVALID)
+ return -EINVAL;
+
+ channel->chcfg |= CHCFG_FILL_SDS(val);
+
+ return 0;
+}
+
+static void rz_dmac_virt_desc_free(struct virt_dma_desc *vd)
+{
+ /*
+ * Place holder
+ * Descriptor allocation is done during alloc_chan_resources and
+ * get freed during free_chan_resources.
+ * list is used to manage the descriptors and avoid any memory
+ * allocation/free during DMA read/write.
+ */
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * IRQ handling
+ */
+
+static void rz_dmac_irq_handle_channel(struct rz_dmac_chan *channel)
+{
+ struct dma_chan *chan = &channel->vc.chan;
+ struct rz_dmac *dmac = to_rz_dmac(chan->device);
+ u32 chstat, chctrl;
+
+ chstat = rz_dmac_ch_readl(channel, CHSTAT, 1);
+ if (chstat & CHSTAT_ER) {
+ dev_err(dmac->dev, "DMAC err CHSTAT_%d = %08X\n",
+ channel->index, chstat);
+ rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
+ goto done;
+ }
+
+ chctrl = rz_dmac_ch_readl(channel, CHCTRL, 1);
+ rz_dmac_ch_writel(channel, chctrl | CHCTRL_CLREND, CHCTRL, 1);
+done:
+ return;
+}
+
+static irqreturn_t rz_dmac_irq_handler(int irq, void *dev_id)
+{
+ struct rz_dmac_chan *channel = dev_id;
+
+ if (channel) {
+ rz_dmac_irq_handle_channel(channel);
+ return IRQ_WAKE_THREAD;
+ }
+ /* handle DMAERR irq */
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rz_dmac_irq_handler_thread(int irq, void *dev_id)
+{
+ struct rz_dmac_chan *channel = dev_id;
+ struct rz_dmac_desc *desc = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->vc.lock, flags);
+
+ if (list_empty(&channel->ld_active)) {
+ /* Someone might have called terminate all */
+ goto out;
+ }
+
+ desc = list_first_entry(&channel->ld_active, struct rz_dmac_desc, node);
+ vchan_cookie_complete(&desc->vd);
+ list_move_tail(channel->ld_active.next, &channel->ld_free);
+ if (!list_empty(&channel->ld_queue)) {
+ desc = list_first_entry(&channel->ld_queue, struct rz_dmac_desc,
+ node);
+ channel->desc = desc;
+ if (rz_dmac_xfer_desc(channel) == 0)
+ list_move_tail(channel->ld_queue.next, &channel->ld_active);
+ }
+out:
+ spin_unlock_irqrestore(&channel->vc.lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * OF xlate and channel filter
+ */
+
+static bool rz_dmac_chan_filter(struct dma_chan *chan, void *arg)
+{
+ struct rz_dmac_chan *channel = to_rz_dmac_chan(chan);
+ struct rz_dmac *dmac = to_rz_dmac(chan->device);
+ struct of_phandle_args *dma_spec = arg;
+ u32 ch_cfg;
+
+ channel->mid_rid = dma_spec->args[0] & MID_RID_MASK;
+ ch_cfg = (dma_spec->args[0] & CHCFG_MASK) >> 10;
+ channel->chcfg = CHCFG_FILL_TM(ch_cfg) | CHCFG_FILL_AM(ch_cfg) |
+ CHCFG_FILL_LVL(ch_cfg) | CHCFG_FILL_HIEN(ch_cfg);
+
+ return !test_and_set_bit(channel->mid_rid, dmac->modules);
+}
+
+static struct dma_chan *rz_dmac_of_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ dma_cap_mask_t mask;
+
+ if (dma_spec->args_count != 1)
+ return NULL;
+
+ /* Only slave DMA channels can be allocated via DT */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ return dma_request_channel(mask, rz_dmac_chan_filter, dma_spec);
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Probe and remove
+ */
+
+static int rz_dmac_chan_probe(struct rz_dmac *dmac,
+ struct rz_dmac_chan *channel,
+ unsigned int index)
+{
+ struct platform_device *pdev = to_platform_device(dmac->dev);
+ struct rz_lmdesc *lmdesc;
+ char pdev_irqname[5];
+ char *irqname;
+ int ret;
+
+ channel->index = index;
+ channel->mid_rid = -EINVAL;
+
+ /* Request the channel interrupt. */
+ sprintf(pdev_irqname, "ch%u", index);
+ channel->irq = platform_get_irq_byname(pdev, pdev_irqname);
+ if (channel->irq < 0)
+ return channel->irq;
+
+ irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u",
+ dev_name(dmac->dev), index);
+ if (!irqname)
+ return -ENOMEM;
+
+ ret = devm_request_threaded_irq(dmac->dev, channel->irq,
+ rz_dmac_irq_handler,
+ rz_dmac_irq_handler_thread, 0,
+ irqname, channel);
+ if (ret) {
+ dev_err(dmac->dev, "failed to request IRQ %u (%d)\n",
+ channel->irq, ret);
+ return ret;
+ }
+
+ /* Set io base address for each channel */
+ if (index < 8) {
+ channel->ch_base = dmac->base + CHANNEL_0_7_OFFSET +
+ EACH_CHANNEL_OFFSET * index;
+ channel->ch_cmn_base = dmac->base + CHANNEL_0_7_COMMON_BASE;
+ } else {
+ channel->ch_base = dmac->base + CHANNEL_8_15_OFFSET +
+ EACH_CHANNEL_OFFSET * (index - 8);
+ channel->ch_cmn_base = dmac->base + CHANNEL_8_15_COMMON_BASE;
+ }
+
+ /* Allocate descriptors */
+ lmdesc = dma_alloc_coherent(&pdev->dev,
+ sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC,
+ &channel->lmdesc.base_dma, GFP_KERNEL);
+ if (!lmdesc) {
+ dev_err(&pdev->dev, "Can't allocate memory (lmdesc)\n");
+ return -ENOMEM;
+ }
+ rz_lmdesc_setup(channel, lmdesc);
+
+ /* Initialize register for each channel */
+ rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
+
+ channel->vc.desc_free = rz_dmac_virt_desc_free;
+ vchan_init(&channel->vc, &dmac->engine);
+ INIT_LIST_HEAD(&channel->ld_queue);
+ INIT_LIST_HEAD(&channel->ld_free);
+ INIT_LIST_HEAD(&channel->ld_active);
+
+ return 0;
+}
+
+static int rz_dmac_parse_of(struct device *dev, struct rz_dmac *dmac)
+{
+ struct device_node *np = dev->of_node;
+ int ret;
+
+ ret = of_property_read_u32(np, "dma-channels", &dmac->n_channels);
+ if (ret < 0) {
+ dev_err(dev, "unable to read dma-channels property\n");
+ return ret;
+ }
+
+ if (!dmac->n_channels || dmac->n_channels > RZ_DMAC_MAX_CHANNELS) {
+ dev_err(dev, "invalid number of channels %u\n", dmac->n_channels);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rz_dmac_probe(struct platform_device *pdev)
+{
+ const char *irqname = "error";
+ struct dma_device *engine;
+ struct rz_dmac *dmac;
+ int channel_num;
+ unsigned int i;
+ int ret;
+ int irq;
+
+ dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL);
+ if (!dmac)
+ return -ENOMEM;
+
+ dmac->dev = &pdev->dev;
+ platform_set_drvdata(pdev, dmac);
+
+ ret = rz_dmac_parse_of(&pdev->dev, dmac);
+ if (ret < 0)
+ return ret;
+
+ dmac->channels = devm_kcalloc(&pdev->dev, dmac->n_channels,
+ sizeof(*dmac->channels), GFP_KERNEL);
+ if (!dmac->channels)
+ return -ENOMEM;
+
+ /* Request resources */
+ dmac->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(dmac->base))
+ return PTR_ERR(dmac->base);
+
+ dmac->ext_base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(dmac->ext_base))
+ return PTR_ERR(dmac->ext_base);
+
+ /* Register interrupt handler for error */
+ irq = platform_get_irq_byname(pdev, irqname);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(&pdev->dev, irq, rz_dmac_irq_handler, 0,
+ irqname, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request IRQ %u (%d)\n",
+ irq, ret);
+ return ret;
+ }
+
+ /* Initialize the channels. */
+ INIT_LIST_HEAD(&dmac->engine.channels);
+
+ for (i = 0; i < dmac->n_channels; i++) {
+ ret = rz_dmac_chan_probe(dmac, &dmac->channels[i], i);
+ if (ret < 0)
+ goto err;
+ }
+
+ /* Register the DMAC as a DMA provider for DT. */
+ ret = of_dma_controller_register(pdev->dev.of_node, rz_dmac_of_xlate,
+ NULL);
+ if (ret < 0)
+ goto err;
+
+ /* Register the DMA engine device. */
+ engine = &dmac->engine;
+ dma_cap_set(DMA_SLAVE, engine->cap_mask);
+ dma_cap_set(DMA_MEMCPY, engine->cap_mask);
+ rz_dmac_writel(dmac, DCTRL_DEFAULT, CHANNEL_0_7_COMMON_BASE + DCTRL);
+ rz_dmac_writel(dmac, DCTRL_DEFAULT, CHANNEL_8_15_COMMON_BASE + DCTRL);
+
+ engine->dev = &pdev->dev;
+
+ engine->device_alloc_chan_resources = rz_dmac_alloc_chan_resources;
+ engine->device_free_chan_resources = rz_dmac_free_chan_resources;
+ engine->device_tx_status = dma_cookie_status;
+ engine->device_prep_slave_sg = rz_dmac_prep_slave_sg;
+ engine->device_prep_dma_memcpy = rz_dmac_prep_dma_memcpy;
+ engine->device_config = rz_dmac_config;
+ engine->device_terminate_all = rz_dmac_terminate_all;
+ engine->device_issue_pending = rz_dmac_issue_pending;
+
+ engine->copy_align = DMAENGINE_ALIGN_1_BYTE;
+ dma_set_max_seg_size(engine->dev, U32_MAX);
+
+ ret = dma_async_device_register(engine);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register\n");
+ goto dma_register_err;
+ }
+ return 0;
+
+dma_register_err:
+ of_dma_controller_free(pdev->dev.of_node);
+err:
+ channel_num = i ? i - 1 : 0;
+ for (i = 0; i < channel_num; i++) {
+ struct rz_dmac_chan *channel = &dmac->channels[i];
+
+ dma_free_coherent(NULL,
+ sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC,
+ channel->lmdesc.base,
+ channel->lmdesc.base_dma);
+ }
+
+ return ret;
+}
+
+static int rz_dmac_remove(struct platform_device *pdev)
+{
+ struct rz_dmac *dmac = platform_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < dmac->n_channels; i++) {
+ struct rz_dmac_chan *channel = &dmac->channels[i];
+
+ dma_free_coherent(NULL,
+ sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC,
+ channel->lmdesc.base,
+ channel->lmdesc.base_dma);
+ }
+ of_dma_controller_free(pdev->dev.of_node);
+ dma_async_device_unregister(&dmac->engine);
+
+ return 0;
+}
+
+static const struct of_device_id of_rz_dmac_match[] = {
+ { .compatible = "renesas,rz-dmac", },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_rz_dmac_match);
+
+static struct platform_driver rz_dmac_driver = {
+ .driver = {
+ .name = "rz-dmac",
+ .of_match_table = of_rz_dmac_match,
+ },
+ .probe = rz_dmac_probe,
+ .remove = rz_dmac_remove,
+};
+
+module_platform_driver(rz_dmac_driver);
+
+MODULE_DESCRIPTION("Renesas RZ/G2L DMA Controller Driver");
+MODULE_AUTHOR("Biju Das <biju.das.jz@...>");
+MODULE_LICENSE("GPL v2");
--
2.17.1


[PATCH 5.10.y-cip 15/22] dmaengine: Extend the dma_slave_width for 128 bytes

Lad Prabhakar
 

From: Biju Das <biju.das.jz@...>

commit ab959c7d4ea086852f35c7ff20ecd79b7471cfad upstream.

Add DMA_SLAVE_BUSWIDTH_128_BYTES to dma_slave_width for DMA engines
and users to select 128 bytes as bus width.

Signed-off-by: Biju Das <biju.das.jz@...>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Link: https://lore.kernel.org/r/20210806095322.2326-3-biju.das.jz@bp.renesas.com
Signed-off-by: Vinod Koul <vkoul@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
include/linux/dmaengine.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index dd357a747780..256592c0a365 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -378,6 +378,7 @@ enum dma_slave_buswidth {
DMA_SLAVE_BUSWIDTH_16_BYTES = 16,
DMA_SLAVE_BUSWIDTH_32_BYTES = 32,
DMA_SLAVE_BUSWIDTH_64_BYTES = 64,
+ DMA_SLAVE_BUSWIDTH_128_BYTES = 128,
};

/**
@@ -396,7 +397,7 @@ enum dma_slave_buswidth {
* @src_addr_width: this is the width in bytes of the source (RX)
* register where DMA data shall be read. If the source
* is memory this may be ignored depending on architecture.
- * Legal values: 1, 2, 3, 4, 8, 16, 32, 64.
+ * Legal values: 1, 2, 3, 4, 8, 16, 32, 64, 128.
* @dst_addr_width: same as src_addr_width but for destination
* target (TX) mutatis mutandis.
* @src_maxburst: the maximum number of words (note: words, as in
--
2.17.1


[PATCH 5.10.y-cip 14/22] dt-bindings: dma: Document RZ/G2L bindings

Lad Prabhakar
 

From: Biju Das <biju.das.jz@...>

commit 9b9b12537d3a7b5bea6b9e8f20bffc2338724269 upstream.

Document RZ/G2L DMAC bindings.

Signed-off-by: Biju Das <biju.das.jz@...>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Reviewed-by: Rob Herring <robh@...>
Link: https://lore.kernel.org/r/20210806095322.2326-2-biju.das.jz@bp.renesas.com
Signed-off-by: Vinod Koul <vkoul@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
.../bindings/dma/renesas,rz-dmac.yaml | 130 ++++++++++++++++++
1 file changed, 130 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml

diff --git a/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml b/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml
new file mode 100644
index 000000000000..7a4f415d74dc
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml
@@ -0,0 +1,130 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/dma/renesas,rz-dmac.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/G2L DMA Controller
+
+maintainers:
+ - Biju Das <biju.das.jz@...>
+
+allOf:
+ - $ref: "dma-controller.yaml#"
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - renesas,r9a07g044-dmac # RZ/G2{L,LC}
+ - const: renesas,rz-dmac
+
+ reg:
+ items:
+ - description: Control and channel register block
+ - description: DMA extended resource selector block
+
+ interrupts:
+ maxItems: 17
+
+ interrupt-names:
+ items:
+ - const: error
+ - const: ch0
+ - const: ch1
+ - const: ch2
+ - const: ch3
+ - const: ch4
+ - const: ch5
+ - const: ch6
+ - const: ch7
+ - const: ch8
+ - const: ch9
+ - const: ch10
+ - const: ch11
+ - const: ch12
+ - const: ch13
+ - const: ch14
+ - const: ch15
+
+ clocks:
+ items:
+ - description: DMA main clock
+ - description: DMA register access clock
+
+ '#dma-cells':
+ const: 1
+ description:
+ The cell specifies the encoded MID/RID values of the DMAC port
+ connected to the DMA client and the slave channel configuration
+ parameters.
+ bits[0:9] - Specifies MID/RID value
+ bit[10] - Specifies DMA request high enable (HIEN)
+ bit[11] - Specifies DMA request detection type (LVL)
+ bits[12:14] - Specifies DMAACK output mode (AM)
+ bit[15] - Specifies Transfer Mode (TM)
+
+ dma-channels:
+ const: 16
+
+ power-domains:
+ maxItems: 1
+
+ resets:
+ items:
+ - description: Reset for DMA ARESETN reset terminal
+ - description: Reset for DMA RST_ASYNC reset terminal
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - interrupt-names
+ - clocks
+ - '#dma-cells'
+ - dma-channels
+ - power-domains
+ - resets
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/r9a07g044-cpg.h>
+
+ dmac: dma-controller@11820000 {
+ compatible = "renesas,r9a07g044-dmac",
+ "renesas,rz-dmac";
+ reg = <0x11820000 0x10000>,
+ <0x11830000 0x10000>;
+ interrupts = <GIC_SPI 141 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 125 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 126 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 127 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 128 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 129 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 130 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 131 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 132 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 133 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 134 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 135 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 136 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 137 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 138 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 139 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 140 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3",
+ "ch4", "ch5", "ch6", "ch7",
+ "ch8", "ch9", "ch10", "ch11",
+ "ch12", "ch13", "ch14", "ch15";
+ clocks = <&cpg CPG_MOD R9A07G044_DMAC_ACLK>,
+ <&cpg CPG_MOD R9A07G044_DMAC_PCLK>;
+ power-domains = <&cpg>;
+ resets = <&cpg R9A07G044_DMAC_ARESETN>,
+ <&cpg R9A07G044_DMAC_RST_ASYNC>;
+ #dma-cells = <1>;
+ dma-channels = <16>;
+ };
--
2.17.1

2421 - 2440 of 9648