xref: /rk3399_rockchip-uboot/drivers/keylad/rk_keylad.c (revision f947fca4e63be90f2fbc2fa6ac2e99fcec95078a)
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 <asm/io.h>
11 #include <clk-uclass.h>
12 #include <asm/arch/hardware.h>
13 #include <asm/arch/clock.h>
14 
15 #define KEYLAD_APB_CMD			0x0450
16 #define REG_APB_CMD_EN			BIT(0)
17 #define VALUE_APB_CMD_DISABLE		0
18 #define VALUE_APB_CMD_ENABLE		BIT(0)
19 
20 #define KEYLAD_APB_PADDR		0x0454
21 #define KEYLAD_APB_PWDATA		0x0458
22 #define KEYLAD_APB_PWRITE		0x045C
23 #define KEYLAD_DATA_CTL			0x0460
24 #define VALUE_DATA_CTL_EN		BIT(15)
25 
26 #define KEYLAD_KEY_SEL			0x0610
27 #define VALUE_KEY_SEL_OUTER_KEY		0x00000000
28 
29 #define KEYLAD_LOCKSTEP_FLAG		0x0618
30 #define KEYLAD_LOCKSTEP_EN		0x061C
31 
32 #define KEY_LADDER_OTP_KEY_REQ		0x0640
33 #define KL_OTP_KEY_REQ_DST_ADDR(addr)	((addr) & 0x3) // 256bit algin address
34 #define KL_OTP_KEY_REQ_BYTE_SWAP	BIT(4)
35 #define KL_OTP_KEY_REQ_WORD_SWAP	BIT(5)
36 #define KL_OTP_KEY_REQ_EN		BIT(8)
37 #define KL_OTP_KEY_ECC_ST		BIT(12)
38 #define KL_OTP_KEY_REQ_SRC_ADDR(addr)	(((addr) & 0xffff) << 16)// byte address, dword align
39 
40 #define KEY_LADDER_KEY_LEN		0x0648
41 #define KL_KEY_LEN(len)			((len) & 0x3f)
42 
43 #define KEYLAD_KEY_REG_SIZE_BYTES	4
44 #define KEYLAD_KEY_REG_NUM		32
45 #define KEYLAD_AREA_NUM			2
46 
47 #define RK_KEYLAD_TIME_OUT		10000  /* max 10ms */
48 
49 #define KEYLAD_POLL_TIMEOUT(condition, timeout, ret) do { \
50 	u32 time_out = timeout; \
51 	while (condition) { \
52 		if (time_out-- == 0) { \
53 			printf("[%s] %d: time out!\n", __func__, __LINE__); \
54 			ret = -ETIMEDOUT; \
55 			break; \
56 		} \
57 		udelay(1); \
58 	} \
59 } while (0)
60 
61 struct rockchip_keylad_priv {
62 	fdt_addr_t			reg;
63 };
64 
65 fdt_addr_t keylad_base;
66 
67 static inline u32 keylad_read(u32 offset)
68 {
69 	return readl(keylad_base + offset);
70 }
71 
72 static inline void keylad_write(u32 offset, u32 val)
73 {
74 	writel(val, keylad_base + offset);
75 }
76 
77 static int rk_get_fwkey_param(u32 keyid, u32 *offset, u32 *max_len)
78 {
79 	switch (keyid) {
80 	case RK_FW_KEY0:
81 		*offset  = OEM_CIPHER_KEY_FW_ADDR;
82 		*max_len = OEM_CIPHER_KEY_FW_LEN;
83 		break;
84 	default:
85 		return -EINVAL;
86 	}
87 
88 	return 0;
89 }
90 
91 static int rk_keylad_send_key(u32 key_reg, u32 n_words, ulong dst_addr)
92 {
93 	int ret = 0;
94 
95 	/* key_reg of 32bits can be 0-31 */
96 	if ((key_reg + n_words) > KEYLAD_KEY_REG_NUM)
97 		return -EINVAL;
98 
99 	for (u32 i = 0; i < n_words; i++) {
100 		/* set destination addr */
101 		keylad_write(KEYLAD_APB_PADDR,
102 			     (dst_addr & 0xffffffff) + (i * KEYLAD_KEY_REG_SIZE_BYTES));
103 		/* select which word of key table to be sent */
104 		keylad_write(KEYLAD_APB_PWDATA, key_reg + i);
105 
106 		keylad_write(KEYLAD_APB_CMD, VALUE_APB_CMD_ENABLE);
107 		KEYLAD_POLL_TIMEOUT((keylad_read(KEYLAD_APB_CMD) & REG_APB_CMD_EN) ==
108 				    VALUE_APB_CMD_ENABLE, RK_KEYLAD_TIME_OUT, ret);
109 	}
110 
111 	return ret;
112 }
113 
114 static int rk_keylad_read_otp_key(u32 otp_offset, u32 keylad_area, u32 keylen)
115 {
116 	int ret = 0;
117 	u32 val = 0;
118 	u32 nbytes = keylen;
119 
120 	/* keylad_area of 256bits can be 0-1 */
121 	if (keylad_area >= KEYLAD_AREA_NUM)
122 		return -EINVAL;
123 
124 //	rk_otp_keylad_read_init();
125 
126 	/* src use byte address, dst use keytable block address */
127 	val = KL_OTP_KEY_REQ_SRC_ADDR(otp_offset / 2) |
128 	      KL_OTP_KEY_REQ_DST_ADDR(keylad_area) |
129 	      KL_OTP_KEY_REQ_BYTE_SWAP |
130 	      KL_OTP_KEY_REQ_EN;
131 
132 	keylad_write(KEYLAD_KEY_SEL, VALUE_KEY_SEL_OUTER_KEY);
133 
134 	keylad_write(KEY_LADDER_KEY_LEN, KL_KEY_LEN(nbytes));
135 
136 	keylad_write(KEY_LADDER_OTP_KEY_REQ, val);
137 
138 	KEYLAD_POLL_TIMEOUT(keylad_read(KEY_LADDER_OTP_KEY_REQ) & KL_OTP_KEY_REQ_EN,
139 			    RK_KEYLAD_TIME_OUT, ret);
140 
141 	val = keylad_read(KEY_LADDER_OTP_KEY_REQ);
142 	if (val & KL_OTP_KEY_ECC_ST) {
143 		printf("KEYLAD transfer OTP key ECC check error!");
144 		ret = -EIO;
145 	}
146 
147 //	rk_otp_keylad_read_deinit();
148 
149 	return ret;
150 }
151 
152 static int rockchip_keylad_transfer_fwkey(struct udevice *dev, ulong dst,
153 					  u32 fw_keyid, u32 keylen)
154 {
155 	int res = 0;
156 	u32 fw_key_offset;
157 	u32 max_key_len = 0;
158 
159 	if (keylen % 4) {
160 		printf("key_len(%u) must be multiple of 4 error.", keylen);
161 		return -EINVAL;
162 	}
163 
164 	res = rk_get_fwkey_param(fw_keyid, &fw_key_offset, &max_key_len);
165 	if (res)
166 		return res;
167 
168 	if (keylen > max_key_len) {
169 		printf("key_len(%u) > %u error.", keylen, max_key_len);
170 		return -EINVAL;
171 	}
172 
173 	res = rk_keylad_read_otp_key(fw_key_offset, 0, keylen);
174 	if (res) {
175 		printf("Keyladder read otp key err: 0x%x.", res);
176 		return res;
177 	}
178 
179 	/// TODO: enable clock
180 	res = rk_keylad_send_key(0, keylen / 4, dst);
181 	if (res) {
182 		printf("Keyladder transfer key err: 0x%x.", res);
183 		return res;
184 	}
185 
186 	return res;
187 }
188 
189 static const struct dm_keylad_ops rockchip_keylad_ops = {
190 	.transfer_fwkey   = rockchip_keylad_transfer_fwkey,
191 };
192 
193 static int rockchip_keylad_ofdata_to_platdata(struct udevice *dev)
194 {
195 	struct rockchip_keylad_priv *priv = dev_get_priv(dev);
196 
197 	memset(priv, 0x00, sizeof(*priv));
198 
199 	priv->reg = (fdt_addr_t)dev_read_addr_ptr(dev);
200 	if (priv->reg == FDT_ADDR_T_NONE)
201 		return -EINVAL;
202 
203 	keylad_base = priv->reg;
204 
205 	return 0;
206 }
207 
208 static const struct udevice_id rockchip_keylad_ids[] = {
209 	{
210 		.compatible = "rockchip,keylad",
211 	},
212 };
213 
214 U_BOOT_DRIVER(rockchip_keylad) = {
215 	.name		= "rockchip_keylad",
216 	.id		= UCLASS_KEYLAD,
217 	.of_match	= rockchip_keylad_ids,
218 	.ops		= &rockchip_keylad_ops,
219 	.ofdata_to_platdata = rockchip_keylad_ofdata_to_platdata,
220 	.priv_auto_alloc_size = sizeof(struct rockchip_keylad_priv),
221 };
222