blob: 60931a513121b5646e7b162b3373de65d1846c38 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Philipp Tomsichfcc1d632017-05-05 19:21:38 +02002/*
3 * eFuse driver for Rockchip devices
4 *
5 * Copyright 2017, Theobroma Systems Design und Consulting GmbH
6 * Written by Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
Philipp Tomsichfcc1d632017-05-05 19:21:38 +02007 */
8
9#include <common.h>
10#include <asm/io.h>
11#include <command.h>
12#include <display_options.h>
13#include <dm.h>
14#include <linux/bitops.h>
15#include <linux/delay.h>
Jonas Karlmanc0189652023-02-22 22:44:40 +000016#include <linux/iopoll.h>
Jonas Karlman26ed3852023-02-22 22:44:39 +000017#include <malloc.h>
Philipp Tomsichfcc1d632017-05-05 19:21:38 +020018#include <misc.h>
19
Jonas Karlman26ed3852023-02-22 22:44:39 +000020#define EFUSE_CTRL 0x0000
Jonas Karlmandececbb2023-02-22 22:44:40 +000021#define RK3036_A_SHIFT 8
22#define RK3036_A_MASK GENMASK(15, 8)
23#define RK3036_ADDR(n) ((n) << RK3036_A_SHIFT)
Jonas Karlman836f4ec2023-02-22 22:44:40 +000024#define RK3128_A_SHIFT 7
25#define RK3128_A_MASK GENMASK(15, 7)
26#define RK3128_ADDR(n) ((n) << RK3128_A_SHIFT)
Jonas Karlman14ad36d2023-02-22 22:44:40 +000027#define RK3288_A_SHIFT 6
28#define RK3288_A_MASK GENMASK(15, 6)
29#define RK3288_ADDR(n) ((n) << RK3288_A_SHIFT)
Jonas Karlman26ed3852023-02-22 22:44:39 +000030#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)
Jonas Karlman14ad36d2023-02-22 22:44:40 +000036#define EFUSE_PGENB BIT(3)
37#define EFUSE_LOAD BIT(2)
38#define EFUSE_STROBE BIT(1)
39#define EFUSE_CSB BIT(0)
Jonas Karlman26ed3852023-02-22 22:44:39 +000040#define EFUSE_DOUT 0x0004
Jonas Karlmanc0189652023-02-22 22:44:40 +000041#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)
Philipp Tomsichfcc1d632017-05-05 19:21:38 +020047
Simon Glassb75b15b2020-12-03 16:55:23 -070048struct rockchip_efuse_plat {
Philipp Tomsichfcc1d632017-05-05 19:21:38 +020049 void __iomem *base;
Philipp Tomsichfcc1d632017-05-05 19:21:38 +020050};
51
Jonas Karlman26ed3852023-02-22 22:44:39 +000052struct rockchip_efuse_data {
53 int (*read)(struct udevice *dev, int offset, void *buf, int size);
Jonas Karlmanc0189652023-02-22 22:44:40 +000054 int offset;
Jonas Karlman26ed3852023-02-22 22:44:39 +000055 int size;
56 int block_size;
57};
58
Philipp Tomsichfcc1d632017-05-05 19:21:38 +020059#if defined(DEBUG)
Jonas Karlman26ed3852023-02-22 22:44:39 +000060static int dump_efuse(struct cmd_tbl *cmdtp, int flag,
61 int argc, char *const argv[])
Philipp Tomsichfcc1d632017-05-05 19:21:38 +020062{
Philipp Tomsichfcc1d632017-05-05 19:21:38 +020063 struct udevice *dev;
Jonas Karlman26ed3852023-02-22 22:44:39 +000064 u8 data[4];
65 int ret, i;
Philipp Tomsichfcc1d632017-05-05 19:21:38 +020066
Philipp Tomsichfcc1d632017-05-05 19:21:38 +020067 ret = uclass_get_device_by_driver(UCLASS_MISC,
Simon Glass65130cd2020-12-28 20:34:56 -070068 DM_DRIVER_GET(rockchip_efuse), &dev);
Philipp Tomsichfcc1d632017-05-05 19:21:38 +020069 if (ret) {
70 printf("%s: no misc-device found\n", __func__);
71 return 0;
72 }
73
Jonas Karlman26ed3852023-02-22 22:44:39 +000074 for (i = 0; true; i += sizeof(data)) {
75 ret = misc_read(dev, i, &data, sizeof(data));
76 if (ret < 0)
77 return 0;
Philipp Tomsichfcc1d632017-05-05 19:21:38 +020078
Jonas Karlman26ed3852023-02-22 22:44:39 +000079 print_buffer(i, data, 1, sizeof(data), sizeof(data));
80 }
Philipp Tomsichfcc1d632017-05-05 19:21:38 +020081
82 return 0;
83}
84
85U_BOOT_CMD(
Jonas Karlman26ed3852023-02-22 22:44:39 +000086 dump_efuse, 1, 1, dump_efuse,
87 "Dump the content of the efuse",
Philipp Tomsichfcc1d632017-05-05 19:21:38 +020088 ""
89);
90#endif
91
Jonas Karlmandececbb2023-02-22 22:44:40 +000092static int rockchip_rk3036_efuse_read(struct udevice *dev, int offset,
93 void *buf, int size)
94{
95 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
96 u8 *buffer = buf;
97
98 /* Switch to read mode */
99 writel(EFUSE_LOAD, efuse->base + EFUSE_CTRL);
100 udelay(2);
101
102 while (size--) {
103 clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3036_A_MASK,
104 RK3036_ADDR(offset++));
105 udelay(2);
106 setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
107 udelay(2);
108 *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
109 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
110 udelay(2);
111 }
112
113 /* Switch to inactive mode */
114 writel(0x0, efuse->base + EFUSE_CTRL);
115
116 return 0;
117}
118
Jonas Karlman836f4ec2023-02-22 22:44:40 +0000119static int rockchip_rk3128_efuse_read(struct udevice *dev, int offset,
120 void *buf, int size)
121{
122 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
123 u8 *buffer = buf;
124
125 /* Switch to read mode */
126 writel(EFUSE_LOAD, efuse->base + EFUSE_CTRL);
127 udelay(2);
128
129 while (size--) {
130 clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3128_A_MASK,
131 RK3128_ADDR(offset++));
132 udelay(2);
133 setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
134 udelay(2);
135 *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
136 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
137 udelay(2);
138 }
139
140 /* Switch to inactive mode */
141 writel(0x0, efuse->base + EFUSE_CTRL);
142
143 return 0;
144}
145
Jonas Karlman14ad36d2023-02-22 22:44:40 +0000146static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset,
147 void *buf, int size)
148{
149 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
150 u8 *buffer = buf;
151
152 /* Switch to read mode */
153 writel(EFUSE_CSB, efuse->base + EFUSE_CTRL);
154 writel(EFUSE_LOAD | EFUSE_PGENB, efuse->base + EFUSE_CTRL);
155 udelay(2);
156
157 while (size--) {
158 clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3288_A_MASK,
159 RK3288_ADDR(offset++));
160 udelay(2);
161 setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
162 udelay(2);
163 *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
164 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
165 udelay(2);
166 }
167
168 /* Switch to standby mode */
169 writel(EFUSE_CSB | EFUSE_PGENB, efuse->base + EFUSE_CTRL);
170
171 return 0;
172}
173
Jonas Karlmanc0189652023-02-22 22:44:40 +0000174static int rockchip_rk3328_efuse_read(struct udevice *dev, int offset,
175 void *buf, int size)
176{
177 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
178 u32 status, *buffer = buf;
179 int ret;
180
181 while (size--) {
182 writel(RK3328_AUTO_RD | RK3328_AUTO_ENB | RK3399_ADDR(offset++),
183 efuse->base + RK3328_AUTO_CTRL);
184 udelay(1);
185
186 ret = readl_poll_sleep_timeout(efuse->base + RK3328_INT_STATUS,
187 status, (status & RK3328_INT_FINISH), 1, 50);
188 if (ret)
189 return ret;
190
191 *buffer++ = readl(efuse->base + RK3328_DOUT);
192 writel(RK3328_INT_FINISH, efuse->base + RK3328_INT_STATUS);
193 }
194
195 return 0;
196}
197
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200198static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset,
199 void *buf, int size)
200{
Jonas Karlman26ed3852023-02-22 22:44:39 +0000201 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
202 u32 *buffer = buf;
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200203
Jonas Karlman26ed3852023-02-22 22:44:39 +0000204 /* Switch to array read mode */
Jonas Karlman14ad36d2023-02-22 22:44:40 +0000205 writel(EFUSE_LOAD | EFUSE_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
Jonas Karlman26ed3852023-02-22 22:44:39 +0000206 efuse->base + EFUSE_CTRL);
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200207 udelay(1);
Jonas Karlman26ed3852023-02-22 22:44:39 +0000208
209 while (size--) {
210 setbits_le32(efuse->base + EFUSE_CTRL,
Jonas Karlman14ad36d2023-02-22 22:44:40 +0000211 EFUSE_STROBE | RK3399_ADDR(offset++));
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200212 udelay(1);
Jonas Karlman26ed3852023-02-22 22:44:39 +0000213 *buffer++ = readl(efuse->base + EFUSE_DOUT);
Jonas Karlman14ad36d2023-02-22 22:44:40 +0000214 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200215 udelay(1);
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200216 }
217
Jonas Karlman26ed3852023-02-22 22:44:39 +0000218 /* Switch to power-down mode */
Jonas Karlman14ad36d2023-02-22 22:44:40 +0000219 writel(RK3399_PD | EFUSE_CSB, efuse->base + EFUSE_CTRL);
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200220
221 return 0;
222}
223
224static int rockchip_efuse_read(struct udevice *dev, int offset,
225 void *buf, int size)
226{
Jonas Karlman26ed3852023-02-22 22:44:39 +0000227 const struct rockchip_efuse_data *data =
228 (void *)dev_get_driver_data(dev);
229 u32 block_start, block_end, block_offset, blocks;
230 u8 *buffer;
231 int ret;
232
233 if (offset < 0 || !buf || size <= 0 || offset + size > data->size)
234 return -EINVAL;
235
236 if (!data->read)
237 return -ENOSYS;
238
Jonas Karlmanc0189652023-02-22 22:44:40 +0000239 offset += data->offset;
240
Jonas Karlman26ed3852023-02-22 22:44:39 +0000241 if (data->block_size <= 1)
242 return data->read(dev, offset, buf, size);
243
244 block_start = offset / data->block_size;
245 block_offset = offset % data->block_size;
246 block_end = DIV_ROUND_UP(offset + size, data->block_size);
247 blocks = block_end - block_start;
248
249 buffer = calloc(blocks, data->block_size);
250 if (!buffer)
251 return -ENOMEM;
252
253 ret = data->read(dev, block_start, buffer, blocks);
254 if (!ret)
255 memcpy(buf, buffer + block_offset, size);
256
257 free(buffer);
258 return ret;
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200259}
260
261static const struct misc_ops rockchip_efuse_ops = {
262 .read = rockchip_efuse_read,
263};
264
Simon Glassaad29ae2020-12-03 16:55:21 -0700265static int rockchip_efuse_of_to_plat(struct udevice *dev)
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200266{
Simon Glassb75b15b2020-12-03 16:55:23 -0700267 struct rockchip_efuse_plat *plat = dev_get_plat(dev);
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200268
Philipp Tomsich3b505962017-09-12 17:32:26 +0200269 plat->base = dev_read_addr_ptr(dev);
Jonas Karlman26ed3852023-02-22 22:44:39 +0000270
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200271 return 0;
272}
273
Jonas Karlmandececbb2023-02-22 22:44:40 +0000274static const struct rockchip_efuse_data rk3036_data = {
275 .read = rockchip_rk3036_efuse_read,
276 .size = 0x20,
277};
278
Jonas Karlman836f4ec2023-02-22 22:44:40 +0000279static const struct rockchip_efuse_data rk3128_data = {
280 .read = rockchip_rk3128_efuse_read,
281 .size = 0x40,
282};
283
Jonas Karlman14ad36d2023-02-22 22:44:40 +0000284static const struct rockchip_efuse_data rk3288_data = {
285 .read = rockchip_rk3288_efuse_read,
286 .size = 0x20,
Jonas Karlmanc0189652023-02-22 22:44:40 +0000287};
288
289static const struct rockchip_efuse_data rk3328_data = {
290 .read = rockchip_rk3328_efuse_read,
291 .offset = 0x60,
292 .size = 0x20,
293 .block_size = 4,
Jonas Karlman14ad36d2023-02-22 22:44:40 +0000294};
295
Jonas Karlman26ed3852023-02-22 22:44:39 +0000296static const struct rockchip_efuse_data rk3399_data = {
297 .read = rockchip_rk3399_efuse_read,
298 .size = 0x80,
299 .block_size = 4,
300};
301
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200302static const struct udevice_id rockchip_efuse_ids[] = {
Jonas Karlman26ed3852023-02-22 22:44:39 +0000303 {
Jonas Karlmandececbb2023-02-22 22:44:40 +0000304 .compatible = "rockchip,rk3036-efuse",
305 .data = (ulong)&rk3036_data,
306 },
307 {
Jonas Karlman14ad36d2023-02-22 22:44:40 +0000308 .compatible = "rockchip,rk3066a-efuse",
309 .data = (ulong)&rk3288_data,
310 },
311 {
Jonas Karlman836f4ec2023-02-22 22:44:40 +0000312 .compatible = "rockchip,rk3128-efuse",
313 .data = (ulong)&rk3128_data,
314 },
315 {
Jonas Karlman14ad36d2023-02-22 22:44:40 +0000316 .compatible = "rockchip,rk3188-efuse",
317 .data = (ulong)&rk3288_data,
318 },
319 {
320 .compatible = "rockchip,rk3228-efuse",
321 .data = (ulong)&rk3288_data,
322 },
323 {
324 .compatible = "rockchip,rk3288-efuse",
325 .data = (ulong)&rk3288_data,
326 },
327 {
Jonas Karlmanc0189652023-02-22 22:44:40 +0000328 .compatible = "rockchip,rk3328-efuse",
329 .data = (ulong)&rk3328_data,
330 },
331 {
Jonas Karlman26ed3852023-02-22 22:44:39 +0000332 .compatible = "rockchip,rk3399-efuse",
333 .data = (ulong)&rk3399_data,
334 },
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200335 {}
336};
337
338U_BOOT_DRIVER(rockchip_efuse) = {
339 .name = "rockchip_efuse",
340 .id = UCLASS_MISC,
341 .of_match = rockchip_efuse_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700342 .of_to_plat = rockchip_efuse_of_to_plat,
Jonas Karlman26ed3852023-02-22 22:44:39 +0000343 .plat_auto = sizeof(struct rockchip_efuse_plat),
Philipp Tomsichfcc1d632017-05-05 19:21:38 +0200344 .ops = &rockchip_efuse_ops,
345};