1 // SPDX-License-Identifier: GPL-2.0+
3 * eFuse driver for Rockchip devices
5 * Copyright 2017, Theobroma Systems Design und Consulting GmbH
6 * Written by Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
12 #include <display_options.h>
14 #include <linux/bitops.h>
15 #include <linux/delay.h>
16 #include <linux/iopoll.h>
20 #define EFUSE_CTRL 0x0000
21 #define RK3036_A_SHIFT 8
22 #define RK3036_A_MASK GENMASK(15, 8)
23 #define RK3036_ADDR(n) ((n) << RK3036_A_SHIFT)
24 #define RK3128_A_SHIFT 7
25 #define RK3128_A_MASK GENMASK(15, 7)
26 #define RK3128_ADDR(n) ((n) << RK3128_A_SHIFT)
27 #define RK3288_A_SHIFT 6
28 #define RK3288_A_MASK GENMASK(15, 6)
29 #define RK3288_ADDR(n) ((n) << RK3288_A_SHIFT)
30 #define RK3399_A_SHIFT 16
31 #define RK3399_A_MASK GENMASK(25, 16)
32 #define RK3399_ADDR(n) ((n) << RK3399_A_SHIFT)
33 #define RK3399_STROBSFTSEL BIT(9)
34 #define RK3399_RSB BIT(7)
35 #define RK3399_PD BIT(5)
36 #define EFUSE_PGENB BIT(3)
37 #define EFUSE_LOAD BIT(2)
38 #define EFUSE_STROBE BIT(1)
39 #define EFUSE_CSB BIT(0)
40 #define EFUSE_DOUT 0x0004
41 #define RK3328_INT_STATUS 0x0018
42 #define RK3328_INT_FINISH BIT(0)
43 #define RK3328_DOUT 0x0020
44 #define RK3328_AUTO_CTRL 0x0024
45 #define RK3328_AUTO_RD BIT(1)
46 #define RK3328_AUTO_ENB BIT(0)
48 struct rockchip_efuse_plat {
52 struct rockchip_efuse_data {
53 int (*read)(struct udevice *dev, int offset, void *buf, int size);
60 static int dump_efuse(struct cmd_tbl *cmdtp, int flag,
61 int argc, char *const argv[])
67 ret = uclass_get_device_by_driver(UCLASS_MISC,
68 DM_DRIVER_GET(rockchip_efuse), &dev);
70 printf("%s: no misc-device found\n", __func__);
74 for (i = 0; true; i += sizeof(data)) {
75 ret = misc_read(dev, i, &data, sizeof(data));
79 print_buffer(i, data, 1, sizeof(data), sizeof(data));
86 dump_efuse, 1, 1, dump_efuse,
87 "Dump the content of the efuse",
92 static int rockchip_rk3036_efuse_read(struct udevice *dev, int offset,
95 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
98 /* Switch to read mode */
99 writel(EFUSE_LOAD, efuse->base + EFUSE_CTRL);
103 clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3036_A_MASK,
104 RK3036_ADDR(offset++));
106 setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
108 *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
109 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
113 /* Switch to inactive mode */
114 writel(0x0, efuse->base + EFUSE_CTRL);
119 static int rockchip_rk3128_efuse_read(struct udevice *dev, int offset,
122 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
125 /* Switch to read mode */
126 writel(EFUSE_LOAD, efuse->base + EFUSE_CTRL);
130 clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3128_A_MASK,
131 RK3128_ADDR(offset++));
133 setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
135 *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
136 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
140 /* Switch to inactive mode */
141 writel(0x0, efuse->base + EFUSE_CTRL);
146 static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset,
149 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
152 /* Switch to read mode */
153 writel(EFUSE_CSB, efuse->base + EFUSE_CTRL);
154 writel(EFUSE_LOAD | EFUSE_PGENB, efuse->base + EFUSE_CTRL);
158 clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3288_A_MASK,
159 RK3288_ADDR(offset++));
161 setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
163 *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
164 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
168 /* Switch to standby mode */
169 writel(EFUSE_CSB | EFUSE_PGENB, efuse->base + EFUSE_CTRL);
174 static int rockchip_rk3328_efuse_read(struct udevice *dev, int offset,
177 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
178 u32 status, *buffer = buf;
182 writel(RK3328_AUTO_RD | RK3328_AUTO_ENB | RK3399_ADDR(offset++),
183 efuse->base + RK3328_AUTO_CTRL);
186 ret = readl_poll_sleep_timeout(efuse->base + RK3328_INT_STATUS,
187 status, (status & RK3328_INT_FINISH), 1, 50);
191 *buffer++ = readl(efuse->base + RK3328_DOUT);
192 writel(RK3328_INT_FINISH, efuse->base + RK3328_INT_STATUS);
198 static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset,
201 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
204 /* Switch to array read mode */
205 writel(EFUSE_LOAD | EFUSE_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
206 efuse->base + EFUSE_CTRL);
210 setbits_le32(efuse->base + EFUSE_CTRL,
211 EFUSE_STROBE | RK3399_ADDR(offset++));
213 *buffer++ = readl(efuse->base + EFUSE_DOUT);
214 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
218 /* Switch to power-down mode */
219 writel(RK3399_PD | EFUSE_CSB, efuse->base + EFUSE_CTRL);
224 static int rockchip_efuse_read(struct udevice *dev, int offset,
227 const struct rockchip_efuse_data *data =
228 (void *)dev_get_driver_data(dev);
229 u32 block_start, block_end, block_offset, blocks;
233 if (offset < 0 || !buf || size <= 0 || offset + size > data->size)
239 offset += data->offset;
241 if (data->block_size <= 1) {
242 ret = data->read(dev, offset, buf, size);
246 block_start = offset / data->block_size;
247 block_offset = offset % data->block_size;
248 block_end = DIV_ROUND_UP(offset + size, data->block_size);
249 blocks = block_end - block_start;
251 buffer = calloc(blocks, data->block_size);
255 ret = data->read(dev, block_start, buffer, blocks);
257 memcpy(buf, buffer + block_offset, size);
262 return ret < 0 ? ret : size;
265 static const struct misc_ops rockchip_efuse_ops = {
266 .read = rockchip_efuse_read,
269 static int rockchip_efuse_of_to_plat(struct udevice *dev)
271 struct rockchip_efuse_plat *plat = dev_get_plat(dev);
273 plat->base = dev_read_addr_ptr(dev);
278 static const struct rockchip_efuse_data rk3036_data = {
279 .read = rockchip_rk3036_efuse_read,
283 static const struct rockchip_efuse_data rk3128_data = {
284 .read = rockchip_rk3128_efuse_read,
288 static const struct rockchip_efuse_data rk3288_data = {
289 .read = rockchip_rk3288_efuse_read,
293 static const struct rockchip_efuse_data rk3328_data = {
294 .read = rockchip_rk3328_efuse_read,
300 static const struct rockchip_efuse_data rk3399_data = {
301 .read = rockchip_rk3399_efuse_read,
306 static const struct udevice_id rockchip_efuse_ids[] = {
308 .compatible = "rockchip,rk3036-efuse",
309 .data = (ulong)&rk3036_data,
312 .compatible = "rockchip,rk3066a-efuse",
313 .data = (ulong)&rk3288_data,
316 .compatible = "rockchip,rk3128-efuse",
317 .data = (ulong)&rk3128_data,
320 .compatible = "rockchip,rk3188-efuse",
321 .data = (ulong)&rk3288_data,
324 .compatible = "rockchip,rk3228-efuse",
325 .data = (ulong)&rk3288_data,
328 .compatible = "rockchip,rk3288-efuse",
329 .data = (ulong)&rk3288_data,
332 .compatible = "rockchip,rk3328-efuse",
333 .data = (ulong)&rk3328_data,
336 .compatible = "rockchip,rk3399-efuse",
337 .data = (ulong)&rk3399_data,
342 U_BOOT_DRIVER(rockchip_efuse) = {
343 .name = "rockchip_efuse",
345 .of_match = rockchip_efuse_ids,
346 .of_to_plat = rockchip_efuse_of_to_plat,
347 .plat_auto = sizeof(struct rockchip_efuse_plat),
348 .ops = &rockchip_efuse_ops,