1 // SPDX-License-Identifier: GPL-2.0-only
3 * i.MX9 OCOTP fusebox driver
8 #include <linux/device.h>
10 #include <linux/module.h>
11 #include <linux/nvmem-provider.h>
13 #include <linux/platform_device.h>
14 #include <linux/slab.h>
23 struct ocotp_map_entry
{
24 u32 start
; /* start word */
25 u32 num
; /* num words */
29 struct ocotp_devtype_data
{
35 nvmem_reg_read_t reg_read
;
36 struct ocotp_map_entry entry
[];
39 struct imx_ocotp_priv
{
42 struct nvmem_config config
;
44 const struct ocotp_devtype_data
*data
;
47 static enum fuse_type
imx_ocotp_fuse_type(void *context
, u32 index
)
49 struct imx_ocotp_priv
*priv
= context
;
50 const struct ocotp_devtype_data
*data
= priv
->data
;
54 for (i
= 0; i
< data
->num_entry
; i
++) {
55 start
= data
->entry
[i
].start
;
56 end
= data
->entry
[i
].start
+ data
->entry
[i
].num
;
58 if (index
>= start
&& index
< end
)
59 return data
->entry
[i
].type
;
65 static int imx_ocotp_reg_read(void *context
, unsigned int offset
, void *val
, size_t bytes
)
67 struct imx_ocotp_priv
*priv
= context
;
68 void __iomem
*reg
= priv
->base
+ priv
->data
->reg_off
;
69 u32 count
, index
, num_bytes
;
76 num_bytes
= round_up(bytes
, 4);
77 count
= num_bytes
>> 2;
79 if (count
> ((priv
->data
->size
>> 2) - index
))
80 count
= (priv
->data
->size
>> 2) - index
;
82 p
= kzalloc(num_bytes
, GFP_KERNEL
);
86 mutex_lock(&priv
->lock
);
90 for (i
= index
; i
< (index
+ count
); i
++) {
91 type
= imx_ocotp_fuse_type(context
, i
);
92 if (type
== FUSE_INVALID
|| type
== FUSE_ELE
) {
98 *buf
++ = readl_relaxed(reg
+ (i
<< 2)) & GENMASK(15, 0);
100 *buf
++ = readl_relaxed(reg
+ (i
<< 2));
103 memcpy(val
, (u8
*)p
, bytes
);
105 mutex_unlock(&priv
->lock
);
112 static int imx_ele_ocotp_probe(struct platform_device
*pdev
)
114 struct device
*dev
= &pdev
->dev
;
115 struct imx_ocotp_priv
*priv
;
116 struct nvmem_device
*nvmem
;
118 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
122 priv
->data
= of_device_get_match_data(dev
);
124 priv
->base
= devm_platform_ioremap_resource(pdev
, 0);
125 if (IS_ERR(priv
->base
))
126 return PTR_ERR(priv
->base
);
128 priv
->config
.dev
= dev
;
129 priv
->config
.name
= "ELE-OCOTP";
130 priv
->config
.id
= NVMEM_DEVID_AUTO
;
131 priv
->config
.owner
= THIS_MODULE
;
132 priv
->config
.size
= priv
->data
->size
;
133 priv
->config
.reg_read
= priv
->data
->reg_read
;
134 priv
->config
.word_size
= 4;
135 priv
->config
.stride
= 1;
136 priv
->config
.priv
= priv
;
137 priv
->config
.read_only
= true;
138 mutex_init(&priv
->lock
);
140 nvmem
= devm_nvmem_register(dev
, &priv
->config
);
142 return PTR_ERR(nvmem
);
147 static const struct ocotp_devtype_data imx93_ocotp_data
= {
149 .reg_read
= imx_ocotp_reg_read
,
155 { 128, 16, FUSE_ELE
},
156 { 182, 1, FUSE_ELE
},
157 { 188, 1, FUSE_ELE
},
158 { 312, 200, FUSE_FSB
}
162 static const struct ocotp_devtype_data imx95_ocotp_data
= {
164 .reg_read
= imx_ocotp_reg_read
,
168 { 0, 1, FUSE_FSB
| FUSE_ECC
},
169 { 7, 1, FUSE_FSB
| FUSE_ECC
},
170 { 9, 3, FUSE_FSB
| FUSE_ECC
},
171 { 12, 24, FUSE_FSB
},
172 { 36, 2, FUSE_FSB
| FUSE_ECC
},
173 { 38, 14, FUSE_FSB
},
175 { 128, 16, FUSE_ELE
},
176 { 188, 1, FUSE_ELE
},
177 { 317, 2, FUSE_FSB
| FUSE_ECC
},
178 { 320, 7, FUSE_FSB
},
179 { 328, 184, FUSE_FSB
}
183 static const struct of_device_id imx_ele_ocotp_dt_ids
[] = {
184 { .compatible
= "fsl,imx93-ocotp", .data
= &imx93_ocotp_data
, },
185 { .compatible
= "fsl,imx95-ocotp", .data
= &imx95_ocotp_data
, },
188 MODULE_DEVICE_TABLE(of
, imx_ele_ocotp_dt_ids
);
190 static struct platform_driver imx_ele_ocotp_driver
= {
192 .name
= "imx_ele_ocotp",
193 .of_match_table
= imx_ele_ocotp_dt_ids
,
195 .probe
= imx_ele_ocotp_probe
,
197 module_platform_driver(imx_ele_ocotp_driver
);
199 MODULE_DESCRIPTION("i.MX OCOTP/ELE driver");
200 MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
201 MODULE_LICENSE("GPL");