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