xref: /rk3399_rockchip-uboot/drivers/keylad/rk_keylad.c (revision 59a8202dce9609b77a96b901fb15f5918aa7b1f7)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2025 Rockchip Electronics Co., Ltd
4  */
5 
6 #include <common.h>
7 #include <clk.h>
8 #include <keylad.h>
9 #include <dm.h>
10 #include <misc.h>
11 #include <asm/io.h>
12 #include <clk-uclass.h>
13 #include <asm/arch/hardware.h>
14 #include <asm/arch/clock.h>
15 
16 #define KEYLAD_APB_CMD			0x0450
17 #define REG_APB_CMD_EN			BIT(0)
18 #define VALUE_APB_CMD_DISABLE		0
19 #define VALUE_APB_CMD_ENABLE		BIT(0)
20 
21 #define KEYLAD_APB_PADDR		0x0454
22 #define KEYLAD_APB_PWDATA		0x0458
23 #define KEYLAD_APB_PWRITE		0x045C
24 #define KEYLAD_DATA_CTL			0x0460
25 #define VALUE_DATA_CTL_EN		BIT(15)
26 
27 #define KEYLAD_KEY_SEL			0x0610
28 #define VALUE_KEY_SEL_OUTER_KEY		0x00000000
29 
30 #define KEYLAD_LOCKSTEP_FLAG		0x0618
31 #define KEYLAD_LOCKSTEP_EN		0x061C
32 
33 #define KEY_LADDER_OTP_KEY_REQ		0x0640
34 #define KL_OTP_KEY_REQ_DST_ADDR(addr)	((addr) & 0x3) // 256bit algin address
35 #define KL_OTP_KEY_REQ_BYTE_SWAP	BIT(4)
36 #define KL_OTP_KEY_REQ_WORD_SWAP	BIT(5)
37 #define KL_OTP_KEY_REQ_EN		BIT(8)
38 #define KL_OTP_KEY_ECC_ST		BIT(12)
39 #define KL_OTP_KEY_REQ_SRC_ADDR(addr)	(((addr) & 0xffff) << 16)// byte address, dword align
40 
41 #define KEY_LADDER_KEY_LEN		0x0648
42 #define KL_KEY_LEN(len)			((len) & 0x3f)
43 
44 #define KEYLAD_KEY_REG_SIZE_BYTES	4
45 #define KEYLAD_KEY_REG_NUM		32
46 #define KEYLAD_AREA_NUM			2
47 
48 #define RK_KEYLAD_TIME_OUT		10000  /* max 10ms */
49 
50 #define KEYLAD_POLL_TIMEOUT(condition, timeout, ret) do { \
51 	u32 time_out = timeout; \
52 	while (condition) { \
53 		if (time_out-- == 0) { \
54 			printf("[%s] %d: time out!\n", __func__, __LINE__); \
55 			ret = -ETIMEDOUT; \
56 			break; \
57 		} \
58 		udelay(1); \
59 	} \
60 } while (0)
61 
62 struct rockchip_keylad_priv {
63 	fdt_addr_t			reg;
64 	char				*clocks;
65 	u32				nclocks;
66 };
67 
68 fdt_addr_t keylad_base;
69 
rk_keylad_do_enable_clk(struct udevice * dev,int enable)70 static int rk_keylad_do_enable_clk(struct udevice *dev, int enable)
71 {
72 	struct rockchip_keylad_priv *priv = dev_get_priv(dev);
73 	struct clk clk;
74 	int i, ret;
75 
76 	for (i = 0; i < priv->nclocks; i++) {
77 		ret = clk_get_by_index(dev, i, &clk);
78 		if (ret < 0) {
79 			printf("Keylad failed to get clk index %d, ret=%d\n", i, ret);
80 			return ret;
81 		}
82 
83 		if (enable)
84 			ret = clk_enable(&clk);
85 		else
86 			ret = clk_disable(&clk);
87 
88 		if (ret < 0 && ret != -ENOSYS) {
89 			printf("Keylad failed to enable(%d) clk(%ld): ret=%d\n",
90 			       enable, clk.id, ret);
91 			return ret;
92 		}
93 	}
94 
95 	return 0;
96 }
97 
rk_keylad_enable_clk(struct udevice * dev)98 static int rk_keylad_enable_clk(struct udevice *dev)
99 {
100 	return rk_keylad_do_enable_clk(dev, 1);
101 }
102 
rk_keylad_disable_clk(struct udevice * dev)103 static int rk_keylad_disable_clk(struct udevice *dev)
104 {
105 	return rk_keylad_do_enable_clk(dev, 0);
106 }
107 
keylad_read(u32 offset)108 static inline u32 keylad_read(u32 offset)
109 {
110 	return readl(keylad_base + offset);
111 }
112 
keylad_write(u32 offset,u32 val)113 static inline void keylad_write(u32 offset, u32 val)
114 {
115 	writel(val, keylad_base + offset);
116 }
117 
rk_get_fwkey_param(u32 keyid,u32 * offset,u32 * max_len)118 static int rk_get_fwkey_param(u32 keyid, u32 *offset, u32 *max_len)
119 {
120 	switch (keyid) {
121 	case RK_FW_KEY0:
122 		*offset  = OTP_FW_ENC_KEY_ADDR;
123 		*max_len = OTP_FW_ENC_KEY_SIZE;
124 		break;
125 	default:
126 		return -EINVAL;
127 	}
128 
129 	return 0;
130 }
131 
rk_keylad_send_key(u32 key_reg,u32 n_words,ulong dst_addr)132 static int rk_keylad_send_key(u32 key_reg, u32 n_words, ulong dst_addr)
133 {
134 	int ret = 0;
135 
136 	/* key_reg of 32bits can be 0-31 */
137 	if ((key_reg + n_words) > KEYLAD_KEY_REG_NUM)
138 		return -EINVAL;
139 
140 	for (u32 i = 0; i < n_words; i++) {
141 		/* set destination addr */
142 		keylad_write(KEYLAD_APB_PADDR,
143 			     (dst_addr & 0xffffffff) + (i * KEYLAD_KEY_REG_SIZE_BYTES));
144 		/* select which word of key table to be sent */
145 		keylad_write(KEYLAD_APB_PWDATA, key_reg + i);
146 
147 		keylad_write(KEYLAD_APB_CMD, VALUE_APB_CMD_ENABLE);
148 		KEYLAD_POLL_TIMEOUT((keylad_read(KEYLAD_APB_CMD) & REG_APB_CMD_EN) ==
149 				    VALUE_APB_CMD_ENABLE, RK_KEYLAD_TIME_OUT, ret);
150 	}
151 
152 	return ret;
153 }
154 
rk_otp_keylad_read_init(void)155 static int rk_otp_keylad_read_init(void)
156 {
157 	struct udevice *dev;
158 
159 	dev = misc_otp_get_device(OTP_S);
160 	if (!dev)
161 		return -ENODEV;
162 
163 	misc_otp_ioctl(dev, IOCTL_REQ_START, NULL);
164 	misc_otp_ioctl(dev, IOCTL_REQ_KEYLAD_INIT, NULL);
165 
166 	return 0;
167 }
168 
rk_otp_keylad_read_deinit(void)169 static int rk_otp_keylad_read_deinit(void)
170 {
171 	struct udevice *dev;
172 
173 	dev = misc_otp_get_device(OTP_S);
174 	if (!dev)
175 		return -ENODEV;
176 
177 	misc_otp_ioctl(dev, IOCTL_REQ_KEYLAD_DEINIT, NULL);
178 	misc_otp_ioctl(dev, IOCTL_REQ_STOP, NULL);
179 
180 	return 0;
181 }
182 
rk_keylad_read_otp_key(u32 otp_offset,u32 keylad_area,u32 keylen)183 static int rk_keylad_read_otp_key(u32 otp_offset, u32 keylad_area, u32 keylen)
184 {
185 	int ret = 0;
186 	u32 val = 0;
187 	u32 nbytes = keylen;
188 
189 	/* keylad_area of 256bits can be 0-1 */
190 	if (keylad_area >= KEYLAD_AREA_NUM)
191 		return -EINVAL;
192 
193 	ret = rk_otp_keylad_read_init();
194 	if (ret) {
195 		printf("Keyladder read otp key init err: 0x%x.", ret);
196 		return ret;
197 	}
198 
199 	/* src use byte address, dst use keytable block address */
200 	val = KL_OTP_KEY_REQ_SRC_ADDR(otp_offset / 2) |
201 	      KL_OTP_KEY_REQ_DST_ADDR(keylad_area) |
202 	      KL_OTP_KEY_REQ_BYTE_SWAP |
203 	      KL_OTP_KEY_REQ_EN;
204 
205 	keylad_write(KEYLAD_KEY_SEL, VALUE_KEY_SEL_OUTER_KEY);
206 
207 	keylad_write(KEY_LADDER_KEY_LEN, KL_KEY_LEN(nbytes));
208 
209 	keylad_write(KEY_LADDER_OTP_KEY_REQ, val);
210 
211 	KEYLAD_POLL_TIMEOUT(keylad_read(KEY_LADDER_OTP_KEY_REQ) & KL_OTP_KEY_REQ_EN,
212 			    RK_KEYLAD_TIME_OUT, ret);
213 
214 	val = keylad_read(KEY_LADDER_OTP_KEY_REQ);
215 	if (val & KL_OTP_KEY_ECC_ST) {
216 		printf("KEYLAD transfer OTP key ECC check error!");
217 		ret = -EIO;
218 	}
219 
220 	rk_otp_keylad_read_deinit();
221 
222 	return ret;
223 }
224 
rockchip_keylad_transfer_fwkey(struct udevice * dev,ulong dst,u32 fw_keyid,u32 keylen)225 static int rockchip_keylad_transfer_fwkey(struct udevice *dev, ulong dst,
226 					  u32 fw_keyid, u32 keylen)
227 {
228 	int res = 0;
229 	u32 fw_key_offset;
230 	u32 max_key_len = 0;
231 
232 	if (keylen % 4) {
233 		printf("key_len(%u) must be multiple of 4 error.", keylen);
234 		return -EINVAL;
235 	}
236 
237 	res = rk_get_fwkey_param(fw_keyid, &fw_key_offset, &max_key_len);
238 	if (res)
239 		return res;
240 
241 	if (keylen > max_key_len) {
242 		printf("key_len(%u) > %u error.", keylen, max_key_len);
243 		return -EINVAL;
244 	}
245 
246 	rk_keylad_enable_clk(dev);
247 
248 	res = rk_keylad_read_otp_key(fw_key_offset, 0, keylen);
249 	if (res) {
250 		printf("Keyladder read otp key err: 0x%x.", res);
251 		return res;
252 	}
253 
254 	res = rk_keylad_send_key(0, keylen / 4, dst);
255 
256 	rk_keylad_disable_clk(dev);
257 
258 	if (res) {
259 		printf("Keyladder transfer key err: 0x%x.", res);
260 		goto exit;
261 	}
262 
263 exit:
264 	return res;
265 }
266 
267 static const struct dm_keylad_ops rockchip_keylad_ops = {
268 	.transfer_fwkey   = rockchip_keylad_transfer_fwkey,
269 };
270 
rockchip_keylad_ofdata_to_platdata(struct udevice * dev)271 static int rockchip_keylad_ofdata_to_platdata(struct udevice *dev)
272 {
273 	struct rockchip_keylad_priv *priv = dev_get_priv(dev);
274 	int len = 0;
275 	int ret = 0;
276 
277 	memset(priv, 0x00, sizeof(*priv));
278 
279 	priv->reg = (fdt_addr_t)dev_read_addr_ptr(dev);
280 	if (priv->reg == FDT_ADDR_T_NONE)
281 		return -EINVAL;
282 
283 	keylad_base = priv->reg;
284 
285 	/* if there is no clocks in dts, just skip it */
286 	if (!dev_read_prop(dev, "clocks", &len)) {
287 		printf("Keylad \"clocks\" property not set.\n");
288 		return 0;
289 	}
290 
291 	priv->clocks = malloc(len);
292 	if (!priv->clocks)
293 		return -ENOMEM;
294 
295 	priv->nclocks = len / (2 * sizeof(u32));
296 	if (dev_read_u32_array(dev, "clocks", (u32 *)priv->clocks,
297 			       priv->nclocks)) {
298 		printf("Keylad can't read \"clocks\" property.\n");
299 		ret = -EINVAL;
300 		goto exit;
301 	}
302 
303 	return 0;
304 exit:
305 	if (priv->clocks)
306 		free(priv->clocks);
307 
308 	return ret;
309 }
310 
rockchip_keylad_probe(struct udevice * dev)311 static int rockchip_keylad_probe(struct udevice *dev)
312 {
313 	rk_keylad_disable_clk(dev);
314 
315 	return 0;
316 }
317 
318 static const struct udevice_id rockchip_keylad_ids[] = {
319 	{
320 		.compatible = "rockchip,keylad",
321 	},
322 };
323 
324 U_BOOT_DRIVER(rockchip_keylad) = {
325 	.name		= "rockchip_keylad",
326 	.id		= UCLASS_KEYLAD,
327 	.of_match	= rockchip_keylad_ids,
328 	.ops		= &rockchip_keylad_ops,
329 	.probe		= rockchip_keylad_probe,
330 	.ofdata_to_platdata = rockchip_keylad_ofdata_to_platdata,
331 	.priv_auto_alloc_size = sizeof(struct rockchip_keylad_priv),
332 };
333