162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * i.MX6 OCOTP fusebox driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2015 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright 2019 NXP 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Based on the barebox ocotp driver, 1062306a36Sopenharmony_ci * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>, 1162306a36Sopenharmony_ci * Orex Computed Radiography 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Write support based on the fsl_otp driver, 1462306a36Sopenharmony_ci * Copyright (C) 2010-2013 Freescale Semiconductor, Inc 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/clk.h> 1862306a36Sopenharmony_ci#include <linux/device.h> 1962306a36Sopenharmony_ci#include <linux/io.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/nvmem-provider.h> 2262306a36Sopenharmony_ci#include <linux/of.h> 2362306a36Sopenharmony_ci#include <linux/platform_device.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/delay.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define IMX_OCOTP_OFFSET_B0W0 0x400 /* Offset from base address of the 2862306a36Sopenharmony_ci * OTP Bank0 Word0 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci#define IMX_OCOTP_OFFSET_PER_WORD 0x10 /* Offset between the start addr 3162306a36Sopenharmony_ci * of two consecutive OTP words. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define IMX_OCOTP_ADDR_CTRL 0x0000 3562306a36Sopenharmony_ci#define IMX_OCOTP_ADDR_CTRL_SET 0x0004 3662306a36Sopenharmony_ci#define IMX_OCOTP_ADDR_CTRL_CLR 0x0008 3762306a36Sopenharmony_ci#define IMX_OCOTP_ADDR_TIMING 0x0010 3862306a36Sopenharmony_ci#define IMX_OCOTP_ADDR_DATA0 0x0020 3962306a36Sopenharmony_ci#define IMX_OCOTP_ADDR_DATA1 0x0030 4062306a36Sopenharmony_ci#define IMX_OCOTP_ADDR_DATA2 0x0040 4162306a36Sopenharmony_ci#define IMX_OCOTP_ADDR_DATA3 0x0050 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define IMX_OCOTP_BM_CTRL_ADDR 0x000000FF 4462306a36Sopenharmony_ci#define IMX_OCOTP_BM_CTRL_BUSY 0x00000100 4562306a36Sopenharmony_ci#define IMX_OCOTP_BM_CTRL_ERROR 0x00000200 4662306a36Sopenharmony_ci#define IMX_OCOTP_BM_CTRL_REL_SHADOWS 0x00000400 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define IMX_OCOTP_BM_CTRL_ADDR_8MP 0x000001FF 4962306a36Sopenharmony_ci#define IMX_OCOTP_BM_CTRL_BUSY_8MP 0x00000200 5062306a36Sopenharmony_ci#define IMX_OCOTP_BM_CTRL_ERROR_8MP 0x00000400 5162306a36Sopenharmony_ci#define IMX_OCOTP_BM_CTRL_REL_SHADOWS_8MP 0x00000800 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define IMX_OCOTP_BM_CTRL_DEFAULT \ 5462306a36Sopenharmony_ci { \ 5562306a36Sopenharmony_ci .bm_addr = IMX_OCOTP_BM_CTRL_ADDR, \ 5662306a36Sopenharmony_ci .bm_busy = IMX_OCOTP_BM_CTRL_BUSY, \ 5762306a36Sopenharmony_ci .bm_error = IMX_OCOTP_BM_CTRL_ERROR, \ 5862306a36Sopenharmony_ci .bm_rel_shadows = IMX_OCOTP_BM_CTRL_REL_SHADOWS,\ 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define IMX_OCOTP_BM_CTRL_8MP \ 6262306a36Sopenharmony_ci { \ 6362306a36Sopenharmony_ci .bm_addr = IMX_OCOTP_BM_CTRL_ADDR_8MP, \ 6462306a36Sopenharmony_ci .bm_busy = IMX_OCOTP_BM_CTRL_BUSY_8MP, \ 6562306a36Sopenharmony_ci .bm_error = IMX_OCOTP_BM_CTRL_ERROR_8MP, \ 6662306a36Sopenharmony_ci .bm_rel_shadows = IMX_OCOTP_BM_CTRL_REL_SHADOWS_8MP,\ 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define TIMING_STROBE_PROG_US 10 /* Min time to blow a fuse */ 7062306a36Sopenharmony_ci#define TIMING_STROBE_READ_NS 37 /* Min time before read */ 7162306a36Sopenharmony_ci#define TIMING_RELAX_NS 17 7262306a36Sopenharmony_ci#define DEF_FSOURCE 1001 /* > 1000 ns */ 7362306a36Sopenharmony_ci#define DEF_STROBE_PROG 10000 /* IPG clocks */ 7462306a36Sopenharmony_ci#define IMX_OCOTP_WR_UNLOCK 0x3E770000 7562306a36Sopenharmony_ci#define IMX_OCOTP_READ_LOCKED_VAL 0xBADABADA 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic DEFINE_MUTEX(ocotp_mutex); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistruct ocotp_priv { 8062306a36Sopenharmony_ci struct device *dev; 8162306a36Sopenharmony_ci struct clk *clk; 8262306a36Sopenharmony_ci void __iomem *base; 8362306a36Sopenharmony_ci const struct ocotp_params *params; 8462306a36Sopenharmony_ci struct nvmem_config *config; 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistruct ocotp_ctrl_reg { 8862306a36Sopenharmony_ci u32 bm_addr; 8962306a36Sopenharmony_ci u32 bm_busy; 9062306a36Sopenharmony_ci u32 bm_error; 9162306a36Sopenharmony_ci u32 bm_rel_shadows; 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistruct ocotp_params { 9562306a36Sopenharmony_ci unsigned int nregs; 9662306a36Sopenharmony_ci unsigned int bank_address_words; 9762306a36Sopenharmony_ci void (*set_timing)(struct ocotp_priv *priv); 9862306a36Sopenharmony_ci struct ocotp_ctrl_reg ctrl; 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int imx_ocotp_wait_for_busy(struct ocotp_priv *priv, u32 flags) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci int count; 10462306a36Sopenharmony_ci u32 c, mask; 10562306a36Sopenharmony_ci u32 bm_ctrl_busy, bm_ctrl_error; 10662306a36Sopenharmony_ci void __iomem *base = priv->base; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci bm_ctrl_busy = priv->params->ctrl.bm_busy; 10962306a36Sopenharmony_ci bm_ctrl_error = priv->params->ctrl.bm_error; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci mask = bm_ctrl_busy | bm_ctrl_error | flags; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci for (count = 10000; count >= 0; count--) { 11462306a36Sopenharmony_ci c = readl(base + IMX_OCOTP_ADDR_CTRL); 11562306a36Sopenharmony_ci if (!(c & mask)) 11662306a36Sopenharmony_ci break; 11762306a36Sopenharmony_ci cpu_relax(); 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (count < 0) { 12162306a36Sopenharmony_ci /* HW_OCOTP_CTRL[ERROR] will be set under the following 12262306a36Sopenharmony_ci * conditions: 12362306a36Sopenharmony_ci * - A write is performed to a shadow register during a shadow 12462306a36Sopenharmony_ci * reload (essentially, while HW_OCOTP_CTRL[RELOAD_SHADOWS] is 12562306a36Sopenharmony_ci * set. In addition, the contents of the shadow register shall 12662306a36Sopenharmony_ci * not be updated. 12762306a36Sopenharmony_ci * - A write is performed to a shadow register which has been 12862306a36Sopenharmony_ci * locked. 12962306a36Sopenharmony_ci * - A read is performed to from a shadow register which has 13062306a36Sopenharmony_ci * been read locked. 13162306a36Sopenharmony_ci * - A program is performed to a fuse word which has been locked 13262306a36Sopenharmony_ci * - A read is performed to from a fuse word which has been read 13362306a36Sopenharmony_ci * locked. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci if (c & bm_ctrl_error) 13662306a36Sopenharmony_ci return -EPERM; 13762306a36Sopenharmony_ci return -ETIMEDOUT; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return 0; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void imx_ocotp_clr_err_if_set(struct ocotp_priv *priv) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci u32 c, bm_ctrl_error; 14662306a36Sopenharmony_ci void __iomem *base = priv->base; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci bm_ctrl_error = priv->params->ctrl.bm_error; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci c = readl(base + IMX_OCOTP_ADDR_CTRL); 15162306a36Sopenharmony_ci if (!(c & bm_ctrl_error)) 15262306a36Sopenharmony_ci return; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci writel(bm_ctrl_error, base + IMX_OCOTP_ADDR_CTRL_CLR); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic int imx_ocotp_read(void *context, unsigned int offset, 15862306a36Sopenharmony_ci void *val, size_t bytes) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct ocotp_priv *priv = context; 16162306a36Sopenharmony_ci unsigned int count; 16262306a36Sopenharmony_ci u8 *buf, *p; 16362306a36Sopenharmony_ci int i, ret; 16462306a36Sopenharmony_ci u32 index, num_bytes; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci index = offset >> 2; 16762306a36Sopenharmony_ci num_bytes = round_up((offset % 4) + bytes, 4); 16862306a36Sopenharmony_ci count = num_bytes >> 2; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (count > (priv->params->nregs - index)) 17162306a36Sopenharmony_ci count = priv->params->nregs - index; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci p = kzalloc(num_bytes, GFP_KERNEL); 17462306a36Sopenharmony_ci if (!p) 17562306a36Sopenharmony_ci return -ENOMEM; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci mutex_lock(&ocotp_mutex); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci buf = p; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 18262306a36Sopenharmony_ci if (ret < 0) { 18362306a36Sopenharmony_ci mutex_unlock(&ocotp_mutex); 18462306a36Sopenharmony_ci dev_err(priv->dev, "failed to prepare/enable ocotp clk\n"); 18562306a36Sopenharmony_ci kfree(p); 18662306a36Sopenharmony_ci return ret; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci ret = imx_ocotp_wait_for_busy(priv, 0); 19062306a36Sopenharmony_ci if (ret < 0) { 19162306a36Sopenharmony_ci dev_err(priv->dev, "timeout during read setup\n"); 19262306a36Sopenharmony_ci goto read_end; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci for (i = index; i < (index + count); i++) { 19662306a36Sopenharmony_ci *(u32 *)buf = readl(priv->base + IMX_OCOTP_OFFSET_B0W0 + 19762306a36Sopenharmony_ci i * IMX_OCOTP_OFFSET_PER_WORD); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* 47.3.1.2 20062306a36Sopenharmony_ci * For "read locked" registers 0xBADABADA will be returned and 20162306a36Sopenharmony_ci * HW_OCOTP_CTRL[ERROR] will be set. It must be cleared by 20262306a36Sopenharmony_ci * software before any new write, read or reload access can be 20362306a36Sopenharmony_ci * issued 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_ci if (*((u32 *)buf) == IMX_OCOTP_READ_LOCKED_VAL) 20662306a36Sopenharmony_ci imx_ocotp_clr_err_if_set(priv); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci buf += 4; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci index = offset % 4; 21262306a36Sopenharmony_ci memcpy(val, &p[index], bytes); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ciread_end: 21562306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 21662306a36Sopenharmony_ci mutex_unlock(&ocotp_mutex); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci kfree(p); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return ret; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic int imx_ocotp_cell_pp(void *context, const char *id, int index, 22462306a36Sopenharmony_ci unsigned int offset, void *data, size_t bytes) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci u8 *buf = data; 22762306a36Sopenharmony_ci int i; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* Deal with some post processing of nvmem cell data */ 23062306a36Sopenharmony_ci if (id && !strcmp(id, "mac-address")) 23162306a36Sopenharmony_ci for (i = 0; i < bytes / 2; i++) 23262306a36Sopenharmony_ci swap(buf[i], buf[bytes - i - 1]); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci unsigned long clk_rate; 24062306a36Sopenharmony_ci unsigned long strobe_read, relax, strobe_prog; 24162306a36Sopenharmony_ci u32 timing; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* 47.3.1.3.1 24462306a36Sopenharmony_ci * Program HW_OCOTP_TIMING[STROBE_PROG] and HW_OCOTP_TIMING[RELAX] 24562306a36Sopenharmony_ci * fields with timing values to match the current frequency of the 24662306a36Sopenharmony_ci * ipg_clk. OTP writes will work at maximum bus frequencies as long 24762306a36Sopenharmony_ci * as the HW_OCOTP_TIMING parameters are set correctly. 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * Note: there are minimum timings required to ensure an OTP fuse burns 25062306a36Sopenharmony_ci * correctly that are independent of the ipg_clk. Those values are not 25162306a36Sopenharmony_ci * formally documented anywhere however, working from the minimum 25262306a36Sopenharmony_ci * timings given in u-boot we can say: 25362306a36Sopenharmony_ci * 25462306a36Sopenharmony_ci * - Minimum STROBE_PROG time is 10 microseconds. Intuitively 10 25562306a36Sopenharmony_ci * microseconds feels about right as representative of a minimum time 25662306a36Sopenharmony_ci * to physically burn out a fuse. 25762306a36Sopenharmony_ci * 25862306a36Sopenharmony_ci * - Minimum STROBE_READ i.e. the time to wait post OTP fuse burn before 25962306a36Sopenharmony_ci * performing another read is 37 nanoseconds 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * - Minimum RELAX timing is 17 nanoseconds. This final RELAX minimum 26262306a36Sopenharmony_ci * timing is not entirely clear the documentation says "This 26362306a36Sopenharmony_ci * count value specifies the time to add to all default timing 26462306a36Sopenharmony_ci * parameters other than the Tpgm and Trd. It is given in number 26562306a36Sopenharmony_ci * of ipg_clk periods." where Tpgm and Trd refer to STROBE_PROG 26662306a36Sopenharmony_ci * and STROBE_READ respectively. What the other timing parameters 26762306a36Sopenharmony_ci * are though, is not specified. Experience shows a zero RELAX 26862306a36Sopenharmony_ci * value will mess up a re-load of the shadow registers post OTP 26962306a36Sopenharmony_ci * burn. 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci clk_rate = clk_get_rate(priv->clk); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci relax = DIV_ROUND_UP(clk_rate * TIMING_RELAX_NS, 1000000000) - 1; 27462306a36Sopenharmony_ci strobe_read = DIV_ROUND_UP(clk_rate * TIMING_STROBE_READ_NS, 27562306a36Sopenharmony_ci 1000000000); 27662306a36Sopenharmony_ci strobe_read += 2 * (relax + 1) - 1; 27762306a36Sopenharmony_ci strobe_prog = DIV_ROUND_CLOSEST(clk_rate * TIMING_STROBE_PROG_US, 27862306a36Sopenharmony_ci 1000000); 27962306a36Sopenharmony_ci strobe_prog += 2 * (relax + 1) - 1; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci timing = readl(priv->base + IMX_OCOTP_ADDR_TIMING) & 0x0FC00000; 28262306a36Sopenharmony_ci timing |= strobe_prog & 0x00000FFF; 28362306a36Sopenharmony_ci timing |= (relax << 12) & 0x0000F000; 28462306a36Sopenharmony_ci timing |= (strobe_read << 16) & 0x003F0000; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING); 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic void imx_ocotp_set_imx7_timing(struct ocotp_priv *priv) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci unsigned long clk_rate; 29262306a36Sopenharmony_ci u64 fsource, strobe_prog; 29362306a36Sopenharmony_ci u32 timing; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1 29662306a36Sopenharmony_ci * 6.4.3.3 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_ci clk_rate = clk_get_rate(priv->clk); 29962306a36Sopenharmony_ci fsource = DIV_ROUND_UP_ULL((u64)clk_rate * DEF_FSOURCE, 30062306a36Sopenharmony_ci NSEC_PER_SEC) + 1; 30162306a36Sopenharmony_ci strobe_prog = DIV_ROUND_CLOSEST_ULL((u64)clk_rate * DEF_STROBE_PROG, 30262306a36Sopenharmony_ci NSEC_PER_SEC) + 1; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci timing = strobe_prog & 0x00000FFF; 30562306a36Sopenharmony_ci timing |= (fsource << 12) & 0x000FF000; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int imx_ocotp_write(void *context, unsigned int offset, void *val, 31162306a36Sopenharmony_ci size_t bytes) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct ocotp_priv *priv = context; 31462306a36Sopenharmony_ci u32 *buf = val; 31562306a36Sopenharmony_ci int ret; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci u32 ctrl; 31862306a36Sopenharmony_ci u8 waddr; 31962306a36Sopenharmony_ci u8 word = 0; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* allow only writing one complete OTP word at a time */ 32262306a36Sopenharmony_ci if ((bytes != priv->config->word_size) || 32362306a36Sopenharmony_ci (offset % priv->config->word_size)) 32462306a36Sopenharmony_ci return -EINVAL; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci mutex_lock(&ocotp_mutex); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 32962306a36Sopenharmony_ci if (ret < 0) { 33062306a36Sopenharmony_ci mutex_unlock(&ocotp_mutex); 33162306a36Sopenharmony_ci dev_err(priv->dev, "failed to prepare/enable ocotp clk\n"); 33262306a36Sopenharmony_ci return ret; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* Setup the write timing values */ 33662306a36Sopenharmony_ci priv->params->set_timing(priv); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* 47.3.1.3.2 33962306a36Sopenharmony_ci * Check that HW_OCOTP_CTRL[BUSY] and HW_OCOTP_CTRL[ERROR] are clear. 34062306a36Sopenharmony_ci * Overlapped accesses are not supported by the controller. Any pending 34162306a36Sopenharmony_ci * write or reload must be completed before a write access can be 34262306a36Sopenharmony_ci * requested. 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_ci ret = imx_ocotp_wait_for_busy(priv, 0); 34562306a36Sopenharmony_ci if (ret < 0) { 34662306a36Sopenharmony_ci dev_err(priv->dev, "timeout during timing setup\n"); 34762306a36Sopenharmony_ci goto write_end; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* 47.3.1.3.3 35162306a36Sopenharmony_ci * Write the requested address to HW_OCOTP_CTRL[ADDR] and program the 35262306a36Sopenharmony_ci * unlock code into HW_OCOTP_CTRL[WR_UNLOCK]. This must be programmed 35362306a36Sopenharmony_ci * for each write access. The lock code is documented in the register 35462306a36Sopenharmony_ci * description. Both the unlock code and address can be written in the 35562306a36Sopenharmony_ci * same operation. 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_ci if (priv->params->bank_address_words != 0) { 35862306a36Sopenharmony_ci /* 35962306a36Sopenharmony_ci * In banked/i.MX7 mode the OTP register bank goes into waddr 36062306a36Sopenharmony_ci * see i.MX 7Solo Applications Processor Reference Manual, Rev. 36162306a36Sopenharmony_ci * 0.1 section 6.4.3.1 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci offset = offset / priv->config->word_size; 36462306a36Sopenharmony_ci waddr = offset / priv->params->bank_address_words; 36562306a36Sopenharmony_ci word = offset & (priv->params->bank_address_words - 1); 36662306a36Sopenharmony_ci } else { 36762306a36Sopenharmony_ci /* 36862306a36Sopenharmony_ci * Non-banked i.MX6 mode. 36962306a36Sopenharmony_ci * OTP write/read address specifies one of 128 word address 37062306a36Sopenharmony_ci * locations 37162306a36Sopenharmony_ci */ 37262306a36Sopenharmony_ci waddr = offset / 4; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci ctrl = readl(priv->base + IMX_OCOTP_ADDR_CTRL); 37662306a36Sopenharmony_ci ctrl &= ~priv->params->ctrl.bm_addr; 37762306a36Sopenharmony_ci ctrl |= waddr & priv->params->ctrl.bm_addr; 37862306a36Sopenharmony_ci ctrl |= IMX_OCOTP_WR_UNLOCK; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci writel(ctrl, priv->base + IMX_OCOTP_ADDR_CTRL); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* 47.3.1.3.4 38362306a36Sopenharmony_ci * Write the data to the HW_OCOTP_DATA register. This will automatically 38462306a36Sopenharmony_ci * set HW_OCOTP_CTRL[BUSY] and clear HW_OCOTP_CTRL[WR_UNLOCK]. To 38562306a36Sopenharmony_ci * protect programming same OTP bit twice, before program OCOTP will 38662306a36Sopenharmony_ci * automatically read fuse value in OTP and use read value to mask 38762306a36Sopenharmony_ci * program data. The controller will use masked program data to program 38862306a36Sopenharmony_ci * a 32-bit word in the OTP per the address in HW_OCOTP_CTRL[ADDR]. Bit 38962306a36Sopenharmony_ci * fields with 1's will result in that OTP bit being programmed. Bit 39062306a36Sopenharmony_ci * fields with 0's will be ignored. At the same time that the write is 39162306a36Sopenharmony_ci * accepted, the controller makes an internal copy of 39262306a36Sopenharmony_ci * HW_OCOTP_CTRL[ADDR] which cannot be updated until the next write 39362306a36Sopenharmony_ci * sequence is initiated. This copy guarantees that erroneous writes to 39462306a36Sopenharmony_ci * HW_OCOTP_CTRL[ADDR] will not affect an active write operation. It 39562306a36Sopenharmony_ci * should also be noted that during the programming HW_OCOTP_DATA will 39662306a36Sopenharmony_ci * shift right (with zero fill). This shifting is required to program 39762306a36Sopenharmony_ci * the OTP serially. During the write operation, HW_OCOTP_DATA cannot be 39862306a36Sopenharmony_ci * modified. 39962306a36Sopenharmony_ci * Note: on i.MX7 there are four data fields to write for banked write 40062306a36Sopenharmony_ci * with the fuse blowing operation only taking place after data0 40162306a36Sopenharmony_ci * has been written. This is why data0 must always be the last 40262306a36Sopenharmony_ci * register written. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci if (priv->params->bank_address_words != 0) { 40562306a36Sopenharmony_ci /* Banked/i.MX7 mode */ 40662306a36Sopenharmony_ci switch (word) { 40762306a36Sopenharmony_ci case 0: 40862306a36Sopenharmony_ci writel(0, priv->base + IMX_OCOTP_ADDR_DATA1); 40962306a36Sopenharmony_ci writel(0, priv->base + IMX_OCOTP_ADDR_DATA2); 41062306a36Sopenharmony_ci writel(0, priv->base + IMX_OCOTP_ADDR_DATA3); 41162306a36Sopenharmony_ci writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA0); 41262306a36Sopenharmony_ci break; 41362306a36Sopenharmony_ci case 1: 41462306a36Sopenharmony_ci writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA1); 41562306a36Sopenharmony_ci writel(0, priv->base + IMX_OCOTP_ADDR_DATA2); 41662306a36Sopenharmony_ci writel(0, priv->base + IMX_OCOTP_ADDR_DATA3); 41762306a36Sopenharmony_ci writel(0, priv->base + IMX_OCOTP_ADDR_DATA0); 41862306a36Sopenharmony_ci break; 41962306a36Sopenharmony_ci case 2: 42062306a36Sopenharmony_ci writel(0, priv->base + IMX_OCOTP_ADDR_DATA1); 42162306a36Sopenharmony_ci writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA2); 42262306a36Sopenharmony_ci writel(0, priv->base + IMX_OCOTP_ADDR_DATA3); 42362306a36Sopenharmony_ci writel(0, priv->base + IMX_OCOTP_ADDR_DATA0); 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci case 3: 42662306a36Sopenharmony_ci writel(0, priv->base + IMX_OCOTP_ADDR_DATA1); 42762306a36Sopenharmony_ci writel(0, priv->base + IMX_OCOTP_ADDR_DATA2); 42862306a36Sopenharmony_ci writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA3); 42962306a36Sopenharmony_ci writel(0, priv->base + IMX_OCOTP_ADDR_DATA0); 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci } else { 43362306a36Sopenharmony_ci /* Non-banked i.MX6 mode */ 43462306a36Sopenharmony_ci writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA0); 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* 47.4.1.4.5 43862306a36Sopenharmony_ci * Once complete, the controller will clear BUSY. A write request to a 43962306a36Sopenharmony_ci * protected or locked region will result in no OTP access and no 44062306a36Sopenharmony_ci * setting of HW_OCOTP_CTRL[BUSY]. In addition HW_OCOTP_CTRL[ERROR] will 44162306a36Sopenharmony_ci * be set. It must be cleared by software before any new write access 44262306a36Sopenharmony_ci * can be issued. 44362306a36Sopenharmony_ci */ 44462306a36Sopenharmony_ci ret = imx_ocotp_wait_for_busy(priv, 0); 44562306a36Sopenharmony_ci if (ret < 0) { 44662306a36Sopenharmony_ci if (ret == -EPERM) { 44762306a36Sopenharmony_ci dev_err(priv->dev, "failed write to locked region"); 44862306a36Sopenharmony_ci imx_ocotp_clr_err_if_set(priv); 44962306a36Sopenharmony_ci } else { 45062306a36Sopenharmony_ci dev_err(priv->dev, "timeout during data write\n"); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci goto write_end; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* 47.3.1.4 45662306a36Sopenharmony_ci * Write Postamble: Due to internal electrical characteristics of the 45762306a36Sopenharmony_ci * OTP during writes, all OTP operations following a write must be 45862306a36Sopenharmony_ci * separated by 2 us after the clearing of HW_OCOTP_CTRL_BUSY following 45962306a36Sopenharmony_ci * the write. 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_ci udelay(2); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* reload all shadow registers */ 46462306a36Sopenharmony_ci writel(priv->params->ctrl.bm_rel_shadows, 46562306a36Sopenharmony_ci priv->base + IMX_OCOTP_ADDR_CTRL_SET); 46662306a36Sopenharmony_ci ret = imx_ocotp_wait_for_busy(priv, 46762306a36Sopenharmony_ci priv->params->ctrl.bm_rel_shadows); 46862306a36Sopenharmony_ci if (ret < 0) 46962306a36Sopenharmony_ci dev_err(priv->dev, "timeout during shadow register reload\n"); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ciwrite_end: 47262306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 47362306a36Sopenharmony_ci mutex_unlock(&ocotp_mutex); 47462306a36Sopenharmony_ci return ret < 0 ? ret : bytes; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic struct nvmem_config imx_ocotp_nvmem_config = { 47862306a36Sopenharmony_ci .name = "imx-ocotp", 47962306a36Sopenharmony_ci .read_only = false, 48062306a36Sopenharmony_ci .word_size = 4, 48162306a36Sopenharmony_ci .stride = 1, 48262306a36Sopenharmony_ci .reg_read = imx_ocotp_read, 48362306a36Sopenharmony_ci .reg_write = imx_ocotp_write, 48462306a36Sopenharmony_ci}; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic const struct ocotp_params imx6q_params = { 48762306a36Sopenharmony_ci .nregs = 128, 48862306a36Sopenharmony_ci .bank_address_words = 0, 48962306a36Sopenharmony_ci .set_timing = imx_ocotp_set_imx6_timing, 49062306a36Sopenharmony_ci .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, 49162306a36Sopenharmony_ci}; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic const struct ocotp_params imx6sl_params = { 49462306a36Sopenharmony_ci .nregs = 64, 49562306a36Sopenharmony_ci .bank_address_words = 0, 49662306a36Sopenharmony_ci .set_timing = imx_ocotp_set_imx6_timing, 49762306a36Sopenharmony_ci .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, 49862306a36Sopenharmony_ci}; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic const struct ocotp_params imx6sll_params = { 50162306a36Sopenharmony_ci .nregs = 80, 50262306a36Sopenharmony_ci .bank_address_words = 0, 50362306a36Sopenharmony_ci .set_timing = imx_ocotp_set_imx6_timing, 50462306a36Sopenharmony_ci .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, 50562306a36Sopenharmony_ci}; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic const struct ocotp_params imx6sx_params = { 50862306a36Sopenharmony_ci .nregs = 128, 50962306a36Sopenharmony_ci .bank_address_words = 0, 51062306a36Sopenharmony_ci .set_timing = imx_ocotp_set_imx6_timing, 51162306a36Sopenharmony_ci .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, 51262306a36Sopenharmony_ci}; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic const struct ocotp_params imx6ul_params = { 51562306a36Sopenharmony_ci .nregs = 144, 51662306a36Sopenharmony_ci .bank_address_words = 0, 51762306a36Sopenharmony_ci .set_timing = imx_ocotp_set_imx6_timing, 51862306a36Sopenharmony_ci .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, 51962306a36Sopenharmony_ci}; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic const struct ocotp_params imx6ull_params = { 52262306a36Sopenharmony_ci .nregs = 80, 52362306a36Sopenharmony_ci .bank_address_words = 0, 52462306a36Sopenharmony_ci .set_timing = imx_ocotp_set_imx6_timing, 52562306a36Sopenharmony_ci .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, 52662306a36Sopenharmony_ci}; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic const struct ocotp_params imx7d_params = { 52962306a36Sopenharmony_ci .nregs = 64, 53062306a36Sopenharmony_ci .bank_address_words = 4, 53162306a36Sopenharmony_ci .set_timing = imx_ocotp_set_imx7_timing, 53262306a36Sopenharmony_ci .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, 53362306a36Sopenharmony_ci}; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic const struct ocotp_params imx7ulp_params = { 53662306a36Sopenharmony_ci .nregs = 256, 53762306a36Sopenharmony_ci .bank_address_words = 0, 53862306a36Sopenharmony_ci .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, 53962306a36Sopenharmony_ci}; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic const struct ocotp_params imx8mq_params = { 54262306a36Sopenharmony_ci .nregs = 256, 54362306a36Sopenharmony_ci .bank_address_words = 0, 54462306a36Sopenharmony_ci .set_timing = imx_ocotp_set_imx6_timing, 54562306a36Sopenharmony_ci .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, 54662306a36Sopenharmony_ci}; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic const struct ocotp_params imx8mm_params = { 54962306a36Sopenharmony_ci .nregs = 256, 55062306a36Sopenharmony_ci .bank_address_words = 0, 55162306a36Sopenharmony_ci .set_timing = imx_ocotp_set_imx6_timing, 55262306a36Sopenharmony_ci .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, 55362306a36Sopenharmony_ci}; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic const struct ocotp_params imx8mn_params = { 55662306a36Sopenharmony_ci .nregs = 256, 55762306a36Sopenharmony_ci .bank_address_words = 0, 55862306a36Sopenharmony_ci .set_timing = imx_ocotp_set_imx6_timing, 55962306a36Sopenharmony_ci .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, 56062306a36Sopenharmony_ci}; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic const struct ocotp_params imx8mp_params = { 56362306a36Sopenharmony_ci .nregs = 384, 56462306a36Sopenharmony_ci .bank_address_words = 0, 56562306a36Sopenharmony_ci .set_timing = imx_ocotp_set_imx6_timing, 56662306a36Sopenharmony_ci .ctrl = IMX_OCOTP_BM_CTRL_8MP, 56762306a36Sopenharmony_ci}; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic const struct of_device_id imx_ocotp_dt_ids[] = { 57062306a36Sopenharmony_ci { .compatible = "fsl,imx6q-ocotp", .data = &imx6q_params }, 57162306a36Sopenharmony_ci { .compatible = "fsl,imx6sl-ocotp", .data = &imx6sl_params }, 57262306a36Sopenharmony_ci { .compatible = "fsl,imx6sx-ocotp", .data = &imx6sx_params }, 57362306a36Sopenharmony_ci { .compatible = "fsl,imx6ul-ocotp", .data = &imx6ul_params }, 57462306a36Sopenharmony_ci { .compatible = "fsl,imx6ull-ocotp", .data = &imx6ull_params }, 57562306a36Sopenharmony_ci { .compatible = "fsl,imx7d-ocotp", .data = &imx7d_params }, 57662306a36Sopenharmony_ci { .compatible = "fsl,imx6sll-ocotp", .data = &imx6sll_params }, 57762306a36Sopenharmony_ci { .compatible = "fsl,imx7ulp-ocotp", .data = &imx7ulp_params }, 57862306a36Sopenharmony_ci { .compatible = "fsl,imx8mq-ocotp", .data = &imx8mq_params }, 57962306a36Sopenharmony_ci { .compatible = "fsl,imx8mm-ocotp", .data = &imx8mm_params }, 58062306a36Sopenharmony_ci { .compatible = "fsl,imx8mn-ocotp", .data = &imx8mn_params }, 58162306a36Sopenharmony_ci { .compatible = "fsl,imx8mp-ocotp", .data = &imx8mp_params }, 58262306a36Sopenharmony_ci { }, 58362306a36Sopenharmony_ci}; 58462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic void imx_ocotp_fixup_cell_info(struct nvmem_device *nvmem, 58762306a36Sopenharmony_ci struct nvmem_layout *layout, 58862306a36Sopenharmony_ci struct nvmem_cell_info *cell) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci cell->read_post_process = imx_ocotp_cell_pp; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic struct nvmem_layout imx_ocotp_layout = { 59462306a36Sopenharmony_ci .fixup_cell_info = imx_ocotp_fixup_cell_info, 59562306a36Sopenharmony_ci}; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic int imx_ocotp_probe(struct platform_device *pdev) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 60062306a36Sopenharmony_ci struct ocotp_priv *priv; 60162306a36Sopenharmony_ci struct nvmem_device *nvmem; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 60462306a36Sopenharmony_ci if (!priv) 60562306a36Sopenharmony_ci return -ENOMEM; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci priv->dev = dev; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci priv->base = devm_platform_ioremap_resource(pdev, 0); 61062306a36Sopenharmony_ci if (IS_ERR(priv->base)) 61162306a36Sopenharmony_ci return PTR_ERR(priv->base); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci priv->clk = devm_clk_get(dev, NULL); 61462306a36Sopenharmony_ci if (IS_ERR(priv->clk)) 61562306a36Sopenharmony_ci return PTR_ERR(priv->clk); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci priv->params = of_device_get_match_data(&pdev->dev); 61862306a36Sopenharmony_ci imx_ocotp_nvmem_config.size = 4 * priv->params->nregs; 61962306a36Sopenharmony_ci imx_ocotp_nvmem_config.dev = dev; 62062306a36Sopenharmony_ci imx_ocotp_nvmem_config.priv = priv; 62162306a36Sopenharmony_ci imx_ocotp_nvmem_config.layout = &imx_ocotp_layout; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci priv->config = &imx_ocotp_nvmem_config; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci clk_prepare_enable(priv->clk); 62662306a36Sopenharmony_ci imx_ocotp_clr_err_if_set(priv); 62762306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci nvmem = devm_nvmem_register(dev, &imx_ocotp_nvmem_config); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(nvmem); 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic struct platform_driver imx_ocotp_driver = { 63562306a36Sopenharmony_ci .probe = imx_ocotp_probe, 63662306a36Sopenharmony_ci .driver = { 63762306a36Sopenharmony_ci .name = "imx_ocotp", 63862306a36Sopenharmony_ci .of_match_table = imx_ocotp_dt_ids, 63962306a36Sopenharmony_ci }, 64062306a36Sopenharmony_ci}; 64162306a36Sopenharmony_cimodule_platform_driver(imx_ocotp_driver); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ciMODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>"); 64462306a36Sopenharmony_ciMODULE_DESCRIPTION("i.MX6/i.MX7 OCOTP fuse box driver"); 64562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 646