1acee2e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23edba6b4SPhilipp Zabel /*
33edba6b4SPhilipp Zabel * i.MX6 OCOTP fusebox driver
43edba6b4SPhilipp Zabel *
53edba6b4SPhilipp Zabel * Copyright (c) 2015 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de>
63edba6b4SPhilipp Zabel *
73311bf18SPeng Fan * Copyright 2019 NXP
83311bf18SPeng Fan *
93edba6b4SPhilipp Zabel * Based on the barebox ocotp driver,
103edba6b4SPhilipp Zabel * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>,
113edba6b4SPhilipp Zabel * Orex Computed Radiography
123edba6b4SPhilipp Zabel *
130642bac7SRichard Leitner * Write support based on the fsl_otp driver,
140642bac7SRichard Leitner * Copyright (C) 2010-2013 Freescale Semiconductor, Inc
153edba6b4SPhilipp Zabel */
163edba6b4SPhilipp Zabel
17deb31970SPeng Fan #include <linux/clk.h>
183edba6b4SPhilipp Zabel #include <linux/device.h>
193edba6b4SPhilipp Zabel #include <linux/io.h>
203edba6b4SPhilipp Zabel #include <linux/module.h>
213edba6b4SPhilipp Zabel #include <linux/nvmem-provider.h>
223edba6b4SPhilipp Zabel #include <linux/of.h>
233edba6b4SPhilipp Zabel #include <linux/platform_device.h>
243edba6b4SPhilipp Zabel #include <linux/slab.h>
250642bac7SRichard Leitner #include <linux/delay.h>
263edba6b4SPhilipp Zabel
279b66587eSRichard Leitner #define IMX_OCOTP_OFFSET_B0W0 0x400 /* Offset from base address of the
289b66587eSRichard Leitner * OTP Bank0 Word0
299b66587eSRichard Leitner */
309b66587eSRichard Leitner #define IMX_OCOTP_OFFSET_PER_WORD 0x10 /* Offset between the start addr
319b66587eSRichard Leitner * of two consecutive OTP words.
329b66587eSRichard Leitner */
330642bac7SRichard Leitner
349b66587eSRichard Leitner #define IMX_OCOTP_ADDR_CTRL 0x0000
350642bac7SRichard Leitner #define IMX_OCOTP_ADDR_CTRL_SET 0x0004
369b66587eSRichard Leitner #define IMX_OCOTP_ADDR_CTRL_CLR 0x0008
370642bac7SRichard Leitner #define IMX_OCOTP_ADDR_TIMING 0x0010
38ffd9115fSBryan O'Donoghue #define IMX_OCOTP_ADDR_DATA0 0x0020
39ffd9115fSBryan O'Donoghue #define IMX_OCOTP_ADDR_DATA1 0x0030
40ffd9115fSBryan O'Donoghue #define IMX_OCOTP_ADDR_DATA2 0x0040
41ffd9115fSBryan O'Donoghue #define IMX_OCOTP_ADDR_DATA3 0x0050
429b66587eSRichard Leitner
43c03bb448SBryan O'Donoghue #define IMX_OCOTP_BM_CTRL_ADDR 0x000000FF
440642bac7SRichard Leitner #define IMX_OCOTP_BM_CTRL_BUSY 0x00000100
459b66587eSRichard Leitner #define IMX_OCOTP_BM_CTRL_ERROR 0x00000200
460642bac7SRichard Leitner #define IMX_OCOTP_BM_CTRL_REL_SHADOWS 0x00000400
479b66587eSRichard Leitner
48c3f4af8bSPeng Fan #define IMX_OCOTP_BM_CTRL_ADDR_8MP 0x000001FF
49c3f4af8bSPeng Fan #define IMX_OCOTP_BM_CTRL_BUSY_8MP 0x00000200
50c3f4af8bSPeng Fan #define IMX_OCOTP_BM_CTRL_ERROR_8MP 0x00000400
51c3f4af8bSPeng Fan #define IMX_OCOTP_BM_CTRL_REL_SHADOWS_8MP 0x00000800
52c3f4af8bSPeng Fan
53226c5126SPeng Fan #define IMX_OCOTP_BM_CTRL_DEFAULT \
54226c5126SPeng Fan { \
55226c5126SPeng Fan .bm_addr = IMX_OCOTP_BM_CTRL_ADDR, \
56226c5126SPeng Fan .bm_busy = IMX_OCOTP_BM_CTRL_BUSY, \
57226c5126SPeng Fan .bm_error = IMX_OCOTP_BM_CTRL_ERROR, \
58226c5126SPeng Fan .bm_rel_shadows = IMX_OCOTP_BM_CTRL_REL_SHADOWS,\
59226c5126SPeng Fan }
60226c5126SPeng Fan
61c3f4af8bSPeng Fan #define IMX_OCOTP_BM_CTRL_8MP \
62c3f4af8bSPeng Fan { \
63c3f4af8bSPeng Fan .bm_addr = IMX_OCOTP_BM_CTRL_ADDR_8MP, \
64c3f4af8bSPeng Fan .bm_busy = IMX_OCOTP_BM_CTRL_BUSY_8MP, \
65c3f4af8bSPeng Fan .bm_error = IMX_OCOTP_BM_CTRL_ERROR_8MP, \
66c3f4af8bSPeng Fan .bm_rel_shadows = IMX_OCOTP_BM_CTRL_REL_SHADOWS_8MP,\
67c3f4af8bSPeng Fan }
68c3f4af8bSPeng Fan
69159dbaf5SBryan O'Donoghue #define TIMING_STROBE_PROG_US 10 /* Min time to blow a fuse */
70159dbaf5SBryan O'Donoghue #define TIMING_STROBE_READ_NS 37 /* Min time before read */
71159dbaf5SBryan O'Donoghue #define TIMING_RELAX_NS 17
72828ae7a4SBryan O'Donoghue #define DEF_FSOURCE 1001 /* > 1000 ns */
73828ae7a4SBryan O'Donoghue #define DEF_STROBE_PROG 10000 /* IPG clocks */
740642bac7SRichard Leitner #define IMX_OCOTP_WR_UNLOCK 0x3E770000
759b66587eSRichard Leitner #define IMX_OCOTP_READ_LOCKED_VAL 0xBADABADA
769b66587eSRichard Leitner
770642bac7SRichard Leitner static DEFINE_MUTEX(ocotp_mutex);
780642bac7SRichard Leitner
793edba6b4SPhilipp Zabel struct ocotp_priv {
803edba6b4SPhilipp Zabel struct device *dev;
81deb31970SPeng Fan struct clk *clk;
823edba6b4SPhilipp Zabel void __iomem *base;
83e20d2b29SBryan O'Donoghue const struct ocotp_params *params;
840642bac7SRichard Leitner struct nvmem_config *config;
853edba6b4SPhilipp Zabel };
863edba6b4SPhilipp Zabel
87226c5126SPeng Fan struct ocotp_ctrl_reg {
88226c5126SPeng Fan u32 bm_addr;
89226c5126SPeng Fan u32 bm_busy;
90226c5126SPeng Fan u32 bm_error;
91226c5126SPeng Fan u32 bm_rel_shadows;
92226c5126SPeng Fan };
93226c5126SPeng Fan
94828ae7a4SBryan O'Donoghue struct ocotp_params {
95828ae7a4SBryan O'Donoghue unsigned int nregs;
96828ae7a4SBryan O'Donoghue unsigned int bank_address_words;
97828ae7a4SBryan O'Donoghue void (*set_timing)(struct ocotp_priv *priv);
98226c5126SPeng Fan struct ocotp_ctrl_reg ctrl;
99828ae7a4SBryan O'Donoghue };
100828ae7a4SBryan O'Donoghue
imx_ocotp_wait_for_busy(struct ocotp_priv * priv,u32 flags)101226c5126SPeng Fan static int imx_ocotp_wait_for_busy(struct ocotp_priv *priv, u32 flags)
1020642bac7SRichard Leitner {
1030642bac7SRichard Leitner int count;
1040642bac7SRichard Leitner u32 c, mask;
105226c5126SPeng Fan u32 bm_ctrl_busy, bm_ctrl_error;
106226c5126SPeng Fan void __iomem *base = priv->base;
1070642bac7SRichard Leitner
108226c5126SPeng Fan bm_ctrl_busy = priv->params->ctrl.bm_busy;
109226c5126SPeng Fan bm_ctrl_error = priv->params->ctrl.bm_error;
110226c5126SPeng Fan
111226c5126SPeng Fan mask = bm_ctrl_busy | bm_ctrl_error | flags;
1120642bac7SRichard Leitner
1130642bac7SRichard Leitner for (count = 10000; count >= 0; count--) {
1140642bac7SRichard Leitner c = readl(base + IMX_OCOTP_ADDR_CTRL);
1150642bac7SRichard Leitner if (!(c & mask))
1160642bac7SRichard Leitner break;
1170642bac7SRichard Leitner cpu_relax();
1180642bac7SRichard Leitner }
1190642bac7SRichard Leitner
1200642bac7SRichard Leitner if (count < 0) {
1210642bac7SRichard Leitner /* HW_OCOTP_CTRL[ERROR] will be set under the following
1220642bac7SRichard Leitner * conditions:
1230642bac7SRichard Leitner * - A write is performed to a shadow register during a shadow
1240642bac7SRichard Leitner * reload (essentially, while HW_OCOTP_CTRL[RELOAD_SHADOWS] is
1250642bac7SRichard Leitner * set. In addition, the contents of the shadow register shall
1260642bac7SRichard Leitner * not be updated.
1270642bac7SRichard Leitner * - A write is performed to a shadow register which has been
1280642bac7SRichard Leitner * locked.
1290642bac7SRichard Leitner * - A read is performed to from a shadow register which has
1300642bac7SRichard Leitner * been read locked.
1310642bac7SRichard Leitner * - A program is performed to a fuse word which has been locked
1320642bac7SRichard Leitner * - A read is performed to from a fuse word which has been read
1330642bac7SRichard Leitner * locked.
1340642bac7SRichard Leitner */
135226c5126SPeng Fan if (c & bm_ctrl_error)
1360642bac7SRichard Leitner return -EPERM;
1370642bac7SRichard Leitner return -ETIMEDOUT;
1380642bac7SRichard Leitner }
1390642bac7SRichard Leitner
1400642bac7SRichard Leitner return 0;
1410642bac7SRichard Leitner }
1420642bac7SRichard Leitner
imx_ocotp_clr_err_if_set(struct ocotp_priv * priv)143226c5126SPeng Fan static void imx_ocotp_clr_err_if_set(struct ocotp_priv *priv)
1449b66587eSRichard Leitner {
145226c5126SPeng Fan u32 c, bm_ctrl_error;
146226c5126SPeng Fan void __iomem *base = priv->base;
147226c5126SPeng Fan
148226c5126SPeng Fan bm_ctrl_error = priv->params->ctrl.bm_error;
1499b66587eSRichard Leitner
1509b66587eSRichard Leitner c = readl(base + IMX_OCOTP_ADDR_CTRL);
151226c5126SPeng Fan if (!(c & bm_ctrl_error))
1529b66587eSRichard Leitner return;
1539b66587eSRichard Leitner
154226c5126SPeng Fan writel(bm_ctrl_error, base + IMX_OCOTP_ADDR_CTRL_CLR);
1559b66587eSRichard Leitner }
1569b66587eSRichard Leitner
imx_ocotp_read(void * context,unsigned int offset,void * val,size_t bytes)15733e5e29cSSrinivas Kandagatla static int imx_ocotp_read(void *context, unsigned int offset,
15833e5e29cSSrinivas Kandagatla void *val, size_t bytes)
1593edba6b4SPhilipp Zabel {
1603edba6b4SPhilipp Zabel struct ocotp_priv *priv = context;
1613edba6b4SPhilipp Zabel unsigned int count;
1623311bf18SPeng Fan u8 *buf, *p;
163deb31970SPeng Fan int i, ret;
1643311bf18SPeng Fan u32 index, num_bytes;
1653edba6b4SPhilipp Zabel
1663edba6b4SPhilipp Zabel index = offset >> 2;
1673311bf18SPeng Fan num_bytes = round_up((offset % 4) + bytes, 4);
1683311bf18SPeng Fan count = num_bytes >> 2;
1693edba6b4SPhilipp Zabel
170e20d2b29SBryan O'Donoghue if (count > (priv->params->nregs - index))
171e20d2b29SBryan O'Donoghue count = priv->params->nregs - index;
1723edba6b4SPhilipp Zabel
1733311bf18SPeng Fan p = kzalloc(num_bytes, GFP_KERNEL);
1743311bf18SPeng Fan if (!p)
1753311bf18SPeng Fan return -ENOMEM;
1763311bf18SPeng Fan
1770642bac7SRichard Leitner mutex_lock(&ocotp_mutex);
1780642bac7SRichard Leitner
1793311bf18SPeng Fan buf = p;
1803311bf18SPeng Fan
181deb31970SPeng Fan ret = clk_prepare_enable(priv->clk);
182deb31970SPeng Fan if (ret < 0) {
1830642bac7SRichard Leitner mutex_unlock(&ocotp_mutex);
184deb31970SPeng Fan dev_err(priv->dev, "failed to prepare/enable ocotp clk\n");
1853311bf18SPeng Fan kfree(p);
186deb31970SPeng Fan return ret;
187deb31970SPeng Fan }
1889b66587eSRichard Leitner
189226c5126SPeng Fan ret = imx_ocotp_wait_for_busy(priv, 0);
1900642bac7SRichard Leitner if (ret < 0) {
1910642bac7SRichard Leitner dev_err(priv->dev, "timeout during read setup\n");
1920642bac7SRichard Leitner goto read_end;
1930642bac7SRichard Leitner }
1940642bac7SRichard Leitner
1959b66587eSRichard Leitner for (i = index; i < (index + count); i++) {
1963311bf18SPeng Fan *(u32 *)buf = readl(priv->base + IMX_OCOTP_OFFSET_B0W0 +
1979b66587eSRichard Leitner i * IMX_OCOTP_OFFSET_PER_WORD);
1989b66587eSRichard Leitner
1999b66587eSRichard Leitner /* 47.3.1.2
2009b66587eSRichard Leitner * For "read locked" registers 0xBADABADA will be returned and
2019b66587eSRichard Leitner * HW_OCOTP_CTRL[ERROR] will be set. It must be cleared by
2029b66587eSRichard Leitner * software before any new write, read or reload access can be
2039b66587eSRichard Leitner * issued
2049b66587eSRichard Leitner */
2053311bf18SPeng Fan if (*((u32 *)buf) == IMX_OCOTP_READ_LOCKED_VAL)
206226c5126SPeng Fan imx_ocotp_clr_err_if_set(priv);
2073311bf18SPeng Fan
2083311bf18SPeng Fan buf += 4;
2099b66587eSRichard Leitner }
2103edba6b4SPhilipp Zabel
2113311bf18SPeng Fan index = offset % 4;
2123311bf18SPeng Fan memcpy(val, &p[index], bytes);
2133311bf18SPeng Fan
2140642bac7SRichard Leitner read_end:
215deb31970SPeng Fan clk_disable_unprepare(priv->clk);
2160642bac7SRichard Leitner mutex_unlock(&ocotp_mutex);
2173311bf18SPeng Fan
2183311bf18SPeng Fan kfree(p);
2193311bf18SPeng Fan
2200642bac7SRichard Leitner return ret;
2210642bac7SRichard Leitner }
2220642bac7SRichard Leitner
imx_ocotp_cell_pp(void * context,const char * id,int index,unsigned int offset,void * data,size_t bytes)2235d8e6e6cSMichael Walle static int imx_ocotp_cell_pp(void *context, const char *id, int index,
2245d8e6e6cSMichael Walle unsigned int offset, void *data, size_t bytes)
225d0221a78SSrinivas Kandagatla {
226d0221a78SSrinivas Kandagatla u8 *buf = data;
227d0221a78SSrinivas Kandagatla int i;
228d0221a78SSrinivas Kandagatla
2296c56a82dSMichael Walle /* Deal with some post processing of nvmem cell data */
2306c56a82dSMichael Walle if (id && !strcmp(id, "mac-address"))
231d0221a78SSrinivas Kandagatla for (i = 0; i < bytes / 2; i++)
232d0221a78SSrinivas Kandagatla swap(buf[i], buf[bytes - i - 1]);
233d0221a78SSrinivas Kandagatla
234d0221a78SSrinivas Kandagatla return 0;
235d0221a78SSrinivas Kandagatla }
236d0221a78SSrinivas Kandagatla
imx_ocotp_set_imx6_timing(struct ocotp_priv * priv)237b50cb68fSBryan O'Donoghue static void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv)
2380642bac7SRichard Leitner {
23913d588baSAnson Huang unsigned long clk_rate;
2400642bac7SRichard Leitner unsigned long strobe_read, relax, strobe_prog;
24113d588baSAnson Huang u32 timing;
2420642bac7SRichard Leitner
2430642bac7SRichard Leitner /* 47.3.1.3.1
2440642bac7SRichard Leitner * Program HW_OCOTP_TIMING[STROBE_PROG] and HW_OCOTP_TIMING[RELAX]
2450642bac7SRichard Leitner * fields with timing values to match the current frequency of the
2460642bac7SRichard Leitner * ipg_clk. OTP writes will work at maximum bus frequencies as long
2470642bac7SRichard Leitner * as the HW_OCOTP_TIMING parameters are set correctly.
248159dbaf5SBryan O'Donoghue *
249159dbaf5SBryan O'Donoghue * Note: there are minimum timings required to ensure an OTP fuse burns
250159dbaf5SBryan O'Donoghue * correctly that are independent of the ipg_clk. Those values are not
251159dbaf5SBryan O'Donoghue * formally documented anywhere however, working from the minimum
252159dbaf5SBryan O'Donoghue * timings given in u-boot we can say:
253159dbaf5SBryan O'Donoghue *
254159dbaf5SBryan O'Donoghue * - Minimum STROBE_PROG time is 10 microseconds. Intuitively 10
255159dbaf5SBryan O'Donoghue * microseconds feels about right as representative of a minimum time
256159dbaf5SBryan O'Donoghue * to physically burn out a fuse.
257159dbaf5SBryan O'Donoghue *
258159dbaf5SBryan O'Donoghue * - Minimum STROBE_READ i.e. the time to wait post OTP fuse burn before
259159dbaf5SBryan O'Donoghue * performing another read is 37 nanoseconds
260159dbaf5SBryan O'Donoghue *
261159dbaf5SBryan O'Donoghue * - Minimum RELAX timing is 17 nanoseconds. This final RELAX minimum
262159dbaf5SBryan O'Donoghue * timing is not entirely clear the documentation says "This
263159dbaf5SBryan O'Donoghue * count value specifies the time to add to all default timing
264159dbaf5SBryan O'Donoghue * parameters other than the Tpgm and Trd. It is given in number
265159dbaf5SBryan O'Donoghue * of ipg_clk periods." where Tpgm and Trd refer to STROBE_PROG
266159dbaf5SBryan O'Donoghue * and STROBE_READ respectively. What the other timing parameters
267159dbaf5SBryan O'Donoghue * are though, is not specified. Experience shows a zero RELAX
268159dbaf5SBryan O'Donoghue * value will mess up a re-load of the shadow registers post OTP
269159dbaf5SBryan O'Donoghue * burn.
2700642bac7SRichard Leitner */
2710642bac7SRichard Leitner clk_rate = clk_get_rate(priv->clk);
2720642bac7SRichard Leitner
273159dbaf5SBryan O'Donoghue relax = DIV_ROUND_UP(clk_rate * TIMING_RELAX_NS, 1000000000) - 1;
274159dbaf5SBryan O'Donoghue strobe_read = DIV_ROUND_UP(clk_rate * TIMING_STROBE_READ_NS,
275159dbaf5SBryan O'Donoghue 1000000000);
276159dbaf5SBryan O'Donoghue strobe_read += 2 * (relax + 1) - 1;
277159dbaf5SBryan O'Donoghue strobe_prog = DIV_ROUND_CLOSEST(clk_rate * TIMING_STROBE_PROG_US,
278159dbaf5SBryan O'Donoghue 1000000);
279159dbaf5SBryan O'Donoghue strobe_prog += 2 * (relax + 1) - 1;
2800642bac7SRichard Leitner
2810493c479SBryan O'Donoghue timing = readl(priv->base + IMX_OCOTP_ADDR_TIMING) & 0x0FC00000;
2820493c479SBryan O'Donoghue timing |= strobe_prog & 0x00000FFF;
2830642bac7SRichard Leitner timing |= (relax << 12) & 0x0000F000;
2840642bac7SRichard Leitner timing |= (strobe_read << 16) & 0x003F0000;
2850642bac7SRichard Leitner
2860642bac7SRichard Leitner writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING);
287b50cb68fSBryan O'Donoghue }
288b50cb68fSBryan O'Donoghue
imx_ocotp_set_imx7_timing(struct ocotp_priv * priv)289828ae7a4SBryan O'Donoghue static void imx_ocotp_set_imx7_timing(struct ocotp_priv *priv)
290828ae7a4SBryan O'Donoghue {
29113d588baSAnson Huang unsigned long clk_rate;
292828ae7a4SBryan O'Donoghue u64 fsource, strobe_prog;
29313d588baSAnson Huang u32 timing;
294828ae7a4SBryan O'Donoghue
295828ae7a4SBryan O'Donoghue /* i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1
296828ae7a4SBryan O'Donoghue * 6.4.3.3
297828ae7a4SBryan O'Donoghue */
298828ae7a4SBryan O'Donoghue clk_rate = clk_get_rate(priv->clk);
299828ae7a4SBryan O'Donoghue fsource = DIV_ROUND_UP_ULL((u64)clk_rate * DEF_FSOURCE,
300828ae7a4SBryan O'Donoghue NSEC_PER_SEC) + 1;
301828ae7a4SBryan O'Donoghue strobe_prog = DIV_ROUND_CLOSEST_ULL((u64)clk_rate * DEF_STROBE_PROG,
302828ae7a4SBryan O'Donoghue NSEC_PER_SEC) + 1;
303828ae7a4SBryan O'Donoghue
304828ae7a4SBryan O'Donoghue timing = strobe_prog & 0x00000FFF;
305828ae7a4SBryan O'Donoghue timing |= (fsource << 12) & 0x000FF000;
306828ae7a4SBryan O'Donoghue
307828ae7a4SBryan O'Donoghue writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING);
308828ae7a4SBryan O'Donoghue }
309828ae7a4SBryan O'Donoghue
imx_ocotp_write(void * context,unsigned int offset,void * val,size_t bytes)310b50cb68fSBryan O'Donoghue static int imx_ocotp_write(void *context, unsigned int offset, void *val,
311b50cb68fSBryan O'Donoghue size_t bytes)
312b50cb68fSBryan O'Donoghue {
313b50cb68fSBryan O'Donoghue struct ocotp_priv *priv = context;
314b50cb68fSBryan O'Donoghue u32 *buf = val;
315b50cb68fSBryan O'Donoghue int ret;
316b50cb68fSBryan O'Donoghue
317b50cb68fSBryan O'Donoghue u32 ctrl;
318b50cb68fSBryan O'Donoghue u8 waddr;
319b50cb68fSBryan O'Donoghue u8 word = 0;
320b50cb68fSBryan O'Donoghue
321b50cb68fSBryan O'Donoghue /* allow only writing one complete OTP word at a time */
322b50cb68fSBryan O'Donoghue if ((bytes != priv->config->word_size) ||
323b50cb68fSBryan O'Donoghue (offset % priv->config->word_size))
324b50cb68fSBryan O'Donoghue return -EINVAL;
325b50cb68fSBryan O'Donoghue
326b50cb68fSBryan O'Donoghue mutex_lock(&ocotp_mutex);
327b50cb68fSBryan O'Donoghue
328b50cb68fSBryan O'Donoghue ret = clk_prepare_enable(priv->clk);
329b50cb68fSBryan O'Donoghue if (ret < 0) {
330b50cb68fSBryan O'Donoghue mutex_unlock(&ocotp_mutex);
331b50cb68fSBryan O'Donoghue dev_err(priv->dev, "failed to prepare/enable ocotp clk\n");
332b50cb68fSBryan O'Donoghue return ret;
333b50cb68fSBryan O'Donoghue }
334b50cb68fSBryan O'Donoghue
335b50cb68fSBryan O'Donoghue /* Setup the write timing values */
336828ae7a4SBryan O'Donoghue priv->params->set_timing(priv);
3370642bac7SRichard Leitner
3380642bac7SRichard Leitner /* 47.3.1.3.2
3390642bac7SRichard Leitner * Check that HW_OCOTP_CTRL[BUSY] and HW_OCOTP_CTRL[ERROR] are clear.
3400642bac7SRichard Leitner * Overlapped accesses are not supported by the controller. Any pending
3410642bac7SRichard Leitner * write or reload must be completed before a write access can be
3420642bac7SRichard Leitner * requested.
3430642bac7SRichard Leitner */
344226c5126SPeng Fan ret = imx_ocotp_wait_for_busy(priv, 0);
3450642bac7SRichard Leitner if (ret < 0) {
3460642bac7SRichard Leitner dev_err(priv->dev, "timeout during timing setup\n");
3470642bac7SRichard Leitner goto write_end;
3480642bac7SRichard Leitner }
3490642bac7SRichard Leitner
3500642bac7SRichard Leitner /* 47.3.1.3.3
3510642bac7SRichard Leitner * Write the requested address to HW_OCOTP_CTRL[ADDR] and program the
3520642bac7SRichard Leitner * unlock code into HW_OCOTP_CTRL[WR_UNLOCK]. This must be programmed
3530642bac7SRichard Leitner * for each write access. The lock code is documented in the register
3540642bac7SRichard Leitner * description. Both the unlock code and address can be written in the
3550642bac7SRichard Leitner * same operation.
3560642bac7SRichard Leitner */
357ffd9115fSBryan O'Donoghue if (priv->params->bank_address_words != 0) {
358ffd9115fSBryan O'Donoghue /*
359ffd9115fSBryan O'Donoghue * In banked/i.MX7 mode the OTP register bank goes into waddr
360ffd9115fSBryan O'Donoghue * see i.MX 7Solo Applications Processor Reference Manual, Rev.
361ffd9115fSBryan O'Donoghue * 0.1 section 6.4.3.1
362ffd9115fSBryan O'Donoghue */
363ffd9115fSBryan O'Donoghue offset = offset / priv->config->word_size;
364ffd9115fSBryan O'Donoghue waddr = offset / priv->params->bank_address_words;
365ffd9115fSBryan O'Donoghue word = offset & (priv->params->bank_address_words - 1);
366ffd9115fSBryan O'Donoghue } else {
367ffd9115fSBryan O'Donoghue /*
368ffd9115fSBryan O'Donoghue * Non-banked i.MX6 mode.
369ffd9115fSBryan O'Donoghue * OTP write/read address specifies one of 128 word address
370ffd9115fSBryan O'Donoghue * locations
371ffd9115fSBryan O'Donoghue */
3720642bac7SRichard Leitner waddr = offset / 4;
373ffd9115fSBryan O'Donoghue }
3740642bac7SRichard Leitner
3750642bac7SRichard Leitner ctrl = readl(priv->base + IMX_OCOTP_ADDR_CTRL);
376226c5126SPeng Fan ctrl &= ~priv->params->ctrl.bm_addr;
377226c5126SPeng Fan ctrl |= waddr & priv->params->ctrl.bm_addr;
3780642bac7SRichard Leitner ctrl |= IMX_OCOTP_WR_UNLOCK;
3790642bac7SRichard Leitner
3800642bac7SRichard Leitner writel(ctrl, priv->base + IMX_OCOTP_ADDR_CTRL);
3810642bac7SRichard Leitner
3820642bac7SRichard Leitner /* 47.3.1.3.4
3830642bac7SRichard Leitner * Write the data to the HW_OCOTP_DATA register. This will automatically
3840642bac7SRichard Leitner * set HW_OCOTP_CTRL[BUSY] and clear HW_OCOTP_CTRL[WR_UNLOCK]. To
3850642bac7SRichard Leitner * protect programming same OTP bit twice, before program OCOTP will
3860642bac7SRichard Leitner * automatically read fuse value in OTP and use read value to mask
3870642bac7SRichard Leitner * program data. The controller will use masked program data to program
3880642bac7SRichard Leitner * a 32-bit word in the OTP per the address in HW_OCOTP_CTRL[ADDR]. Bit
3890642bac7SRichard Leitner * fields with 1's will result in that OTP bit being programmed. Bit
3900642bac7SRichard Leitner * fields with 0's will be ignored. At the same time that the write is
3910642bac7SRichard Leitner * accepted, the controller makes an internal copy of
3920642bac7SRichard Leitner * HW_OCOTP_CTRL[ADDR] which cannot be updated until the next write
3930642bac7SRichard Leitner * sequence is initiated. This copy guarantees that erroneous writes to
3940642bac7SRichard Leitner * HW_OCOTP_CTRL[ADDR] will not affect an active write operation. It
3950642bac7SRichard Leitner * should also be noted that during the programming HW_OCOTP_DATA will
3960642bac7SRichard Leitner * shift right (with zero fill). This shifting is required to program
3970642bac7SRichard Leitner * the OTP serially. During the write operation, HW_OCOTP_DATA cannot be
3980642bac7SRichard Leitner * modified.
399ffd9115fSBryan O'Donoghue * Note: on i.MX7 there are four data fields to write for banked write
400ffd9115fSBryan O'Donoghue * with the fuse blowing operation only taking place after data0
401ffd9115fSBryan O'Donoghue * has been written. This is why data0 must always be the last
402ffd9115fSBryan O'Donoghue * register written.
4030642bac7SRichard Leitner */
404ffd9115fSBryan O'Donoghue if (priv->params->bank_address_words != 0) {
405ffd9115fSBryan O'Donoghue /* Banked/i.MX7 mode */
406ffd9115fSBryan O'Donoghue switch (word) {
407ffd9115fSBryan O'Donoghue case 0:
408ffd9115fSBryan O'Donoghue writel(0, priv->base + IMX_OCOTP_ADDR_DATA1);
409ffd9115fSBryan O'Donoghue writel(0, priv->base + IMX_OCOTP_ADDR_DATA2);
410ffd9115fSBryan O'Donoghue writel(0, priv->base + IMX_OCOTP_ADDR_DATA3);
411ffd9115fSBryan O'Donoghue writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA0);
412ffd9115fSBryan O'Donoghue break;
413ffd9115fSBryan O'Donoghue case 1:
414ffd9115fSBryan O'Donoghue writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA1);
415ffd9115fSBryan O'Donoghue writel(0, priv->base + IMX_OCOTP_ADDR_DATA2);
416ffd9115fSBryan O'Donoghue writel(0, priv->base + IMX_OCOTP_ADDR_DATA3);
417ffd9115fSBryan O'Donoghue writel(0, priv->base + IMX_OCOTP_ADDR_DATA0);
418ffd9115fSBryan O'Donoghue break;
419ffd9115fSBryan O'Donoghue case 2:
420ffd9115fSBryan O'Donoghue writel(0, priv->base + IMX_OCOTP_ADDR_DATA1);
421ffd9115fSBryan O'Donoghue writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA2);
422ffd9115fSBryan O'Donoghue writel(0, priv->base + IMX_OCOTP_ADDR_DATA3);
423ffd9115fSBryan O'Donoghue writel(0, priv->base + IMX_OCOTP_ADDR_DATA0);
424ffd9115fSBryan O'Donoghue break;
425ffd9115fSBryan O'Donoghue case 3:
426ffd9115fSBryan O'Donoghue writel(0, priv->base + IMX_OCOTP_ADDR_DATA1);
427ffd9115fSBryan O'Donoghue writel(0, priv->base + IMX_OCOTP_ADDR_DATA2);
428ffd9115fSBryan O'Donoghue writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA3);
429ffd9115fSBryan O'Donoghue writel(0, priv->base + IMX_OCOTP_ADDR_DATA0);
430ffd9115fSBryan O'Donoghue break;
431ffd9115fSBryan O'Donoghue }
432ffd9115fSBryan O'Donoghue } else {
433ffd9115fSBryan O'Donoghue /* Non-banked i.MX6 mode */
434ffd9115fSBryan O'Donoghue writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA0);
435ffd9115fSBryan O'Donoghue }
4360642bac7SRichard Leitner
4370642bac7SRichard Leitner /* 47.4.1.4.5
4380642bac7SRichard Leitner * Once complete, the controller will clear BUSY. A write request to a
4390642bac7SRichard Leitner * protected or locked region will result in no OTP access and no
4400642bac7SRichard Leitner * setting of HW_OCOTP_CTRL[BUSY]. In addition HW_OCOTP_CTRL[ERROR] will
4410642bac7SRichard Leitner * be set. It must be cleared by software before any new write access
4420642bac7SRichard Leitner * can be issued.
4430642bac7SRichard Leitner */
444226c5126SPeng Fan ret = imx_ocotp_wait_for_busy(priv, 0);
4450642bac7SRichard Leitner if (ret < 0) {
4460642bac7SRichard Leitner if (ret == -EPERM) {
4470642bac7SRichard Leitner dev_err(priv->dev, "failed write to locked region");
448226c5126SPeng Fan imx_ocotp_clr_err_if_set(priv);
4490642bac7SRichard Leitner } else {
4500642bac7SRichard Leitner dev_err(priv->dev, "timeout during data write\n");
4510642bac7SRichard Leitner }
4520642bac7SRichard Leitner goto write_end;
4530642bac7SRichard Leitner }
4540642bac7SRichard Leitner
4550642bac7SRichard Leitner /* 47.3.1.4
4560642bac7SRichard Leitner * Write Postamble: Due to internal electrical characteristics of the
4570642bac7SRichard Leitner * OTP during writes, all OTP operations following a write must be
4580642bac7SRichard Leitner * separated by 2 us after the clearing of HW_OCOTP_CTRL_BUSY following
4590642bac7SRichard Leitner * the write.
4600642bac7SRichard Leitner */
4610642bac7SRichard Leitner udelay(2);
4620642bac7SRichard Leitner
4630642bac7SRichard Leitner /* reload all shadow registers */
464226c5126SPeng Fan writel(priv->params->ctrl.bm_rel_shadows,
4650642bac7SRichard Leitner priv->base + IMX_OCOTP_ADDR_CTRL_SET);
466226c5126SPeng Fan ret = imx_ocotp_wait_for_busy(priv,
467226c5126SPeng Fan priv->params->ctrl.bm_rel_shadows);
4680e2abffdSAnson Huang if (ret < 0)
4690642bac7SRichard Leitner dev_err(priv->dev, "timeout during shadow register reload\n");
4700642bac7SRichard Leitner
4710642bac7SRichard Leitner write_end:
4720642bac7SRichard Leitner clk_disable_unprepare(priv->clk);
4730642bac7SRichard Leitner mutex_unlock(&ocotp_mutex);
4740e2abffdSAnson Huang return ret < 0 ? ret : bytes;
4753edba6b4SPhilipp Zabel }
4763edba6b4SPhilipp Zabel
4773edba6b4SPhilipp Zabel static struct nvmem_config imx_ocotp_nvmem_config = {
4783edba6b4SPhilipp Zabel .name = "imx-ocotp",
4790642bac7SRichard Leitner .read_only = false,
48033e5e29cSSrinivas Kandagatla .word_size = 4,
4813311bf18SPeng Fan .stride = 1,
48233e5e29cSSrinivas Kandagatla .reg_read = imx_ocotp_read,
4830642bac7SRichard Leitner .reg_write = imx_ocotp_write,
4843edba6b4SPhilipp Zabel };
4853edba6b4SPhilipp Zabel
486e20d2b29SBryan O'Donoghue static const struct ocotp_params imx6q_params = {
487e20d2b29SBryan O'Donoghue .nregs = 128,
488ffd9115fSBryan O'Donoghue .bank_address_words = 0,
489828ae7a4SBryan O'Donoghue .set_timing = imx_ocotp_set_imx6_timing,
490226c5126SPeng Fan .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
491e20d2b29SBryan O'Donoghue };
492e20d2b29SBryan O'Donoghue
493e20d2b29SBryan O'Donoghue static const struct ocotp_params imx6sl_params = {
494e20d2b29SBryan O'Donoghue .nregs = 64,
495ffd9115fSBryan O'Donoghue .bank_address_words = 0,
496828ae7a4SBryan O'Donoghue .set_timing = imx_ocotp_set_imx6_timing,
497226c5126SPeng Fan .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
498e20d2b29SBryan O'Donoghue };
499e20d2b29SBryan O'Donoghue
5006da27821SAnson Huang static const struct ocotp_params imx6sll_params = {
501414a98abSPeng Fan .nregs = 80,
5026da27821SAnson Huang .bank_address_words = 0,
5036da27821SAnson Huang .set_timing = imx_ocotp_set_imx6_timing,
504226c5126SPeng Fan .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
5056da27821SAnson Huang };
5066da27821SAnson Huang
507e20d2b29SBryan O'Donoghue static const struct ocotp_params imx6sx_params = {
508e20d2b29SBryan O'Donoghue .nregs = 128,
509ffd9115fSBryan O'Donoghue .bank_address_words = 0,
510828ae7a4SBryan O'Donoghue .set_timing = imx_ocotp_set_imx6_timing,
511226c5126SPeng Fan .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
512e20d2b29SBryan O'Donoghue };
513e20d2b29SBryan O'Donoghue
514e20d2b29SBryan O'Donoghue static const struct ocotp_params imx6ul_params = {
5157d6e10f5SPeng Fan .nregs = 144,
516ffd9115fSBryan O'Donoghue .bank_address_words = 0,
517828ae7a4SBryan O'Donoghue .set_timing = imx_ocotp_set_imx6_timing,
518226c5126SPeng Fan .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
519e20d2b29SBryan O'Donoghue };
520e20d2b29SBryan O'Donoghue
521ffbc34bfSStefan Wahren static const struct ocotp_params imx6ull_params = {
5222382c1b0SPeng Fan .nregs = 80,
523ffbc34bfSStefan Wahren .bank_address_words = 0,
524ffbc34bfSStefan Wahren .set_timing = imx_ocotp_set_imx6_timing,
525226c5126SPeng Fan .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
526ffbc34bfSStefan Wahren };
527ffbc34bfSStefan Wahren
528e20d2b29SBryan O'Donoghue static const struct ocotp_params imx7d_params = {
529e20d2b29SBryan O'Donoghue .nregs = 64,
530ffd9115fSBryan O'Donoghue .bank_address_words = 4,
531828ae7a4SBryan O'Donoghue .set_timing = imx_ocotp_set_imx7_timing,
532226c5126SPeng Fan .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
533e20d2b29SBryan O'Donoghue };
534e20d2b29SBryan O'Donoghue
535c8b63ddcSAnson Huang static const struct ocotp_params imx7ulp_params = {
536c8b63ddcSAnson Huang .nregs = 256,
537c8b63ddcSAnson Huang .bank_address_words = 0,
538226c5126SPeng Fan .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
539c8b63ddcSAnson Huang };
540c8b63ddcSAnson Huang
54138e7b6efSLucas Stach static const struct ocotp_params imx8mq_params = {
54238e7b6efSLucas Stach .nregs = 256,
5435a1c1724SLeonard Crestez .bank_address_words = 0,
5445a1c1724SLeonard Crestez .set_timing = imx_ocotp_set_imx6_timing,
545226c5126SPeng Fan .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
54638e7b6efSLucas Stach };
54738e7b6efSLucas Stach
5484112c853SBryan O'Donoghue static const struct ocotp_params imx8mm_params = {
5494112c853SBryan O'Donoghue .nregs = 256,
5504112c853SBryan O'Donoghue .bank_address_words = 0,
5514112c853SBryan O'Donoghue .set_timing = imx_ocotp_set_imx6_timing,
552226c5126SPeng Fan .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
5534112c853SBryan O'Donoghue };
5544112c853SBryan O'Donoghue
555d93b5d4aSAnson Huang static const struct ocotp_params imx8mn_params = {
556d93b5d4aSAnson Huang .nregs = 256,
557d93b5d4aSAnson Huang .bank_address_words = 0,
558d93b5d4aSAnson Huang .set_timing = imx_ocotp_set_imx6_timing,
559226c5126SPeng Fan .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
560d93b5d4aSAnson Huang };
561d93b5d4aSAnson Huang
562c3f4af8bSPeng Fan static const struct ocotp_params imx8mp_params = {
563c3f4af8bSPeng Fan .nregs = 384,
564c3f4af8bSPeng Fan .bank_address_words = 0,
565c3f4af8bSPeng Fan .set_timing = imx_ocotp_set_imx6_timing,
566c3f4af8bSPeng Fan .ctrl = IMX_OCOTP_BM_CTRL_8MP,
567c3f4af8bSPeng Fan };
568c3f4af8bSPeng Fan
5693edba6b4SPhilipp Zabel static const struct of_device_id imx_ocotp_dt_ids[] = {
570e20d2b29SBryan O'Donoghue { .compatible = "fsl,imx6q-ocotp", .data = &imx6q_params },
571e20d2b29SBryan O'Donoghue { .compatible = "fsl,imx6sl-ocotp", .data = &imx6sl_params },
572e20d2b29SBryan O'Donoghue { .compatible = "fsl,imx6sx-ocotp", .data = &imx6sx_params },
573e20d2b29SBryan O'Donoghue { .compatible = "fsl,imx6ul-ocotp", .data = &imx6ul_params },
574ffbc34bfSStefan Wahren { .compatible = "fsl,imx6ull-ocotp", .data = &imx6ull_params },
575e20d2b29SBryan O'Donoghue { .compatible = "fsl,imx7d-ocotp", .data = &imx7d_params },
5766da27821SAnson Huang { .compatible = "fsl,imx6sll-ocotp", .data = &imx6sll_params },
577c8b63ddcSAnson Huang { .compatible = "fsl,imx7ulp-ocotp", .data = &imx7ulp_params },
57838e7b6efSLucas Stach { .compatible = "fsl,imx8mq-ocotp", .data = &imx8mq_params },
5794112c853SBryan O'Donoghue { .compatible = "fsl,imx8mm-ocotp", .data = &imx8mm_params },
580d93b5d4aSAnson Huang { .compatible = "fsl,imx8mn-ocotp", .data = &imx8mn_params },
581c3f4af8bSPeng Fan { .compatible = "fsl,imx8mp-ocotp", .data = &imx8mp_params },
5823edba6b4SPhilipp Zabel { },
5833edba6b4SPhilipp Zabel };
5843edba6b4SPhilipp Zabel MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids);
5853edba6b4SPhilipp Zabel
imx_ocotp_fixup_dt_cell_info(struct nvmem_device * nvmem,struct nvmem_cell_info * cell)586*1172460eSMiquel Raynal static void imx_ocotp_fixup_dt_cell_info(struct nvmem_device *nvmem,
5876c56a82dSMichael Walle struct nvmem_cell_info *cell)
5886c56a82dSMichael Walle {
5896c56a82dSMichael Walle cell->read_post_process = imx_ocotp_cell_pp;
5906c56a82dSMichael Walle }
5916c56a82dSMichael Walle
imx_ocotp_probe(struct platform_device * pdev)5923edba6b4SPhilipp Zabel static int imx_ocotp_probe(struct platform_device *pdev)
5933edba6b4SPhilipp Zabel {
5943edba6b4SPhilipp Zabel struct device *dev = &pdev->dev;
5953edba6b4SPhilipp Zabel struct ocotp_priv *priv;
5963edba6b4SPhilipp Zabel struct nvmem_device *nvmem;
5973edba6b4SPhilipp Zabel
5983edba6b4SPhilipp Zabel priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
5993edba6b4SPhilipp Zabel if (!priv)
6003edba6b4SPhilipp Zabel return -ENOMEM;
6013edba6b4SPhilipp Zabel
6024cefb74aSRichard Leitner priv->dev = dev;
6034cefb74aSRichard Leitner
6043b26cd88SAnson Huang priv->base = devm_platform_ioremap_resource(pdev, 0);
6053edba6b4SPhilipp Zabel if (IS_ERR(priv->base))
6063edba6b4SPhilipp Zabel return PTR_ERR(priv->base);
6073edba6b4SPhilipp Zabel
6084cefb74aSRichard Leitner priv->clk = devm_clk_get(dev, NULL);
609deb31970SPeng Fan if (IS_ERR(priv->clk))
610deb31970SPeng Fan return PTR_ERR(priv->clk);
611deb31970SPeng Fan
612e20d2b29SBryan O'Donoghue priv->params = of_device_get_match_data(&pdev->dev);
6132cc3b37fSRafał Miłecki imx_ocotp_nvmem_config.add_legacy_fixed_of_cells = true;
614e20d2b29SBryan O'Donoghue imx_ocotp_nvmem_config.size = 4 * priv->params->nregs;
6153edba6b4SPhilipp Zabel imx_ocotp_nvmem_config.dev = dev;
61633e5e29cSSrinivas Kandagatla imx_ocotp_nvmem_config.priv = priv;
617*1172460eSMiquel Raynal imx_ocotp_nvmem_config.fixup_dt_cell_info = &imx_ocotp_fixup_dt_cell_info;
6186c56a82dSMichael Walle
6190642bac7SRichard Leitner priv->config = &imx_ocotp_nvmem_config;
6200642bac7SRichard Leitner
621226c5126SPeng Fan clk_prepare_enable(priv->clk);
622226c5126SPeng Fan imx_ocotp_clr_err_if_set(priv);
623226c5126SPeng Fan clk_disable_unprepare(priv->clk);
624226c5126SPeng Fan
625226c5126SPeng Fan nvmem = devm_nvmem_register(dev, &imx_ocotp_nvmem_config);
6263edba6b4SPhilipp Zabel
627a830274fSAndrey Smirnov return PTR_ERR_OR_ZERO(nvmem);
6283edba6b4SPhilipp Zabel }
6293edba6b4SPhilipp Zabel
6303edba6b4SPhilipp Zabel static struct platform_driver imx_ocotp_driver = {
6313edba6b4SPhilipp Zabel .probe = imx_ocotp_probe,
6323edba6b4SPhilipp Zabel .driver = {
6333edba6b4SPhilipp Zabel .name = "imx_ocotp",
6343edba6b4SPhilipp Zabel .of_match_table = imx_ocotp_dt_ids,
6353edba6b4SPhilipp Zabel },
6363edba6b4SPhilipp Zabel };
6373edba6b4SPhilipp Zabel module_platform_driver(imx_ocotp_driver);
6383edba6b4SPhilipp Zabel
6393edba6b4SPhilipp Zabel MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>");
640aef9a4deSBryan O'Donoghue MODULE_DESCRIPTION("i.MX6/i.MX7 OCOTP fuse box driver");
6413edba6b4SPhilipp Zabel MODULE_LICENSE("GPL v2");
642