u-boot/drivers/crypto/ace_sha.c
Tom Rini 83d290c56f SPDX: Convert all of our single license tags to Linux Kernel style
When U-Boot started using SPDX tags we were among the early adopters and
there weren't a lot of other examples to borrow from.  So we picked the
area of the file that usually had a full license text and replaced it
with an appropriate SPDX-License-Identifier: entry.  Since then, the
Linux Kernel has adopted SPDX tags and they place it as the very first
line in a file (except where shebangs are used, then it's second line)
and with slightly different comment styles than us.

In part due to community overlap, in part due to better tag visibility
and in part for other minor reasons, switch over to that style.

This commit changes all instances where we have a single declared
license in the tag as both the before and after are identical in tag
contents.  There's also a few places where I found we did not have a tag
and have introduced one.

Signed-off-by: Tom Rini <trini@konsulko.com>
2018-05-07 09:34:12 -04:00

184 lines
4.9 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Advanced Crypto Engine - SHA Firmware
* Copyright (c) 2012 Samsung Electronics
*/
#include <common.h>
#include "ace_sha.h"
#ifdef CONFIG_SHA_HW_ACCEL
#include <u-boot/sha256.h>
#include <u-boot/sha1.h>
#include <linux/errno.h>
/* SHA1 value for the message of zero length */
static const unsigned char sha1_digest_emptymsg[SHA1_SUM_LEN] = {
0xDA, 0x39, 0xA3, 0xEE, 0x5E, 0x6B, 0x4B, 0x0D,
0x32, 0x55, 0xBF, 0xFF, 0x95, 0x60, 0x18, 0x90,
0xAF, 0xD8, 0x07, 0x09};
/* SHA256 value for the message of zero length */
static const unsigned char sha256_digest_emptymsg[SHA256_SUM_LEN] = {
0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14,
0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24,
0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C,
0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55};
int ace_sha_hash_digest(const unsigned char *pbuf, unsigned int buf_len,
unsigned char *pout, unsigned int hash_type)
{
unsigned int i, reg, len;
unsigned int *pdigest;
struct exynos_ace_sfr *ace_sha_reg =
(struct exynos_ace_sfr *)samsung_get_base_ace_sfr();
if (buf_len == 0) {
/* ACE H/W cannot compute hash value for empty string */
if (hash_type == ACE_SHA_TYPE_SHA1)
memcpy(pout, sha1_digest_emptymsg, SHA1_SUM_LEN);
else
memcpy(pout, sha256_digest_emptymsg, SHA256_SUM_LEN);
return 0;
}
/* Flush HRDMA */
writel(ACE_FC_HRDMACFLUSH_ON, &ace_sha_reg->fc_hrdmac);
writel(ACE_FC_HRDMACFLUSH_OFF, &ace_sha_reg->fc_hrdmac);
/* Set byte swap of data in */
writel(ACE_HASH_SWAPDI_ON | ACE_HASH_SWAPDO_ON | ACE_HASH_SWAPIV_ON,
&ace_sha_reg->hash_byteswap);
/* Select Hash input mux as external source */
reg = readl(&ace_sha_reg->fc_fifoctrl);
reg = (reg & ~ACE_FC_SELHASH_MASK) | ACE_FC_SELHASH_EXOUT;
writel(reg, &ace_sha_reg->fc_fifoctrl);
/* Set Hash as SHA1 or SHA256 and start Hash engine */
reg = (hash_type == ACE_SHA_TYPE_SHA1) ?
ACE_HASH_ENGSEL_SHA1HASH : ACE_HASH_ENGSEL_SHA256HASH;
reg |= ACE_HASH_STARTBIT_ON;
writel(reg, &ace_sha_reg->hash_control);
/* Enable FIFO mode */
writel(ACE_HASH_FIFO_ON, &ace_sha_reg->hash_fifo_mode);
/* Set message length */
writel(buf_len, &ace_sha_reg->hash_msgsize_low);
writel(0, &ace_sha_reg->hash_msgsize_high);
/* Set HRDMA */
writel((unsigned int)pbuf, &ace_sha_reg->fc_hrdmas);
writel(buf_len, &ace_sha_reg->fc_hrdmal);
while ((readl(&ace_sha_reg->hash_status) & ACE_HASH_MSGDONE_MASK) ==
ACE_HASH_MSGDONE_OFF) {
/*
* PRNG error bit goes HIGH if a PRNG request occurs without
* a complete seed setup. We are using this bit to check h/w
* fault because proper setup is not expected in that case.
*/
if ((readl(&ace_sha_reg->hash_status)
& ACE_HASH_PRNGERROR_MASK) == ACE_HASH_PRNGERROR_ON)
return -EBUSY;
}
/* Clear MSG_DONE bit */
writel(ACE_HASH_MSGDONE_ON, &ace_sha_reg->hash_status);
/* Read hash result */
pdigest = (unsigned int *)pout;
len = (hash_type == ACE_SHA_TYPE_SHA1) ? SHA1_SUM_LEN : SHA256_SUM_LEN;
for (i = 0; i < len / 4; i++)
pdigest[i] = readl(&ace_sha_reg->hash_result[i]);
/* Clear HRDMA pending bit */
writel(ACE_FC_HRDMA, &ace_sha_reg->fc_intpend);
return 0;
}
void hw_sha256(const unsigned char *pbuf, unsigned int buf_len,
unsigned char *pout, unsigned int chunk_size)
{
if (ace_sha_hash_digest(pbuf, buf_len, pout, ACE_SHA_TYPE_SHA256))
debug("ACE was not setup properly or it is faulty\n");
}
void hw_sha1(const unsigned char *pbuf, unsigned int buf_len,
unsigned char *pout, unsigned int chunk_size)
{
if (ace_sha_hash_digest(pbuf, buf_len, pout, ACE_SHA_TYPE_SHA1))
debug("ACE was not setup properly or it is faulty\n");
}
#endif /* CONFIG_SHA_HW_ACCEL */
#ifdef CONFIG_LIB_HW_RAND
static unsigned int seed_done;
void srand(unsigned int seed)
{
struct exynos_ace_sfr *reg =
(struct exynos_ace_sfr *)samsung_get_base_ace_sfr();
int i, status;
/* Seed data */
for (i = 0; i < ACE_HASH_PRNG_REG_NUM; i++)
writel(seed << i, &reg->hash_seed[i]);
/* Wait for seed setup done */
while (1) {
status = readl(&reg->hash_status);
if ((status & ACE_HASH_SEEDSETTING_MASK) ||
(status & ACE_HASH_PRNGERROR_MASK))
break;
}
seed_done = 1;
}
unsigned int rand(void)
{
struct exynos_ace_sfr *reg =
(struct exynos_ace_sfr *)samsung_get_base_ace_sfr();
int i, status;
unsigned int seed = (unsigned int)&status;
unsigned int ret = 0;
if (!seed_done)
srand(seed);
/* Start PRNG */
writel(ACE_HASH_ENGSEL_PRNG | ACE_HASH_STARTBIT_ON, &reg->hash_control);
/* Wait for PRNG done */
while (1) {
status = readl(&reg->hash_status);
if (status & ACE_HASH_PRNGDONE_MASK)
break;
if (status & ACE_HASH_PRNGERROR_MASK) {
seed_done = 0;
return 0;
}
}
/* Clear Done IRQ */
writel(ACE_HASH_PRNGDONE_MASK, &reg->hash_status);
/* Read a PRNG result */
for (i = 0; i < ACE_HASH_PRNG_REG_NUM; i++)
ret += readl(&reg->hash_prng[i]);
seed_done = 0;
return ret;
}
unsigned int rand_r(unsigned int *seedp)
{
srand(*seedp);
return rand();
}
#endif /* CONFIG_LIB_HW_RAND */