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