1acbb1eb7SAkshay Saraswat /*
2acbb1eb7SAkshay Saraswat * Advanced Crypto Engine - SHA Firmware
3acbb1eb7SAkshay Saraswat * Copyright (c) 2012 Samsung Electronics
4acbb1eb7SAkshay Saraswat *
51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
6acbb1eb7SAkshay Saraswat */
7acbb1eb7SAkshay Saraswat #include <common.h>
80bd93724SPrzemyslaw Marczak #include "ace_sha.h"
90bd93724SPrzemyslaw Marczak
100bd93724SPrzemyslaw Marczak #ifdef CONFIG_SHA_HW_ACCEL
112b9912e6SJeroen Hofstee #include <u-boot/sha256.h>
122b9912e6SJeroen Hofstee #include <u-boot/sha1.h>
13*1221ce45SMasahiro Yamada #include <linux/errno.h>
14acbb1eb7SAkshay Saraswat
15acbb1eb7SAkshay Saraswat /* SHA1 value for the message of zero length */
16acbb1eb7SAkshay Saraswat static const unsigned char sha1_digest_emptymsg[SHA1_SUM_LEN] = {
17acbb1eb7SAkshay Saraswat 0xDA, 0x39, 0xA3, 0xEE, 0x5E, 0x6B, 0x4B, 0x0D,
18acbb1eb7SAkshay Saraswat 0x32, 0x55, 0xBF, 0xFF, 0x95, 0x60, 0x18, 0x90,
19acbb1eb7SAkshay Saraswat 0xAF, 0xD8, 0x07, 0x09};
20acbb1eb7SAkshay Saraswat
21acbb1eb7SAkshay Saraswat /* SHA256 value for the message of zero length */
22acbb1eb7SAkshay Saraswat static const unsigned char sha256_digest_emptymsg[SHA256_SUM_LEN] = {
23acbb1eb7SAkshay Saraswat 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14,
24acbb1eb7SAkshay Saraswat 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24,
25acbb1eb7SAkshay Saraswat 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C,
26acbb1eb7SAkshay Saraswat 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55};
27acbb1eb7SAkshay Saraswat
ace_sha_hash_digest(const unsigned char * pbuf,unsigned int buf_len,unsigned char * pout,unsigned int hash_type)28acbb1eb7SAkshay Saraswat int ace_sha_hash_digest(const unsigned char *pbuf, unsigned int buf_len,
29acbb1eb7SAkshay Saraswat unsigned char *pout, unsigned int hash_type)
30acbb1eb7SAkshay Saraswat {
31acbb1eb7SAkshay Saraswat unsigned int i, reg, len;
32acbb1eb7SAkshay Saraswat unsigned int *pdigest;
33acbb1eb7SAkshay Saraswat struct exynos_ace_sfr *ace_sha_reg =
34acbb1eb7SAkshay Saraswat (struct exynos_ace_sfr *)samsung_get_base_ace_sfr();
35acbb1eb7SAkshay Saraswat
36acbb1eb7SAkshay Saraswat if (buf_len == 0) {
37acbb1eb7SAkshay Saraswat /* ACE H/W cannot compute hash value for empty string */
38acbb1eb7SAkshay Saraswat if (hash_type == ACE_SHA_TYPE_SHA1)
39acbb1eb7SAkshay Saraswat memcpy(pout, sha1_digest_emptymsg, SHA1_SUM_LEN);
40acbb1eb7SAkshay Saraswat else
41acbb1eb7SAkshay Saraswat memcpy(pout, sha256_digest_emptymsg, SHA256_SUM_LEN);
42acbb1eb7SAkshay Saraswat return 0;
43acbb1eb7SAkshay Saraswat }
44acbb1eb7SAkshay Saraswat
45acbb1eb7SAkshay Saraswat /* Flush HRDMA */
46acbb1eb7SAkshay Saraswat writel(ACE_FC_HRDMACFLUSH_ON, &ace_sha_reg->fc_hrdmac);
47acbb1eb7SAkshay Saraswat writel(ACE_FC_HRDMACFLUSH_OFF, &ace_sha_reg->fc_hrdmac);
48acbb1eb7SAkshay Saraswat
49acbb1eb7SAkshay Saraswat /* Set byte swap of data in */
50acbb1eb7SAkshay Saraswat writel(ACE_HASH_SWAPDI_ON | ACE_HASH_SWAPDO_ON | ACE_HASH_SWAPIV_ON,
51acbb1eb7SAkshay Saraswat &ace_sha_reg->hash_byteswap);
52acbb1eb7SAkshay Saraswat
53acbb1eb7SAkshay Saraswat /* Select Hash input mux as external source */
54acbb1eb7SAkshay Saraswat reg = readl(&ace_sha_reg->fc_fifoctrl);
55acbb1eb7SAkshay Saraswat reg = (reg & ~ACE_FC_SELHASH_MASK) | ACE_FC_SELHASH_EXOUT;
56acbb1eb7SAkshay Saraswat writel(reg, &ace_sha_reg->fc_fifoctrl);
57acbb1eb7SAkshay Saraswat
58acbb1eb7SAkshay Saraswat /* Set Hash as SHA1 or SHA256 and start Hash engine */
59acbb1eb7SAkshay Saraswat reg = (hash_type == ACE_SHA_TYPE_SHA1) ?
60acbb1eb7SAkshay Saraswat ACE_HASH_ENGSEL_SHA1HASH : ACE_HASH_ENGSEL_SHA256HASH;
61acbb1eb7SAkshay Saraswat reg |= ACE_HASH_STARTBIT_ON;
62acbb1eb7SAkshay Saraswat writel(reg, &ace_sha_reg->hash_control);
63acbb1eb7SAkshay Saraswat
64acbb1eb7SAkshay Saraswat /* Enable FIFO mode */
65acbb1eb7SAkshay Saraswat writel(ACE_HASH_FIFO_ON, &ace_sha_reg->hash_fifo_mode);
66acbb1eb7SAkshay Saraswat
67acbb1eb7SAkshay Saraswat /* Set message length */
68acbb1eb7SAkshay Saraswat writel(buf_len, &ace_sha_reg->hash_msgsize_low);
69acbb1eb7SAkshay Saraswat writel(0, &ace_sha_reg->hash_msgsize_high);
70acbb1eb7SAkshay Saraswat
71acbb1eb7SAkshay Saraswat /* Set HRDMA */
72acbb1eb7SAkshay Saraswat writel((unsigned int)pbuf, &ace_sha_reg->fc_hrdmas);
73acbb1eb7SAkshay Saraswat writel(buf_len, &ace_sha_reg->fc_hrdmal);
74acbb1eb7SAkshay Saraswat
75acbb1eb7SAkshay Saraswat while ((readl(&ace_sha_reg->hash_status) & ACE_HASH_MSGDONE_MASK) ==
76acbb1eb7SAkshay Saraswat ACE_HASH_MSGDONE_OFF) {
77acbb1eb7SAkshay Saraswat /*
78acbb1eb7SAkshay Saraswat * PRNG error bit goes HIGH if a PRNG request occurs without
79acbb1eb7SAkshay Saraswat * a complete seed setup. We are using this bit to check h/w
80acbb1eb7SAkshay Saraswat * fault because proper setup is not expected in that case.
81acbb1eb7SAkshay Saraswat */
82acbb1eb7SAkshay Saraswat if ((readl(&ace_sha_reg->hash_status)
83acbb1eb7SAkshay Saraswat & ACE_HASH_PRNGERROR_MASK) == ACE_HASH_PRNGERROR_ON)
84acbb1eb7SAkshay Saraswat return -EBUSY;
85acbb1eb7SAkshay Saraswat }
86acbb1eb7SAkshay Saraswat
87acbb1eb7SAkshay Saraswat /* Clear MSG_DONE bit */
88acbb1eb7SAkshay Saraswat writel(ACE_HASH_MSGDONE_ON, &ace_sha_reg->hash_status);
89acbb1eb7SAkshay Saraswat
90acbb1eb7SAkshay Saraswat /* Read hash result */
91acbb1eb7SAkshay Saraswat pdigest = (unsigned int *)pout;
92acbb1eb7SAkshay Saraswat len = (hash_type == ACE_SHA_TYPE_SHA1) ? SHA1_SUM_LEN : SHA256_SUM_LEN;
93acbb1eb7SAkshay Saraswat
94acbb1eb7SAkshay Saraswat for (i = 0; i < len / 4; i++)
95acbb1eb7SAkshay Saraswat pdigest[i] = readl(&ace_sha_reg->hash_result[i]);
96acbb1eb7SAkshay Saraswat
97acbb1eb7SAkshay Saraswat /* Clear HRDMA pending bit */
98acbb1eb7SAkshay Saraswat writel(ACE_FC_HRDMA, &ace_sha_reg->fc_intpend);
99acbb1eb7SAkshay Saraswat
100acbb1eb7SAkshay Saraswat return 0;
101acbb1eb7SAkshay Saraswat }
102acbb1eb7SAkshay Saraswat
hw_sha256(const unsigned char * pbuf,unsigned int buf_len,unsigned char * pout,unsigned int chunk_size)103acbb1eb7SAkshay Saraswat void hw_sha256(const unsigned char *pbuf, unsigned int buf_len,
104acbb1eb7SAkshay Saraswat unsigned char *pout, unsigned int chunk_size)
105acbb1eb7SAkshay Saraswat {
106acbb1eb7SAkshay Saraswat if (ace_sha_hash_digest(pbuf, buf_len, pout, ACE_SHA_TYPE_SHA256))
107acbb1eb7SAkshay Saraswat debug("ACE was not setup properly or it is faulty\n");
108acbb1eb7SAkshay Saraswat }
109acbb1eb7SAkshay Saraswat
hw_sha1(const unsigned char * pbuf,unsigned int buf_len,unsigned char * pout,unsigned int chunk_size)110acbb1eb7SAkshay Saraswat void hw_sha1(const unsigned char *pbuf, unsigned int buf_len,
111acbb1eb7SAkshay Saraswat unsigned char *pout, unsigned int chunk_size)
112acbb1eb7SAkshay Saraswat {
113acbb1eb7SAkshay Saraswat if (ace_sha_hash_digest(pbuf, buf_len, pout, ACE_SHA_TYPE_SHA1))
114acbb1eb7SAkshay Saraswat debug("ACE was not setup properly or it is faulty\n");
115acbb1eb7SAkshay Saraswat }
1160bd93724SPrzemyslaw Marczak #endif /* CONFIG_SHA_HW_ACCEL */
1170bd93724SPrzemyslaw Marczak
1180bd93724SPrzemyslaw Marczak #ifdef CONFIG_LIB_HW_RAND
1190bd93724SPrzemyslaw Marczak static unsigned int seed_done;
1200bd93724SPrzemyslaw Marczak
srand(unsigned int seed)1210bd93724SPrzemyslaw Marczak void srand(unsigned int seed)
1220bd93724SPrzemyslaw Marczak {
1230bd93724SPrzemyslaw Marczak struct exynos_ace_sfr *reg =
1240bd93724SPrzemyslaw Marczak (struct exynos_ace_sfr *)samsung_get_base_ace_sfr();
1250bd93724SPrzemyslaw Marczak int i, status;
1260bd93724SPrzemyslaw Marczak
1270bd93724SPrzemyslaw Marczak /* Seed data */
1280bd93724SPrzemyslaw Marczak for (i = 0; i < ACE_HASH_PRNG_REG_NUM; i++)
1290bd93724SPrzemyslaw Marczak writel(seed << i, ®->hash_seed[i]);
1300bd93724SPrzemyslaw Marczak
1310bd93724SPrzemyslaw Marczak /* Wait for seed setup done */
1320bd93724SPrzemyslaw Marczak while (1) {
1330bd93724SPrzemyslaw Marczak status = readl(®->hash_status);
1340bd93724SPrzemyslaw Marczak if ((status & ACE_HASH_SEEDSETTING_MASK) ||
1350bd93724SPrzemyslaw Marczak (status & ACE_HASH_PRNGERROR_MASK))
1360bd93724SPrzemyslaw Marczak break;
1370bd93724SPrzemyslaw Marczak }
1380bd93724SPrzemyslaw Marczak
1390bd93724SPrzemyslaw Marczak seed_done = 1;
1400bd93724SPrzemyslaw Marczak }
1410bd93724SPrzemyslaw Marczak
rand(void)1420bd93724SPrzemyslaw Marczak unsigned int rand(void)
1430bd93724SPrzemyslaw Marczak {
1440bd93724SPrzemyslaw Marczak struct exynos_ace_sfr *reg =
1450bd93724SPrzemyslaw Marczak (struct exynos_ace_sfr *)samsung_get_base_ace_sfr();
1460bd93724SPrzemyslaw Marczak int i, status;
1470bd93724SPrzemyslaw Marczak unsigned int seed = (unsigned int)&status;
1480bd93724SPrzemyslaw Marczak unsigned int ret = 0;
1490bd93724SPrzemyslaw Marczak
1500bd93724SPrzemyslaw Marczak if (!seed_done)
1510bd93724SPrzemyslaw Marczak srand(seed);
1520bd93724SPrzemyslaw Marczak
1530bd93724SPrzemyslaw Marczak /* Start PRNG */
1540bd93724SPrzemyslaw Marczak writel(ACE_HASH_ENGSEL_PRNG | ACE_HASH_STARTBIT_ON, ®->hash_control);
1550bd93724SPrzemyslaw Marczak
1560bd93724SPrzemyslaw Marczak /* Wait for PRNG done */
1570bd93724SPrzemyslaw Marczak while (1) {
1580bd93724SPrzemyslaw Marczak status = readl(®->hash_status);
1590bd93724SPrzemyslaw Marczak if (status & ACE_HASH_PRNGDONE_MASK)
1600bd93724SPrzemyslaw Marczak break;
1610bd93724SPrzemyslaw Marczak if (status & ACE_HASH_PRNGERROR_MASK) {
1620bd93724SPrzemyslaw Marczak seed_done = 0;
1630bd93724SPrzemyslaw Marczak return 0;
1640bd93724SPrzemyslaw Marczak }
1650bd93724SPrzemyslaw Marczak }
1660bd93724SPrzemyslaw Marczak
1670bd93724SPrzemyslaw Marczak /* Clear Done IRQ */
1680bd93724SPrzemyslaw Marczak writel(ACE_HASH_PRNGDONE_MASK, ®->hash_status);
1690bd93724SPrzemyslaw Marczak
1700bd93724SPrzemyslaw Marczak /* Read a PRNG result */
1710bd93724SPrzemyslaw Marczak for (i = 0; i < ACE_HASH_PRNG_REG_NUM; i++)
1720bd93724SPrzemyslaw Marczak ret += readl(®->hash_prng[i]);
1730bd93724SPrzemyslaw Marczak
1740bd93724SPrzemyslaw Marczak seed_done = 0;
1750bd93724SPrzemyslaw Marczak return ret;
1760bd93724SPrzemyslaw Marczak }
1770bd93724SPrzemyslaw Marczak
rand_r(unsigned int * seedp)1780bd93724SPrzemyslaw Marczak unsigned int rand_r(unsigned int *seedp)
1790bd93724SPrzemyslaw Marczak {
1800bd93724SPrzemyslaw Marczak srand(*seedp);
1810bd93724SPrzemyslaw Marczak
1820bd93724SPrzemyslaw Marczak return rand();
1830bd93724SPrzemyslaw Marczak }
1840bd93724SPrzemyslaw Marczak #endif /* CONFIG_LIB_HW_RAND */
185