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