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