xref: /rk3399_rockchip-uboot/drivers/crypto/ace_sha.c (revision 1221ce459d04a428f8880f58581f671b736c3c27)
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, &reg->hash_seed[i]);
1300bd93724SPrzemyslaw Marczak 
1310bd93724SPrzemyslaw Marczak 	/* Wait for seed setup done */
1320bd93724SPrzemyslaw Marczak 	while (1) {
1330bd93724SPrzemyslaw Marczak 		status = readl(&reg->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, &reg->hash_control);
1550bd93724SPrzemyslaw Marczak 
1560bd93724SPrzemyslaw Marczak 	/* Wait for PRNG done */
1570bd93724SPrzemyslaw Marczak 	while (1) {
1580bd93724SPrzemyslaw Marczak 		status = readl(&reg->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, &reg->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(&reg->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