blob: 6493ea108ec7fafd92b14adf613cf29907411c64 [file] [log] [blame]
Jim Liu3bfce8c2022-06-07 16:32:08 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2021 Nuvoton Technology Corp.
4 */
5
6#include <common.h>
7#include <dm.h>
8#include <uboot_aes.h>
9#include <asm/io.h>
10#include <asm/arch/aes.h>
11#include <asm/arch/otp.h>
12#include <malloc.h>
13
14#define ONE_SECOND 0xC00000
15
16struct npcm_aes_priv {
17 struct npcm_aes_regs *regs;
18};
19
20static struct npcm_aes_priv *aes_priv;
21static u8 fkeyind_to_set = 0xff;
22
23static int second_timeout(u32 *addr, u32 bitmask, u32 bitpol)
24{
25 ulong time, i = 0;
26
27 time = get_timer(0);
28
29 /* default 1 second timeout */
30 while (((readl(addr) & bitmask) == bitpol) && i < ONE_SECOND)
31 i++;
32
33 if (i == ONE_SECOND) {
34 printf("%xms timeout: addr = %x, mask = %x\n", (u32)get_timer(time),
35 *addr, bitmask);
36 return -1;
37 }
38
39 return 0;
40}
41
42int npcm_aes_select_key(u8 fkeyind)
43{
44 if (npcm_otp_is_fuse_array_disabled(NPCM_KEY_SA)) {
45 printf("AES key access denied\n");
46 return -EACCES;
47 }
48
49 if (fkeyind < 4)
50 fkeyind_to_set = fkeyind;
51
52 return 0;
53}
54
55static int npcm_aes_init(u8 dec_enc)
56{
57 struct npcm_aes_regs *regs = aes_priv->regs;
58 u32 ctrl, orgctrlval, wrtimeout;
59
60 /* reset hw */
61 writel(readl(&regs->aes_sw_reset) | SW_RESET_BIT, &regs->aes_sw_reset);
62 writel(readl(&regs->aes_fifo_status) | DIN_FIFO_OVERFLOW, &regs->aes_fifo_status);
63 writel(readl(&regs->aes_fifo_status) | DOUT_FIFO_UNDERFLOW, &regs->aes_fifo_status);
64
65 /* Workaround to over come Errata #648 */
66 orgctrlval = readl(&regs->aes_control);
67 ctrl = (0x00002004 | dec_enc); /* AES256(CBC) */
68
69 if (ctrl != orgctrlval) {
70 writel(ctrl, &regs->aes_control);
71
72 if (ctrl != readl(&regs->aes_control)) {
73 u32 read_ctrl;
74 int intwr;
75
76 for (wrtimeout = 0; wrtimeout < 1000; wrtimeout++) {
77 for (intwr = 0 ; intwr < 10; intwr++) {
78 writel(ctrl, &regs->aes_control);
79 writew(ctrl, (u16 *)&regs->aes_control + 1);
80 /* Write configurable info in a single write operation */
81 mb();
82 }
83
84 read_ctrl = readl(&regs->aes_control);
85 if (ctrl == read_ctrl)
86 break;
87 }
88
89 if (wrtimeout == 1000) {
90 printf("\nTIMEOUT expected data=0x%x Actual AES_CONTROL data 0x%x\n\n",
91 ctrl, read_ctrl);
92 return -EAGAIN;
93 }
94
95 printf("Workaround success, wrtimeout = %d\n", wrtimeout);
96 }
97 }
98
99 if (second_timeout(&regs->aes_busy, AES_BUSY_BIT, AES_BUSY_BIT))
100 return -EAGAIN;
101
102 return 0;
103}
104
105static inline void npcm_aes_load_iv(u8 *iv)
106{
107 struct npcm_aes_regs *regs = aes_priv->regs;
108 u32 *p = (u32 *)iv;
109 u32 i;
110
111 /* Initialization Vector is loaded in 32-bit chunks */
112 for (i = 0; i < (SIZE_AES_BLOCK / sizeof(u32)); i++)
113 writel(p[i], &regs->aes_iv_0 + i);
114}
115
116static inline void npcm_aes_load_key(u8 *key)
117{
118 struct npcm_aes_regs *regs = aes_priv->regs;
119 u32 *p = (u32 *)key;
120 u32 i;
121
122 /* The key can be loaded either via the configuration or by using sideband
123 * key port (aes_select_key).
124 * If aes_select_key has been called ('fkeyind_to_set' was set to desired
125 * key index) and no key is specified (key is NULL), we should use the
126 * key index. Otherwise, we write the given key to the registers.
127 */
128 if (!key && fkeyind_to_set < 4) {
129 npcm_otp_select_key(fkeyind_to_set);
130
131 /* Sample the new key */
132 writel(readl(&regs->aes_sk) | AES_SK_BIT, &regs->aes_sk);
133
134 } else {
135 /* Initialization Vector is loaded in 32-bit chunks */
136 for (i = 0; i < (2 * SIZE_AES_BLOCK / sizeof(u32)); i++)
137 writel(p[i], &regs->aes_key_0 + i);
138
139 fkeyind_to_set = 0xff;
140 }
141}
142
143static inline void npcm_aes_write(u32 *in)
144{
145 struct npcm_aes_regs *regs = aes_priv->regs;
146 u32 i;
147
148 /* 16 Byte AES Block is written in 32-bit chunks */
149 for (i = 0; i < (SIZE_AES_BLOCK / sizeof(u32)); i++)
150 writel(in[i], &regs->aes_fifo_data);
151}
152
153static inline void npcm_aes_read(u32 *out)
154{
155 struct npcm_aes_regs *regs = aes_priv->regs;
156 u32 i;
157
158 /* Data is read in 32-bit chunks */
159 for (i = 0; i < (SIZE_AES_BLOCK / sizeof(u32)); i++)
160 out[i] = readl(&regs->aes_fifo_data);
161}
162
163static void npcm_aes_feed(u32 num_aes_blocks, u32 *datain, u32 *dataout)
164{
165 struct npcm_aes_regs *regs = aes_priv->regs;
166 u32 aes_datablk;
167 u32 total_blocks = num_aes_blocks;
168 u32 blocks_left = num_aes_blocks;
169
170 /* data mode */
171 writel(readl(&regs->aes_busy) | AES_BUSY_BIT, &regs->aes_busy);
172
173 /* Clear overflow and underflow */
174 writel(readl(&regs->aes_fifo_status) | DIN_FIFO_OVERFLOW, &regs->aes_fifo_status);
175 writel(readl(&regs->aes_fifo_status) | DOUT_FIFO_UNDERFLOW, &regs->aes_fifo_status);
176
177 /* datain/dataout is advanced in 32-bit chunks */
178 aes_datablk = (SIZE_AES_BLOCK / sizeof(u32));
179
180 /* Quit if there is no complete blocks */
181 if (total_blocks == 0)
182 return;
183
184 /* Write the first block */
185 if (total_blocks > 1) {
186 npcm_aes_write(datain);
187 datain += aes_datablk;
188 blocks_left--;
189 }
190
191 /* Write the second block */
192 if (total_blocks > 2) {
193 second_timeout(&regs->aes_fifo_status, DIN_FIFO_EMPTY, 0);
194 npcm_aes_write(datain);
195 datain += aes_datablk;
196 blocks_left--;
197 }
198
199 /* Write & read available blocks */
200 while (blocks_left > 0) {
201 second_timeout(&regs->aes_fifo_status, DIN_FIFO_FULL, DIN_FIFO_FULL);
202
203 /* Write next block */
204 npcm_aes_write(datain);
205 datain += aes_datablk;
206
207 /* Wait till DOUT FIFO is empty */
208 second_timeout(&regs->aes_fifo_status, DOUT_FIFO_EMPTY, DOUT_FIFO_EMPTY);
209
210 /* Read next block */
211 npcm_aes_read(dataout);
212 dataout += aes_datablk;
213
214 blocks_left--;
215 }
216
217 if (total_blocks > 2) {
218 second_timeout(&regs->aes_fifo_status, DOUT_FIFO_FULL, 0);
219
220 /* Read next block */
221 npcm_aes_read(dataout);
222 dataout += aes_datablk;
223
224 second_timeout(&regs->aes_fifo_status, DOUT_FIFO_FULL, 0);
225
226 /* Read next block */
227 npcm_aes_read(dataout);
228 dataout += aes_datablk;
229 } else if (total_blocks > 1) {
230 second_timeout(&regs->aes_fifo_status, DOUT_FIFO_FULL, 0);
231
232 /* Read next block */
233 npcm_aes_read(dataout);
234 dataout += aes_datablk;
235 }
236}
237
238void aes_expand_key(u8 *key, u32 key_size, u8 *expkey)
239{
240 /* npcm hw expands the key automatically, just copy it */
241 memcpy(expkey, key, SIZE_AES_BLOCK * 2);
242}
243
244void aes_cbc_encrypt_blocks(u32 key_size, u8 *key_exp, u8 *iv, u8 *src, u8 *dst,
245 u32 num_aes_blocks)
246{
247 if (npcm_aes_init(AES_OP_ENCRYPT))
248 return;
249
250 npcm_aes_load_iv(iv);
251
252 npcm_aes_load_key(key_exp);
253
254 npcm_aes_feed(num_aes_blocks, (u32 *)src, (u32 *)dst);
255}
256
257void aes_cbc_decrypt_blocks(u32 key_size, u8 *key_exp, u8 *iv, u8 *src, u8 *dst,
258 u32 num_aes_blocks)
259{
260 if (npcm_aes_init(AES_OP_DECRYPT))
261 return;
262
263 npcm_aes_load_iv(iv);
264
265 npcm_aes_load_key(key_exp);
266
267 npcm_aes_feed(num_aes_blocks, (u32 *)src, (u32 *)dst);
268}
269
270static int npcm_aes_bind(struct udevice *dev)
271{
272 aes_priv = calloc(1, sizeof(struct npcm_aes_priv));
273 if (!aes_priv) {
274 printf("%s: %d\n", __func__, __LINE__);
275 return -ENOMEM;
276 }
277
278 aes_priv->regs = dev_read_addr_ptr(dev);
279 if (!aes_priv->regs) {
280 printf("Cannot find aes reg address, binding failed\n");
281 return -EINVAL;
282 }
283
284 printf("AES: NPCM AES module bind OK\n");
285
286 return 0;
287}
288
289static const struct udevice_id npcm_aes_ids[] = {
290 { .compatible = "nuvoton,npcm845-aes" },
291 { .compatible = "nuvoton,npcm750-aes" },
292 { }
293};
294
295U_BOOT_DRIVER(npcm_aes) = {
296 .name = "npcm_aes",
297 .id = UCLASS_MISC,
298 .of_match = npcm_aes_ids,
299 .priv_auto = sizeof(struct npcm_aes_priv),
300 .bind = npcm_aes_bind,
301};