crypto: nuvoton: Add NPCM7xx AES driver
[platform/kernel/u-boot.git] / drivers / crypto / nuvoton / npcm_aes.c
1 // 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
16 struct npcm_aes_priv {
17         struct npcm_aes_regs *regs;
18 };
19
20 static struct npcm_aes_priv *aes_priv;
21 static u8 fkeyind_to_set = 0xff;
22
23 static 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
42 int 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
55 static 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
105 static 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
116 static 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
143 static 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
153 static 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
163 static 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
238 void 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
244 void 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
257 void 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
270 static 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
289 static const struct udevice_id npcm_aes_ids[] = {
290         { .compatible = "nuvoton,npcm845-aes" },
291         { .compatible = "nuvoton,npcm750-aes" },
292         { }
293 };
294
295 U_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 };