summaryrefslogtreecommitdiffstats
path: root/drivers/nvmem/ocotp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/nvmem/ocotp.c')
-rw-r--r--drivers/nvmem/ocotp.c322
1 files changed, 216 insertions, 106 deletions
diff --git a/drivers/nvmem/ocotp.c b/drivers/nvmem/ocotp.c
index 9fcbd1a6a4..c282efefa8 100644
--- a/drivers/nvmem/ocotp.c
+++ b/drivers/nvmem/ocotp.c
@@ -14,6 +14,7 @@
*/
#include <common.h>
+#include <deep-probe.h>
#include <driver.h>
#include <malloc.h>
#include <xfuncs.h>
@@ -23,11 +24,17 @@
#include <io.h>
#include <of.h>
#include <clock.h>
-#include <regmap.h>
+#include <linux/regmap.h>
+#include <linux/bits.h>
#include <linux/clk.h>
-#include <mach/ocotp.h>
#include <machine_id.h>
-#include <mach/ocotp-fusemap.h>
+#ifdef CONFIG_ARCH_IMX
+#include <mach/imx/ocotp.h>
+#include <mach/imx/ocotp-fusemap.h>
+#else
+#include <mach/mxs/ocotp.h>
+#include <mach/mxs/ocotp-fusemap.h>
+#endif
#include <soc/imx8m/featctrl.h>
#include <linux/nvmem-provider.h>
@@ -46,12 +53,12 @@
#define OCOTP_READ_CTRL 0x30
#define OCOTP_READ_FUSE_DATA 0x40
-#define MX7_OCOTP_DATA0 0x20
-#define MX7_OCOTP_DATA1 0x30
-#define MX7_OCOTP_DATA2 0x40
-#define MX7_OCOTP_DATA3 0x50
-#define MX7_OCOTP_READ_CTRL 0x60
-#define MX7_OCOTP_READ_FUSE_DATA0 0x70
+#define MX7_OCOTP_DATA0 0x20
+#define MX7_OCOTP_DATA1 0x30
+#define MX7_OCOTP_DATA2 0x40
+#define MX7_OCOTP_DATA3 0x50
+#define MX7_OCOTP_READ_CTRL 0x60
+#define MX7_OCOTP_READ_FUSE_DATA0 0x70
#define MX7_OCOTP_READ_FUSE_DATA1 0x80
#define MX7_OCOTP_READ_FUSE_DATA2 0x90
#define MX7_OCOTP_READ_FUSE_DATA3 0xA0
@@ -60,25 +67,31 @@
#define DEF_STROBE_PROG 10000 /* IPG clocks */
/* OCOTP Registers bits and masks */
-#define OCOTP_CTRL_WR_UNLOCK 16
+#define OCOTP_CTRL_ADDR GENMASK(7, 0)
+#define OCOTP_CTRL_BUSY BIT(8)
+#define OCOTP_CTRL_ERROR BIT(9)
+#define OCOTP_CTRL_RELOAD_SHADOWS BIT(10)
+#define OCOTP_CTRL_WR_UNLOCK GENMASK(31, 16)
#define OCOTP_CTRL_WR_UNLOCK_KEY 0x3E77
-#define OCOTP_CTRL_WR_UNLOCK_MASK 0xFFFF0000
-#define OCOTP_CTRL_ADDR 0
-#define OCOTP_CTRL_ADDR_MASK 0x000000FF
-#define OCOTP_CTRL_BUSY (1 << 8)
-#define OCOTP_CTRL_ERROR (1 << 9)
-#define OCOTP_CTRL_RELOAD_SHADOWS (1 << 10)
-#define OCOTP_TIMING_STROBE_READ_MASK 0x003F0000
-#define OCOTP_TIMING_RELAX_MASK 0x0000F000
-#define OCOTP_TIMING_STROBE_PROG_MASK 0x00000FFF
-#define OCOTP_TIMING_WAIT_MASK 0x0FC00000
+/*
+ * i.MX8MP OCOTP CTRL has a different layout. See RM Rev.1 06/2021
+ * Section 6.3.5.1.2.4
+ */
+#define OCOTP_CTRL_ADDR_8MP GENMASK(8, 0)
+#define OCOTP_CTRL_BUSY_8MP BIT(9)
+#define OCOTP_CTRL_ERROR_8MP BIT(10)
+#define OCOTP_CTRL_RELOAD_SHADOWS_8MP BIT(11)
+#define OCOTP_CTRL_WR_UNLOCK_8MP GENMASK(31, 16)
-#define OCOTP_READ_CTRL_READ_FUSE 0x00000001
+#define OCOTP_TIMING_STROBE_READ GENMASK(21, 16)
+#define OCOTP_TIMING_RELAX GENMASK(15, 12)
+#define OCOTP_TIMING_STROBE_PROG GENMASK(11, 0)
+#define OCOTP_TIMING_WAIT GENMASK(27, 22)
-#define BF(value, field) FIELD_PREP(field##_MASK, value)
+#define OCOTP_READ_CTRL_READ_FUSE BIT(1)
-#define OCOTP_OFFSET_TO_ADDR(o) (OCOTP_OFFSET_TO_INDEX(o) * 4)
+#define OCOTP_OFFSET_TO_ADDR(o) (OCOTP_OFFSET_TO_INDEX(o) * 4)
/* Other definitions */
#define IMX6_OTP_DATA_ERROR_VAL 0xBADABADA
@@ -88,19 +101,46 @@
#define MAC_OFFSET_0 (0x22 * 4)
#define IMX6UL_MAC_OFFSET_1 (0x23 * 4)
#define MAC_OFFSET_1 (0x24 * 4)
+#define IMX8MP_MAC_OFFSET_1 (0x25 * 4)
#define MAX_MAC_OFFSETS 2
#define MAC_BYTES 8
#define UNIQUE_ID_NUM 2
+#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask))
+
enum imx_ocotp_format_mac_direction {
OCOTP_HW_TO_MAC,
OCOTP_MAC_TO_HW,
};
+struct ocotp_ctrl_reg {
+ u32 bm_addr;
+ u32 bm_busy;
+ u32 bm_error;
+ u32 bm_reload_shadows;
+ u32 bm_wr_unlock;
+};
+
+const struct ocotp_ctrl_reg ocotp_ctrl_reg_default = {
+ .bm_addr = OCOTP_CTRL_ADDR,
+ .bm_busy = OCOTP_CTRL_BUSY,
+ .bm_error = OCOTP_CTRL_ERROR,
+ .bm_reload_shadows = OCOTP_CTRL_RELOAD_SHADOWS,
+ .bm_wr_unlock = OCOTP_CTRL_WR_UNLOCK,
+};
+
+const struct ocotp_ctrl_reg ocotp_ctrl_reg_8mp = {
+ .bm_addr = OCOTP_CTRL_ADDR_8MP,
+ .bm_busy = OCOTP_CTRL_BUSY_8MP,
+ .bm_error = OCOTP_CTRL_ERROR_8MP,
+ .bm_reload_shadows = OCOTP_CTRL_RELOAD_SHADOWS_8MP,
+ .bm_wr_unlock = OCOTP_CTRL_WR_UNLOCK_8MP,
+};
+
struct ocotp_priv;
struct imx_ocotp_data {
- int num_regs;
+ int nregs;
u32 (*addr_to_offset)(u32 addr);
void (*format_mac)(u8 *dst, const u8 *src,
enum imx_ocotp_format_mac_direction dir);
@@ -110,6 +150,7 @@ struct imx_ocotp_data {
u8 mac_offsets[MAX_MAC_OFFSETS];
u8 mac_offsets_num;
struct imx8m_featctrl_data *feat;
+ const struct ocotp_ctrl_reg *ctrl;
};
struct ocotp_priv_ethaddr {
@@ -123,14 +164,13 @@ struct ocotp_priv {
struct regmap *map;
void __iomem *base;
struct clk *clk;
- struct device_d dev;
+ struct device dev;
int permanent_write_enable;
int sense_enable;
struct ocotp_priv_ethaddr ethaddr[MAX_MAC_OFFSETS];
struct regmap_config map_config;
const struct imx_ocotp_data *data;
int mac_offset_idx;
- struct nvmem_config config;
};
static struct ocotp_priv *imx_ocotp;
@@ -175,10 +215,10 @@ static int imx6_ocotp_set_timing(struct ocotp_priv *priv)
1000000);
strobe_prog += 2 * (relax + 1) - 1;
- timing = readl(priv->base + OCOTP_TIMING) & OCOTP_TIMING_WAIT_MASK;
- timing |= BF(relax, OCOTP_TIMING_RELAX);
- timing |= BF(strobe_read, OCOTP_TIMING_STROBE_READ);
- timing |= BF(strobe_prog, OCOTP_TIMING_STROBE_PROG);
+ timing = readl(priv->base + OCOTP_TIMING) & OCOTP_TIMING_WAIT;
+ timing |= FIELD_PREP(OCOTP_TIMING_RELAX, relax);
+ timing |= FIELD_PREP(OCOTP_TIMING_STROBE_READ, strobe_read);
+ timing |= FIELD_PREP(OCOTP_TIMING_STROBE_PROG, strobe_prog);
writel(timing, priv->base + OCOTP_TIMING);
@@ -209,8 +249,9 @@ static int imx7_ocotp_set_timing(struct ocotp_priv *priv)
static int imx6_ocotp_wait_busy(struct ocotp_priv *priv, u32 flags)
{
uint64_t start = get_time_ns();
+ u32 bm_ctrl_busy = priv->data->ctrl->bm_busy;
- while (readl(priv->base + OCOTP_CTRL) & (OCOTP_CTRL_BUSY | flags))
+ while (readl(priv->base + OCOTP_CTRL) & (bm_ctrl_busy | flags))
if (is_timeout(start, MSECOND))
return -ETIMEDOUT;
@@ -234,15 +275,18 @@ static int imx6_ocotp_prepare(struct ocotp_priv *priv)
static int imx6_fuse_read_addr(struct ocotp_priv *priv, u32 addr, u32 *pdata)
{
+ const u32 bm_ctrl_error = priv->data->ctrl->bm_error;
+ const u32 bm_ctrl_addr = priv->data->ctrl->bm_addr;
+ const u32 bm_ctrl_wr_unlock = priv->data->ctrl->bm_wr_unlock;
u32 ctrl_reg;
int ret;
- writel(OCOTP_CTRL_ERROR, priv->base + OCOTP_CTRL_CLR);
+ writel(bm_ctrl_error, priv->base + OCOTP_CTRL_CLR);
ctrl_reg = readl(priv->base + OCOTP_CTRL);
- ctrl_reg &= ~OCOTP_CTRL_ADDR_MASK;
- ctrl_reg &= ~OCOTP_CTRL_WR_UNLOCK_MASK;
- ctrl_reg |= BF(addr, OCOTP_CTRL_ADDR);
+ ctrl_reg &= ~bm_ctrl_addr;
+ ctrl_reg &= ~bm_ctrl_wr_unlock;
+ ctrl_reg |= field_prep(bm_ctrl_addr, addr);
writel(ctrl_reg, priv->base + OCOTP_CTRL);
writel(OCOTP_READ_CTRL_READ_FUSE, priv->base + OCOTP_READ_CTRL);
@@ -250,7 +294,7 @@ static int imx6_fuse_read_addr(struct ocotp_priv *priv, u32 addr, u32 *pdata)
if (ret)
return ret;
- if (readl(priv->base + OCOTP_CTRL) & OCOTP_CTRL_ERROR)
+ if (readl(priv->base + OCOTP_CTRL) & bm_ctrl_error)
*pdata = 0xbadabada;
else
*pdata = readl(priv->base + OCOTP_READ_FUSE_DATA);
@@ -260,6 +304,9 @@ static int imx6_fuse_read_addr(struct ocotp_priv *priv, u32 addr, u32 *pdata)
static int imx7_fuse_read_addr(struct ocotp_priv *priv, u32 index, u32 *pdata)
{
+ const u32 bm_ctrl_error = priv->data->ctrl->bm_error;
+ const u32 bm_ctrl_addr = priv->data->ctrl->bm_addr;
+ const u32 bm_ctrl_wr_unlock = priv->data->ctrl->bm_wr_unlock;
u32 ctrl_reg;
u32 bank_addr;
u16 word;
@@ -268,12 +315,12 @@ static int imx7_fuse_read_addr(struct ocotp_priv *priv, u32 index, u32 *pdata)
word = index & 0x3;
bank_addr = index >> 2;
- writel(OCOTP_CTRL_ERROR, priv->base + OCOTP_CTRL_CLR);
+ writel(bm_ctrl_error, priv->base + OCOTP_CTRL_CLR);
ctrl_reg = readl(priv->base + OCOTP_CTRL);
- ctrl_reg &= ~OCOTP_CTRL_ADDR_MASK;
- ctrl_reg &= ~OCOTP_CTRL_WR_UNLOCK_MASK;
- ctrl_reg |= BF(bank_addr, OCOTP_CTRL_ADDR);
+ ctrl_reg &= ~bm_ctrl_addr;
+ ctrl_reg &= ~bm_ctrl_wr_unlock;
+ ctrl_reg |= field_prep(bm_ctrl_addr, bank_addr);
writel(ctrl_reg, priv->base + OCOTP_CTRL);
writel(OCOTP_READ_CTRL_READ_FUSE, priv->base + MX7_OCOTP_READ_CTRL);
@@ -281,7 +328,7 @@ static int imx7_fuse_read_addr(struct ocotp_priv *priv, u32 index, u32 *pdata)
if (ret)
return ret;
- if (readl(priv->base + OCOTP_CTRL) & OCOTP_CTRL_ERROR)
+ if (readl(priv->base + OCOTP_CTRL) & bm_ctrl_error)
*pdata = 0xbadabada;
else
switch (word) {
@@ -344,25 +391,29 @@ static int imx_ocotp_reg_read(void *ctx, unsigned int reg, unsigned int *val)
static void imx_ocotp_clear_unlock(struct ocotp_priv *priv, u32 index)
{
+ const u32 bm_ctrl_error = priv->data->ctrl->bm_error;
+ const u32 bm_ctrl_addr = priv->data->ctrl->bm_addr;
+ const u32 bm_ctrl_wr_unlock = priv->data->ctrl->bm_wr_unlock;
u32 ctrl_reg;
- writel(OCOTP_CTRL_ERROR, priv->base + OCOTP_CTRL_CLR);
+ writel(bm_ctrl_error, priv->base + OCOTP_CTRL_CLR);
/* Control register */
ctrl_reg = readl(priv->base + OCOTP_CTRL);
- ctrl_reg &= ~OCOTP_CTRL_ADDR_MASK;
- ctrl_reg |= BF(index, OCOTP_CTRL_ADDR);
- ctrl_reg |= BF(OCOTP_CTRL_WR_UNLOCK_KEY, OCOTP_CTRL_WR_UNLOCK);
+ ctrl_reg &= ~bm_ctrl_addr;
+ ctrl_reg |= field_prep(bm_ctrl_addr, index);
+ ctrl_reg |= field_prep(bm_ctrl_wr_unlock, OCOTP_CTRL_WR_UNLOCK_KEY);
writel(ctrl_reg, priv->base + OCOTP_CTRL);
}
static int imx6_fuse_blow_addr(struct ocotp_priv *priv, u32 index, u32 value)
{
+ const u32 bm_ctrl_error = priv->data->ctrl->bm_error;
int ret;
imx_ocotp_clear_unlock(priv, index);
- writel(OCOTP_CTRL_ERROR, priv->base + OCOTP_CTRL_CLR);
+ writel(bm_ctrl_error, priv->base + OCOTP_CTRL_CLR);
writel(value, priv->base + OCOTP_DATA);
ret = imx6_ocotp_wait_busy(priv, 0);
@@ -423,16 +474,19 @@ static int imx7_fuse_blow_addr(struct ocotp_priv *priv, u32 index, u32 value)
static int imx6_ocotp_reload_shadow(struct ocotp_priv *priv)
{
+ const u32 bm_ctrl_reload_shadows = priv->data->ctrl->bm_reload_shadows;
+
dev_info(&priv->dev, "reloading shadow registers...\n");
- writel(OCOTP_CTRL_RELOAD_SHADOWS, priv->base + OCOTP_CTRL_SET);
+ writel(bm_ctrl_reload_shadows, priv->base + OCOTP_CTRL_SET);
udelay(1);
- return imx6_ocotp_wait_busy(priv, OCOTP_CTRL_RELOAD_SHADOWS);
+ return imx6_ocotp_wait_busy(priv, bm_ctrl_reload_shadows);
}
static int imx6_ocotp_blow_one_u32(struct ocotp_priv *priv, u32 index, u32 data,
u32 *pfused_value)
{
+ const u32 bm_ctrl_error = priv->data->ctrl->bm_error;
int ret;
ret = imx6_ocotp_prepare(priv);
@@ -447,7 +501,7 @@ static int imx6_ocotp_blow_one_u32(struct ocotp_priv *priv, u32 index, u32 data,
return ret;
}
- if (readl(priv->base + OCOTP_CTRL) & OCOTP_CTRL_ERROR) {
+ if (readl(priv->base + OCOTP_CTRL) & bm_ctrl_error) {
dev_err(&priv->dev, "bad write status\n");
return -EFAULT;
}
@@ -492,11 +546,17 @@ static void imx_ocotp_field_decode(uint32_t field, unsigned *word,
*mask = GENMASK(width, 0);
}
+static int imx_ocotp_ensure_probed(void);
+
int imx_ocotp_read_field(uint32_t field, unsigned *value)
{
unsigned word, bit, mask, val;
int ret;
+ ret = imx_ocotp_ensure_probed();
+ if (ret)
+ return ret;
+
imx_ocotp_field_decode(field, &word, &bit, &mask);
ret = imx_ocotp_reg_read(imx_ocotp, word, &val);
@@ -519,6 +579,10 @@ int imx_ocotp_write_field(uint32_t field, unsigned value)
unsigned word, bit, mask;
int ret;
+ ret = imx_ocotp_ensure_probed();
+ if (ret)
+ return ret;
+
imx_ocotp_field_decode(field, &word, &bit, &mask);
value &= mask;
@@ -536,14 +600,27 @@ int imx_ocotp_write_field(uint32_t field, unsigned value)
int imx_ocotp_permanent_write(int enable)
{
+ int ret;
+
+ ret = imx_ocotp_ensure_probed();
+ if (ret)
+ return ret;
+
imx_ocotp->permanent_write_enable = enable;
return 0;
}
-bool imx_ocotp_sense_enable(bool enable)
+int imx_ocotp_sense_enable(bool enable)
{
- const bool old_value = imx_ocotp->sense_enable;
+ bool old_value;
+ int ret;
+
+ ret = imx_ocotp_ensure_probed();
+ if (ret)
+ return ret;
+
+ old_value = imx_ocotp->sense_enable;
imx_ocotp->sense_enable = enable;
return old_value;
}
@@ -593,12 +670,12 @@ static int imx_ocotp_read_mac(const struct imx_ocotp_data *data,
u8 buf[MAC_BYTES];
int ret;
- ret = regmap_bulk_read(map, offset, buf, MAC_BYTES);
+ ret = regmap_bulk_read(map, offset, buf, MAC_BYTES / 4);
if (ret < 0)
return ret;
- if (offset != IMX6UL_MAC_OFFSET_1)
+ if (offset != IMX6UL_MAC_OFFSET_1 && offset != IMX8MP_MAC_OFFSET_1)
data->format_mac(mac, buf, OCOTP_HW_TO_MAC);
else
data->format_mac(mac, buf + 2, OCOTP_HW_TO_MAC);
@@ -620,11 +697,12 @@ static int imx_ocotp_set_mac(struct param_d *param, void *priv)
struct ocotp_priv_ethaddr *ethaddr = priv;
int ret;
- ret = regmap_bulk_read(ethaddr->map, ethaddr->offset, buf, MAC_BYTES);
+ ret = regmap_bulk_read(ethaddr->map, ethaddr->offset, buf, MAC_BYTES / 4);
if (ret < 0)
return ret;
- if (ethaddr->offset != IMX6UL_MAC_OFFSET_1)
+ if (ethaddr->offset != IMX6UL_MAC_OFFSET_1 &&
+ ethaddr->offset != IMX8MP_MAC_OFFSET_1)
ethaddr->data->format_mac(buf, ethaddr->value,
OCOTP_MAC_TO_HW);
else
@@ -632,7 +710,7 @@ static int imx_ocotp_set_mac(struct param_d *param, void *priv)
OCOTP_MAC_TO_HW);
return regmap_bulk_write(ethaddr->map, ethaddr->offset,
- buf, MAC_BYTES);
+ buf, MAC_BYTES / 4);
}
static struct regmap_bus imx_ocotp_regmap_bus = {
@@ -640,20 +718,33 @@ static struct regmap_bus imx_ocotp_regmap_bus = {
.reg_read = imx_ocotp_reg_read,
};
+static int imx_ocotp_cell_pp(void *context, const char *id, unsigned int offset,
+ void *data, size_t bytes)
+{
+ /* Deal with some post processing of nvmem cell data */
+ if (id && !strcmp(id, "mac-address")) {
+ u8 *buf = data;
+ int i;
+
+ for (i = 0; i < bytes/2; i++)
+ swap(buf[i], buf[bytes - i - 1]);
+ }
+
+ return 0;
+}
+
static int imx_ocotp_init_dt(struct ocotp_priv *priv)
{
char mac[MAC_BYTES];
const __be32 *prop;
- struct device_node *node = priv->dev.parent->device_node;
- u32 tester4;
- int ret, len;
+ struct device_node *node = priv->dev.parent->of_node;
+ u32 tester3, tester4;
+ int ret, len = 0;
if (!node)
return 0;
prop = of_get_property(node, "barebox,provide-mac-address", &len);
- if (!prop)
- return 0;
for (; len >= MAC_ADDRESS_PROPLEN; len -= MAC_ADDRESS_PROPLEN) {
struct device_node *rnode;
@@ -675,25 +766,15 @@ static int imx_ocotp_init_dt(struct ocotp_priv *priv)
if (!of_property_read_bool(node, "barebox,feature-controller"))
return 0;
- ret = regmap_read(priv->map, OCOTP_OFFSET_TO_ADDR(0x450), &tester4);
+ ret = regmap_read(priv->map, OCOTP_OFFSET_TO_ADDR(0x440), &tester3);
if (ret != 0)
return ret;
- return imx8m_feat_ctrl_init(priv->dev.parent, tester4, priv->data->feat);
-}
-
-static int imx_ocotp_write(void *ctx, unsigned offset, const void *val, size_t bytes)
-{
- struct ocotp_priv *priv = ctx;
-
- return regmap_bulk_write(priv->map, offset, val, bytes);
-}
-
-static int imx_ocotp_read(void *ctx, unsigned offset, void *val, size_t bytes)
-{
- struct ocotp_priv *priv = ctx;
+ ret = regmap_read(priv->map, OCOTP_OFFSET_TO_ADDR(0x450), &tester4);
+ if (ret != 0)
+ return ret;
- return regmap_bulk_read(priv->map, offset, val, bytes);
+ return imx8m_feat_ctrl_init(priv->dev.parent, tester3, tester4, priv->data->feat);
}
static void imx_ocotp_set_unique_machine_id(void)
@@ -709,12 +790,7 @@ static void imx_ocotp_set_unique_machine_id(void)
machine_id_set_hashable(unique_id_parts, sizeof(unique_id_parts));
}
-static const struct nvmem_bus imx_ocotp_nvmem_bus = {
- .write = imx_ocotp_write,
- .read = imx_ocotp_read,
-};
-
-static int imx_ocotp_probe(struct device_d *dev)
+static int imx_ocotp_probe(struct device *dev)
{
struct resource *iores;
struct ocotp_priv *priv;
@@ -745,21 +821,14 @@ static int imx_ocotp_probe(struct device_d *dev)
priv->map_config.reg_bits = 32;
priv->map_config.val_bits = 32;
priv->map_config.reg_stride = 4;
- priv->map_config.max_register = data->num_regs - 1;
+ priv->map_config.max_register = priv->map_config.reg_stride * (data->nregs - 1);
priv->map = regmap_init(dev, &imx_ocotp_regmap_bus, priv, &priv->map_config);
if (IS_ERR(priv->map))
return PTR_ERR(priv->map);
- priv->config.name = "imx-ocotp";
- priv->config.dev = dev;
- priv->config.priv = priv;
- priv->config.stride = 4;
- priv->config.word_size = 4;
- priv->config.size = data->num_regs;
- priv->config.bus = &imx_ocotp_nvmem_bus;
-
- nvmem = nvmem_register(&priv->config);
+ nvmem = nvmem_regmap_register_with_pp(priv->map, "imx-ocotp",
+ imx_ocotp_cell_pp);
if (IS_ERR(nvmem))
return PTR_ERR(nvmem);
@@ -836,7 +905,7 @@ static u32 vf610_addr_to_offset(u32 addr)
}
static struct imx_ocotp_data imx6q_ocotp_data = {
- .num_regs = 512,
+ .nregs = 128,
.addr_to_offset = imx6q_addr_to_offset,
.mac_offsets_num = 1,
.mac_offsets = { MAC_OFFSET_0 },
@@ -844,10 +913,11 @@ static struct imx_ocotp_data imx6q_ocotp_data = {
.set_timing = imx6_ocotp_set_timing,
.fuse_blow = imx6_fuse_blow_addr,
.fuse_read = imx6_fuse_read_addr,
+ .ctrl = &ocotp_ctrl_reg_default,
};
static struct imx_ocotp_data imx6sl_ocotp_data = {
- .num_regs = 256,
+ .nregs = 64,
.addr_to_offset = imx6sl_addr_to_offset,
.mac_offsets_num = 1,
.mac_offsets = { MAC_OFFSET_0 },
@@ -855,10 +925,11 @@ static struct imx_ocotp_data imx6sl_ocotp_data = {
.set_timing = imx6_ocotp_set_timing,
.fuse_blow = imx6_fuse_blow_addr,
.fuse_read = imx6_fuse_read_addr,
+ .ctrl = &ocotp_ctrl_reg_default,
};
static struct imx_ocotp_data imx6ul_ocotp_data = {
- .num_regs = 512,
+ .nregs = 144,
.addr_to_offset = imx6q_addr_to_offset,
.mac_offsets_num = 2,
.mac_offsets = { MAC_OFFSET_0, IMX6UL_MAC_OFFSET_1 },
@@ -866,10 +937,11 @@ static struct imx_ocotp_data imx6ul_ocotp_data = {
.set_timing = imx6_ocotp_set_timing,
.fuse_blow = imx6_fuse_blow_addr,
.fuse_read = imx6_fuse_read_addr,
+ .ctrl = &ocotp_ctrl_reg_default,
};
static struct imx_ocotp_data imx6ull_ocotp_data = {
- .num_regs = 256,
+ .nregs = 80,
.addr_to_offset = imx6q_addr_to_offset,
.mac_offsets_num = 2,
.mac_offsets = { MAC_OFFSET_0, IMX6UL_MAC_OFFSET_1 },
@@ -877,10 +949,11 @@ static struct imx_ocotp_data imx6ull_ocotp_data = {
.set_timing = imx6_ocotp_set_timing,
.fuse_blow = imx6_fuse_blow_addr,
.fuse_read = imx6_fuse_read_addr,
+ .ctrl = &ocotp_ctrl_reg_default,
};
static struct imx_ocotp_data vf610_ocotp_data = {
- .num_regs = 512,
+ .nregs = 128,
.addr_to_offset = vf610_addr_to_offset,
.mac_offsets_num = 2,
.mac_offsets = { MAC_OFFSET_0, MAC_OFFSET_1 },
@@ -888,18 +961,35 @@ static struct imx_ocotp_data vf610_ocotp_data = {
.set_timing = imx6_ocotp_set_timing,
.fuse_blow = imx6_fuse_blow_addr,
.fuse_read = imx6_fuse_read_addr,
+ .ctrl = &ocotp_ctrl_reg_default,
+};
+
+static struct imx8m_featctrl_data imx8mp_featctrl_data = {
+ .tester3.cpu_bitmask = 0xc0000,
+ .tester3.vpu_bitmask = 0x43000000,
+ .tester4.npu_bitmask = 0x8,
+ .tester4.gpu_bitmask = 0xc0,
+ .tester4.mipi_dsi_bitmask = 0x60000,
+ .tester4.lvds_bitmask = 0x180000,
+ .tester4.isp_bitmask = 0x3,
+ .tester4.dsp_bitmask = 0x10,
};
static struct imx_ocotp_data imx8mp_ocotp_data = {
- .num_regs = 1024,
+ .nregs = 384,
.addr_to_offset = imx6sl_addr_to_offset,
.mac_offsets_num = 2,
- .mac_offsets = { 0x90, 0x96 },
+ .mac_offsets = { 0x90, 0x94 },
.format_mac = imx_ocotp_format_mac,
+ .feat = &imx8mp_featctrl_data,
+ .set_timing = imx6_ocotp_set_timing,
+ .fuse_blow = imx6_fuse_blow_addr,
+ .fuse_read = imx6_fuse_read_addr,
+ .ctrl = &ocotp_ctrl_reg_8mp,
};
static struct imx_ocotp_data imx8mq_ocotp_data = {
- .num_regs = 2048,
+ .nregs = 256,
.addr_to_offset = imx6sl_addr_to_offset,
.mac_offsets_num = 1,
.mac_offsets = { 0x90 },
@@ -907,14 +997,16 @@ static struct imx_ocotp_data imx8mq_ocotp_data = {
.set_timing = imx6_ocotp_set_timing,
.fuse_blow = imx6_fuse_blow_addr,
.fuse_read = imx6_fuse_read_addr,
+ .ctrl = &ocotp_ctrl_reg_default,
};
static struct imx8m_featctrl_data imx8mm_featctrl_data = {
- .vpu_bitmask = 0x1c0000,
+ .tester4.vpu_bitmask = 0x1c0000,
+ .tester4.cpu_bitmask = 0x3,
};
static struct imx_ocotp_data imx8mm_ocotp_data = {
- .num_regs = 2048,
+ .nregs = 256,
.addr_to_offset = imx6sl_addr_to_offset,
.mac_offsets_num = 1,
.mac_offsets = { 0x90 },
@@ -923,14 +1015,16 @@ static struct imx_ocotp_data imx8mm_ocotp_data = {
.fuse_blow = imx6_fuse_blow_addr,
.fuse_read = imx6_fuse_read_addr,
.feat = &imx8mm_featctrl_data,
+ .ctrl = &ocotp_ctrl_reg_default,
};
static struct imx8m_featctrl_data imx8mn_featctrl_data = {
- .gpu_bitmask = 0x1000000,
+ .tester4.gpu_bitmask = 0x1000000,
+ .tester4.cpu_bitmask = 0x3,
};
static struct imx_ocotp_data imx8mn_ocotp_data = {
- .num_regs = 2048,
+ .nregs = 256,
.addr_to_offset = imx6sl_addr_to_offset,
.mac_offsets_num = 1,
.mac_offsets = { 0x90 },
@@ -939,10 +1033,11 @@ static struct imx_ocotp_data imx8mn_ocotp_data = {
.fuse_blow = imx6_fuse_blow_addr,
.fuse_read = imx6_fuse_read_addr,
.feat = &imx8mn_featctrl_data,
+ .ctrl = &ocotp_ctrl_reg_default,
};
static struct imx_ocotp_data imx7d_ocotp_data = {
- .num_regs = 2048,
+ .nregs = 64,
.addr_to_offset = imx6sl_addr_to_offset,
.mac_offsets_num = 1,
.mac_offsets = { MAC_OFFSET_0, IMX6UL_MAC_OFFSET_1 },
@@ -950,6 +1045,7 @@ static struct imx_ocotp_data imx7d_ocotp_data = {
.set_timing = imx7_ocotp_set_timing,
.fuse_blow = imx7_fuse_blow_addr,
.fuse_read = imx7_fuse_read_addr,
+ .ctrl = &ocotp_ctrl_reg_default,
};
static __maybe_unused struct of_device_id imx_ocotp_dt_ids[] = {
@@ -990,8 +1086,22 @@ static __maybe_unused struct of_device_id imx_ocotp_dt_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids);
+
+static int imx_ocotp_ensure_probed(void)
+{
+ if (!imx_ocotp && deep_probe_is_supported()) {
+ int ret;
+
+ ret = of_devices_ensure_probed_by_dev_id(imx_ocotp_dt_ids);
+ if (ret)
+ return ret;
+ }
+
+ return imx_ocotp ? 0 : -EPROBE_DEFER;
+}
-static struct driver_d imx_ocotp_driver = {
+static struct driver imx_ocotp_driver = {
.name = "imx_ocotp",
.probe = imx_ocotp_probe,
.of_compatible = DRV_OF_COMPAT(imx_ocotp_dt_ids),