Date   

Re: [PATCH 4.19.y-cip 0/2] Add sound support to R8A774E1 SoC

Pavel Machek
 

Hi!

This patch series adds sound support to Renesas R8A774E1 SoC.

All the patches have been cherry picked from Linux v5.10-rc5.
Thanks, applied and pushed out.

Best regards,
Pavel

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


Re: [PATCH 4.19.y-cip 2/7] memory: add Renesas RPC-IF driver

Pavel Machek
 

Hi!

+void rpcif_enable_rpm(struct rpcif *rpc)
+{
+ pm_runtime_enable(rpc->dev);
+}
+EXPORT_SYMBOL(rpcif_enable_rpm);
+
+void rpcif_disable_rpm(struct rpcif *rpc)
+{
+ pm_runtime_put_sync(rpc->dev);
+}
+EXPORT_SYMBOL(rpcif_disable_rpm);
Should these go to header as static inlines?
Would be nice will make them inline and squash it in the current
patch.
For this series, maybe squashing is not neccessary. It is pretty good
as-is.

+static int wait_msg_xfer_end(struct rpcif *rpc)
+{
+ u32 sts;
+
+ return regmap_read_poll_timeout(rpc->regmap, RPCIF_CMNSR, sts,
+ sts & RPCIF_CMNSR_TEND, 0,
+ USEC_PER_SEC);
+}
This can't be right. sts is used uninitialized here.
Third parameter in regmap_read_poll_timeout() is the variable in which value is read and the fourth parameter condition has to be tied with the third parameter (there are similar instance in the kernel).
Okay, that's some rather evil code. It should really be
REGMAP_READ_POLL_TIMEOUT, because it is macro with weird semantics.

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


Re: [PATCH 4.19.y-cip 7/7] spi: add Renesas RPC-IF driver

Lad Prabhakar
 

Hi Pavel,

Thank you for the review.

-----Original Message-----
From: Pavel Machek <pavel@...>
Sent: 23 November 2020 19:52
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 4.19.y-cip 7/7] spi: add Renesas RPC-IF driver

Hi!

commit eb8d6d464a27850498dced21a8450e85d4a02009 upstream.

Add the SPI driver for the Renesas RPC-IF. It's the "front end" driver
using the "back end" APIs in the main driver to talk to the real hardware.
We only implement the 'spi-mem' interface -- there's no need to implement
the usual SPI driver methods...

Based on the original patch by Mason Yang <masonccyang@...>.

Signed-off-by: Sergei Shtylyov <sergei.shtylyov@...>
Link: https://lore.kernel.org/r/1ece0e6c-71af-f0f1-709e-571f4b0b4853@cogentembedded.com
Signed-off-by: Mark Brown <broonie@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/spi/Kconfig | 6 ++
drivers/spi/Makefile | 1 +
drivers/spi/spi-rpc-if.c | 216 +++++++++++++++++++++++++++++++++++++++
3 files changed, 223 insertions(+)
create mode 100644 drivers/spi/spi-rpc-if.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 0a7fd56c1ed9..461315967f96 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -514,6 +514,12 @@ config SPI_RB4XX
help
SPI controller driver for the Mikrotik RB4xx series boards.

+config SPI_RPCIF
+ tristate "Renesas RPC-IF SPI driver"
+ depends on RENESAS_RPCIF
+ help
+ SPI driver for Renesas R-Car Gen3 RPC-IF.
Few lines here explaining the acronyms etc. would be nice.
Will do.

+ error = spi_register_controller(ctlr);
+ if (error) {
+ dev_err(&pdev->dev, "spi_register_controller failed\n");
+ goto err_put_ctlr;
+ }
+ return 0;
+
+err_put_ctlr:
+ rpcif_disable_rpm(rpc);
+ spi_controller_put(ctlr);
+
+ return error;
+}
With just one user of the error exit, I'd avoid the goto.
Agreed shall fix that.

+#ifdef CONFIG_PM_SLEEP
+static int rpcif_spi_suspend(struct device *dev)
+{
+ struct spi_controller *ctlr = dev_get_drvdata(dev);
+
+ return spi_controller_suspend(ctlr);
+}
+
+static int rpcif_spi_resume(struct device *dev)
+{
+ struct spi_controller *ctlr = dev_get_drvdata(dev);
+
+ return spi_controller_resume(ctlr);
+}
+
+static SIMPLE_DEV_PM_OPS(rpcif_spi_pm_ops, rpcif_spi_suspend, rpcif_spi_resume);
+#define DEV_PM_OPS (&rpcif_spi_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver rpcif_spi_driver = {
+ .probe = rpcif_spi_probe,
+ .remove = rpcif_spi_remove,
+ .driver = {
+ .name = "rpc-if-spi",
+ .pm = DEV_PM_OPS,
+ },
+};
Can you just add "__maybe_unused" annotation and avoid the ifdefs,
like atmel-quadspi.c does?
Agreed will replace that.

Cheers,
Prabhakar

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


Re: [PATCH 4.19.y-cip 6/7] spi: spi-mem: Add a new API to support direct mapping

Lad Prabhakar
 

Hi Pavel,

Thank you for the review.

-----Original Message-----
From: Pavel Machek <pavel@...>
Sent: 23 November 2020 19:46
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 4.19.y-cip 6/7] spi: spi-mem: Add a new API to support direct mapping

Hi!

commit aa167f3fed0c37e0e4c707d4331d827661f46644 upstream.

Most modern SPI controllers can directly map a SPI memory (or a portion
of the SPI memory) in the CPU address space. Most of the time this
brings significant performance improvements as it automates the whole
process of sending SPI memory operations every time a new region is
accessed.

This new API allows SPI memory drivers to create direct mappings and
then use them to access the memory instead of using
spi_mem_exec_op().
+ * Return: the amount of data read from the memory device or a negative error
+ * code. Note that the returned size might be smaller than @len, and the caller
+ * is responsible for calling spi_mem_dirmap_read() again when that happens.
+ */
+ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, void *buf)
+{
+ struct spi_controller *ctlr = desc->mem->spi->controller;
+ ssize_t ret;
+
+ if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
+ return -EINVAL;
+
+ if (!len)
+ return 0;
+
+ if (desc->nodirmap) {
+ ret = spi_mem_no_dirmap_read(desc, offs, len, buf);
I'd do return ... here.
Agreed.

+ } else if (ctlr->mem_ops && ctlr->mem_ops->dirmap_read) {
+ ret = spi_mem_access_start(desc->mem);
+ if (ret)
+ return ret;
+
+ ret = ctlr->mem_ops->dirmap_read(desc, offs, len, buf);
+
+ spi_mem_access_end(desc->mem);
and here.
Ditto.

+ } else {
+ ret = -ENOTSUPP;
+ }
To help with if/else nesting. spi_mem_dirmap_write could use same
treatment.
Agreed will fix that and squash the changes in current patch and post it as part of v2.

Cheers,
Prabhakar

Best regards,
Pavel

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


Re: [PATCH 4.19.y-cip 5/7] spi: spi-mem: Split spi_mem_exec_op() code

Lad Prabhakar
 

Hi Pavel,

Thank you for the review.

-----Original Message-----
From: Pavel Machek <pavel@...>
Sent: 23 November 2020 19:44
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 4.19.y-cip 5/7] spi: spi-mem: Split spi_mem_exec_op() code

Hi!

From: Boris Brezillon <boris.brezillon@...>

commit f86c24f4795303e4024bc113196de32782f6ccb5 upstream.

The logic surrounding the ->exec_op() call applies to direct mapping
accessors. Move this code to separate functions to avoid duplicating
code.
+++ b/drivers/spi/spi-mem.c
@@ -213,6 +213,44 @@ bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
}
EXPORT_SYMBOL_GPL(spi_mem_supports_op);

+static int spi_mem_access_start(struct spi_mem *mem)
+{
+ struct spi_controller *ctlr = mem->spi->controller;
...
+ if (ctlr->auto_runtime_pm) {
+ int ret;
+
+ ret = pm_runtime_get_sync(ctlr->dev.parent);
+ if (ret < 0) {
+ dev_err(&ctlr->dev, "Failed to power device: %d\n",
+ ret);
+ return ret;
+ }
This misses pm_runtime_put() in the error case.
Agreed (pm_runtime_put_noidle()).

+ mutex_lock(&ctlr->bus_lock_mutex);
+ mutex_lock(&ctlr->io_mutex);
Plus hiding locking into function like this ... is quite
"interesting".
😊

Cheers,
Prabhakar

Best regards,
Pavel

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


Re: [PATCH 4.19.y-cip 2/7] memory: add Renesas RPC-IF driver

Lad Prabhakar
 

Hi Pavel,

Thank you for the review.

-----Original Message-----
From: Pavel Machek <pavel@...>
Sent: 23 November 2020 19:39
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 4.19.y-cip 2/7] memory: add Renesas RPC-IF driver

Hi!

From: Sergei Shtylyov <sergei.shtylyov@...>
+int rpcif_manual_xfer(struct rpcif *rpc);
+ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf);
+
+#endif // __RENESAS_RPC_IF_H
Oh and I'd use normal C comment here.
Agreed not sure why checkpatch failed to catch this for upstream.

Cheers,
Prabhakar

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


Re: [PATCH 4.19.y-cip 2/7] memory: add Renesas RPC-IF driver

Lad Prabhakar
 

Hi Pavel,

Thank you for the review.

-----Original Message-----
From: Pavel Machek <pavel@...>
Sent: 23 November 2020 19:38
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 4.19.y-cip 2/7] memory: add Renesas RPC-IF driver

Hi!

+EXPORT_SYMBOL(rpcif_sw_init);
EXPORT_SYMBOL_GPL?
Agreed will fix that and squash that in the current patch.

+void rpcif_enable_rpm(struct rpcif *rpc)
+{
+ pm_runtime_enable(rpc->dev);
+}
+EXPORT_SYMBOL(rpcif_enable_rpm);
+
+void rpcif_disable_rpm(struct rpcif *rpc)
+{
+ pm_runtime_put_sync(rpc->dev);
+}
+EXPORT_SYMBOL(rpcif_disable_rpm);
Should these go to header as static inlines?
Would be nice will make them inline and squash it in the current patch.

+static int wait_msg_xfer_end(struct rpcif *rpc)
+{
+ u32 sts;
+
+ return regmap_read_poll_timeout(rpc->regmap, RPCIF_CMNSR, sts,
+ sts & RPCIF_CMNSR_TEND, 0,
+ USEC_PER_SEC);
+}
This can't be right. sts is used uninitialized here.
Third parameter in regmap_read_poll_timeout() is the variable in which value is read and the fourth parameter condition has to be tied with the third parameter (there are similar instance in the kernel).

+int rpcif_manual_xfer(struct rpcif *rpc)
+{
+ default:
+ regmap_write(rpc->regmap, RPCIF_SMENR, rpc->enable);
+ regmap_write(rpc->regmap, RPCIF_SMCR,
+ rpc->smcr | RPCIF_SMCR_SPIE);
+ ret = wait_msg_xfer_end(rpc);
+ if (ret)
+ goto err_out;
+ }
+
+exit:
+ pm_runtime_put(rpc->dev);
+ return ret;
+
+err_out:
+ ret = reset_control_reset(rpc->rstc);
+ rpcif_hw_init(rpc, rpc->bus_size == 2);
+ goto exit;
+}
So we get failure in wait_msg_xfer_end(rpc); but then
reset_control_reset(rpc->rstc); returns success and whole function
returns success. Is that ok?
Good catch this needs fixing (upstream too).

+static int rpcif_probe(struct platform_device *pdev)
+{
+ struct platform_device *vdev;
+ struct device_node *flash;
+ const char *name;
+
+ flash = of_get_next_child(pdev->dev.of_node, NULL);
+ if (!flash) {
+ dev_warn(&pdev->dev, "no flash node found\n");
+ return -ENODEV;
+ }
Does this need corresponding of_node_put()?
Agreed this needs fixing (upstream too).

+struct rpcif_op {
Weird formatting; we normally use spaces (not tabs) for this.
Agreed will fix that.

+ struct {
+ u8 buswidth;
...
+ struct {
+ u8 ncycles;
+ u8 buswidth;
+ } dummy;
Are you sure this will be consistent accross architectures? Should the
structure be marked attribute packed or something?
Should be OK as this driver is intended only on R-Car Gen3 and RZ/G2x (arm64).

Cheers,
Prabhakar

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


Re: [PATCH 4.19.y-cip 7/7] spi: add Renesas RPC-IF driver

Pavel Machek
 

Hi!

commit eb8d6d464a27850498dced21a8450e85d4a02009 upstream.

Add the SPI driver for the Renesas RPC-IF. It's the "front end" driver
using the "back end" APIs in the main driver to talk to the real hardware.
We only implement the 'spi-mem' interface -- there's no need to implement
the usual SPI driver methods...

Based on the original patch by Mason Yang <masonccyang@...>.

Signed-off-by: Sergei Shtylyov <sergei.shtylyov@...>
Link: https://lore.kernel.org/r/1ece0e6c-71af-f0f1-709e-571f4b0b4853@cogentembedded.com
Signed-off-by: Mark Brown <broonie@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/spi/Kconfig | 6 ++
drivers/spi/Makefile | 1 +
drivers/spi/spi-rpc-if.c | 216 +++++++++++++++++++++++++++++++++++++++
3 files changed, 223 insertions(+)
create mode 100644 drivers/spi/spi-rpc-if.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 0a7fd56c1ed9..461315967f96 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -514,6 +514,12 @@ config SPI_RB4XX
help
SPI controller driver for the Mikrotik RB4xx series boards.

+config SPI_RPCIF
+ tristate "Renesas RPC-IF SPI driver"
+ depends on RENESAS_RPCIF
+ help
+ SPI driver for Renesas R-Car Gen3 RPC-IF.
Few lines here explaining the acronyms etc. would be nice.

+ error = spi_register_controller(ctlr);
+ if (error) {
+ dev_err(&pdev->dev, "spi_register_controller failed\n");
+ goto err_put_ctlr;
+ }
+ return 0;
+
+err_put_ctlr:
+ rpcif_disable_rpm(rpc);
+ spi_controller_put(ctlr);
+
+ return error;
+}
With just one user of the error exit, I'd avoid the goto.

+#ifdef CONFIG_PM_SLEEP
+static int rpcif_spi_suspend(struct device *dev)
+{
+ struct spi_controller *ctlr = dev_get_drvdata(dev);
+
+ return spi_controller_suspend(ctlr);
+}
+
+static int rpcif_spi_resume(struct device *dev)
+{
+ struct spi_controller *ctlr = dev_get_drvdata(dev);
+
+ return spi_controller_resume(ctlr);
+}
+
+static SIMPLE_DEV_PM_OPS(rpcif_spi_pm_ops, rpcif_spi_suspend, rpcif_spi_resume);
+#define DEV_PM_OPS (&rpcif_spi_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver rpcif_spi_driver = {
+ .probe = rpcif_spi_probe,
+ .remove = rpcif_spi_remove,
+ .driver = {
+ .name = "rpc-if-spi",
+ .pm = DEV_PM_OPS,
+ },
+};
Can you just add "__maybe_unused" annotation and avoid the ifdefs,
like atmel-quadspi.c does?

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


Re: [PATCH 4.19.y-cip 6/7] spi: spi-mem: Add a new API to support direct mapping

Pavel Machek
 

Hi!

commit aa167f3fed0c37e0e4c707d4331d827661f46644 upstream.

Most modern SPI controllers can directly map a SPI memory (or a portion
of the SPI memory) in the CPU address space. Most of the time this
brings significant performance improvements as it automates the whole
process of sending SPI memory operations every time a new region is
accessed.

This new API allows SPI memory drivers to create direct mappings and
then use them to access the memory instead of using
spi_mem_exec_op().
+ * Return: the amount of data read from the memory device or a negative error
+ * code. Note that the returned size might be smaller than @len, and the caller
+ * is responsible for calling spi_mem_dirmap_read() again when that happens.
+ */
+ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, void *buf)
+{
+ struct spi_controller *ctlr = desc->mem->spi->controller;
+ ssize_t ret;
+
+ if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
+ return -EINVAL;
+
+ if (!len)
+ return 0;
+
+ if (desc->nodirmap) {
+ ret = spi_mem_no_dirmap_read(desc, offs, len, buf);
I'd do return ... here.

+ } else if (ctlr->mem_ops && ctlr->mem_ops->dirmap_read) {
+ ret = spi_mem_access_start(desc->mem);
+ if (ret)
+ return ret;
+
+ ret = ctlr->mem_ops->dirmap_read(desc, offs, len, buf);
+
+ spi_mem_access_end(desc->mem);
and here.

+ } else {
+ ret = -ENOTSUPP;
+ }
To help with if/else nesting. spi_mem_dirmap_write could use same
treatment.

Best regards,
Pavel

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


Re: [PATCH 4.19.y-cip 5/7] spi: spi-mem: Split spi_mem_exec_op() code

Pavel Machek
 

Hi!

From: Boris Brezillon <boris.brezillon@...>

commit f86c24f4795303e4024bc113196de32782f6ccb5 upstream.

The logic surrounding the ->exec_op() call applies to direct mapping
accessors. Move this code to separate functions to avoid duplicating
code.
+++ b/drivers/spi/spi-mem.c
@@ -213,6 +213,44 @@ bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
}
EXPORT_SYMBOL_GPL(spi_mem_supports_op);

+static int spi_mem_access_start(struct spi_mem *mem)
+{
+ struct spi_controller *ctlr = mem->spi->controller;
...
+ if (ctlr->auto_runtime_pm) {
+ int ret;
+
+ ret = pm_runtime_get_sync(ctlr->dev.parent);
+ if (ret < 0) {
+ dev_err(&ctlr->dev, "Failed to power device: %d\n",
+ ret);
+ return ret;
+ }
This misses pm_runtime_put() in the error case.

+ mutex_lock(&ctlr->bus_lock_mutex);
+ mutex_lock(&ctlr->io_mutex);
Plus hiding locking into function like this ... is quite
"interesting".

Best regards,
Pavel

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


Re: [PATCH 4.19.y-cip 2/7] memory: add Renesas RPC-IF driver

Pavel Machek
 

Hi!

From: Sergei Shtylyov <sergei.shtylyov@...>
+int rpcif_manual_xfer(struct rpcif *rpc);
+ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf);
+
+#endif // __RENESAS_RPC_IF_H
Oh and I'd use normal C comment here.

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


Re: [PATCH 4.19.y-cip 2/7] memory: add Renesas RPC-IF driver

Pavel Machek
 

Hi!

+EXPORT_SYMBOL(rpcif_sw_init);
EXPORT_SYMBOL_GPL?

+void rpcif_enable_rpm(struct rpcif *rpc)
+{
+ pm_runtime_enable(rpc->dev);
+}
+EXPORT_SYMBOL(rpcif_enable_rpm);
+
+void rpcif_disable_rpm(struct rpcif *rpc)
+{
+ pm_runtime_put_sync(rpc->dev);
+}
+EXPORT_SYMBOL(rpcif_disable_rpm);
Should these go to header as static inlines?

+static int wait_msg_xfer_end(struct rpcif *rpc)
+{
+ u32 sts;
+
+ return regmap_read_poll_timeout(rpc->regmap, RPCIF_CMNSR, sts,
+ sts & RPCIF_CMNSR_TEND, 0,
+ USEC_PER_SEC);
+}
This can't be right. sts is used uninitialized here.

+int rpcif_manual_xfer(struct rpcif *rpc)
+{
+ default:
+ regmap_write(rpc->regmap, RPCIF_SMENR, rpc->enable);
+ regmap_write(rpc->regmap, RPCIF_SMCR,
+ rpc->smcr | RPCIF_SMCR_SPIE);
+ ret = wait_msg_xfer_end(rpc);
+ if (ret)
+ goto err_out;
+ }
+
+exit:
+ pm_runtime_put(rpc->dev);
+ return ret;
+
+err_out:
+ ret = reset_control_reset(rpc->rstc);
+ rpcif_hw_init(rpc, rpc->bus_size == 2);
+ goto exit;
+}
So we get failure in wait_msg_xfer_end(rpc); but then
reset_control_reset(rpc->rstc); returns success and whole function
returns success. Is that ok?

+static int rpcif_probe(struct platform_device *pdev)
+{
+ struct platform_device *vdev;
+ struct device_node *flash;
+ const char *name;
+
+ flash = of_get_next_child(pdev->dev.of_node, NULL);
+ if (!flash) {
+ dev_warn(&pdev->dev, "no flash node found\n");
+ return -ENODEV;
+ }
Does this need corresponding of_node_put()?

+struct rpcif_op {
Weird formatting; we normally use spaces (not tabs) for this.

+ struct {
+ u8 buswidth;
...
+ struct {
+ u8 ncycles;
+ u8 buswidth;
+ } dummy;
Are you sure this will be consistent accross architectures? Should the
structure be marked attribute packed or something?

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


A lot of compiles failing

Pavel Machek
 

Hi!

This is going on for a few days now, but today it seems worse than
usual:

https://gitlab.com/cip-project/cip-kernel/linux-cip/-/pipelines/220169843

builds are failing, 'HTTP 500 curl 22' error, so not a real build
problem. I can probably just click restart... 6 times. But something
is not there, and it is getting worse.

Best regards,
Pavel


g for pod gitlab/runner-bcrayztp-project-2678032-concurrent-7hmhsr to be running, status is Pending
74Running on runner-bcrayztp-project-2678032-concurrent-7hmhsr via cip-project-v3-gitlab-runner-6dbd79945f-wdqqw...
76
Fetching changes with git depth set to 10...
00:18
77Initialized empty Git repository in /builds/cip-project/cip-kernel/linux-cip/.git/
78Created fresh repository.
79error: RPC failed; HTTP 500 curl 22 The requested URL returned error: 500
80fatal: the remote end hung up unexpectedly
82
Uploading artifacts...
00:00
83WARNING: output: no matching files
84ERROR: No files to upload
86ERROR: Job failed: command terminated with exit code 1
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: [PATCH 4.19.y-cip 0/2] Add sound support to R8A774E1 SoC

Pavel Machek
 

Hi!

This patch series adds sound support to Renesas R8A774E1 SoC.

All the patches have been cherry picked from Linux v5.10-rc5.
I don't see any problems here. If there are no other comments, I can
apply it.

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


Re: [PATCH 4.19.y-cip 0/7] Add RPC-IF driver for RZ/G2x SoC's

Lad Prabhakar
 

Hi,

-----Original Message-----
From: cip-dev@... <cip-dev@...> On Behalf Of Lad Prabhakar via
lists.cip-project.org
Sent: 23 November 2020 12:04
To: cip-dev@...; Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@...>; Pavel Machek
<pavel@...>
Cc: Biju Das <biju.das.jz@...>
Subject: [cip-dev] [PATCH 4.19.y-cip 0/7] Add RPC-IF driver for RZ/G2x SoC's

Hi Nobuhiro, Pavel,

This patch series adds SPI driver for the Renesas RPC-IF.
Alongside relevant changes for spi-mem have been also
backported. This enables accessing SPI flash chip connected
to RPC-IF on RZ/G2x boards.

We currently only aim to backport just the driver hence there
are no changes to dts/i files. The driver has been tested on
RZ/G2{EM} (I shall reply to this e-mail with the results) with
all the required dts/i changes [1].
Attached are the test results for RZ/G2{EM}.

Cheers,
Prabhakar

Currently we are upstreaming clock [2] and pinctrl [3] changes
required for RPC-IF interface on RZ/G2x SoC's once that hits
v5.11 we shall backport it.

All the patches have been cherry picked from Linux 5.9-rc5.

[1]
https://jpn01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fprabhakarlad%2Fcip%2Fco
mmits%2Fmaster&amp;data=04%7C01%7Cprabhakar.mahadev-
lad.rj%40bp.renesas.com%7C8e71f2e5942e45872a1108d88fa7dd65%7C53d82571da1947e49cb4625a166a4a2a%7C0%7C0%
7C637417298430851440%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXV
CI6Mn0%3D%7C1000&amp;sdata=DZWkJ8%2FDxbajvUrYyXqmCbZupzJVlbp4X4Uv41ziYDg%3D&amp;reserved=0
[2]
https://jpn01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fproject%2Flin
ux-renesas-soc%2Flist%2F%3Fseries%3D365697&amp;data=04%7C01%7Cprabhakar.mahadev-
lad.rj%40bp.renesas.com%7C8e71f2e5942e45872a1108d88fa7dd65%7C53d82571da1947e49cb4625a166a4a2a%7C0%7C0%
7C637417298430861437%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXV
CI6Mn0%3D%7C1000&amp;sdata=vXiHtwxTw2n7Bdug0YuaGoz%2FojdV4i2LW60ahxdvndU%3D&amp;reserved=0
[3]
https://jpn01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fproject%2Flin
ux-renesas-soc%2Flist%2F%3Fseries%3D387535&amp;data=04%7C01%7Cprabhakar.mahadev-
lad.rj%40bp.renesas.com%7C8e71f2e5942e45872a1108d88fa7dd65%7C53d82571da1947e49cb4625a166a4a2a%7C0%7C0%
7C637417298430861437%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXV
CI6Mn0%3D%7C1000&amp;sdata=CSlWNaoxlVedSnTXGQuZeZ2rNap1p8YQcA5VrnDfFbM%3D&amp;reserved=0

Cheers,
Prabhakar

Boris Brezillon (3):
spi: spi-mem: Add SPI_MEM_NO_DATA to the spi_mem_data_dir enum
spi: spi-mem: Split spi_mem_exec_op() code
spi: spi-mem: Add a new API to support direct mapping

Naga Sureshkumar Relli (1):
spi: spi-mem: export spi_mem_default_supports_op()

Sergei Shtylyov (3):
dt-bindings: memory: document Renesas RPC-IF bindings
memory: add Renesas RPC-IF driver
spi: add Renesas RPC-IF driver

.../memory-controllers/renesas,rpc-if.yaml | 88 +++
drivers/memory/Kconfig | 9 +
drivers/memory/Makefile | 1 +
drivers/memory/renesas-rpc-if.c | 603 ++++++++++++++++++
drivers/spi/Kconfig | 6 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-mem.c | 273 +++++++-
drivers/spi/spi-rpc-if.c | 216 +++++++
include/linux/spi/spi-mem.h | 93 +++
include/memory/renesas-rpc-if.h | 87 +++
10 files changed, 1353 insertions(+), 24 deletions(-)
create mode 100644 Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml
create mode 100644 drivers/memory/renesas-rpc-if.c
create mode 100644 drivers/spi/spi-rpc-if.c
create mode 100644 include/memory/renesas-rpc-if.h

--
2.17.1


[PATCH 4.19.y-cip 7/7] spi: add Renesas RPC-IF driver

Lad Prabhakar
 

From: Sergei Shtylyov <sergei.shtylyov@...>

commit eb8d6d464a27850498dced21a8450e85d4a02009 upstream.

Add the SPI driver for the Renesas RPC-IF. It's the "front end" driver
using the "back end" APIs in the main driver to talk to the real hardware.
We only implement the 'spi-mem' interface -- there's no need to implement
the usual SPI driver methods...

Based on the original patch by Mason Yang <masonccyang@...>.

Signed-off-by: Sergei Shtylyov <sergei.shtylyov@...>
Link: https://lore.kernel.org/r/1ece0e6c-71af-f0f1-709e-571f4b0b4853@cogentembedded.com
Signed-off-by: Mark Brown <broonie@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/spi/Kconfig | 6 ++
drivers/spi/Makefile | 1 +
drivers/spi/spi-rpc-if.c | 216 +++++++++++++++++++++++++++++++++++++++
3 files changed, 223 insertions(+)
create mode 100644 drivers/spi/spi-rpc-if.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 0a7fd56c1ed9..461315967f96 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -514,6 +514,12 @@ config SPI_RB4XX
help
SPI controller driver for the Mikrotik RB4xx series boards.

+config SPI_RPCIF
+ tristate "Renesas RPC-IF SPI driver"
+ depends on RENESAS_RPCIF
+ help
+ SPI driver for Renesas R-Car Gen3 RPC-IF.
+
config SPI_RSPI
tristate "Renesas RSPI/QSPI controller"
depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index a90d55970036..e0b5478fde62 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
+obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
spi-s3c24xx-hw-y := spi-s3c24xx.o
diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c
new file mode 100644
index 000000000000..ed3e548227f4
--- /dev/null
+++ b/drivers/spi/spi-rpc-if.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// RPC-IF SPI/QSPI/Octa driver
+//
+// Copyright (C) 2018 ~ 2019 Renesas Solutions Corp.
+// Copyright (C) 2019 Macronix International Co., Ltd.
+// Copyright (C) 2019 - 2020 Cogent Embedded, Inc.
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+
+#include <memory/renesas-rpc-if.h>
+
+#include <asm/unaligned.h>
+
+static void rpcif_spi_mem_prepare(struct spi_device *spi_dev,
+ const struct spi_mem_op *spi_op,
+ u64 *offs, size_t *len)
+{
+ struct rpcif *rpc = spi_controller_get_devdata(spi_dev->controller);
+ struct rpcif_op rpc_op = { };
+
+ rpc_op.cmd.opcode = spi_op->cmd.opcode;
+ rpc_op.cmd.buswidth = spi_op->cmd.buswidth;
+
+ if (spi_op->addr.nbytes) {
+ rpc_op.addr.buswidth = spi_op->addr.buswidth;
+ rpc_op.addr.nbytes = spi_op->addr.nbytes;
+ rpc_op.addr.val = spi_op->addr.val;
+ }
+
+ if (spi_op->dummy.nbytes) {
+ rpc_op.dummy.buswidth = spi_op->dummy.buswidth;
+ rpc_op.dummy.ncycles = spi_op->dummy.nbytes * 8 /
+ spi_op->dummy.buswidth;
+ }
+
+ if (spi_op->data.nbytes || (offs && len)) {
+ rpc_op.data.buswidth = spi_op->data.buswidth;
+ rpc_op.data.nbytes = spi_op->data.nbytes;
+ switch (spi_op->data.dir) {
+ case SPI_MEM_DATA_IN:
+ rpc_op.data.dir = RPCIF_DATA_IN;
+ rpc_op.data.buf.in = spi_op->data.buf.in;
+ break;
+ case SPI_MEM_DATA_OUT:
+ rpc_op.data.dir = RPCIF_DATA_OUT;
+ rpc_op.data.buf.out = spi_op->data.buf.out;
+ break;
+ case SPI_MEM_NO_DATA:
+ rpc_op.data.dir = RPCIF_NO_DATA;
+ break;
+ }
+ } else {
+ rpc_op.data.dir = RPCIF_NO_DATA;
+ }
+
+ rpcif_prepare(rpc, &rpc_op, offs, len);
+}
+
+static bool rpcif_spi_mem_supports_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ if (!spi_mem_default_supports_op(mem, op))
+ return false;
+
+ if (op->data.buswidth > 4 || op->addr.buswidth > 4 ||
+ op->dummy.buswidth > 4 || op->cmd.buswidth > 4 ||
+ op->addr.nbytes > 4)
+ return false;
+
+ return true;
+}
+
+static ssize_t rpcif_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, void *buf)
+{
+ struct rpcif *rpc =
+ spi_controller_get_devdata(desc->mem->spi->controller);
+
+ if (offs + desc->info.offset + len > U32_MAX)
+ return -EINVAL;
+
+ rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len);
+
+ return rpcif_dirmap_read(rpc, offs, len, buf);
+}
+
+static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
+{
+ struct rpcif *rpc =
+ spi_controller_get_devdata(desc->mem->spi->controller);
+
+ if (desc->info.offset + desc->info.length > U32_MAX)
+ return -ENOTSUPP;
+
+ if (!rpcif_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
+ return -ENOTSUPP;
+
+ if (!rpc->dirmap && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN)
+ return -ENOTSUPP;
+
+ if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT)
+ return -ENOTSUPP;
+
+ return 0;
+}
+
+static int rpcif_spi_mem_exec_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ struct rpcif *rpc =
+ spi_controller_get_devdata(mem->spi->controller);
+
+ rpcif_spi_mem_prepare(mem->spi, op, NULL, NULL);
+
+ return rpcif_manual_xfer(rpc);
+}
+
+static const struct spi_controller_mem_ops rpcif_spi_mem_ops = {
+ .supports_op = rpcif_spi_mem_supports_op,
+ .exec_op = rpcif_spi_mem_exec_op,
+ .dirmap_create = rpcif_spi_mem_dirmap_create,
+ .dirmap_read = rpcif_spi_mem_dirmap_read,
+};
+
+static int rpcif_spi_probe(struct platform_device *pdev)
+{
+ struct device *parent = pdev->dev.parent;
+ struct spi_controller *ctlr;
+ struct rpcif *rpc;
+ int error;
+
+ ctlr = spi_alloc_master(&pdev->dev, sizeof(*rpc));
+ if (!ctlr)
+ return -ENOMEM;
+
+ rpc = spi_controller_get_devdata(ctlr);
+ rpcif_sw_init(rpc, parent);
+
+ platform_set_drvdata(pdev, ctlr);
+
+ ctlr->dev.of_node = parent->of_node;
+
+ rpcif_enable_rpm(rpc);
+
+ ctlr->num_chipselect = 1;
+ ctlr->mem_ops = &rpcif_spi_mem_ops;
+
+ ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
+ ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_QUAD | SPI_RX_QUAD;
+ ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
+
+ rpcif_hw_init(rpc, false);
+
+ error = spi_register_controller(ctlr);
+ if (error) {
+ dev_err(&pdev->dev, "spi_register_controller failed\n");
+ goto err_put_ctlr;
+ }
+ return 0;
+
+err_put_ctlr:
+ rpcif_disable_rpm(rpc);
+ spi_controller_put(ctlr);
+
+ return error;
+}
+
+static int rpcif_spi_remove(struct platform_device *pdev)
+{
+ struct spi_controller *ctlr = platform_get_drvdata(pdev);
+ struct rpcif *rpc = spi_controller_get_devdata(ctlr);
+
+ spi_unregister_controller(ctlr);
+ rpcif_disable_rpm(rpc);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int rpcif_spi_suspend(struct device *dev)
+{
+ struct spi_controller *ctlr = dev_get_drvdata(dev);
+
+ return spi_controller_suspend(ctlr);
+}
+
+static int rpcif_spi_resume(struct device *dev)
+{
+ struct spi_controller *ctlr = dev_get_drvdata(dev);
+
+ return spi_controller_resume(ctlr);
+}
+
+static SIMPLE_DEV_PM_OPS(rpcif_spi_pm_ops, rpcif_spi_suspend, rpcif_spi_resume);
+#define DEV_PM_OPS (&rpcif_spi_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver rpcif_spi_driver = {
+ .probe = rpcif_spi_probe,
+ .remove = rpcif_spi_remove,
+ .driver = {
+ .name = "rpc-if-spi",
+ .pm = DEV_PM_OPS,
+ },
+};
+module_platform_driver(rpcif_spi_driver);
+
+MODULE_DESCRIPTION("Renesas RPC-IF SPI driver");
+MODULE_LICENSE("GPL v2");
--
2.17.1


[PATCH 4.19.y-cip 6/7] spi: spi-mem: Add a new API to support direct mapping

Lad Prabhakar
 

From: Boris Brezillon <boris.brezillon@...>

commit aa167f3fed0c37e0e4c707d4331d827661f46644 upstream.

Most modern SPI controllers can directly map a SPI memory (or a portion
of the SPI memory) in the CPU address space. Most of the time this
brings significant performance improvements as it automates the whole
process of sending SPI memory operations every time a new region is
accessed.

This new API allows SPI memory drivers to create direct mappings and
then use them to access the memory instead of using spi_mem_exec_op().

Signed-off-by: Boris Brezillon <boris.brezillon@...>
Reviewed-by: Miquel Raynal <miquel.raynal@...>
Signed-off-by: Mark Brown <broonie@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/spi/spi-mem.c | 204 ++++++++++++++++++++++++++++++++++++
include/linux/spi/spi-mem.h | 80 ++++++++++++++
2 files changed, 284 insertions(+)

diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 0908f979f6a8..349ab2077f19 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -432,6 +432,210 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
}
EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);

+static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, void *buf)
+{
+ struct spi_mem_op op = desc->info.op_tmpl;
+ int ret;
+
+ op.addr.val = desc->info.offset + offs;
+ op.data.buf.in = buf;
+ op.data.nbytes = len;
+ ret = spi_mem_adjust_op_size(desc->mem, &op);
+ if (ret)
+ return ret;
+
+ ret = spi_mem_exec_op(desc->mem, &op);
+ if (ret)
+ return ret;
+
+ return op.data.nbytes;
+}
+
+static ssize_t spi_mem_no_dirmap_write(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, const void *buf)
+{
+ struct spi_mem_op op = desc->info.op_tmpl;
+ int ret;
+
+ op.addr.val = desc->info.offset + offs;
+ op.data.buf.out = buf;
+ op.data.nbytes = len;
+ ret = spi_mem_adjust_op_size(desc->mem, &op);
+ if (ret)
+ return ret;
+
+ ret = spi_mem_exec_op(desc->mem, &op);
+ if (ret)
+ return ret;
+
+ return op.data.nbytes;
+}
+
+/**
+ * spi_mem_dirmap_create() - Create a direct mapping descriptor
+ * @mem: SPI mem device this direct mapping should be created for
+ * @info: direct mapping information
+ *
+ * This function is creating a direct mapping descriptor which can then be used
+ * to access the memory using spi_mem_dirmap_read() or spi_mem_dirmap_write().
+ * If the SPI controller driver does not support direct mapping, this function
+ * fallback to an implementation using spi_mem_exec_op(), so that the caller
+ * doesn't have to bother implementing a fallback on his own.
+ *
+ * Return: a valid pointer in case of success, and ERR_PTR() otherwise.
+ */
+struct spi_mem_dirmap_desc *
+spi_mem_dirmap_create(struct spi_mem *mem,
+ const struct spi_mem_dirmap_info *info)
+{
+ struct spi_controller *ctlr = mem->spi->controller;
+ struct spi_mem_dirmap_desc *desc;
+ int ret = -ENOTSUPP;
+
+ /* Make sure the number of address cycles is between 1 and 8 bytes. */
+ if (!info->op_tmpl.addr.nbytes || info->op_tmpl.addr.nbytes > 8)
+ return ERR_PTR(-EINVAL);
+
+ /* data.dir should either be SPI_MEM_DATA_IN or SPI_MEM_DATA_OUT. */
+ if (info->op_tmpl.data.dir == SPI_MEM_NO_DATA)
+ return ERR_PTR(-EINVAL);
+
+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return ERR_PTR(-ENOMEM);
+
+ desc->mem = mem;
+ desc->info = *info;
+ if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create)
+ ret = ctlr->mem_ops->dirmap_create(desc);
+
+ if (ret) {
+ desc->nodirmap = true;
+ if (!spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
+ ret = -ENOTSUPP;
+ else
+ ret = 0;
+ }
+
+ if (ret) {
+ kfree(desc);
+ return ERR_PTR(ret);
+ }
+
+ return desc;
+}
+EXPORT_SYMBOL_GPL(spi_mem_dirmap_create);
+
+/**
+ * spi_mem_dirmap_destroy() - Destroy a direct mapping descriptor
+ * @desc: the direct mapping descriptor to destroy
+ * @info: direct mapping information
+ *
+ * This function destroys a direct mapping descriptor previously created by
+ * spi_mem_dirmap_create().
+ */
+void spi_mem_dirmap_destroy(struct spi_mem_dirmap_desc *desc)
+{
+ struct spi_controller *ctlr = desc->mem->spi->controller;
+
+ if (!desc->nodirmap && ctlr->mem_ops && ctlr->mem_ops->dirmap_destroy)
+ ctlr->mem_ops->dirmap_destroy(desc);
+}
+EXPORT_SYMBOL_GPL(spi_mem_dirmap_destroy);
+
+/**
+ * spi_mem_dirmap_dirmap_read() - Read data through a direct mapping
+ * @desc: direct mapping descriptor
+ * @offs: offset to start reading from. Note that this is not an absolute
+ * offset, but the offset within the direct mapping which already has
+ * its own offset
+ * @len: length in bytes
+ * @buf: destination buffer. This buffer must be DMA-able
+ *
+ * This function reads data from a memory device using a direct mapping
+ * previously instantiated with spi_mem_dirmap_create().
+ *
+ * Return: the amount of data read from the memory device or a negative error
+ * code. Note that the returned size might be smaller than @len, and the caller
+ * is responsible for calling spi_mem_dirmap_read() again when that happens.
+ */
+ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, void *buf)
+{
+ struct spi_controller *ctlr = desc->mem->spi->controller;
+ ssize_t ret;
+
+ if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
+ return -EINVAL;
+
+ if (!len)
+ return 0;
+
+ if (desc->nodirmap) {
+ ret = spi_mem_no_dirmap_read(desc, offs, len, buf);
+ } else if (ctlr->mem_ops && ctlr->mem_ops->dirmap_read) {
+ ret = spi_mem_access_start(desc->mem);
+ if (ret)
+ return ret;
+
+ ret = ctlr->mem_ops->dirmap_read(desc, offs, len, buf);
+
+ spi_mem_access_end(desc->mem);
+ } else {
+ ret = -ENOTSUPP;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(spi_mem_dirmap_read);
+
+/**
+ * spi_mem_dirmap_dirmap_write() - Write data through a direct mapping
+ * @desc: direct mapping descriptor
+ * @offs: offset to start writing from. Note that this is not an absolute
+ * offset, but the offset within the direct mapping which already has
+ * its own offset
+ * @len: length in bytes
+ * @buf: source buffer. This buffer must be DMA-able
+ *
+ * This function writes data to a memory device using a direct mapping
+ * previously instantiated with spi_mem_dirmap_create().
+ *
+ * Return: the amount of data written to the memory device or a negative error
+ * code. Note that the returned size might be smaller than @len, and the caller
+ * is responsible for calling spi_mem_dirmap_write() again when that happens.
+ */
+ssize_t spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, const void *buf)
+{
+ struct spi_controller *ctlr = desc->mem->spi->controller;
+ ssize_t ret;
+
+ if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_OUT)
+ return -EINVAL;
+
+ if (!len)
+ return 0;
+
+ if (desc->nodirmap) {
+ ret = spi_mem_no_dirmap_write(desc, offs, len, buf);
+ } else if (ctlr->mem_ops && ctlr->mem_ops->dirmap_write) {
+ ret = spi_mem_access_start(desc->mem);
+ if (ret)
+ return ret;
+
+ ret = ctlr->mem_ops->dirmap_write(desc, offs, len, buf);
+
+ spi_mem_access_end(desc->mem);
+ } else {
+ ret = -ENOTSUPP;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(spi_mem_dirmap_write);
+
static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv)
{
return container_of(drv, struct spi_mem_driver, spidrv.driver);
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 253a8d451d4c..762b3974cf9c 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -124,6 +124,49 @@ struct spi_mem_op {
.data = __data, \
}

+/**
+ * struct spi_mem_dirmap_info - Direct mapping information
+ * @op_tmpl: operation template that should be used by the direct mapping when
+ * the memory device is accessed
+ * @offset: absolute offset this direct mapping is pointing to
+ * @length: length in byte of this direct mapping
+ *
+ * These information are used by the controller specific implementation to know
+ * the portion of memory that is directly mapped and the spi_mem_op that should
+ * be used to access the device.
+ * A direct mapping is only valid for one direction (read or write) and this
+ * direction is directly encoded in the ->op_tmpl.data.dir field.
+ */
+struct spi_mem_dirmap_info {
+ struct spi_mem_op op_tmpl;
+ u64 offset;
+ u64 length;
+};
+
+/**
+ * struct spi_mem_dirmap_desc - Direct mapping descriptor
+ * @mem: the SPI memory device this direct mapping is attached to
+ * @info: information passed at direct mapping creation time
+ * @nodirmap: set to 1 if the SPI controller does not implement
+ * ->mem_ops->dirmap_create() or when this function returned an
+ * error. If @nodirmap is true, all spi_mem_dirmap_{read,write}()
+ * calls will use spi_mem_exec_op() to access the memory. This is a
+ * degraded mode that allows spi_mem drivers to use the same code
+ * no matter whether the controller supports direct mapping or not
+ * @priv: field pointing to controller specific data
+ *
+ * Common part of a direct mapping descriptor. This object is created by
+ * spi_mem_dirmap_create() and controller implementation of ->create_dirmap()
+ * can create/attach direct mapping resources to the descriptor in the ->priv
+ * field.
+ */
+struct spi_mem_dirmap_desc {
+ struct spi_mem *mem;
+ struct spi_mem_dirmap_info info;
+ unsigned int nodirmap;
+ void *priv;
+};
+
/**
* struct spi_mem - describes a SPI memory device
* @spi: the underlying SPI device
@@ -179,10 +222,32 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
* Note that if the implementation of this function allocates memory
* dynamically, then it should do so with devm_xxx(), as we don't
* have a ->free_name() function.
+ * @dirmap_create: create a direct mapping descriptor that can later be used to
+ * access the memory device. This method is optional
+ * @dirmap_destroy: destroy a memory descriptor previous created by
+ * ->dirmap_create()
+ * @dirmap_read: read data from the memory device using the direct mapping
+ * created by ->dirmap_create(). The function can return less
+ * data than requested (for example when the request is crossing
+ * the currently mapped area), and the caller of
+ * spi_mem_dirmap_read() is responsible for calling it again in
+ * this case.
+ * @dirmap_write: write data to the memory device using the direct mapping
+ * created by ->dirmap_create(). The function can return less
+ * data than requested (for example when the request is crossing
+ * the currently mapped area), and the caller of
+ * spi_mem_dirmap_write() is responsible for calling it again in
+ * this case.
*
* This interface should be implemented by SPI controllers providing an
* high-level interface to execute SPI memory operation, which is usually the
* case for QSPI controllers.
+ *
+ * Note on ->dirmap_{read,write}(): drivers should avoid accessing the direct
+ * mapping from the CPU because doing that can stall the CPU waiting for the
+ * SPI mem transaction to finish, and this will make real-time maintainers
+ * unhappy and might make your system less reactive. Instead, drivers should
+ * use DMA to access this direct mapping.
*/
struct spi_controller_mem_ops {
int (*adjust_op_size)(struct spi_mem *mem, struct spi_mem_op *op);
@@ -191,6 +256,12 @@ struct spi_controller_mem_ops {
int (*exec_op)(struct spi_mem *mem,
const struct spi_mem_op *op);
const char *(*get_name)(struct spi_mem *mem);
+ int (*dirmap_create)(struct spi_mem_dirmap_desc *desc);
+ void (*dirmap_destroy)(struct spi_mem_dirmap_desc *desc);
+ ssize_t (*dirmap_read)(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, void *buf);
+ ssize_t (*dirmap_write)(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, const void *buf);
};

/**
@@ -262,6 +333,15 @@ int spi_mem_exec_op(struct spi_mem *mem,

const char *spi_mem_get_name(struct spi_mem *mem);

+struct spi_mem_dirmap_desc *
+spi_mem_dirmap_create(struct spi_mem *mem,
+ const struct spi_mem_dirmap_info *info);
+void spi_mem_dirmap_destroy(struct spi_mem_dirmap_desc *desc);
+ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, void *buf);
+ssize_t spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, const void *buf);
+
int spi_mem_driver_register_with_owner(struct spi_mem_driver *drv,
struct module *owner);

--
2.17.1


[PATCH 4.19.y-cip 5/7] spi: spi-mem: Split spi_mem_exec_op() code

Lad Prabhakar
 

From: Boris Brezillon <boris.brezillon@...>

commit f86c24f4795303e4024bc113196de32782f6ccb5 upstream.

The logic surrounding the ->exec_op() call applies to direct mapping
accessors. Move this code to separate functions to avoid duplicating
code.

Signed-off-by: Boris Brezillon <boris.brezillon@...>
Reviewed-by: Miquel Raynal <miquel.raynal@...>
Signed-off-by: Mark Brown <broonie@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/spi/spi-mem.c | 63 ++++++++++++++++++++++++++++---------------
1 file changed, 42 insertions(+), 21 deletions(-)

diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index b319a9f0138c..0908f979f6a8 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -213,6 +213,44 @@ bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
}
EXPORT_SYMBOL_GPL(spi_mem_supports_op);

+static int spi_mem_access_start(struct spi_mem *mem)
+{
+ struct spi_controller *ctlr = mem->spi->controller;
+
+ /*
+ * Flush the message queue before executing our SPI memory
+ * operation to prevent preemption of regular SPI transfers.
+ */
+ spi_flush_queue(ctlr);
+
+ if (ctlr->auto_runtime_pm) {
+ int ret;
+
+ ret = pm_runtime_get_sync(ctlr->dev.parent);
+ if (ret < 0) {
+ dev_err(&ctlr->dev, "Failed to power device: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ mutex_lock(&ctlr->bus_lock_mutex);
+ mutex_lock(&ctlr->io_mutex);
+
+ return 0;
+}
+
+static void spi_mem_access_end(struct spi_mem *mem)
+{
+ struct spi_controller *ctlr = mem->spi->controller;
+
+ mutex_unlock(&ctlr->io_mutex);
+ mutex_unlock(&ctlr->bus_lock_mutex);
+
+ if (ctlr->auto_runtime_pm)
+ pm_runtime_put(ctlr->dev.parent);
+}
+
/**
* spi_mem_exec_op() - Execute a memory operation
* @mem: the SPI memory
@@ -242,30 +280,13 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
return -ENOTSUPP;

if (ctlr->mem_ops) {
- /*
- * Flush the message queue before executing our SPI memory
- * operation to prevent preemption of regular SPI transfers.
- */
- spi_flush_queue(ctlr);
-
- if (ctlr->auto_runtime_pm) {
- ret = pm_runtime_get_sync(ctlr->dev.parent);
- if (ret < 0) {
- dev_err(&ctlr->dev,
- "Failed to power device: %d\n",
- ret);
- return ret;
- }
- }
+ ret = spi_mem_access_start(mem);
+ if (ret)
+ return ret;

- mutex_lock(&ctlr->bus_lock_mutex);
- mutex_lock(&ctlr->io_mutex);
ret = ctlr->mem_ops->exec_op(mem, op);
- mutex_unlock(&ctlr->io_mutex);
- mutex_unlock(&ctlr->bus_lock_mutex);

- if (ctlr->auto_runtime_pm)
- pm_runtime_put(ctlr->dev.parent);
+ spi_mem_access_end(mem);

/*
* Some controllers only optimize specific paths (typically the
--
2.17.1


[PATCH 4.19.y-cip 4/7] spi: spi-mem: export spi_mem_default_supports_op()

Lad Prabhakar
 

From: Naga Sureshkumar Relli <naga.sureshkumar.relli@...>

commit 46109648052fe778c75f199d72255c899578d6f7 upstream.

Export spi_mem_default_supports_op(), so that controller drivers
can use this.
spi-mem driver already exports this using EXPORT_SYMBOL,
but not declared it in spi-mem.h.
This patch declares spi_mem_default_supports_op() in spi-mem.h and
also removes the static from the function prototype.

This patch also squashes upstream commit 72e6841608b9 ("spi: spi-mem: Fix
build error without CONFIG_SPI_MEM")' in the current patch as commit
46109648052f ("spi: spi-mem: export spi_mem_default_supports_op()")'
introduced below build error when built without CONFIG_SPI_MEM:

drivers/spi/spi-zynq-qspi.o: In function `zynq_qspi_supports_op':
spi-zynq-qspi.c:(.text+0x1da): undefined reference to `spi_mem_default_supports_op'

Signed-off-by: Naga Sureshkumar Relli <naga.sureshkumar.relli@...>
Signed-off-by: Mark Brown <broonie@...>
Signed-off-by: YueHaibing <yuehaibing@...>
Signed-off-by: Mark Brown <broonie@...>
[PL: manually applied the changes, squashed commit 72e6841608b9
("spi: spi-mem: Fix build error without CONFIG_SPI_MEM")' in current patch]
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/spi/spi-mem.c | 4 ++--
include/linux/spi/spi-mem.h | 11 +++++++++++
2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 967f581bca4f..b319a9f0138c 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -128,8 +128,8 @@ static int spi_check_buswidth_req(struct spi_mem *mem, u8 buswidth, bool tx)
return -ENOTSUPP;
}

-static bool spi_mem_default_supports_op(struct spi_mem *mem,
- const struct spi_mem_op *op)
+bool spi_mem_default_supports_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
{
if (spi_check_buswidth_req(mem, op->cmd.buswidth, true))
return false;
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 80db2de83402..253a8d451d4c 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -224,6 +224,10 @@ int spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr,
void spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
const struct spi_mem_op *op,
struct sg_table *sg);
+
+bool spi_mem_default_supports_op(struct spi_mem *mem,
+ const struct spi_mem_op *op);
+
#else
static inline int
spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr,
@@ -239,6 +243,13 @@ spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
struct sg_table *sg)
{
}
+
+bool spi_mem_default_supports_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ return false;
+}
+
#endif /* CONFIG_SPI_MEM */

int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op);
--
2.17.1


[PATCH 4.19.y-cip 3/7] spi: spi-mem: Add SPI_MEM_NO_DATA to the spi_mem_data_dir enum

Lad Prabhakar
 

From: Boris Brezillon <boris.brezillon@...>

commit 0ebb261a0b2d090de618a383d2378d4a00834958 upstream.

When defining spi_mem_op templates we don't necessarily know the size
that will be passed when the template is actually used, and basing the
supports_op() check on op->data.nbytes to know whether there will be
data transferred for a specific operation is this not possible.

Add SPI_MEM_NO_DATA to the spi_mem_data_dir enum so that we can base
our checks on op->data.dir instead of op->data.nbytes.

Signed-off-by: Boris Brezillon <boris.brezillon@...>
Reviewed-by: Miquel Raynal <miquel.raynal@...>
Signed-off-by: Mark Brown <broonie@...>
[PL: manually applied the changes]
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/spi/spi-mem.c | 2 +-
include/linux/spi/spi-mem.h | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 62a7b80801d2..967f581bca4f 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -142,7 +142,7 @@ static bool spi_mem_default_supports_op(struct spi_mem *mem,
spi_check_buswidth_req(mem, op->dummy.buswidth, true))
return false;

- if (op->data.nbytes &&
+ if (op->data.dir != SPI_MEM_NO_DATA &&
spi_check_buswidth_req(mem, op->data.buswidth,
op->data.dir == SPI_MEM_DATA_OUT))
return false;
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 69ee30456864..80db2de83402 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -57,10 +57,12 @@
/**
* enum spi_mem_data_dir - describes the direction of a SPI memory data
* transfer from the controller perspective
+ * @SPI_MEM_NO_DATA: no data transferred
* @SPI_MEM_DATA_IN: data coming from the SPI memory
* @SPI_MEM_DATA_OUT: data sent the SPI memory
*/
enum spi_mem_data_dir {
+ SPI_MEM_NO_DATA,
SPI_MEM_DATA_IN,
SPI_MEM_DATA_OUT,
};
--
2.17.1

4321 - 4340 of 10158