blob: 99220d5b1eab84f4deca8f2f98be8a606d563d14 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Philipp Tomsich49cd8e82017-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 Tomsich49cd8e82017-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 Karlman433260a2023-02-22 22:44:39 +000016#include <malloc.h>
Philipp Tomsich49cd8e82017-05-05 19:21:38 +020017#include <misc.h>
18
Jonas Karlman433260a2023-02-22 22:44:39 +000019#define EFUSE_CTRL 0x0000
Jonas Karlman6f95b3e2023-02-22 22:44:40 +000020#define RK3288_A_SHIFT 6
21#define RK3288_A_MASK GENMASK(15, 6)
22#define RK3288_ADDR(n) ((n) << RK3288_A_SHIFT)
Jonas Karlman433260a2023-02-22 22:44:39 +000023#define RK3399_A_SHIFT 16
24#define RK3399_A_MASK GENMASK(25, 16)
25#define RK3399_ADDR(n) ((n) << RK3399_A_SHIFT)
26#define RK3399_STROBSFTSEL BIT(9)
27#define RK3399_RSB BIT(7)
28#define RK3399_PD BIT(5)
Jonas Karlman6f95b3e2023-02-22 22:44:40 +000029#define EFUSE_PGENB BIT(3)
30#define EFUSE_LOAD BIT(2)
31#define EFUSE_STROBE BIT(1)
32#define EFUSE_CSB BIT(0)
Jonas Karlman433260a2023-02-22 22:44:39 +000033#define EFUSE_DOUT 0x0004
Philipp Tomsich49cd8e82017-05-05 19:21:38 +020034
Simon Glass8a8d24b2020-12-03 16:55:23 -070035struct rockchip_efuse_plat {
Philipp Tomsich49cd8e82017-05-05 19:21:38 +020036 void __iomem *base;
Jonas Karlman433260a2023-02-22 22:44:39 +000037};
38
39struct rockchip_efuse_data {
40 int (*read)(struct udevice *dev, int offset, void *buf, int size);
41 int size;
42 int block_size;
Philipp Tomsich49cd8e82017-05-05 19:21:38 +020043};
44
45#if defined(DEBUG)
Jonas Karlman433260a2023-02-22 22:44:39 +000046static int dump_efuse(struct cmd_tbl *cmdtp, int flag,
47 int argc, char *const argv[])
Philipp Tomsich49cd8e82017-05-05 19:21:38 +020048{
Philipp Tomsich49cd8e82017-05-05 19:21:38 +020049 struct udevice *dev;
Jonas Karlman433260a2023-02-22 22:44:39 +000050 u8 data[4];
51 int ret, i;
Philipp Tomsich49cd8e82017-05-05 19:21:38 +020052
Philipp Tomsich49cd8e82017-05-05 19:21:38 +020053 ret = uclass_get_device_by_driver(UCLASS_MISC,
Simon Glass65e25be2020-12-28 20:34:56 -070054 DM_DRIVER_GET(rockchip_efuse), &dev);
Philipp Tomsich49cd8e82017-05-05 19:21:38 +020055 if (ret) {
56 printf("%s: no misc-device found\n", __func__);
57 return 0;
58 }
59
Jonas Karlman433260a2023-02-22 22:44:39 +000060 for (i = 0; true; i += sizeof(data)) {
61 ret = misc_read(dev, i, &data, sizeof(data));
62 if (ret < 0)
63 return 0;
Philipp Tomsich49cd8e82017-05-05 19:21:38 +020064
Jonas Karlman433260a2023-02-22 22:44:39 +000065 print_buffer(i, data, 1, sizeof(data), sizeof(data));
66 }
Philipp Tomsich49cd8e82017-05-05 19:21:38 +020067
68 return 0;
69}
70
71U_BOOT_CMD(
Jonas Karlman433260a2023-02-22 22:44:39 +000072 dump_efuse, 1, 1, dump_efuse,
73 "Dump the content of the efuse",
Philipp Tomsich49cd8e82017-05-05 19:21:38 +020074 ""
75);
76#endif
77
Jonas Karlman6f95b3e2023-02-22 22:44:40 +000078static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset,
79 void *buf, int size)
80{
81 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
82 u8 *buffer = buf;
83
84 /* Switch to read mode */
85 writel(EFUSE_CSB, efuse->base + EFUSE_CTRL);
86 writel(EFUSE_LOAD | EFUSE_PGENB, efuse->base + EFUSE_CTRL);
87 udelay(2);
88
89 while (size--) {
90 clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3288_A_MASK,
91 RK3288_ADDR(offset++));
92 udelay(2);
93 setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
94 udelay(2);
95 *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
96 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
97 udelay(2);
98 }
99
100 /* Switch to standby mode */
101 writel(EFUSE_CSB | EFUSE_PGENB, efuse->base + EFUSE_CTRL);
102
103 return 0;
104}
105
Philipp Tomsich49cd8e82017-05-05 19:21:38 +0200106static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset,
107 void *buf, int size)
108{
Jonas Karlman433260a2023-02-22 22:44:39 +0000109 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
110 u32 *buffer = buf;
Philipp Tomsich49cd8e82017-05-05 19:21:38 +0200111
Jonas Karlman433260a2023-02-22 22:44:39 +0000112 /* Switch to array read mode */
Jonas Karlman6f95b3e2023-02-22 22:44:40 +0000113 writel(EFUSE_LOAD | EFUSE_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
Jonas Karlman433260a2023-02-22 22:44:39 +0000114 efuse->base + EFUSE_CTRL);
Philipp Tomsich49cd8e82017-05-05 19:21:38 +0200115 udelay(1);
Philipp Tomsich49cd8e82017-05-05 19:21:38 +0200116
Jonas Karlman433260a2023-02-22 22:44:39 +0000117 while (size--) {
118 setbits_le32(efuse->base + EFUSE_CTRL,
Jonas Karlman6f95b3e2023-02-22 22:44:40 +0000119 EFUSE_STROBE | RK3399_ADDR(offset++));
Jonas Karlman433260a2023-02-22 22:44:39 +0000120 udelay(1);
121 *buffer++ = readl(efuse->base + EFUSE_DOUT);
Jonas Karlman6f95b3e2023-02-22 22:44:40 +0000122 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
Jonas Karlman433260a2023-02-22 22:44:39 +0000123 udelay(1);
Philipp Tomsich49cd8e82017-05-05 19:21:38 +0200124 }
125
Jonas Karlman433260a2023-02-22 22:44:39 +0000126 /* Switch to power-down mode */
Jonas Karlman6f95b3e2023-02-22 22:44:40 +0000127 writel(RK3399_PD | EFUSE_CSB, efuse->base + EFUSE_CTRL);
Philipp Tomsich49cd8e82017-05-05 19:21:38 +0200128
129 return 0;
130}
131
132static int rockchip_efuse_read(struct udevice *dev, int offset,
133 void *buf, int size)
134{
Jonas Karlman433260a2023-02-22 22:44:39 +0000135 const struct rockchip_efuse_data *data =
136 (void *)dev_get_driver_data(dev);
137 u32 block_start, block_end, block_offset, blocks;
138 u8 *buffer;
139 int ret;
140
141 if (offset < 0 || !buf || size <= 0 || offset + size > data->size)
142 return -EINVAL;
143
144 if (!data->read)
145 return -ENOSYS;
146
147 if (data->block_size <= 1)
148 return data->read(dev, offset, buf, size);
149
150 block_start = offset / data->block_size;
151 block_offset = offset % data->block_size;
152 block_end = DIV_ROUND_UP(offset + size, data->block_size);
153 blocks = block_end - block_start;
154
155 buffer = calloc(blocks, data->block_size);
156 if (!buffer)
157 return -ENOMEM;
158
159 ret = data->read(dev, block_start, buffer, blocks);
160 if (!ret)
161 memcpy(buf, buffer + block_offset, size);
162
163 free(buffer);
164 return ret;
Philipp Tomsich49cd8e82017-05-05 19:21:38 +0200165}
166
167static const struct misc_ops rockchip_efuse_ops = {
168 .read = rockchip_efuse_read,
169};
170
Simon Glassd1998a92020-12-03 16:55:21 -0700171static int rockchip_efuse_of_to_plat(struct udevice *dev)
Philipp Tomsich49cd8e82017-05-05 19:21:38 +0200172{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700173 struct rockchip_efuse_plat *plat = dev_get_plat(dev);
Philipp Tomsich49cd8e82017-05-05 19:21:38 +0200174
Philipp Tomsichf6230a02017-09-12 17:32:26 +0200175 plat->base = dev_read_addr_ptr(dev);
Jonas Karlman433260a2023-02-22 22:44:39 +0000176
Philipp Tomsich49cd8e82017-05-05 19:21:38 +0200177 return 0;
178}
179
Jonas Karlman6f95b3e2023-02-22 22:44:40 +0000180static const struct rockchip_efuse_data rk3288_data = {
181 .read = rockchip_rk3288_efuse_read,
182 .size = 0x20,
183};
184
Jonas Karlman433260a2023-02-22 22:44:39 +0000185static const struct rockchip_efuse_data rk3399_data = {
186 .read = rockchip_rk3399_efuse_read,
187 .size = 0x80,
188 .block_size = 4,
189};
190
Philipp Tomsich49cd8e82017-05-05 19:21:38 +0200191static const struct udevice_id rockchip_efuse_ids[] = {
Jonas Karlman433260a2023-02-22 22:44:39 +0000192 {
Jonas Karlman6f95b3e2023-02-22 22:44:40 +0000193 .compatible = "rockchip,rk3066a-efuse",
194 .data = (ulong)&rk3288_data,
195 },
196 {
197 .compatible = "rockchip,rk3188-efuse",
198 .data = (ulong)&rk3288_data,
199 },
200 {
201 .compatible = "rockchip,rk3228-efuse",
202 .data = (ulong)&rk3288_data,
203 },
204 {
205 .compatible = "rockchip,rk3288-efuse",
206 .data = (ulong)&rk3288_data,
207 },
208 {
Jonas Karlman433260a2023-02-22 22:44:39 +0000209 .compatible = "rockchip,rk3399-efuse",
210 .data = (ulong)&rk3399_data,
211 },
Philipp Tomsich49cd8e82017-05-05 19:21:38 +0200212 {}
213};
214
215U_BOOT_DRIVER(rockchip_efuse) = {
216 .name = "rockchip_efuse",
217 .id = UCLASS_MISC,
218 .of_match = rockchip_efuse_ids,
Simon Glassd1998a92020-12-03 16:55:21 -0700219 .of_to_plat = rockchip_efuse_of_to_plat,
Jonas Karlman433260a2023-02-22 22:44:39 +0000220 .plat_auto = sizeof(struct rockchip_efuse_plat),
Philipp Tomsich49cd8e82017-05-05 19:21:38 +0200221 .ops = &rockchip_efuse_ops,
222};