xref: /rk3399_rockchip-uboot/drivers/misc/rockchip-efuse.c (revision 785b4fbf6c5db1eb4c0ddf983292d7ab077c4212)
1 /*
2  * eFuse driver for Rockchip devices
3  *
4  * Copyright 2017, Theobroma Systems Design und Consulting GmbH
5  * Written by Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
6  *
7  * SPDX-License-Identifier:	GPL-2.0+
8  */
9 
10 #include <common.h>
11 #include <asm/io.h>
12 #include <command.h>
13 #include <display_options.h>
14 #include <dm.h>
15 #include <linux/bitops.h>
16 #include <linux/delay.h>
17 #include <misc.h>
18 
19 #define RK3399_A_SHIFT          16
20 #define RK3399_A_MASK           0x3ff
21 #define RK3399_NFUSES           32
22 #define RK3399_BYTES_PER_FUSE   4
23 #define RK3399_STROBSFTSEL      BIT(9)
24 #define RK3399_RSB              BIT(7)
25 #define RK3399_PD               BIT(5)
26 #define RK3399_PGENB            BIT(3)
27 #define RK3399_LOAD             BIT(2)
28 #define RK3399_STROBE           BIT(1)
29 #define RK3399_CSB              BIT(0)
30 
31 #define RK3288_A_SHIFT          6
32 #define RK3288_A_MASK           0x3ff
33 #define RK3288_NFUSES           32
34 #define RK3288_BYTES_PER_FUSE   1
35 #define RK3288_PGENB            BIT(3)
36 #define RK3288_LOAD             BIT(2)
37 #define RK3288_STROBE           BIT(1)
38 #define RK3288_CSB              BIT(0)
39 
40 typedef int (*EFUSE_READ)(struct udevice *dev, int offset, void *buf, int size);
41 
42 struct rockchip_efuse_regs {
43 	u32 ctrl;      /* 0x00  efuse control register */
44 	u32 dout;      /* 0x04  efuse data out register */
45 	u32 rf;        /* 0x08  efuse redundancy bit used register */
46 	u32 _rsvd0;
47 	u32 jtag_pass; /* 0x10  JTAG password */
48 	u32 strobe_finish_ctrl;
49 		       /* 0x14	efuse strobe finish control register */
50 };
51 
52 struct rockchip_efuse_platdata {
53 	void __iomem *base;
54 	struct clk *clk;
55 };
56 
57 #if defined(DEBUG)
58 static int dump_efuses(cmd_tbl_t *cmdtp, int flag,
59 		       int argc, char * const argv[])
60 {
61 	/*
62 	 * N.B.: This function is tailored towards the RK3399 and assumes that
63 	 *       there's always 32 fuses x 32 bits (i.e. 128 bytes of data) to
64 	 *       be read.
65 	 */
66 
67 	struct udevice *dev;
68 	u8 fuses[128] = {0};
69 	int ret;
70 
71 	/* retrieve the device */
72 	ret = uclass_get_device_by_driver(UCLASS_MISC,
73 					  DM_GET_DRIVER(rockchip_efuse), &dev);
74 	if (ret) {
75 		printf("%s: no misc-device found\n", __func__);
76 		return 0;
77 	}
78 
79 	ret = misc_read(dev, 0, &fuses, sizeof(fuses));
80 	if (ret) {
81 		printf("%s: misc_read failed\n", __func__);
82 		return 0;
83 	}
84 
85 	printf("efuse-contents:\n");
86 	print_buffer(0, fuses, 1, 128, 16);
87 
88 	return 0;
89 }
90 
91 U_BOOT_CMD(
92 	rockchip_dump_efuses, 1, 1, dump_efuses,
93 	"Dump the content of the efuses",
94 	""
95 );
96 #endif
97 
98 static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset,
99 				      void *buf, int size)
100 {
101 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
102 	struct rockchip_efuse_regs *efuse =
103 		(struct rockchip_efuse_regs *)plat->base;
104 
105 	unsigned int addr_start, addr_end, addr_offset;
106 	u32 out_value;
107 	u8  bytes[RK3399_NFUSES * RK3399_BYTES_PER_FUSE];
108 	int i = 0;
109 	u32 addr;
110 
111 	addr_start = offset / RK3399_BYTES_PER_FUSE;
112 	addr_offset = offset % RK3399_BYTES_PER_FUSE;
113 	addr_end = DIV_ROUND_UP(offset + size, RK3399_BYTES_PER_FUSE);
114 
115 	/* cap to the size of the efuse block */
116 	if (addr_end > RK3399_NFUSES)
117 		addr_end = RK3399_NFUSES;
118 
119 	writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
120 	       &efuse->ctrl);
121 	udelay(1);
122 	for (addr = addr_start; addr < addr_end; addr++) {
123 		setbits_le32(&efuse->ctrl,
124 			     RK3399_STROBE | (addr << RK3399_A_SHIFT));
125 		udelay(1);
126 		out_value = readl(&efuse->dout);
127 		clrbits_le32(&efuse->ctrl, RK3399_STROBE);
128 		udelay(1);
129 
130 		memcpy(&bytes[i], &out_value, RK3399_BYTES_PER_FUSE);
131 		i += RK3399_BYTES_PER_FUSE;
132 	}
133 
134 	/* Switch to standby mode */
135 	writel(RK3399_PD | RK3399_CSB, &efuse->ctrl);
136 
137 	memcpy(buf, bytes + addr_offset, size);
138 
139 	return 0;
140 }
141 
142 static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset,
143 				      void *buf, int size)
144 {
145 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
146 	struct rockchip_efuse_regs *efuse =
147 		(struct rockchip_efuse_regs *)plat->base;
148 	u8 *buffer = buf;
149 	int max_size = RK3288_NFUSES * RK3288_BYTES_PER_FUSE;
150 
151 	if (size > (max_size - offset))
152 		size = max_size - offset;
153 
154 	/* Switch to read mode */
155 	writel(RK3288_LOAD | RK3288_PGENB, &efuse->ctrl);
156 	udelay(1);
157 
158 	while (size--) {
159 		writel(readl(&efuse->ctrl) &
160 				(~(RK3288_A_MASK << RK3288_A_SHIFT)),
161 				&efuse->ctrl);
162 		/* set addr */
163 		writel(readl(&efuse->ctrl) |
164 				((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT),
165 				&efuse->ctrl);
166 		udelay(1);
167 		/* strobe low to high */
168 		writel(readl(&efuse->ctrl) |
169 				RK3288_STROBE, &efuse->ctrl);
170 		ndelay(60);
171 		/* read data */
172 		*buffer++ = readl(&efuse->dout);
173 		/* reset strobe to low */
174 		writel(readl(&efuse->ctrl) &
175 				(~RK3288_STROBE), &efuse->ctrl);
176 		udelay(1);
177 	}
178 
179 	/* Switch to standby mode */
180 	writel(RK3288_PGENB | RK3288_CSB, &efuse->ctrl);
181 
182 	return 0;
183 }
184 
185 static int rockchip_efuse_read(struct udevice *dev, int offset,
186 			       void *buf, int size)
187 {
188 	EFUSE_READ efuse_read = NULL;
189 
190 	efuse_read = (EFUSE_READ)dev_get_driver_data(dev);
191 	if (!efuse_read)
192 		return -ENOSYS;
193 
194 	return (*efuse_read)(dev, offset, buf, size);
195 }
196 
197 static const struct misc_ops rockchip_efuse_ops = {
198 	.read = rockchip_efuse_read,
199 };
200 
201 static int rockchip_efuse_ofdata_to_platdata(struct udevice *dev)
202 {
203 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
204 
205 	plat->base = dev_read_addr_ptr(dev);
206 	return 0;
207 }
208 
209 static const struct udevice_id rockchip_efuse_ids[] = {
210 	{
211 		.compatible = "rockchip,rockchip-efuse",
212 		.data = (ulong)&rockchip_rk3288_efuse_read,
213 	},
214 	{
215 		.compatible = "rockchip,rk3066a-efuse",
216 		.data = (ulong)&rockchip_rk3288_efuse_read,
217 	},
218 	{
219 		.compatible = "rockchip,rk3188-efuse",
220 		.data = (ulong)&rockchip_rk3288_efuse_read,
221 	},
222 	{
223 		.compatible = "rockchip,rk322x-efuse",
224 		.data = (ulong)&rockchip_rk3288_efuse_read,
225 	},
226 	{
227 		.compatible = "rockchip,rk3399-efuse",
228 		.data = (ulong)&rockchip_rk3399_efuse_read,
229 	},
230 	{}
231 };
232 
233 U_BOOT_DRIVER(rockchip_efuse) = {
234 	.name = "rockchip_efuse",
235 	.id = UCLASS_MISC,
236 	.of_match = rockchip_efuse_ids,
237 	.ofdata_to_platdata = rockchip_efuse_ofdata_to_platdata,
238 	.platdata_auto_alloc_size = sizeof(struct rockchip_efuse_platdata),
239 	.ops = &rockchip_efuse_ops,
240 };
241