151 lines
4.7 KiB
Diff
151 lines
4.7 KiB
Diff
From: Florian Fainelli <f.fainelli@gmail.com>
|
|
Subject: [PATCH v3 2/9] mtd: rawnand: brcmnand: Allow SoC to provide I/O operations
|
|
Date: Fri, 07 Jan 2022 10:46:07 -0800
|
|
Content-Type: text/plain; charset="utf-8"
|
|
|
|
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 | 28 +++++++++++++++++++++--
|
|
drivers/mtd/nand/raw/brcmnand/brcmnand.h | 29 ++++++++++++++++++++++++
|
|
2 files changed, 55 insertions(+), 2 deletions(-)
|
|
|
|
--- 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(stru
|
|
|
|
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_devic
|
|
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);
|
|
--- 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 v
|
|
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);
|
|
|