diff mbox series

[v2,2/9] mtd: rawnand: brcmnand: Allow SoC to provide I/O operations

Message ID 20220107001328.2233896-3-f.fainelli@gmail.com (mailing list archive)
State Not Applicable
Delegated to: Johannes Berg
Headers show
Series BCMA support for brcmnand | expand

Commit Message

Florian Fainelli Jan. 7, 2022, 12:13 a.m. UTC
Allow a brcmnand_soc instance to provide a custom set of I/O operations
which we will require when using this driver on a BCMA bus which is not
directly memory mapped I/O. Update the nand_{read,write}_reg accordingly
to use the SoC operations if provided.

To minimize the penalty on other SoCs which do support standard MMIO
accesses, we use a static key which is disabled by default and gets
enabled if a soc implementation does provide I/O operations.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/mtd/nand/raw/brcmnand/brcmnand.c | 30 ++++++++++++++++++++++--
 drivers/mtd/nand/raw/brcmnand/brcmnand.h | 29 +++++++++++++++++++++++
 2 files changed, 57 insertions(+), 2 deletions(-)

Comments

Florian Fainelli Jan. 7, 2022, 3:10 a.m. UTC | #1
On 1/6/2022 4:13 PM, Florian Fainelli wrote:
> Allow a brcmnand_soc instance to provide a custom set of I/O operations
> which we will require when using this driver on a BCMA bus which is not
> directly memory mapped I/O. Update the nand_{read,write}_reg accordingly
> to use the SoC operations if provided.
> 
> To minimize the penalty on other SoCs which do support standard MMIO
> accesses, we use a static key which is disabled by default and gets
> enabled if a soc implementation does provide I/O operations.
> 
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> ---

[snip]

>   	init_completion(&ctrl->done);
>   	init_completion(&ctrl->dma_done);
>   	init_completion(&ctrl->edu_done);
> @@ -3145,6 +3169,8 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
>   		/* Enable interrupt */
>   		ctrl->soc->ctlrdy_ack(ctrl->soc);
>   		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
> +		if (brcmnand_soc_has_ops(soc))
> +			static_branch_enable(&brcmnand_soc_has_ops_key);

This hunk got mistakenly added with a rebase, I will wait for additional 
comments before spinning a new version.
Miquel Raynal Jan. 7, 2022, 7:22 a.m. UTC | #2
Hi Florian,

f.fainelli@gmail.com wrote on Thu, 6 Jan 2022 19:10:12 -0800:

> On 1/6/2022 4:13 PM, Florian Fainelli wrote:
> > Allow a brcmnand_soc instance to provide a custom set of I/O operations
> > which we will require when using this driver on a BCMA bus which is not
> > directly memory mapped I/O. Update the nand_{read,write}_reg accordingly
> > to use the SoC operations if provided.
> > 
> > To minimize the penalty on other SoCs which do support standard MMIO
> > accesses, we use a static key which is disabled by default and gets
> > enabled if a soc implementation does provide I/O operations.
> > 
> > Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> > ---  
> 
> [snip]
> 
> >   	init_completion(&ctrl->done);
> >   	init_completion(&ctrl->dma_done);
> >   	init_completion(&ctrl->edu_done);
> > @@ -3145,6 +3169,8 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
> >   		/* Enable interrupt */
> >   		ctrl->soc->ctlrdy_ack(ctrl->soc);
> >   		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
> > +		if (brcmnand_soc_has_ops(soc))
> > +			static_branch_enable(&brcmnand_soc_has_ops_key);  
> 
> This hunk got mistakenly added with a rebase, I will wait for additional comments before spinning a new version.

FYI the series LGTM otherwise.

Thanks,
Miquèl
diff mbox series

Patch

diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 63080ae3aef1..9c3909c34dc2 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -25,6 +25,7 @@ 
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/slab.h>
+#include <linux/static_key.h>
 #include <linux/list.h>
 #include <linux/log2.h>
 
@@ -207,6 +208,8 @@  enum {
 
 struct brcmnand_host;
 
+static DEFINE_STATIC_KEY_FALSE(brcmnand_soc_has_ops_key);
+
 struct brcmnand_controller {
 	struct device		*dev;
 	struct nand_controller	controller;
@@ -592,15 +595,25 @@  enum {
 	INTFC_CTLR_READY		= BIT(31),
 };
 
+static inline bool brcmnand_non_mmio_ops(struct brcmnand_controller *ctrl)
+{
+	return static_branch_unlikely(&brcmnand_soc_has_ops_key);
+}
+
 static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs)
 {
+	if (brcmnand_non_mmio_ops(ctrl))
+		return brcmnand_soc_read(ctrl->soc, offs);
 	return brcmnand_readl(ctrl->nand_base + offs);
 }
 
 static inline void nand_writereg(struct brcmnand_controller *ctrl, u32 offs,
 				 u32 val)
 {
-	brcmnand_writel(val, ctrl->nand_base + offs);
+	if (brcmnand_non_mmio_ops(ctrl))
+		brcmnand_soc_write(ctrl->soc, val, offs);
+	else
+		brcmnand_writel(val, ctrl->nand_base + offs);
 }
 
 static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
@@ -766,13 +779,18 @@  static inline void brcmnand_rmw_reg(struct brcmnand_controller *ctrl,
 
 static inline u32 brcmnand_read_fc(struct brcmnand_controller *ctrl, int word)
 {
+	if (brcmnand_non_mmio_ops(ctrl))
+		return brcmnand_soc_read(ctrl->soc, BRCMNAND_NON_MMIO_FC_ADDR);
 	return __raw_readl(ctrl->nand_fc + word * 4);
 }
 
 static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl,
 				     int word, u32 val)
 {
-	__raw_writel(val, ctrl->nand_fc + word * 4);
+	if (brcmnand_non_mmio_ops(ctrl))
+		brcmnand_soc_write(ctrl->soc, val, BRCMNAND_NON_MMIO_FC_ADDR);
+	else
+		__raw_writel(val, ctrl->nand_fc + word * 4);
 }
 
 static inline void edu_writel(struct brcmnand_controller *ctrl,
@@ -3000,6 +3018,12 @@  int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
 	ctrl->dev = dev;
 	ctrl->soc = soc;
 
+	/* Enable the static key if the soc provides I/O operations indicating
+	 * that a non-memory mapped IO access path must be used
+	 */
+	if (brcmnand_soc_has_ops(ctrl->soc))
+		static_branch_enable(&brcmnand_soc_has_ops_key);
+
 	init_completion(&ctrl->done);
 	init_completion(&ctrl->dma_done);
 	init_completion(&ctrl->edu_done);
@@ -3145,6 +3169,8 @@  int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
 		/* Enable interrupt */
 		ctrl->soc->ctlrdy_ack(ctrl->soc);
 		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
+		if (brcmnand_soc_has_ops(soc))
+			static_branch_enable(&brcmnand_soc_has_ops_key);
 	} else {
 		/* Use standard interrupt infrastructure */
 		ret = devm_request_irq(dev, ctrl->irq, brcmnand_ctlrdy_irq, 0,
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.h b/drivers/mtd/nand/raw/brcmnand/brcmnand.h
index eb498fbe505e..f1f93d85f50d 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.h
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.h
@@ -11,12 +11,25 @@ 
 
 struct platform_device;
 struct dev_pm_ops;
+struct brcmnand_io_ops;
+
+/* Special register offset constant to intercept a non-MMIO access
+ * to the flash cache register space. This is intentionally large
+ * not to overlap with an existing offset.
+ */
+#define BRCMNAND_NON_MMIO_FC_ADDR	0xffffffff
 
 struct brcmnand_soc {
 	bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
 	void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
 	void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
 				 bool is_param);
+	const struct brcmnand_io_ops *ops;
+};
+
+struct brcmnand_io_ops {
+	u32 (*read_reg)(struct brcmnand_soc *soc, u32 offset);
+	void (*write_reg)(struct brcmnand_soc *soc, u32 val, u32 offset);
 };
 
 static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc,
@@ -58,6 +71,22 @@  static inline void brcmnand_writel(u32 val, void __iomem *addr)
 		writel_relaxed(val, addr);
 }
 
+static inline bool brcmnand_soc_has_ops(struct brcmnand_soc *soc)
+{
+	return soc && soc->ops && soc->ops->read_reg && soc->ops->write_reg;
+}
+
+static inline u32 brcmnand_soc_read(struct brcmnand_soc *soc, u32 offset)
+{
+	return soc->ops->read_reg(soc, offset);
+}
+
+static inline void brcmnand_soc_write(struct brcmnand_soc *soc, u32 val,
+				      u32 offset)
+{
+	soc->ops->write_reg(soc, val, offset);
+}
+
 int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc);
 int brcmnand_remove(struct platform_device *pdev);