23f5df30158631e7c92b12e303637daf06f38e44
[openwrt/staging/blogic.git] /
1 From: Florian Fainelli <f.fainelli@gmail.com>
2 Subject: [PATCH v3 2/9] mtd: rawnand: brcmnand: Allow SoC to provide I/O operations
3 Date: Fri, 07 Jan 2022 10:46:07 -0800
4 Content-Type: text/plain; charset="utf-8"
5
6 Allow a brcmnand_soc instance to provide a custom set of I/O operations
7 which we will require when using this driver on a BCMA bus which is not
8 directly memory mapped I/O. Update the nand_{read,write}_reg accordingly
9 to use the SoC operations if provided.
10
11 To minimize the penalty on other SoCs which do support standard MMIO
12 accesses, we use a static key which is disabled by default and gets
13 enabled if a soc implementation does provide I/O operations.
14
15 Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
16 ---
17 drivers/mtd/nand/raw/brcmnand/brcmnand.c | 28 +++++++++++++++++++++--
18 drivers/mtd/nand/raw/brcmnand/brcmnand.h | 29 ++++++++++++++++++++++++
19 2 files changed, 55 insertions(+), 2 deletions(-)
20
21 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
22 +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
23 @@ -25,6 +25,7 @@
24 #include <linux/of.h>
25 #include <linux/of_platform.h>
26 #include <linux/slab.h>
27 +#include <linux/static_key.h>
28 #include <linux/list.h>
29 #include <linux/log2.h>
30
31 @@ -207,6 +208,8 @@ enum {
32
33 struct brcmnand_host;
34
35 +static DEFINE_STATIC_KEY_FALSE(brcmnand_soc_has_ops_key);
36 +
37 struct brcmnand_controller {
38 struct device *dev;
39 struct nand_controller controller;
40 @@ -589,15 +592,25 @@ enum {
41 INTFC_CTLR_READY = BIT(31),
42 };
43
44 +static inline bool brcmnand_non_mmio_ops(struct brcmnand_controller *ctrl)
45 +{
46 + return static_branch_unlikely(&brcmnand_soc_has_ops_key);
47 +}
48 +
49 static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs)
50 {
51 + if (brcmnand_non_mmio_ops(ctrl))
52 + return brcmnand_soc_read(ctrl->soc, offs);
53 return brcmnand_readl(ctrl->nand_base + offs);
54 }
55
56 static inline void nand_writereg(struct brcmnand_controller *ctrl, u32 offs,
57 u32 val)
58 {
59 - brcmnand_writel(val, ctrl->nand_base + offs);
60 + if (brcmnand_non_mmio_ops(ctrl))
61 + brcmnand_soc_write(ctrl->soc, val, offs);
62 + else
63 + brcmnand_writel(val, ctrl->nand_base + offs);
64 }
65
66 static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
67 @@ -763,13 +776,18 @@ static inline void brcmnand_rmw_reg(stru
68
69 static inline u32 brcmnand_read_fc(struct brcmnand_controller *ctrl, int word)
70 {
71 + if (brcmnand_non_mmio_ops(ctrl))
72 + return brcmnand_soc_read(ctrl->soc, BRCMNAND_NON_MMIO_FC_ADDR);
73 return __raw_readl(ctrl->nand_fc + word * 4);
74 }
75
76 static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl,
77 int word, u32 val)
78 {
79 - __raw_writel(val, ctrl->nand_fc + word * 4);
80 + if (brcmnand_non_mmio_ops(ctrl))
81 + brcmnand_soc_write(ctrl->soc, val, BRCMNAND_NON_MMIO_FC_ADDR);
82 + else
83 + __raw_writel(val, ctrl->nand_fc + word * 4);
84 }
85
86 static inline void edu_writel(struct brcmnand_controller *ctrl,
87 @@ -2951,6 +2969,12 @@ int brcmnand_probe(struct platform_devic
88 ctrl->dev = dev;
89 ctrl->soc = soc;
90
91 + /* Enable the static key if the soc provides I/O operations indicating
92 + * that a non-memory mapped IO access path must be used
93 + */
94 + if (brcmnand_soc_has_ops(ctrl->soc))
95 + static_branch_enable(&brcmnand_soc_has_ops_key);
96 +
97 init_completion(&ctrl->done);
98 init_completion(&ctrl->dma_done);
99 init_completion(&ctrl->edu_done);
100 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.h
101 +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.h
102 @@ -11,12 +11,25 @@
103
104 struct platform_device;
105 struct dev_pm_ops;
106 +struct brcmnand_io_ops;
107 +
108 +/* Special register offset constant to intercept a non-MMIO access
109 + * to the flash cache register space. This is intentionally large
110 + * not to overlap with an existing offset.
111 + */
112 +#define BRCMNAND_NON_MMIO_FC_ADDR 0xffffffff
113
114 struct brcmnand_soc {
115 bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
116 void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
117 void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
118 bool is_param);
119 + const struct brcmnand_io_ops *ops;
120 +};
121 +
122 +struct brcmnand_io_ops {
123 + u32 (*read_reg)(struct brcmnand_soc *soc, u32 offset);
124 + void (*write_reg)(struct brcmnand_soc *soc, u32 val, u32 offset);
125 };
126
127 static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc,
128 @@ -58,6 +71,22 @@ static inline void brcmnand_writel(u32 v
129 writel_relaxed(val, addr);
130 }
131
132 +static inline bool brcmnand_soc_has_ops(struct brcmnand_soc *soc)
133 +{
134 + return soc && soc->ops && soc->ops->read_reg && soc->ops->write_reg;
135 +}
136 +
137 +static inline u32 brcmnand_soc_read(struct brcmnand_soc *soc, u32 offset)
138 +{
139 + return soc->ops->read_reg(soc, offset);
140 +}
141 +
142 +static inline void brcmnand_soc_write(struct brcmnand_soc *soc, u32 val,
143 + u32 offset)
144 +{
145 + soc->ops->write_reg(soc, val, offset);
146 +}
147 +
148 int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc);
149 int brcmnand_remove(struct platform_device *pdev);
150