summaryrefslogtreecommitdiffstats
path: root/drivers/nvmem
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-11-16 12:10:59 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-11-16 12:10:59 -0500
commit2bf16b7a73caf3435f782e4170cfe563675e10f9 (patch)
tree7f4c5b28a02f08c4d6fd69dd43db5872b07c20c4 /drivers/nvmem
parentb9743042b3d31fed271ae19aee79dd86817904f0 (diff)
parentf13d1a8a801dae552ef495c84a223280586a9f67 (diff)
Merge tag 'char-misc-4.15-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc updates from Greg KH: "Here is the big set of char/misc and other driver subsystem patches for 4.15-rc1. There are small changes all over here, hyperv driver updates, pcmcia driver updates, w1 driver updats, vme driver updates, nvmem driver updates, and lots of other little one-off driver updates as well. The shortlog has the full details. All of these have been in linux-next for quite a while with no reported issues" * tag 'char-misc-4.15-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (90 commits) VME: Return -EBUSY when DMA list in use w1: keep balance of mutex locks and refcnts MAINTAINERS: Update VME subsystem tree. nvmem: sunxi-sid: add support for A64/H5's SID controller nvmem: imx-ocotp: Update module description nvmem: imx-ocotp: Enable i.MX7D OTP write support nvmem: imx-ocotp: Add i.MX7D timing write clock setup support nvmem: imx-ocotp: Move i.MX6 write clock setup to dedicated function nvmem: imx-ocotp: Add support for banked OTP addressing nvmem: imx-ocotp: Pass parameters via a struct nvmem: imx-ocotp: Restrict OTP write to IMX6 processors nvmem: uniphier: add UniPhier eFuse driver dt-bindings: nvmem: add description for UniPhier eFuse nvmem: set nvmem->owner to nvmem->dev->driver->owner if unset nvmem: qfprom: fix different address space warnings of sparse nvmem: mtk-efuse: fix different address space warnings of sparse nvmem: mtk-efuse: use stack for nvmem_config instead of malloc'ing it nvmem: imx-iim: use stack for nvmem_config instead of malloc'ing it thunderbolt: tb: fix use after free in tb_activate_pcie_devices MAINTAINERS: Add git tree for Thunderbolt development ...
Diffstat (limited to 'drivers/nvmem')
-rw-r--r--drivers/nvmem/Kconfig35
-rw-r--r--drivers/nvmem/Makefile6
-rw-r--r--drivers/nvmem/bcm-ocotp.c1
-rw-r--r--drivers/nvmem/core.c13
-rw-r--r--drivers/nvmem/imx-iim.c24
-rw-r--r--drivers/nvmem/imx-ocotp.c193
-rw-r--r--drivers/nvmem/lpc18xx_eeprom.c1
-rw-r--r--drivers/nvmem/lpc18xx_otp.c1
-rw-r--r--drivers/nvmem/meson-efuse.c5
-rw-r--r--drivers/nvmem/meson-mx-efuse.c265
-rw-r--r--drivers/nvmem/mtk-efuse.c47
-rw-r--r--drivers/nvmem/mxs-ocotp.c1
-rw-r--r--drivers/nvmem/qfprom.c27
-rw-r--r--drivers/nvmem/rockchip-efuse.c5
-rw-r--r--drivers/nvmem/snvs_lpgpr.c156
-rw-r--r--drivers/nvmem/sunxi_sid.c7
-rw-r--r--drivers/nvmem/uniphier-efuse.c97
-rw-r--r--drivers/nvmem/vf610-ocotp.c1
18 files changed, 784 insertions, 101 deletions
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 101ced4c84be..ff505af064ba 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -123,6 +123,17 @@ config NVMEM_SUNXI_SID
123 This driver can also be built as a module. If so, the module 123 This driver can also be built as a module. If so, the module
124 will be called nvmem_sunxi_sid. 124 will be called nvmem_sunxi_sid.
125 125
126config UNIPHIER_EFUSE
127 tristate "UniPhier SoCs eFuse support"
128 depends on ARCH_UNIPHIER || COMPILE_TEST
129 depends on HAS_IOMEM
130 help
131 This is a simple driver to dump specified values of UniPhier SoC
132 from eFuse.
133
134 This driver can also be built as a module. If so, the module
135 will be called nvmem-uniphier-efuse.
136
126config NVMEM_VF610_OCOTP 137config NVMEM_VF610_OCOTP
127 tristate "VF610 SoC OCOTP support" 138 tristate "VF610 SoC OCOTP support"
128 depends on SOC_VF610 || COMPILE_TEST 139 depends on SOC_VF610 || COMPILE_TEST
@@ -135,13 +146,33 @@ config NVMEM_VF610_OCOTP
135 be called nvmem-vf610-ocotp. 146 be called nvmem-vf610-ocotp.
136 147
137config MESON_EFUSE 148config MESON_EFUSE
138 tristate "Amlogic eFuse Support" 149 tristate "Amlogic Meson GX eFuse Support"
139 depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM 150 depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM
140 help 151 help
141 This is a driver to retrieve specific values from the eFuse found on 152 This is a driver to retrieve specific values from the eFuse found on
142 the Amlogic Meson SoCs. 153 the Amlogic Meson GX SoCs.
143 154
144 This driver can also be built as a module. If so, the module 155 This driver can also be built as a module. If so, the module
145 will be called nvmem_meson_efuse. 156 will be called nvmem_meson_efuse.
146 157
158config MESON_MX_EFUSE
159 tristate "Amlogic Meson6/Meson8/Meson8b eFuse Support"
160 depends on ARCH_MESON || COMPILE_TEST
161 help
162 This is a driver to retrieve specific values from the eFuse found on
163 the Amlogic Meson6, Meson8 and Meson8b SoCs.
164
165 This driver can also be built as a module. If so, the module
166 will be called nvmem_meson_mx_efuse.
167
168config NVMEM_SNVS_LPGPR
169 tristate "Support for Low Power General Purpose Register"
170 depends on SOC_IMX6 || COMPILE_TEST
171 help
172 This is a driver for Low Power General Purpose Register (LPGPR) available on
173 i.MX6 SoCs in Secure Non-Volatile Storage (SNVS) of this chip.
174
175 This driver can also be built as a module. If so, the module
176 will be called nvmem-snvs-lpgpr.
177
147endif 178endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 6f7a77fb3ee7..e54dcfa6565a 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -27,7 +27,13 @@ obj-$(CONFIG_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o
27nvmem_rockchip_efuse-y := rockchip-efuse.o 27nvmem_rockchip_efuse-y := rockchip-efuse.o
28obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o 28obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o
29nvmem_sunxi_sid-y := sunxi_sid.o 29nvmem_sunxi_sid-y := sunxi_sid.o
30obj-$(CONFIG_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o
31nvmem-uniphier-efuse-y := uniphier-efuse.o
30obj-$(CONFIG_NVMEM_VF610_OCOTP) += nvmem-vf610-ocotp.o 32obj-$(CONFIG_NVMEM_VF610_OCOTP) += nvmem-vf610-ocotp.o
31nvmem-vf610-ocotp-y := vf610-ocotp.o 33nvmem-vf610-ocotp-y := vf610-ocotp.o
32obj-$(CONFIG_MESON_EFUSE) += nvmem_meson_efuse.o 34obj-$(CONFIG_MESON_EFUSE) += nvmem_meson_efuse.o
33nvmem_meson_efuse-y := meson-efuse.o 35nvmem_meson_efuse-y := meson-efuse.o
36obj-$(CONFIG_MESON_MX_EFUSE) += nvmem_meson_mx_efuse.o
37nvmem_meson_mx_efuse-y := meson-mx-efuse.o
38obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o
39nvmem_snvs_lpgpr-y := snvs_lpgpr.o
diff --git a/drivers/nvmem/bcm-ocotp.c b/drivers/nvmem/bcm-ocotp.c
index 3c56e3b2bd65..5e9e324427f9 100644
--- a/drivers/nvmem/bcm-ocotp.c
+++ b/drivers/nvmem/bcm-ocotp.c
@@ -232,7 +232,6 @@ static struct nvmem_config bcm_otpc_nvmem_config = {
232 .read_only = false, 232 .read_only = false,
233 .word_size = 4, 233 .word_size = 4,
234 .stride = 4, 234 .stride = 4,
235 .owner = THIS_MODULE,
236 .reg_read = bcm_otpc_read, 235 .reg_read = bcm_otpc_read,
237 .reg_write = bcm_otpc_write, 236 .reg_write = bcm_otpc_write,
238}; 237};
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index d12e5de78e70..5a5cefd12153 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -462,6 +462,8 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
462 462
463 nvmem->id = rval; 463 nvmem->id = rval;
464 nvmem->owner = config->owner; 464 nvmem->owner = config->owner;
465 if (!nvmem->owner && config->dev->driver)
466 nvmem->owner = config->dev->driver->owner;
465 nvmem->stride = config->stride; 467 nvmem->stride = config->stride;
466 nvmem->word_size = config->word_size; 468 nvmem->word_size = config->word_size;
467 nvmem->size = config->size; 469 nvmem->size = config->size;
@@ -615,7 +617,7 @@ static struct nvmem_device *nvmem_find(const char *name)
615 return to_nvmem_device(d); 617 return to_nvmem_device(d);
616} 618}
617 619
618#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) 620#if IS_ENABLED(CONFIG_OF)
619/** 621/**
620 * of_nvmem_device_get() - Get nvmem device from a given id 622 * of_nvmem_device_get() - Get nvmem device from a given id
621 * 623 *
@@ -753,7 +755,7 @@ static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id)
753 return cell; 755 return cell;
754} 756}
755 757
756#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) 758#if IS_ENABLED(CONFIG_OF)
757/** 759/**
758 * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 760 * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id
759 * 761 *
@@ -946,8 +948,7 @@ void nvmem_cell_put(struct nvmem_cell *cell)
946} 948}
947EXPORT_SYMBOL_GPL(nvmem_cell_put); 949EXPORT_SYMBOL_GPL(nvmem_cell_put);
948 950
949static inline void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, 951static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf)
950 void *buf)
951{ 952{
952 u8 *p, *b; 953 u8 *p, *b;
953 int i, bit_offset = cell->bit_offset; 954 int i, bit_offset = cell->bit_offset;
@@ -1028,8 +1029,8 @@ void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
1028} 1029}
1029EXPORT_SYMBOL_GPL(nvmem_cell_read); 1030EXPORT_SYMBOL_GPL(nvmem_cell_read);
1030 1031
1031static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, 1032static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell,
1032 u8 *_buf, int len) 1033 u8 *_buf, int len)
1033{ 1034{
1034 struct nvmem_device *nvmem = cell->nvmem; 1035 struct nvmem_device *nvmem = cell->nvmem;
1035 int i, rc, nbits, bit_offset = cell->bit_offset; 1036 int i, rc, nbits, bit_offset = cell->bit_offset;
diff --git a/drivers/nvmem/imx-iim.c b/drivers/nvmem/imx-iim.c
index 52ff65e0673f..52cfe91d9762 100644
--- a/drivers/nvmem/imx-iim.c
+++ b/drivers/nvmem/imx-iim.c
@@ -34,7 +34,6 @@ struct imx_iim_drvdata {
34struct iim_priv { 34struct iim_priv {
35 void __iomem *base; 35 void __iomem *base;
36 struct clk *clk; 36 struct clk *clk;
37 struct nvmem_config nvmem;
38}; 37};
39 38
40static int imx_iim_read(void *context, unsigned int offset, 39static int imx_iim_read(void *context, unsigned int offset,
@@ -108,7 +107,7 @@ static int imx_iim_probe(struct platform_device *pdev)
108 struct resource *res; 107 struct resource *res;
109 struct iim_priv *iim; 108 struct iim_priv *iim;
110 struct nvmem_device *nvmem; 109 struct nvmem_device *nvmem;
111 struct nvmem_config *cfg; 110 struct nvmem_config cfg = {};
112 const struct imx_iim_drvdata *drvdata = NULL; 111 const struct imx_iim_drvdata *drvdata = NULL;
113 112
114 iim = devm_kzalloc(dev, sizeof(*iim), GFP_KERNEL); 113 iim = devm_kzalloc(dev, sizeof(*iim), GFP_KERNEL);
@@ -130,19 +129,16 @@ static int imx_iim_probe(struct platform_device *pdev)
130 if (IS_ERR(iim->clk)) 129 if (IS_ERR(iim->clk))
131 return PTR_ERR(iim->clk); 130 return PTR_ERR(iim->clk);
132 131
133 cfg = &iim->nvmem; 132 cfg.name = "imx-iim",
133 cfg.read_only = true,
134 cfg.word_size = 1,
135 cfg.stride = 1,
136 cfg.reg_read = imx_iim_read,
137 cfg.dev = dev;
138 cfg.size = drvdata->nregs;
139 cfg.priv = iim;
134 140
135 cfg->name = "imx-iim", 141 nvmem = nvmem_register(&cfg);
136 cfg->read_only = true,
137 cfg->word_size = 1,
138 cfg->stride = 1,
139 cfg->owner = THIS_MODULE,
140 cfg->reg_read = imx_iim_read,
141 cfg->dev = dev;
142 cfg->size = drvdata->nregs;
143 cfg->priv = iim;
144
145 nvmem = nvmem_register(cfg);
146 if (IS_ERR(nvmem)) 142 if (IS_ERR(nvmem))
147 return PTR_ERR(nvmem); 143 return PTR_ERR(nvmem);
148 144
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index 193ca8fd350a..d7ba351a70c9 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -40,14 +40,19 @@
40#define IMX_OCOTP_ADDR_CTRL_SET 0x0004 40#define IMX_OCOTP_ADDR_CTRL_SET 0x0004
41#define IMX_OCOTP_ADDR_CTRL_CLR 0x0008 41#define IMX_OCOTP_ADDR_CTRL_CLR 0x0008
42#define IMX_OCOTP_ADDR_TIMING 0x0010 42#define IMX_OCOTP_ADDR_TIMING 0x0010
43#define IMX_OCOTP_ADDR_DATA 0x0020 43#define IMX_OCOTP_ADDR_DATA0 0x0020
44#define IMX_OCOTP_ADDR_DATA1 0x0030
45#define IMX_OCOTP_ADDR_DATA2 0x0040
46#define IMX_OCOTP_ADDR_DATA3 0x0050
44 47
45#define IMX_OCOTP_BM_CTRL_ADDR 0x0000007F 48#define IMX_OCOTP_BM_CTRL_ADDR 0x0000007F
46#define IMX_OCOTP_BM_CTRL_BUSY 0x00000100 49#define IMX_OCOTP_BM_CTRL_BUSY 0x00000100
47#define IMX_OCOTP_BM_CTRL_ERROR 0x00000200 50#define IMX_OCOTP_BM_CTRL_ERROR 0x00000200
48#define IMX_OCOTP_BM_CTRL_REL_SHADOWS 0x00000400 51#define IMX_OCOTP_BM_CTRL_REL_SHADOWS 0x00000400
49 52
50#define DEF_RELAX 20 /* > 16.5ns */ 53#define DEF_RELAX 20 /* > 16.5ns */
54#define DEF_FSOURCE 1001 /* > 1000 ns */
55#define DEF_STROBE_PROG 10000 /* IPG clocks */
51#define IMX_OCOTP_WR_UNLOCK 0x3E770000 56#define IMX_OCOTP_WR_UNLOCK 0x3E770000
52#define IMX_OCOTP_READ_LOCKED_VAL 0xBADABADA 57#define IMX_OCOTP_READ_LOCKED_VAL 0xBADABADA
53 58
@@ -57,10 +62,16 @@ struct ocotp_priv {
57 struct device *dev; 62 struct device *dev;
58 struct clk *clk; 63 struct clk *clk;
59 void __iomem *base; 64 void __iomem *base;
60 unsigned int nregs; 65 const struct ocotp_params *params;
61 struct nvmem_config *config; 66 struct nvmem_config *config;
62}; 67};
63 68
69struct ocotp_params {
70 unsigned int nregs;
71 unsigned int bank_address_words;
72 void (*set_timing)(struct ocotp_priv *priv);
73};
74
64static int imx_ocotp_wait_for_busy(void __iomem *base, u32 flags) 75static int imx_ocotp_wait_for_busy(void __iomem *base, u32 flags)
65{ 76{
66 int count; 77 int count;
@@ -121,8 +132,8 @@ static int imx_ocotp_read(void *context, unsigned int offset,
121 index = offset >> 2; 132 index = offset >> 2;
122 count = bytes >> 2; 133 count = bytes >> 2;
123 134
124 if (count > (priv->nregs - index)) 135 if (count > (priv->params->nregs - index))
125 count = priv->nregs - index; 136 count = priv->params->nregs - index;
126 137
127 mutex_lock(&ocotp_mutex); 138 mutex_lock(&ocotp_mutex);
128 139
@@ -160,6 +171,52 @@ read_end:
160 return ret; 171 return ret;
161} 172}
162 173
174static void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv)
175{
176 unsigned long clk_rate = 0;
177 unsigned long strobe_read, relax, strobe_prog;
178 u32 timing = 0;
179
180 /* 47.3.1.3.1
181 * Program HW_OCOTP_TIMING[STROBE_PROG] and HW_OCOTP_TIMING[RELAX]
182 * fields with timing values to match the current frequency of the
183 * ipg_clk. OTP writes will work at maximum bus frequencies as long
184 * as the HW_OCOTP_TIMING parameters are set correctly.
185 */
186 clk_rate = clk_get_rate(priv->clk);
187
188 relax = clk_rate / (1000000000 / DEF_RELAX) - 1;
189 strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1;
190 strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1;
191
192 timing = strobe_prog & 0x00000FFF;
193 timing |= (relax << 12) & 0x0000F000;
194 timing |= (strobe_read << 16) & 0x003F0000;
195
196 writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING);
197}
198
199static void imx_ocotp_set_imx7_timing(struct ocotp_priv *priv)
200{
201 unsigned long clk_rate = 0;
202 u64 fsource, strobe_prog;
203 u32 timing = 0;
204
205 /* i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1
206 * 6.4.3.3
207 */
208 clk_rate = clk_get_rate(priv->clk);
209 fsource = DIV_ROUND_UP_ULL((u64)clk_rate * DEF_FSOURCE,
210 NSEC_PER_SEC) + 1;
211 strobe_prog = DIV_ROUND_CLOSEST_ULL((u64)clk_rate * DEF_STROBE_PROG,
212 NSEC_PER_SEC) + 1;
213
214 timing = strobe_prog & 0x00000FFF;
215 timing |= (fsource << 12) & 0x000FF000;
216
217 writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING);
218}
219
163static int imx_ocotp_write(void *context, unsigned int offset, void *val, 220static int imx_ocotp_write(void *context, unsigned int offset, void *val,
164 size_t bytes) 221 size_t bytes)
165{ 222{
@@ -167,11 +224,9 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
167 u32 *buf = val; 224 u32 *buf = val;
168 int ret; 225 int ret;
169 226
170 unsigned long clk_rate = 0;
171 unsigned long strobe_read, relax, strobe_prog;
172 u32 timing = 0;
173 u32 ctrl; 227 u32 ctrl;
174 u8 waddr; 228 u8 waddr;
229 u8 word = 0;
175 230
176 /* allow only writing one complete OTP word at a time */ 231 /* allow only writing one complete OTP word at a time */
177 if ((bytes != priv->config->word_size) || 232 if ((bytes != priv->config->word_size) ||
@@ -187,23 +242,8 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
187 return ret; 242 return ret;
188 } 243 }
189 244
190 /* 47.3.1.3.1 245 /* Setup the write timing values */
191 * Program HW_OCOTP_TIMING[STROBE_PROG] and HW_OCOTP_TIMING[RELAX] 246 priv->params->set_timing(priv);
192 * fields with timing values to match the current frequency of the
193 * ipg_clk. OTP writes will work at maximum bus frequencies as long
194 * as the HW_OCOTP_TIMING parameters are set correctly.
195 */
196 clk_rate = clk_get_rate(priv->clk);
197
198 relax = clk_rate / (1000000000 / DEF_RELAX) - 1;
199 strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1;
200 strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1;
201
202 timing = strobe_prog & 0x00000FFF;
203 timing |= (relax << 12) & 0x0000F000;
204 timing |= (strobe_read << 16) & 0x003F0000;
205
206 writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING);
207 247
208 /* 47.3.1.3.2 248 /* 47.3.1.3.2
209 * Check that HW_OCOTP_CTRL[BUSY] and HW_OCOTP_CTRL[ERROR] are clear. 249 * Check that HW_OCOTP_CTRL[BUSY] and HW_OCOTP_CTRL[ERROR] are clear.
@@ -224,8 +264,23 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
224 * description. Both the unlock code and address can be written in the 264 * description. Both the unlock code and address can be written in the
225 * same operation. 265 * same operation.
226 */ 266 */
227 /* OTP write/read address specifies one of 128 word address locations */ 267 if (priv->params->bank_address_words != 0) {
228 waddr = offset / 4; 268 /*
269 * In banked/i.MX7 mode the OTP register bank goes into waddr
270 * see i.MX 7Solo Applications Processor Reference Manual, Rev.
271 * 0.1 section 6.4.3.1
272 */
273 offset = offset / priv->config->word_size;
274 waddr = offset / priv->params->bank_address_words;
275 word = offset & (priv->params->bank_address_words - 1);
276 } else {
277 /*
278 * Non-banked i.MX6 mode.
279 * OTP write/read address specifies one of 128 word address
280 * locations
281 */
282 waddr = offset / 4;
283 }
229 284
230 ctrl = readl(priv->base + IMX_OCOTP_ADDR_CTRL); 285 ctrl = readl(priv->base + IMX_OCOTP_ADDR_CTRL);
231 ctrl &= ~IMX_OCOTP_BM_CTRL_ADDR; 286 ctrl &= ~IMX_OCOTP_BM_CTRL_ADDR;
@@ -251,8 +306,43 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
251 * shift right (with zero fill). This shifting is required to program 306 * shift right (with zero fill). This shifting is required to program
252 * the OTP serially. During the write operation, HW_OCOTP_DATA cannot be 307 * the OTP serially. During the write operation, HW_OCOTP_DATA cannot be
253 * modified. 308 * modified.
309 * Note: on i.MX7 there are four data fields to write for banked write
310 * with the fuse blowing operation only taking place after data0
311 * has been written. This is why data0 must always be the last
312 * register written.
254 */ 313 */
255 writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA); 314 if (priv->params->bank_address_words != 0) {
315 /* Banked/i.MX7 mode */
316 switch (word) {
317 case 0:
318 writel(0, priv->base + IMX_OCOTP_ADDR_DATA1);
319 writel(0, priv->base + IMX_OCOTP_ADDR_DATA2);
320 writel(0, priv->base + IMX_OCOTP_ADDR_DATA3);
321 writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA0);
322 break;
323 case 1:
324 writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA1);
325 writel(0, priv->base + IMX_OCOTP_ADDR_DATA2);
326 writel(0, priv->base + IMX_OCOTP_ADDR_DATA3);
327 writel(0, priv->base + IMX_OCOTP_ADDR_DATA0);
328 break;
329 case 2:
330 writel(0, priv->base + IMX_OCOTP_ADDR_DATA1);
331 writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA2);
332 writel(0, priv->base + IMX_OCOTP_ADDR_DATA3);
333 writel(0, priv->base + IMX_OCOTP_ADDR_DATA0);
334 break;
335 case 3:
336 writel(0, priv->base + IMX_OCOTP_ADDR_DATA1);
337 writel(0, priv->base + IMX_OCOTP_ADDR_DATA2);
338 writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA3);
339 writel(0, priv->base + IMX_OCOTP_ADDR_DATA0);
340 break;
341 }
342 } else {
343 /* Non-banked i.MX6 mode */
344 writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA0);
345 }
256 346
257 /* 47.4.1.4.5 347 /* 47.4.1.4.5
258 * Once complete, the controller will clear BUSY. A write request to a 348 * Once complete, the controller will clear BUSY. A write request to a
@@ -303,17 +393,46 @@ static struct nvmem_config imx_ocotp_nvmem_config = {
303 .read_only = false, 393 .read_only = false,
304 .word_size = 4, 394 .word_size = 4,
305 .stride = 4, 395 .stride = 4,
306 .owner = THIS_MODULE,
307 .reg_read = imx_ocotp_read, 396 .reg_read = imx_ocotp_read,
308 .reg_write = imx_ocotp_write, 397 .reg_write = imx_ocotp_write,
309}; 398};
310 399
400static const struct ocotp_params imx6q_params = {
401 .nregs = 128,
402 .bank_address_words = 0,
403 .set_timing = imx_ocotp_set_imx6_timing,
404};
405
406static const struct ocotp_params imx6sl_params = {
407 .nregs = 64,
408 .bank_address_words = 0,
409 .set_timing = imx_ocotp_set_imx6_timing,
410};
411
412static const struct ocotp_params imx6sx_params = {
413 .nregs = 128,
414 .bank_address_words = 0,
415 .set_timing = imx_ocotp_set_imx6_timing,
416};
417
418static const struct ocotp_params imx6ul_params = {
419 .nregs = 128,
420 .bank_address_words = 0,
421 .set_timing = imx_ocotp_set_imx6_timing,
422};
423
424static const struct ocotp_params imx7d_params = {
425 .nregs = 64,
426 .bank_address_words = 4,
427 .set_timing = imx_ocotp_set_imx7_timing,
428};
429
311static const struct of_device_id imx_ocotp_dt_ids[] = { 430static const struct of_device_id imx_ocotp_dt_ids[] = {
312 { .compatible = "fsl,imx6q-ocotp", (void *)128 }, 431 { .compatible = "fsl,imx6q-ocotp", .data = &imx6q_params },
313 { .compatible = "fsl,imx6sl-ocotp", (void *)64 }, 432 { .compatible = "fsl,imx6sl-ocotp", .data = &imx6sl_params },
314 { .compatible = "fsl,imx6sx-ocotp", (void *)128 }, 433 { .compatible = "fsl,imx6sx-ocotp", .data = &imx6sx_params },
315 { .compatible = "fsl,imx6ul-ocotp", (void *)128 }, 434 { .compatible = "fsl,imx6ul-ocotp", .data = &imx6ul_params },
316 { .compatible = "fsl,imx7d-ocotp", (void *)64 }, 435 { .compatible = "fsl,imx7d-ocotp", .data = &imx7d_params },
317 { }, 436 { },
318}; 437};
319MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids); 438MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids);
@@ -342,8 +461,8 @@ static int imx_ocotp_probe(struct platform_device *pdev)
342 return PTR_ERR(priv->clk); 461 return PTR_ERR(priv->clk);
343 462
344 of_id = of_match_device(imx_ocotp_dt_ids, dev); 463 of_id = of_match_device(imx_ocotp_dt_ids, dev);
345 priv->nregs = (unsigned long)of_id->data; 464 priv->params = of_device_get_match_data(&pdev->dev);
346 imx_ocotp_nvmem_config.size = 4 * priv->nregs; 465 imx_ocotp_nvmem_config.size = 4 * priv->params->nregs;
347 imx_ocotp_nvmem_config.dev = dev; 466 imx_ocotp_nvmem_config.dev = dev;
348 imx_ocotp_nvmem_config.priv = priv; 467 imx_ocotp_nvmem_config.priv = priv;
349 priv->config = &imx_ocotp_nvmem_config; 468 priv->config = &imx_ocotp_nvmem_config;
@@ -375,5 +494,5 @@ static struct platform_driver imx_ocotp_driver = {
375module_platform_driver(imx_ocotp_driver); 494module_platform_driver(imx_ocotp_driver);
376 495
377MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>"); 496MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>");
378MODULE_DESCRIPTION("i.MX6 OCOTP fuse box driver"); 497MODULE_DESCRIPTION("i.MX6/i.MX7 OCOTP fuse box driver");
379MODULE_LICENSE("GPL v2"); 498MODULE_LICENSE("GPL v2");
diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c
index 6c7e2c424a4e..b1af966206a6 100644
--- a/drivers/nvmem/lpc18xx_eeprom.c
+++ b/drivers/nvmem/lpc18xx_eeprom.c
@@ -159,7 +159,6 @@ static struct nvmem_config lpc18xx_nvmem_config = {
159 .word_size = 4, 159 .word_size = 4,
160 .reg_read = lpc18xx_eeprom_read, 160 .reg_read = lpc18xx_eeprom_read,
161 .reg_write = lpc18xx_eeprom_gather_write, 161 .reg_write = lpc18xx_eeprom_gather_write,
162 .owner = THIS_MODULE,
163}; 162};
164 163
165static int lpc18xx_eeprom_probe(struct platform_device *pdev) 164static int lpc18xx_eeprom_probe(struct platform_device *pdev)
diff --git a/drivers/nvmem/lpc18xx_otp.c b/drivers/nvmem/lpc18xx_otp.c
index be8d07403ffc..95268db155e9 100644
--- a/drivers/nvmem/lpc18xx_otp.c
+++ b/drivers/nvmem/lpc18xx_otp.c
@@ -64,7 +64,6 @@ static struct nvmem_config lpc18xx_otp_nvmem_config = {
64 .read_only = true, 64 .read_only = true,
65 .word_size = LPC18XX_OTP_WORD_SIZE, 65 .word_size = LPC18XX_OTP_WORD_SIZE,
66 .stride = LPC18XX_OTP_WORD_SIZE, 66 .stride = LPC18XX_OTP_WORD_SIZE,
67 .owner = THIS_MODULE,
68 .reg_read = lpc18xx_otp_read, 67 .reg_read = lpc18xx_otp_read,
69}; 68};
70 69
diff --git a/drivers/nvmem/meson-efuse.c b/drivers/nvmem/meson-efuse.c
index 70bfc9839bb2..a43c68f90937 100644
--- a/drivers/nvmem/meson-efuse.c
+++ b/drivers/nvmem/meson-efuse.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Amlogic eFuse Driver 2 * Amlogic Meson GX eFuse Driver
3 * 3 *
4 * Copyright (c) 2016 Endless Computers, Inc. 4 * Copyright (c) 2016 Endless Computers, Inc.
5 * Author: Carlo Caione <carlo@endlessm.com> 5 * Author: Carlo Caione <carlo@endlessm.com>
@@ -37,7 +37,6 @@ static int meson_efuse_read(void *context, unsigned int offset,
37 37
38static struct nvmem_config econfig = { 38static struct nvmem_config econfig = {
39 .name = "meson-efuse", 39 .name = "meson-efuse",
40 .owner = THIS_MODULE,
41 .stride = 1, 40 .stride = 1,
42 .word_size = 1, 41 .word_size = 1,
43 .read_only = true, 42 .read_only = true,
@@ -89,5 +88,5 @@ static struct platform_driver meson_efuse_driver = {
89module_platform_driver(meson_efuse_driver); 88module_platform_driver(meson_efuse_driver);
90 89
91MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>"); 90MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>");
92MODULE_DESCRIPTION("Amlogic Meson NVMEM driver"); 91MODULE_DESCRIPTION("Amlogic Meson GX NVMEM driver");
93MODULE_LICENSE("GPL v2"); 92MODULE_LICENSE("GPL v2");
diff --git a/drivers/nvmem/meson-mx-efuse.c b/drivers/nvmem/meson-mx-efuse.c
new file mode 100644
index 000000000000..a346b4923550
--- /dev/null
+++ b/drivers/nvmem/meson-mx-efuse.c
@@ -0,0 +1,265 @@
1/*
2 * Amlogic Meson6, Meson8 and Meson8b eFuse Driver
3 *
4 * Copyright (c) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of version 2 of the GNU General Public License as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 */
15
16#include <linux/bitfield.h>
17#include <linux/bitops.h>
18#include <linux/clk.h>
19#include <linux/delay.h>
20#include <linux/io.h>
21#include <linux/iopoll.h>
22#include <linux/module.h>
23#include <linux/nvmem-provider.h>
24#include <linux/of.h>
25#include <linux/of_device.h>
26#include <linux/platform_device.h>
27#include <linux/sizes.h>
28#include <linux/slab.h>
29
30#define MESON_MX_EFUSE_CNTL1 0x04
31#define MESON_MX_EFUSE_CNTL1_PD_ENABLE BIT(27)
32#define MESON_MX_EFUSE_CNTL1_AUTO_RD_BUSY BIT(26)
33#define MESON_MX_EFUSE_CNTL1_AUTO_RD_START BIT(25)
34#define MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE BIT(24)
35#define MESON_MX_EFUSE_CNTL1_BYTE_WR_DATA GENMASK(23, 16)
36#define MESON_MX_EFUSE_CNTL1_AUTO_WR_BUSY BIT(14)
37#define MESON_MX_EFUSE_CNTL1_AUTO_WR_START BIT(13)
38#define MESON_MX_EFUSE_CNTL1_AUTO_WR_ENABLE BIT(12)
39#define MESON_MX_EFUSE_CNTL1_BYTE_ADDR_SET BIT(11)
40#define MESON_MX_EFUSE_CNTL1_BYTE_ADDR_MASK GENMASK(10, 0)
41
42#define MESON_MX_EFUSE_CNTL2 0x08
43
44#define MESON_MX_EFUSE_CNTL4 0x10
45#define MESON_MX_EFUSE_CNTL4_ENCRYPT_ENABLE BIT(10)
46
47struct meson_mx_efuse_platform_data {
48 const char *name;
49 unsigned int word_size;
50};
51
52struct meson_mx_efuse {
53 void __iomem *base;
54 struct clk *core_clk;
55 struct nvmem_device *nvmem;
56 struct nvmem_config config;
57};
58
59static void meson_mx_efuse_mask_bits(struct meson_mx_efuse *efuse, u32 reg,
60 u32 mask, u32 set)
61{
62 u32 data;
63
64 data = readl(efuse->base + reg);
65 data &= ~mask;
66 data |= (set & mask);
67
68 writel(data, efuse->base + reg);
69}
70
71static int meson_mx_efuse_hw_enable(struct meson_mx_efuse *efuse)
72{
73 int err;
74
75 err = clk_prepare_enable(efuse->core_clk);
76 if (err)
77 return err;
78
79 /* power up the efuse */
80 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
81 MESON_MX_EFUSE_CNTL1_PD_ENABLE, 0);
82
83 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL4,
84 MESON_MX_EFUSE_CNTL4_ENCRYPT_ENABLE, 0);
85
86 return 0;
87}
88
89static void meson_mx_efuse_hw_disable(struct meson_mx_efuse *efuse)
90{
91 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
92 MESON_MX_EFUSE_CNTL1_PD_ENABLE,
93 MESON_MX_EFUSE_CNTL1_PD_ENABLE);
94
95 clk_disable_unprepare(efuse->core_clk);
96}
97
98static int meson_mx_efuse_read_addr(struct meson_mx_efuse *efuse,
99 unsigned int addr, u32 *value)
100{
101 int err;
102 u32 regval;
103
104 /* write the address to read */
105 regval = FIELD_PREP(MESON_MX_EFUSE_CNTL1_BYTE_ADDR_MASK, addr);
106 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
107 MESON_MX_EFUSE_CNTL1_BYTE_ADDR_MASK, regval);
108
109 /* inform the hardware that we changed the address */
110 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
111 MESON_MX_EFUSE_CNTL1_BYTE_ADDR_SET,
112 MESON_MX_EFUSE_CNTL1_BYTE_ADDR_SET);
113 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
114 MESON_MX_EFUSE_CNTL1_BYTE_ADDR_SET, 0);
115
116 /* start the read process */
117 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
118 MESON_MX_EFUSE_CNTL1_AUTO_RD_START,
119 MESON_MX_EFUSE_CNTL1_AUTO_RD_START);
120 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
121 MESON_MX_EFUSE_CNTL1_AUTO_RD_START, 0);
122
123 /*
124 * perform a dummy read to ensure that the HW has the RD_BUSY bit set
125 * when polling for the status below.
126 */
127 readl(efuse->base + MESON_MX_EFUSE_CNTL1);
128
129 err = readl_poll_timeout_atomic(efuse->base + MESON_MX_EFUSE_CNTL1,
130 regval,
131 (!(regval & MESON_MX_EFUSE_CNTL1_AUTO_RD_BUSY)),
132 1, 1000);
133 if (err) {
134 dev_err(efuse->config.dev,
135 "Timeout while reading efuse address %u\n", addr);
136 return err;
137 }
138
139 *value = readl(efuse->base + MESON_MX_EFUSE_CNTL2);
140
141 return 0;
142}
143
144static int meson_mx_efuse_read(void *context, unsigned int offset,
145 void *buf, size_t bytes)
146{
147 struct meson_mx_efuse *efuse = context;
148 u32 tmp;
149 int err, i, addr;
150
151 err = meson_mx_efuse_hw_enable(efuse);
152 if (err)
153 return err;
154
155 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
156 MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE,
157 MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE);
158
159 for (i = offset; i < offset + bytes; i += efuse->config.word_size) {
160 addr = i / efuse->config.word_size;
161
162 err = meson_mx_efuse_read_addr(efuse, addr, &tmp);
163 if (err)
164 break;
165
166 memcpy(buf + i, &tmp, efuse->config.word_size);
167 }
168
169 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
170 MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE, 0);
171
172 meson_mx_efuse_hw_disable(efuse);
173
174 return err;
175}
176
177static const struct meson_mx_efuse_platform_data meson6_efuse_data = {
178 .name = "meson6-efuse",
179 .word_size = 1,
180};
181
182static const struct meson_mx_efuse_platform_data meson8_efuse_data = {
183 .name = "meson8-efuse",
184 .word_size = 4,
185};
186
187static const struct meson_mx_efuse_platform_data meson8b_efuse_data = {
188 .name = "meson8b-efuse",
189 .word_size = 4,
190};
191
192static const struct of_device_id meson_mx_efuse_match[] = {
193 { .compatible = "amlogic,meson6-efuse", .data = &meson6_efuse_data },
194 { .compatible = "amlogic,meson8-efuse", .data = &meson8_efuse_data },
195 { .compatible = "amlogic,meson8b-efuse", .data = &meson8b_efuse_data },
196 { /* sentinel */ },
197};
198MODULE_DEVICE_TABLE(of, meson_mx_efuse_match);
199
200static int meson_mx_efuse_probe(struct platform_device *pdev)
201{
202 const struct meson_mx_efuse_platform_data *drvdata;
203 struct meson_mx_efuse *efuse;
204 struct resource *res;
205
206 drvdata = of_device_get_match_data(&pdev->dev);
207 if (!drvdata)
208 return -EINVAL;
209
210 efuse = devm_kzalloc(&pdev->dev, sizeof(*efuse), GFP_KERNEL);
211 if (!efuse)
212 return -ENOMEM;
213
214 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
215 efuse->base = devm_ioremap_resource(&pdev->dev, res);
216 if (IS_ERR(efuse->base))
217 return PTR_ERR(efuse->base);
218
219 efuse->config.name = devm_kstrdup(&pdev->dev, drvdata->name,
220 GFP_KERNEL);
221 efuse->config.owner = THIS_MODULE;
222 efuse->config.dev = &pdev->dev;
223 efuse->config.priv = efuse;
224 efuse->config.stride = drvdata->word_size;
225 efuse->config.word_size = drvdata->word_size;
226 efuse->config.size = SZ_512;
227 efuse->config.read_only = true;
228 efuse->config.reg_read = meson_mx_efuse_read;
229
230 efuse->core_clk = devm_clk_get(&pdev->dev, "core");
231 if (IS_ERR(efuse->core_clk)) {
232 dev_err(&pdev->dev, "Failed to get core clock\n");
233 return PTR_ERR(efuse->core_clk);
234 }
235
236 efuse->nvmem = nvmem_register(&efuse->config);
237 if (IS_ERR(efuse->nvmem))
238 return PTR_ERR(efuse->nvmem);
239
240 platform_set_drvdata(pdev, efuse);
241
242 return 0;
243}
244
245static int meson_mx_efuse_remove(struct platform_device *pdev)
246{
247 struct meson_mx_efuse *efuse = platform_get_drvdata(pdev);
248
249 return nvmem_unregister(efuse->nvmem);
250}
251
252static struct platform_driver meson_mx_efuse_driver = {
253 .probe = meson_mx_efuse_probe,
254 .remove = meson_mx_efuse_remove,
255 .driver = {
256 .name = "meson-mx-efuse",
257 .of_match_table = meson_mx_efuse_match,
258 },
259};
260
261module_platform_driver(meson_mx_efuse_driver);
262
263MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
264MODULE_DESCRIPTION("Amlogic Meson MX eFuse NVMEM driver");
265MODULE_LICENSE("GPL v2");
diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c
index 32fd572e18c5..9ee3479cfc7b 100644
--- a/drivers/nvmem/mtk-efuse.c
+++ b/drivers/nvmem/mtk-efuse.c
@@ -18,15 +18,19 @@
18#include <linux/nvmem-provider.h> 18#include <linux/nvmem-provider.h>
19#include <linux/platform_device.h> 19#include <linux/platform_device.h>
20 20
21struct mtk_efuse_priv {
22 void __iomem *base;
23};
24
21static int mtk_reg_read(void *context, 25static int mtk_reg_read(void *context,
22 unsigned int reg, void *_val, size_t bytes) 26 unsigned int reg, void *_val, size_t bytes)
23{ 27{
24 void __iomem *base = context; 28 struct mtk_efuse_priv *priv = context;
25 u32 *val = _val; 29 u32 *val = _val;
26 int i = 0, words = bytes / 4; 30 int i = 0, words = bytes / 4;
27 31
28 while (words--) 32 while (words--)
29 *val++ = readl(base + reg + (i++ * 4)); 33 *val++ = readl(priv->base + reg + (i++ * 4));
30 34
31 return 0; 35 return 0;
32} 36}
@@ -34,12 +38,12 @@ static int mtk_reg_read(void *context,
34static int mtk_reg_write(void *context, 38static int mtk_reg_write(void *context,
35 unsigned int reg, void *_val, size_t bytes) 39 unsigned int reg, void *_val, size_t bytes)
36{ 40{
37 void __iomem *base = context; 41 struct mtk_efuse_priv *priv = context;
38 u32 *val = _val; 42 u32 *val = _val;
39 int i = 0, words = bytes / 4; 43 int i = 0, words = bytes / 4;
40 44
41 while (words--) 45 while (words--)
42 writel(*val++, base + reg + (i++ * 4)); 46 writel(*val++, priv->base + reg + (i++ * 4));
43 47
44 return 0; 48 return 0;
45} 49}
@@ -49,27 +53,26 @@ static int mtk_efuse_probe(struct platform_device *pdev)
49 struct device *dev = &pdev->dev; 53 struct device *dev = &pdev->dev;
50 struct resource *res; 54 struct resource *res;
51 struct nvmem_device *nvmem; 55 struct nvmem_device *nvmem;
52 struct nvmem_config *econfig; 56 struct nvmem_config econfig = {};
53 void __iomem *base; 57 struct mtk_efuse_priv *priv;
54 58
55 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 59 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
56 base = devm_ioremap_resource(dev, res); 60 if (!priv)
57 if (IS_ERR(base))
58 return PTR_ERR(base);
59
60 econfig = devm_kzalloc(dev, sizeof(*econfig), GFP_KERNEL);
61 if (!econfig)
62 return -ENOMEM; 61 return -ENOMEM;
63 62
64 econfig->stride = 4; 63 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
65 econfig->word_size = 4; 64 priv->base = devm_ioremap_resource(dev, res);
66 econfig->reg_read = mtk_reg_read; 65 if (IS_ERR(priv->base))
67 econfig->reg_write = mtk_reg_write; 66 return PTR_ERR(priv->base);
68 econfig->size = resource_size(res); 67
69 econfig->priv = base; 68 econfig.stride = 4;
70 econfig->dev = dev; 69 econfig.word_size = 4;
71 econfig->owner = THIS_MODULE; 70 econfig.reg_read = mtk_reg_read;
72 nvmem = nvmem_register(econfig); 71 econfig.reg_write = mtk_reg_write;
72 econfig.size = resource_size(res);
73 econfig.priv = priv;
74 econfig.dev = dev;
75 nvmem = nvmem_register(&econfig);
73 if (IS_ERR(nvmem)) 76 if (IS_ERR(nvmem))
74 return PTR_ERR(nvmem); 77 return PTR_ERR(nvmem);
75 78
diff --git a/drivers/nvmem/mxs-ocotp.c b/drivers/nvmem/mxs-ocotp.c
index d26dd03cec80..7018e2ef5714 100644
--- a/drivers/nvmem/mxs-ocotp.c
+++ b/drivers/nvmem/mxs-ocotp.c
@@ -118,7 +118,6 @@ static struct nvmem_config ocotp_config = {
118 .name = "mxs-ocotp", 118 .name = "mxs-ocotp",
119 .stride = 16, 119 .stride = 16,
120 .word_size = 4, 120 .word_size = 4,
121 .owner = THIS_MODULE,
122 .reg_read = mxs_ocotp_read, 121 .reg_read = mxs_ocotp_read,
123}; 122};
124 123
diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c
index 2bdb6c389328..cb3b48b47d64 100644
--- a/drivers/nvmem/qfprom.c
+++ b/drivers/nvmem/qfprom.c
@@ -17,15 +17,19 @@
17#include <linux/nvmem-provider.h> 17#include <linux/nvmem-provider.h>
18#include <linux/platform_device.h> 18#include <linux/platform_device.h>
19 19
20struct qfprom_priv {
21 void __iomem *base;
22};
23
20static int qfprom_reg_read(void *context, 24static int qfprom_reg_read(void *context,
21 unsigned int reg, void *_val, size_t bytes) 25 unsigned int reg, void *_val, size_t bytes)
22{ 26{
23 void __iomem *base = context; 27 struct qfprom_priv *priv = context;
24 u8 *val = _val; 28 u8 *val = _val;
25 int i = 0, words = bytes; 29 int i = 0, words = bytes;
26 30
27 while (words--) 31 while (words--)
28 *val++ = readb(base + reg + i++); 32 *val++ = readb(priv->base + reg + i++);
29 33
30 return 0; 34 return 0;
31} 35}
@@ -33,12 +37,12 @@ static int qfprom_reg_read(void *context,
33static int qfprom_reg_write(void *context, 37static int qfprom_reg_write(void *context,
34 unsigned int reg, void *_val, size_t bytes) 38 unsigned int reg, void *_val, size_t bytes)
35{ 39{
36 void __iomem *base = context; 40 struct qfprom_priv *priv = context;
37 u8 *val = _val; 41 u8 *val = _val;
38 int i = 0, words = bytes; 42 int i = 0, words = bytes;
39 43
40 while (words--) 44 while (words--)
41 writeb(*val++, base + reg + i++); 45 writeb(*val++, priv->base + reg + i++);
42 46
43 return 0; 47 return 0;
44} 48}
@@ -52,7 +56,6 @@ static int qfprom_remove(struct platform_device *pdev)
52 56
53static struct nvmem_config econfig = { 57static struct nvmem_config econfig = {
54 .name = "qfprom", 58 .name = "qfprom",
55 .owner = THIS_MODULE,
56 .stride = 1, 59 .stride = 1,
57 .word_size = 1, 60 .word_size = 1,
58 .reg_read = qfprom_reg_read, 61 .reg_read = qfprom_reg_read,
@@ -64,16 +67,20 @@ static int qfprom_probe(struct platform_device *pdev)
64 struct device *dev = &pdev->dev; 67 struct device *dev = &pdev->dev;
65 struct resource *res; 68 struct resource *res;
66 struct nvmem_device *nvmem; 69 struct nvmem_device *nvmem;
67 void __iomem *base; 70 struct qfprom_priv *priv;
71
72 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
73 if (!priv)
74 return -ENOMEM;
68 75
69 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 76 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
70 base = devm_ioremap_resource(dev, res); 77 priv->base = devm_ioremap_resource(dev, res);
71 if (IS_ERR(base)) 78 if (IS_ERR(priv->base))
72 return PTR_ERR(base); 79 return PTR_ERR(priv->base);
73 80
74 econfig.size = resource_size(res); 81 econfig.size = resource_size(res);
75 econfig.dev = dev; 82 econfig.dev = dev;
76 econfig.priv = base; 83 econfig.priv = priv;
77 84
78 nvmem = nvmem_register(&econfig); 85 nvmem = nvmem_register(&econfig);
79 if (IS_ERR(nvmem)) 86 if (IS_ERR(nvmem))
diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c
index 63e3eb55f3ac..123de77ca5d6 100644
--- a/drivers/nvmem/rockchip-efuse.c
+++ b/drivers/nvmem/rockchip-efuse.c
@@ -149,7 +149,6 @@ static int rockchip_rk3399_efuse_read(void *context, unsigned int offset,
149 149
150static struct nvmem_config econfig = { 150static struct nvmem_config econfig = {
151 .name = "rockchip-efuse", 151 .name = "rockchip-efuse",
152 .owner = THIS_MODULE,
153 .stride = 1, 152 .stride = 1,
154 .word_size = 1, 153 .word_size = 1,
155 .read_only = true, 154 .read_only = true,
@@ -178,6 +177,10 @@ static const struct of_device_id rockchip_efuse_match[] = {
178 .data = (void *)&rockchip_rk3288_efuse_read, 177 .data = (void *)&rockchip_rk3288_efuse_read,
179 }, 178 },
180 { 179 {
180 .compatible = "rockchip,rk3368-efuse",
181 .data = (void *)&rockchip_rk3288_efuse_read,
182 },
183 {
181 .compatible = "rockchip,rk3399-efuse", 184 .compatible = "rockchip,rk3399-efuse",
182 .data = (void *)&rockchip_rk3399_efuse_read, 185 .data = (void *)&rockchip_rk3399_efuse_read,
183 }, 186 },
diff --git a/drivers/nvmem/snvs_lpgpr.c b/drivers/nvmem/snvs_lpgpr.c
new file mode 100644
index 000000000000..e5c2a4a17f03
--- /dev/null
+++ b/drivers/nvmem/snvs_lpgpr.c
@@ -0,0 +1,156 @@
1/*
2 * Copyright (c) 2015 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de>
3 * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation.
8 */
9
10#include <linux/mfd/syscon.h>
11#include <linux/module.h>
12#include <linux/nvmem-provider.h>
13#include <linux/of_device.h>
14#include <linux/regmap.h>
15
16#define IMX6Q_SNVS_HPLR 0x00
17#define IMX6Q_GPR_SL BIT(5)
18#define IMX6Q_SNVS_LPLR 0x34
19#define IMX6Q_GPR_HL BIT(5)
20#define IMX6Q_SNVS_LPGPR 0x68
21
22struct snvs_lpgpr_cfg {
23 int offset;
24 int offset_hplr;
25 int offset_lplr;
26};
27
28struct snvs_lpgpr_priv {
29 struct device_d *dev;
30 struct regmap *regmap;
31 struct nvmem_config cfg;
32 const struct snvs_lpgpr_cfg *dcfg;
33};
34
35static const struct snvs_lpgpr_cfg snvs_lpgpr_cfg_imx6q = {
36 .offset = IMX6Q_SNVS_LPGPR,
37 .offset_hplr = IMX6Q_SNVS_HPLR,
38 .offset_lplr = IMX6Q_SNVS_LPLR,
39};
40
41static int snvs_lpgpr_write(void *context, unsigned int offset, void *val,
42 size_t bytes)
43{
44 struct snvs_lpgpr_priv *priv = context;
45 const struct snvs_lpgpr_cfg *dcfg = priv->dcfg;
46 unsigned int lock_reg;
47 int ret;
48
49 ret = regmap_read(priv->regmap, dcfg->offset_hplr, &lock_reg);
50 if (ret < 0)
51 return ret;
52
53 if (lock_reg & IMX6Q_GPR_SL)
54 return -EPERM;
55
56 ret = regmap_read(priv->regmap, dcfg->offset_lplr, &lock_reg);
57 if (ret < 0)
58 return ret;
59
60 if (lock_reg & IMX6Q_GPR_HL)
61 return -EPERM;
62
63 return regmap_bulk_write(priv->regmap, dcfg->offset + offset, val,
64 bytes / 4);
65}
66
67static int snvs_lpgpr_read(void *context, unsigned int offset, void *val,
68 size_t bytes)
69{
70 struct snvs_lpgpr_priv *priv = context;
71 const struct snvs_lpgpr_cfg *dcfg = priv->dcfg;
72
73 return regmap_bulk_read(priv->regmap, dcfg->offset + offset,
74 val, bytes / 4);
75}
76
77static int snvs_lpgpr_probe(struct platform_device *pdev)
78{
79 struct device *dev = &pdev->dev;
80 struct device_node *node = dev->of_node;
81 struct device_node *syscon_node;
82 struct snvs_lpgpr_priv *priv;
83 struct nvmem_config *cfg;
84 struct nvmem_device *nvmem;
85 const struct snvs_lpgpr_cfg *dcfg;
86
87 if (!node)
88 return -ENOENT;
89
90 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
91 if (!priv)
92 return -ENOMEM;
93
94 dcfg = of_device_get_match_data(dev);
95 if (!dcfg)
96 return -EINVAL;
97
98 syscon_node = of_get_parent(node);
99 if (!syscon_node)
100 return -ENODEV;
101
102 priv->regmap = syscon_node_to_regmap(syscon_node);
103 of_node_put(syscon_node);
104 if (IS_ERR(priv->regmap))
105 return PTR_ERR(priv->regmap);
106
107 priv->dcfg = dcfg;
108
109 cfg = &priv->cfg;
110 cfg->priv = priv;
111 cfg->name = dev_name(dev);
112 cfg->dev = dev;
113 cfg->stride = 4,
114 cfg->word_size = 4,
115 cfg->size = 4,
116 cfg->owner = THIS_MODULE,
117 cfg->reg_read = snvs_lpgpr_read,
118 cfg->reg_write = snvs_lpgpr_write,
119
120 nvmem = nvmem_register(cfg);
121 if (IS_ERR(nvmem))
122 return PTR_ERR(nvmem);
123
124 platform_set_drvdata(pdev, nvmem);
125
126 return 0;
127}
128
129static int snvs_lpgpr_remove(struct platform_device *pdev)
130{
131 struct nvmem_device *nvmem = platform_get_drvdata(pdev);
132
133 return nvmem_unregister(nvmem);
134}
135
136static const struct of_device_id snvs_lpgpr_dt_ids[] = {
137 { .compatible = "fsl,imx6q-snvs-lpgpr", .data = &snvs_lpgpr_cfg_imx6q },
138 { .compatible = "fsl,imx6ul-snvs-lpgpr",
139 .data = &snvs_lpgpr_cfg_imx6q },
140 { },
141};
142MODULE_DEVICE_TABLE(of, snvs_lpgpr_dt_ids);
143
144static struct platform_driver snvs_lpgpr_driver = {
145 .probe = snvs_lpgpr_probe,
146 .remove = snvs_lpgpr_remove,
147 .driver = {
148 .name = "snvs_lpgpr",
149 .of_match_table = snvs_lpgpr_dt_ids,
150 },
151};
152module_platform_driver(snvs_lpgpr_driver);
153
154MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
155MODULE_DESCRIPTION("Low Power General Purpose Register in i.MX6 Secure Non-Volatile Storage");
156MODULE_LICENSE("GPL v2");
diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
index 0d6648be93b8..99bd54d85fcb 100644
--- a/drivers/nvmem/sunxi_sid.c
+++ b/drivers/nvmem/sunxi_sid.c
@@ -40,7 +40,6 @@ static struct nvmem_config econfig = {
40 .read_only = true, 40 .read_only = true,
41 .stride = 4, 41 .stride = 4,
42 .word_size = 1, 42 .word_size = 1,
43 .owner = THIS_MODULE,
44}; 43};
45 44
46struct sunxi_sid_cfg { 45struct sunxi_sid_cfg {
@@ -199,10 +198,16 @@ static const struct sunxi_sid_cfg sun8i_h3_cfg = {
199 .need_register_readout = true, 198 .need_register_readout = true,
200}; 199};
201 200
201static const struct sunxi_sid_cfg sun50i_a64_cfg = {
202 .value_offset = 0x200,
203 .size = 0x100,
204};
205
202static const struct of_device_id sunxi_sid_of_match[] = { 206static const struct of_device_id sunxi_sid_of_match[] = {
203 { .compatible = "allwinner,sun4i-a10-sid", .data = &sun4i_a10_cfg }, 207 { .compatible = "allwinner,sun4i-a10-sid", .data = &sun4i_a10_cfg },
204 { .compatible = "allwinner,sun7i-a20-sid", .data = &sun7i_a20_cfg }, 208 { .compatible = "allwinner,sun7i-a20-sid", .data = &sun7i_a20_cfg },
205 { .compatible = "allwinner,sun8i-h3-sid", .data = &sun8i_h3_cfg }, 209 { .compatible = "allwinner,sun8i-h3-sid", .data = &sun8i_h3_cfg },
210 { .compatible = "allwinner,sun50i-a64-sid", .data = &sun50i_a64_cfg },
206 {/* sentinel */}, 211 {/* sentinel */},
207}; 212};
208MODULE_DEVICE_TABLE(of, sunxi_sid_of_match); 213MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
diff --git a/drivers/nvmem/uniphier-efuse.c b/drivers/nvmem/uniphier-efuse.c
new file mode 100644
index 000000000000..9d278b4e1dc7
--- /dev/null
+++ b/drivers/nvmem/uniphier-efuse.c
@@ -0,0 +1,97 @@
1/*
2 * UniPhier eFuse driver
3 *
4 * Copyright (C) 2017 Socionext Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/device.h>
17#include <linux/io.h>
18#include <linux/module.h>
19#include <linux/nvmem-provider.h>
20#include <linux/platform_device.h>
21
22struct uniphier_efuse_priv {
23 void __iomem *base;
24};
25
26static int uniphier_reg_read(void *context,
27 unsigned int reg, void *_val, size_t bytes)
28{
29 struct uniphier_efuse_priv *priv = context;
30 u32 *val = _val;
31 int offs;
32
33 for (offs = 0; offs < bytes; offs += sizeof(u32))
34 *val++ = readl(priv->base + reg + offs);
35
36 return 0;
37}
38
39static int uniphier_efuse_probe(struct platform_device *pdev)
40{
41 struct device *dev = &pdev->dev;
42 struct resource *res;
43 struct nvmem_device *nvmem;
44 struct nvmem_config econfig = {};
45 struct uniphier_efuse_priv *priv;
46
47 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
48 if (!priv)
49 return -ENOMEM;
50
51 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
52 priv->base = devm_ioremap_resource(dev, res);
53 if (IS_ERR(priv->base))
54 return PTR_ERR(priv->base);
55
56 econfig.stride = 4;
57 econfig.word_size = 4;
58 econfig.read_only = true;
59 econfig.reg_read = uniphier_reg_read;
60 econfig.size = resource_size(res);
61 econfig.priv = priv;
62 econfig.dev = dev;
63 nvmem = nvmem_register(&econfig);
64 if (IS_ERR(nvmem))
65 return PTR_ERR(nvmem);
66
67 platform_set_drvdata(pdev, nvmem);
68
69 return 0;
70}
71
72static int uniphier_efuse_remove(struct platform_device *pdev)
73{
74 struct nvmem_device *nvmem = platform_get_drvdata(pdev);
75
76 return nvmem_unregister(nvmem);
77}
78
79static const struct of_device_id uniphier_efuse_of_match[] = {
80 { .compatible = "socionext,uniphier-efuse",},
81 {/* sentinel */},
82};
83MODULE_DEVICE_TABLE(of, uniphier_efuse_of_match);
84
85static struct platform_driver uniphier_efuse_driver = {
86 .probe = uniphier_efuse_probe,
87 .remove = uniphier_efuse_remove,
88 .driver = {
89 .name = "uniphier-efuse",
90 .of_match_table = uniphier_efuse_of_match,
91 },
92};
93module_platform_driver(uniphier_efuse_driver);
94
95MODULE_AUTHOR("Keiji Hayashibara <hayashibara.keiji@socionext.com>");
96MODULE_DESCRIPTION("UniPhier eFuse driver");
97MODULE_LICENSE("GPL v2");
diff --git a/drivers/nvmem/vf610-ocotp.c b/drivers/nvmem/vf610-ocotp.c
index 72e4faabce29..5ae9e002f195 100644
--- a/drivers/nvmem/vf610-ocotp.c
+++ b/drivers/nvmem/vf610-ocotp.c
@@ -206,7 +206,6 @@ static int vf610_ocotp_read(void *context, unsigned int offset,
206 206
207static struct nvmem_config ocotp_config = { 207static struct nvmem_config ocotp_config = {
208 .name = "ocotp", 208 .name = "ocotp",
209 .owner = THIS_MODULE,
210 .stride = 4, 209 .stride = 4,
211 .word_size = 4, 210 .word_size = 4,
212 .reg_read = vf610_ocotp_read, 211 .reg_read = vf610_ocotp_read,