blob: 6da162069aa73bbf432a15369e92eeb371939de2 [file] [log] [blame]
Jim Liu74dbae22022-06-07 16:32:09 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
Jim Liu400ae942024-04-29 14:38:03 +08003 * Copyright (c) 2024 Nuvoton Technology Corp.
Jim Liu74dbae22022-06-07 16:32:09 +08004 */
5
Jim Liu74dbae22022-06-07 16:32:09 +08006#include <dm.h>
7#include <hash.h>
8#include <malloc.h>
Jim Liu74dbae22022-06-07 16:32:09 +08009#include <asm/io.h>
Jim Liu400ae942024-04-29 14:38:03 +080010#include <linux/iopoll.h>
Jim Liu74dbae22022-06-07 16:32:09 +080011
Jim Liu400ae942024-04-29 14:38:03 +080012#define SHA512_BLOCK_LENGTH (1024 / 8)
Jim Liu74dbae22022-06-07 16:32:09 +080013
Jim Liu400ae942024-04-29 14:38:03 +080014/* Register fields */
Jim Liu74dbae22022-06-07 16:32:09 +080015#define HASH_CTR_STS_SHA_EN BIT(0)
16#define HASH_CTR_STS_SHA_BUSY BIT(1)
17#define HASH_CTR_STS_SHA_RST BIT(2)
18#define HASH_CFG_SHA1_SHA2 BIT(0)
Jim Liu400ae942024-04-29 14:38:03 +080019#define SHA512_CMD_SHA_512 BIT(3)
20#define SHA512_CMD_INTERNAL_ROUND BIT(2)
21#define SHA512_CMD_WRITE BIT(1)
22#define SHA512_CMD_READ BIT(0)
Jim Liu74dbae22022-06-07 16:32:09 +080023
Jim Liu400ae942024-04-29 14:38:03 +080024enum {
25 type_sha1 = 0,
26 type_sha256,
27 type_sha384,
28 type_sha512,
Jim Liu74dbae22022-06-07 16:32:09 +080029};
30
31struct npcm_sha_regs {
Jim Liu400ae942024-04-29 14:38:03 +080032 u8 data_in;
33 u8 data_out;
34 u8 ctr_sts;
35 u8 hash_cfg;
36 u8 sha512_cmd;
Jim Liu74dbae22022-06-07 16:32:09 +080037};
38
Jim Liu400ae942024-04-29 14:38:03 +080039struct hash_info {
40 u32 block_sz;
41 u32 digest_len;
42 u8 length_bytes;
43 u8 type;
Jim Liu74dbae22022-06-07 16:32:09 +080044};
45
Jim Liu400ae942024-04-29 14:38:03 +080046struct message_block {
47 u64 length[2];
48 u64 nonhash_sz;
49 u8 buffer[SHA512_BLOCK_LENGTH * 2];
Jim Liu74dbae22022-06-07 16:32:09 +080050};
51
Jim Liu400ae942024-04-29 14:38:03 +080052struct npcm_sha_priv {
53 void *base;
54 struct npcm_sha_regs *regs;
55 struct hash_info *hash;
56 struct message_block block;
57 bool internal_round;
58 bool support_sha512;
59};
Jim Liu74dbae22022-06-07 16:32:09 +080060
Jim Liu400ae942024-04-29 14:38:03 +080061static struct npcm_sha_regs npcm_sha_reg_tbl[] = {
62 { .data_in = 0x0, .data_out = 0x20, .ctr_sts = 0x4, .hash_cfg = 0x8 },
63 { .data_in = 0x10, .data_out = 0x1c, .ctr_sts = 0x14, .sha512_cmd = 0x18 },
64};
Jim Liu74dbae22022-06-07 16:32:09 +080065
Jim Liu400ae942024-04-29 14:38:03 +080066static struct hash_info npcm_hash_tbl[] = {
67 { .type = type_sha1, .block_sz = 64, .digest_len = 160, .length_bytes = 8 },
68 { .type = type_sha256, .block_sz = 64, .digest_len = 256, .length_bytes = 8 },
69 { .type = type_sha384, .block_sz = 128, .digest_len = 384, .length_bytes = 16 },
70 { .type = type_sha512, .block_sz = 128, .digest_len = 512, .length_bytes = 16 },
71};
Jim Liu74dbae22022-06-07 16:32:09 +080072
Jim Liu400ae942024-04-29 14:38:03 +080073static struct npcm_sha_priv *sha_priv;
Jim Liu74dbae22022-06-07 16:32:09 +080074
Jim Liu400ae942024-04-29 14:38:03 +080075static int npcm_sha_init(u8 type)
Jim Liu74dbae22022-06-07 16:32:09 +080076{
Jim Liu400ae942024-04-29 14:38:03 +080077 struct message_block *block = &sha_priv->block;
Jim Liu74dbae22022-06-07 16:32:09 +080078
Jim Liu400ae942024-04-29 14:38:03 +080079 if (type > type_sha512 ||
80 (!sha_priv->support_sha512 &&
81 (type == type_sha384 || type == type_sha512)))
82 return -ENOTSUPP;
Jim Liu74dbae22022-06-07 16:32:09 +080083
Jim Liu400ae942024-04-29 14:38:03 +080084 sha_priv->regs = &npcm_sha_reg_tbl[type / 2];
85 sha_priv->hash = &npcm_hash_tbl[type];
86 block->length[0] = 0;
87 block->length[1] = 0;
88 block->nonhash_sz = 0;
89 sha_priv->internal_round = false;
Jim Liu74dbae22022-06-07 16:32:09 +080090
91 return 0;
92}
93
Jim Liu400ae942024-04-29 14:38:03 +080094static void npcm_sha_reset(void)
Jim Liu74dbae22022-06-07 16:32:09 +080095{
Jim Liu400ae942024-04-29 14:38:03 +080096 struct npcm_sha_regs *regs = sha_priv->regs;
97 struct hash_info *hash = sha_priv->hash;
98 u8 val;
Jim Liu74dbae22022-06-07 16:32:09 +080099
Jim Liu400ae942024-04-29 14:38:03 +0800100 if (hash->type == type_sha1)
101 writeb(HASH_CFG_SHA1_SHA2, sha_priv->base + regs->hash_cfg);
102 else if (hash->type == type_sha256)
103 writeb(0, sha_priv->base + regs->hash_cfg);
104 else if (hash->type == type_sha384)
105 writeb(0, sha_priv->base + regs->sha512_cmd);
106 else if (hash->type == type_sha512)
107 writeb(SHA512_CMD_SHA_512, sha_priv->base + regs->sha512_cmd);
Jim Liu74dbae22022-06-07 16:32:09 +0800108
Jim Liu400ae942024-04-29 14:38:03 +0800109 val = readb(sha_priv->base + regs->ctr_sts) & ~HASH_CTR_STS_SHA_EN;
110 writeb(val | HASH_CTR_STS_SHA_RST, sha_priv->base + regs->ctr_sts);
Jim Liu74dbae22022-06-07 16:32:09 +0800111}
112
Jim Liu400ae942024-04-29 14:38:03 +0800113static void npcm_sha_enable(bool on)
Jim Liu74dbae22022-06-07 16:32:09 +0800114{
Jim Liu400ae942024-04-29 14:38:03 +0800115 struct npcm_sha_regs *regs = sha_priv->regs;
116 u8 val;
Jim Liu74dbae22022-06-07 16:32:09 +0800117
Jim Liu400ae942024-04-29 14:38:03 +0800118 val = readb(sha_priv->base + regs->ctr_sts) & ~HASH_CTR_STS_SHA_EN;
119 val |= on;
120 writeb(val | on, sha_priv->base + regs->ctr_sts);
Jim Liu74dbae22022-06-07 16:32:09 +0800121}
122
Jim Liu400ae942024-04-29 14:38:03 +0800123static int npcm_sha_flush_block(u8 *block)
Jim Liu74dbae22022-06-07 16:32:09 +0800124{
125 struct npcm_sha_regs *regs = sha_priv->regs;
Jim Liu400ae942024-04-29 14:38:03 +0800126 struct hash_info *hash = sha_priv->hash;
127 u32 *blk_dw = (u32 *)block;
128 u8 val;
129 int i;
Jim Liu74dbae22022-06-07 16:32:09 +0800130
Jim Liu400ae942024-04-29 14:38:03 +0800131 if (readb_poll_timeout(sha_priv->base + regs->ctr_sts, val,
132 !(val & HASH_CTR_STS_SHA_BUSY), 100))
133 return -ETIMEDOUT;
Jim Liu74dbae22022-06-07 16:32:09 +0800134
Jim Liu400ae942024-04-29 14:38:03 +0800135 if (hash->type == type_sha384 || hash->type == type_sha512) {
136 val = SHA512_CMD_WRITE;
137 if (hash->type == type_sha512)
138 val |= SHA512_CMD_SHA_512;
139 if (sha_priv->internal_round)
140 val |= SHA512_CMD_INTERNAL_ROUND;
141 writeb(val, sha_priv->base + regs->sha512_cmd);
142 }
143 for (i = 0; i < (hash->block_sz / sizeof(u32)); i++)
144 writel(blk_dw[i], sha_priv->base + regs->data_in);
Jim Liu74dbae22022-06-07 16:32:09 +0800145
Jim Liu400ae942024-04-29 14:38:03 +0800146 sha_priv->internal_round = true;
Jim Liu74dbae22022-06-07 16:32:09 +0800147
148 return 0;
149}
150
Jim Liu400ae942024-04-29 14:38:03 +0800151static int npcm_sha_update_block(const u8 *in, u32 len)
Jim Liu74dbae22022-06-07 16:32:09 +0800152{
Jim Liu400ae942024-04-29 14:38:03 +0800153 struct message_block *block = &sha_priv->block;
154 struct hash_info *hash = sha_priv->hash;
155 u8 *buffer = &block->buffer[0];
156 u32 block_sz = hash->block_sz;
157 u32 hash_sz;
Jim Liu74dbae22022-06-07 16:32:09 +0800158
Jim Liu400ae942024-04-29 14:38:03 +0800159 hash_sz = (block->nonhash_sz + len) > block_sz ?
160 (block_sz - block->nonhash_sz) : len;
161 memcpy(buffer + block->nonhash_sz, in, hash_sz);
162 block->nonhash_sz += hash_sz;
163 block->length[0] += hash_sz;
164 if (block->length[0] < hash_sz)
165 block->length[1]++;
Jim Liu74dbae22022-06-07 16:32:09 +0800166
Jim Liu400ae942024-04-29 14:38:03 +0800167 if (block->nonhash_sz == block_sz) {
168 block->nonhash_sz = 0;
169 if (npcm_sha_flush_block(buffer))
170 return -EBUSY;
171 }
Jim Liu74dbae22022-06-07 16:32:09 +0800172
Jim Liu400ae942024-04-29 14:38:03 +0800173 return hash_sz;
174}
Jim Liu74dbae22022-06-07 16:32:09 +0800175
Jim Liu400ae942024-04-29 14:38:03 +0800176static int npcm_sha_update(const u8 *input, u32 len)
177{
178 int hash_sz;
Jim Liu74dbae22022-06-07 16:32:09 +0800179
180 while (len) {
Jim Liu400ae942024-04-29 14:38:03 +0800181 hash_sz = npcm_sha_update_block(input, len);
182 if (hash_sz < 0) {
183 printf("SHA512 module busy\n");
184 return -EBUSY;
Jim Liu74dbae22022-06-07 16:32:09 +0800185 }
Jim Liu400ae942024-04-29 14:38:03 +0800186 len -= hash_sz;
187 input += hash_sz;
Jim Liu74dbae22022-06-07 16:32:09 +0800188 }
189
Jim Liu74dbae22022-06-07 16:32:09 +0800190 return 0;
191}
192
Jim Liu400ae942024-04-29 14:38:03 +0800193static int npcm_sha_finish(u8 *out)
Jim Liu74dbae22022-06-07 16:32:09 +0800194{
195 struct npcm_sha_regs *regs = sha_priv->regs;
Jim Liu400ae942024-04-29 14:38:03 +0800196 struct message_block *block = &sha_priv->block;
197 struct hash_info *hash = sha_priv->hash;
198 u8 *buffer = &block->buffer[0];
199 u32 block_sz = hash->block_sz;
200 u32 *out32 = (u32 *)out;
201 u32 zero_len, val;
202 u64 *length;
203 u8 reg_data_out;
204 int i;
Jim Liu74dbae22022-06-07 16:32:09 +0800205
Jim Liu400ae942024-04-29 14:38:03 +0800206 /* Padding, minimal padding size is last_byte+length_bytes */
207 if ((block_sz - block->nonhash_sz) >= (hash->length_bytes + 1))
208 zero_len = block_sz - block->nonhash_sz - (hash->length_bytes + 1);
209 else
210 zero_len = block_sz * 2 - block->nonhash_sz - (hash->length_bytes + 1);
211 /* Last byte */
212 buffer[block->nonhash_sz++] = 0x80;
213 /* Zero bits padding */
214 memset(&buffer[block->nonhash_sz], 0, zero_len);
215 block->nonhash_sz += zero_len;
216 /* Message length */
217 length = (u64 *)&buffer[block->nonhash_sz];
218 if (hash->length_bytes == 16) {
219 *length++ = cpu_to_be64(block->length[1] << 3 | block->length[0] >> 61);
220 block->nonhash_sz += 8;
Jim Liu74dbae22022-06-07 16:32:09 +0800221 }
Jim Liu400ae942024-04-29 14:38:03 +0800222 *length = cpu_to_be64(block->length[0] << 3);
223 block->nonhash_sz += 8;
224 if (npcm_sha_flush_block(&block->buffer[0]))
225 return -ETIMEDOUT;
Jim Liu74dbae22022-06-07 16:32:09 +0800226
Jim Liu400ae942024-04-29 14:38:03 +0800227 /* After padding, the last message may produce 2 blocks */
228 if (block->nonhash_sz > block_sz) {
229 if (npcm_sha_flush_block(&block->buffer[block_sz]))
230 return -ETIMEDOUT;
231 }
232 /* Read digest */
233 if (readb_poll_timeout(sha_priv->base + regs->ctr_sts, val,
234 !(val & HASH_CTR_STS_SHA_BUSY), 100))
235 return -ETIMEDOUT;
236 if (hash->type == type_sha384)
237 writeb(SHA512_CMD_READ, sha_priv->base + regs->sha512_cmd);
238 else if (hash->type == type_sha512)
239 writeb(SHA512_CMD_SHA_512 | SHA512_CMD_READ,
240 sha_priv->base + regs->sha512_cmd);
Jim Liu74dbae22022-06-07 16:32:09 +0800241
Jim Liu400ae942024-04-29 14:38:03 +0800242 reg_data_out = regs->data_out;
243 for (i = 0; i < (hash->digest_len / 32); i++) {
244 *out32 = readl(sha_priv->base + reg_data_out);
245 out32++;
246 if (hash->type == type_sha1 || hash->type == type_sha256)
247 reg_data_out += 4;
248 }
Jim Liu74dbae22022-06-07 16:32:09 +0800249
250 return 0;
251}
252
Jim Liu400ae942024-04-29 14:38:03 +0800253int npcm_sha_calc(const u8 *input, u32 len, u8 *output, u8 type)
Jim Liu74dbae22022-06-07 16:32:09 +0800254{
Jim Liu400ae942024-04-29 14:38:03 +0800255 if (npcm_sha_init(type))
256 return -ENOTSUPP;
257 npcm_sha_reset();
258 npcm_sha_enable(true);
259 npcm_sha_update(input, len);
260 npcm_sha_finish(output);
261 npcm_sha_enable(false);
Jim Liu74dbae22022-06-07 16:32:09 +0800262
263 return 0;
264}
265
Jim Liu400ae942024-04-29 14:38:03 +0800266void hw_sha512(const unsigned char *input, unsigned int len,
267 unsigned char *output, unsigned int chunk_sz)
Jim Liu74dbae22022-06-07 16:32:09 +0800268{
Jim Liu400ae942024-04-29 14:38:03 +0800269 if (!sha_priv->support_sha512) {
270 puts(" HW accelerator not support\n");
271 return;
272 }
273 puts(" using BMC HW accelerator\n");
274 npcm_sha_calc(input, len, output, type_sha512);
Jim Liu74dbae22022-06-07 16:32:09 +0800275}
Jim Liu74dbae22022-06-07 16:32:09 +0800276
Jim Liu400ae942024-04-29 14:38:03 +0800277void hw_sha384(const unsigned char *input, unsigned int len,
278 unsigned char *output, unsigned int chunk_sz)
Jim Liu74dbae22022-06-07 16:32:09 +0800279{
Jim Liu400ae942024-04-29 14:38:03 +0800280 if (!sha_priv->support_sha512) {
281 puts(" HW accelerator not support\n");
282 return;
Jim Liu74dbae22022-06-07 16:32:09 +0800283 }
Jim Liu400ae942024-04-29 14:38:03 +0800284 puts(" using BMC HW accelerator\n");
285 npcm_sha_calc(input, len, output, type_sha384);
Jim Liu74dbae22022-06-07 16:32:09 +0800286}
287
Jim Liu400ae942024-04-29 14:38:03 +0800288void hw_sha256(const unsigned char *input, unsigned int len,
289 unsigned char *output, unsigned int chunk_sz)
Jim Liu74dbae22022-06-07 16:32:09 +0800290{
Jim Liu400ae942024-04-29 14:38:03 +0800291 puts(" using BMC HW accelerator\n");
292 npcm_sha_calc(input, len, output, type_sha256);
Jim Liu74dbae22022-06-07 16:32:09 +0800293}
294
Jim Liu400ae942024-04-29 14:38:03 +0800295void hw_sha1(const unsigned char *input, unsigned int len,
296 unsigned char *output, unsigned int chunk_sz)
Jim Liu74dbae22022-06-07 16:32:09 +0800297{
Jim Liu400ae942024-04-29 14:38:03 +0800298 puts(" using BMC HW accelerator\n");
299 npcm_sha_calc(input, len, output, type_sha1);
Jim Liu74dbae22022-06-07 16:32:09 +0800300}
301
Jim Liu400ae942024-04-29 14:38:03 +0800302int hw_sha_init(struct hash_algo *algo, void **ctxp)
Jim Liu74dbae22022-06-07 16:32:09 +0800303{
Jim Liu400ae942024-04-29 14:38:03 +0800304 if (!strcmp("sha1", algo->name)) {
305 npcm_sha_init(type_sha1);
306 } else if (!strcmp("sha256", algo->name)) {
307 npcm_sha_init(type_sha256);
308 } else if (!strcmp("sha384", algo->name)) {
309 if (!sha_priv->support_sha512)
310 return -ENOTSUPP;
311 npcm_sha_init(type_sha384);
312 } else if (!strcmp("sha512", algo->name)) {
313 if (!sha_priv->support_sha512)
314 return -ENOTSUPP;
315 npcm_sha_init(type_sha512);
316 } else {
317 return -ENOTSUPP;
318 }
Jim Liu74dbae22022-06-07 16:32:09 +0800319
Jim Liu400ae942024-04-29 14:38:03 +0800320 printf("Using npcm SHA engine\n");
321 npcm_sha_reset();
322 npcm_sha_enable(true);
Jim Liu74dbae22022-06-07 16:32:09 +0800323
Jim Liu400ae942024-04-29 14:38:03 +0800324 return 0;
Jim Liu74dbae22022-06-07 16:32:09 +0800325}
326
Jim Liu400ae942024-04-29 14:38:03 +0800327int hw_sha_update(struct hash_algo *algo, void *ctx, const void *buf,
328 unsigned int size, int is_last)
Jim Liu74dbae22022-06-07 16:32:09 +0800329{
Jim Liu400ae942024-04-29 14:38:03 +0800330 return npcm_sha_update(buf, size);
Jim Liu74dbae22022-06-07 16:32:09 +0800331}
332
Jim Liu400ae942024-04-29 14:38:03 +0800333int hw_sha_finish(struct hash_algo *algo, void *ctx, void *dest_buf,
334 int size)
Jim Liu74dbae22022-06-07 16:32:09 +0800335{
Jim Liu400ae942024-04-29 14:38:03 +0800336 int ret;
Jim Liu74dbae22022-06-07 16:32:09 +0800337
Jim Liu400ae942024-04-29 14:38:03 +0800338 ret = npcm_sha_finish(dest_buf);
339 npcm_sha_enable(false);
Jim Liu74dbae22022-06-07 16:32:09 +0800340
Jim Liu400ae942024-04-29 14:38:03 +0800341 return ret;
Jim Liu74dbae22022-06-07 16:32:09 +0800342}
343
344static int npcm_sha_bind(struct udevice *dev)
345{
346 sha_priv = calloc(1, sizeof(struct npcm_sha_priv));
347 if (!sha_priv)
348 return -ENOMEM;
349
Jim Liu400ae942024-04-29 14:38:03 +0800350 sha_priv->base = dev_read_addr_ptr(dev);
351 if (!sha_priv->base) {
Jim Liu74dbae22022-06-07 16:32:09 +0800352 printf("Cannot find sha reg address, binding failed\n");
353 return -EINVAL;
354 }
355
Jim Liu400ae942024-04-29 14:38:03 +0800356 if (IS_ENABLED(CONFIG_ARCH_NPCM8XX))
357 sha_priv->support_sha512 = true;
358
Jim Liu74dbae22022-06-07 16:32:09 +0800359 printf("SHA: NPCM SHA module bind OK\n");
360
361 return 0;
362}
363
364static const struct udevice_id npcm_sha_ids[] = {
365 { .compatible = "nuvoton,npcm845-sha" },
366 { .compatible = "nuvoton,npcm750-sha" },
367 { }
368};
369
370U_BOOT_DRIVER(npcm_sha) = {
371 .name = "npcm_sha",
372 .id = UCLASS_MISC,
373 .of_match = npcm_sha_ids,
374 .priv_auto = sizeof(struct npcm_sha_priv),
375 .bind = npcm_sha_bind,
376};