xref: /openbmc/u-boot/drivers/crypto/aspeed_acry.c (revision 594c58806ba2fd31db19b644c3803800d3c59cca)
14f7bd3b2SChia-Wei Wang // SPDX-License-Identifier: GPL-2.0-or-later
24f7bd3b2SChia-Wei Wang /*
35c5ceee2SNeal Liu  * Copyright ASPEED Technology Inc.
44f7bd3b2SChia-Wei Wang  */
55c5ceee2SNeal Liu #include <config.h>
64f7bd3b2SChia-Wei Wang #include <common.h>
74f7bd3b2SChia-Wei Wang #include <clk.h>
85c5ceee2SNeal Liu #include <dm.h>
95c5ceee2SNeal Liu #include <asm/types.h>
105c5ceee2SNeal Liu #include <asm/io.h>
114f7bd3b2SChia-Wei Wang #include <dm/device.h>
124f7bd3b2SChia-Wei Wang #include <dm/fdtaddr.h>
135c5ceee2SNeal Liu #include <linux/delay.h>
145c5ceee2SNeal Liu #include <u-boot/rsa-mod-exp.h>
155c5ceee2SNeal Liu 
165c5ceee2SNeal Liu /* ACRY register offsets */
175c5ceee2SNeal Liu #define ACRY_CTRL1		0x00
185c5ceee2SNeal Liu #define   ACRY_CTRL1_RSA_DMA		BIT(1)
195c5ceee2SNeal Liu #define   ACRY_CTRL1_RSA_START		BIT(0)
205c5ceee2SNeal Liu #define ACRY_CTRL2		0x44
215c5ceee2SNeal Liu #define ACRY_CTRL3		0x48
225c5ceee2SNeal Liu #define   ACRY_CTRL3_SRAM_AHB_ACCESS	BIT(8)
235c5ceee2SNeal Liu #define   ACRY_CTRL3_ECC_RSA_MODE_MASK	GENMASK(5, 4)
245c5ceee2SNeal Liu #define   ACRY_CTRL3_ECC_RSA_MODE_SHIFT	4
255c5ceee2SNeal Liu #define ACRY_DMA_DRAM_SADDR	0x4c
265c5ceee2SNeal Liu #define ACRY_DMA_DMEM_TADDR	0x50
275c5ceee2SNeal Liu #define   ACRY_DMA_DMEM_TADDR_LEN_MASK	GENMASK(15, 0)
285c5ceee2SNeal Liu #define   ACRY_DMA_DMEM_TADDR_LEN_SHIFT	0
295c5ceee2SNeal Liu #define ACRY_RSA_PARAM		0x58
305c5ceee2SNeal Liu #define   ACRY_RSA_PARAM_EXP_MASK	GENMASK(31, 16)
315c5ceee2SNeal Liu #define   ACRY_RSA_PARAM_EXP_SHIFT	16
325c5ceee2SNeal Liu #define   ACRY_RSA_PARAM_MOD_MASK	GENMASK(15, 0)
335c5ceee2SNeal Liu #define   ACRY_RSA_PARAM_MOD_SHIFT	0
345c5ceee2SNeal Liu #define ACRY_RSA_INT_EN		0x3f8
355c5ceee2SNeal Liu #define   ACRY_RSA_INT_EN_RSA_READY	BIT(2)
365c5ceee2SNeal Liu #define   ACRY_RSA_INT_EN_RSA_CMPLT	BIT(1)
375c5ceee2SNeal Liu #define ACRY_RSA_INT_STS	0x3fc
385c5ceee2SNeal Liu #define   ACRY_RSA_INT_STS_RSA_READY	BIT(2)
395c5ceee2SNeal Liu #define   ACRY_RSA_INT_STS_RSA_CMPLT	BIT(1)
405c5ceee2SNeal Liu 
415c5ceee2SNeal Liu /* misc. constant */
425c5ceee2SNeal Liu #define ACRY_ECC_MODE	2
435c5ceee2SNeal Liu #define ACRY_RSA_MODE	3
445c5ceee2SNeal Liu #define ACRY_CTX_BUFSZ	0x600
454f7bd3b2SChia-Wei Wang 
464f7bd3b2SChia-Wei Wang struct aspeed_acry {
475c5ceee2SNeal Liu 	phys_addr_t base;
485c5ceee2SNeal Liu 	phys_addr_t sram_base; /* internal sram */
494f7bd3b2SChia-Wei Wang 	struct clk clk;
504f7bd3b2SChia-Wei Wang };
514f7bd3b2SChia-Wei Wang 
aspeed_acry_mod_exp(struct udevice * dev,const uint8_t * sig,uint32_t sig_len,struct key_prop * prop,uint8_t * out)525c5ceee2SNeal Liu static int aspeed_acry_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
535c5ceee2SNeal Liu 			       struct key_prop *prop, uint8_t *out)
545c5ceee2SNeal Liu {
555c5ceee2SNeal Liu 	int i, j;
565c5ceee2SNeal Liu 	u8 *ctx;
575c5ceee2SNeal Liu 	u8 *ptr;
585c5ceee2SNeal Liu 	u32 reg;
595c5ceee2SNeal Liu 	struct aspeed_acry *acry = dev_get_priv(dev);
605c5ceee2SNeal Liu 
615c5ceee2SNeal Liu 	ctx = memalign(16, ACRY_CTX_BUFSZ);
625c5ceee2SNeal Liu 	if (!ctx)
635c5ceee2SNeal Liu 		return -ENOMEM;
645c5ceee2SNeal Liu 
655c5ceee2SNeal Liu 	memset(ctx, 0, ACRY_CTX_BUFSZ);
665c5ceee2SNeal Liu 
675c5ceee2SNeal Liu 	ptr = (u8 *)prop->public_exponent;
685c5ceee2SNeal Liu 	for (i = prop->exp_len - 1, j = 0; i >= 0; --i) {
695c5ceee2SNeal Liu 		ctx[j] = ptr[i];
705c5ceee2SNeal Liu 		j++;
715c5ceee2SNeal Liu 		j = (j % 16) ? j : j + 32;
725c5ceee2SNeal Liu 	}
735c5ceee2SNeal Liu 
745c5ceee2SNeal Liu 	ptr = (u8 *)prop->modulus;
755c5ceee2SNeal Liu 	for (i = (prop->num_bits >> 3) - 1, j = 0; i >= 0; --i) {
765c5ceee2SNeal Liu 		ctx[j + 16] = ptr[i];
775c5ceee2SNeal Liu 		j++;
785c5ceee2SNeal Liu 		j = (j % 16) ? j : j + 32;
795c5ceee2SNeal Liu 	}
805c5ceee2SNeal Liu 
815c5ceee2SNeal Liu 	ptr = (u8 *)sig;
825c5ceee2SNeal Liu 	for (i = sig_len - 1, j = 0; i >= 0; --i) {
835c5ceee2SNeal Liu 		ctx[j + 32] = ptr[i];
845c5ceee2SNeal Liu 		j++;
855c5ceee2SNeal Liu 		j = (j % 16) ? j : j + 32;
865c5ceee2SNeal Liu 	}
875c5ceee2SNeal Liu 
885c5ceee2SNeal Liu 	writel((u32)ctx, acry->base + ACRY_DMA_DRAM_SADDR);
895c5ceee2SNeal Liu 
905c5ceee2SNeal Liu 	reg = (((prop->exp_len << 3) << ACRY_RSA_PARAM_EXP_SHIFT) & ACRY_RSA_PARAM_EXP_MASK) |
915c5ceee2SNeal Liu 		  ((prop->num_bits << ACRY_RSA_PARAM_MOD_SHIFT) & ACRY_RSA_PARAM_MOD_MASK);
925c5ceee2SNeal Liu 	writel(reg, acry->base + ACRY_RSA_PARAM);
935c5ceee2SNeal Liu 
945c5ceee2SNeal Liu 	reg = (ACRY_CTX_BUFSZ << ACRY_DMA_DMEM_TADDR_LEN_SHIFT) & ACRY_DMA_DMEM_TADDR_LEN_MASK;
955c5ceee2SNeal Liu 	writel(reg, acry->base + ACRY_DMA_DMEM_TADDR);
965c5ceee2SNeal Liu 
975c5ceee2SNeal Liu 	reg = (ACRY_RSA_MODE << ACRY_CTRL3_ECC_RSA_MODE_SHIFT) & ACRY_CTRL3_ECC_RSA_MODE_MASK;
985c5ceee2SNeal Liu 	writel(reg, acry->base + ACRY_CTRL3);
995c5ceee2SNeal Liu 
1005c5ceee2SNeal Liu 	writel(ACRY_CTRL1_RSA_DMA | ACRY_CTRL1_RSA_START, acry->base + ACRY_CTRL1);
1015c5ceee2SNeal Liu 
1025c5ceee2SNeal Liu 	/* polling RSA status */
1035c5ceee2SNeal Liu 	while (1) {
1045c5ceee2SNeal Liu 		reg = readl(acry->base + ACRY_RSA_INT_STS);
1055c5ceee2SNeal Liu 		if ((reg & ACRY_RSA_INT_STS_RSA_READY) && (reg & ACRY_RSA_INT_STS_RSA_CMPLT)) {
1065c5ceee2SNeal Liu 			writel(reg, acry->base + ACRY_RSA_INT_STS);
1075c5ceee2SNeal Liu 			break;
1085c5ceee2SNeal Liu 		}
1095c5ceee2SNeal Liu 		udelay(20);
1105c5ceee2SNeal Liu 	}
1115c5ceee2SNeal Liu 
1125c5ceee2SNeal Liu 	/* grant SRAM access permission to CPU */
1135c5ceee2SNeal Liu 	writel(0x0, acry->base + ACRY_CTRL1);
1145c5ceee2SNeal Liu 	writel(ACRY_CTRL3_SRAM_AHB_ACCESS, acry->base + ACRY_CTRL3);
1155c5ceee2SNeal Liu 	udelay(20);
1165c5ceee2SNeal Liu 
1175c5ceee2SNeal Liu 	for (i = (prop->num_bits / 8) - 1, j = 0; i >= 0; --i) {
1185c5ceee2SNeal Liu 		out[i] = readb(acry->sram_base + (j + 32));
1195c5ceee2SNeal Liu 		j++;
1205c5ceee2SNeal Liu 		j = (j % 16) ? j : j + 32;
1215c5ceee2SNeal Liu 	}
1225c5ceee2SNeal Liu 
1235c5ceee2SNeal Liu 	free(ctx);
1245c5ceee2SNeal Liu 
1255c5ceee2SNeal Liu 	return 0;
1265c5ceee2SNeal Liu }
1275c5ceee2SNeal Liu 
aspeed_acry_probe(struct udevice * dev)1284f7bd3b2SChia-Wei Wang static int aspeed_acry_probe(struct udevice *dev)
1294f7bd3b2SChia-Wei Wang {
1304f7bd3b2SChia-Wei Wang 	struct aspeed_acry *acry = dev_get_priv(dev);
1314f7bd3b2SChia-Wei Wang 	int ret;
1324f7bd3b2SChia-Wei Wang 
1334f7bd3b2SChia-Wei Wang 	ret = clk_get_by_index(dev, 0, &acry->clk);
1344f7bd3b2SChia-Wei Wang 	if (ret < 0) {
1354f7bd3b2SChia-Wei Wang 		debug("Can't get clock for %s: %d\n", dev->name, ret);
1364f7bd3b2SChia-Wei Wang 		return ret;
1374f7bd3b2SChia-Wei Wang 	}
1384f7bd3b2SChia-Wei Wang 
1394f7bd3b2SChia-Wei Wang 	ret = clk_enable(&acry->clk);
1404f7bd3b2SChia-Wei Wang 	if (ret) {
1414f7bd3b2SChia-Wei Wang 		debug("Failed to enable acry clock (%d)\n", ret);
1424f7bd3b2SChia-Wei Wang 		return ret;
1434f7bd3b2SChia-Wei Wang 	}
1444f7bd3b2SChia-Wei Wang 
1455c5ceee2SNeal Liu 	acry->base = devfdt_get_addr_index(dev, 0);
1465c5ceee2SNeal Liu 	if (acry->base == FDT_ADDR_T_NONE) {
1475c5ceee2SNeal Liu 		debug("Failed to get acry base\n");
1485c5ceee2SNeal Liu 		return acry->base;
1495c5ceee2SNeal Liu 	}
1505c5ceee2SNeal Liu 
1515c5ceee2SNeal Liu 	acry->sram_base = devfdt_get_addr_index(dev, 1);
1525c5ceee2SNeal Liu 	if (acry->sram_base == FDT_ADDR_T_NONE) {
1535c5ceee2SNeal Liu 		debug("Failed to get acry SRAM base\n");
1545c5ceee2SNeal Liu 		return acry->sram_base;
1555c5ceee2SNeal Liu 	}
1565c5ceee2SNeal Liu 
1575c5ceee2SNeal Liu 	/* grant SRAM access permission to CPU */
1585c5ceee2SNeal Liu 	writel(ACRY_CTRL3_SRAM_AHB_ACCESS, acry->base + ACRY_CTRL3);
1595c5ceee2SNeal Liu 
1604f7bd3b2SChia-Wei Wang 	return ret;
1614f7bd3b2SChia-Wei Wang }
1624f7bd3b2SChia-Wei Wang 
aspeed_acry_remove(struct udevice * dev)1634f7bd3b2SChia-Wei Wang static int aspeed_acry_remove(struct udevice *dev)
1644f7bd3b2SChia-Wei Wang {
1654f7bd3b2SChia-Wei Wang 	struct aspeed_acry *acry = dev_get_priv(dev);
1664f7bd3b2SChia-Wei Wang 
1674f7bd3b2SChia-Wei Wang 	clk_disable(&acry->clk);
1684f7bd3b2SChia-Wei Wang 
1694f7bd3b2SChia-Wei Wang 	return 0;
1704f7bd3b2SChia-Wei Wang }
1714f7bd3b2SChia-Wei Wang 
1725c5ceee2SNeal Liu static const struct mod_exp_ops aspeed_acry_ops = {
1735c5ceee2SNeal Liu 	.mod_exp = aspeed_acry_mod_exp,
1745c5ceee2SNeal Liu };
1755c5ceee2SNeal Liu 
1764f7bd3b2SChia-Wei Wang static const struct udevice_id aspeed_acry_ids[] = {
1774f7bd3b2SChia-Wei Wang 	{ .compatible = "aspeed,ast2600-acry" },
1784f7bd3b2SChia-Wei Wang 	{ }
1794f7bd3b2SChia-Wei Wang };
1804f7bd3b2SChia-Wei Wang 
1814f7bd3b2SChia-Wei Wang U_BOOT_DRIVER(aspeed_acry) = {
1824f7bd3b2SChia-Wei Wang 	.name = "aspeed_acry",
1835c5ceee2SNeal Liu 	.id = UCLASS_MOD_EXP,
1844f7bd3b2SChia-Wei Wang 	.of_match = aspeed_acry_ids,
1854f7bd3b2SChia-Wei Wang 	.probe = aspeed_acry_probe,
1864f7bd3b2SChia-Wei Wang 	.remove = aspeed_acry_remove,
187*594c5880SNeal Liu 	.priv_auto_alloc_size = sizeof(struct aspeed_acry),
1885c5ceee2SNeal Liu 	.ops = &aspeed_acry_ops,
1894f7bd3b2SChia-Wei Wang 	.flags = DM_FLAG_PRE_RELOC,
1904f7bd3b2SChia-Wei Wang };
191