// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright 2021 ASPEED Technology Inc. */ #include #include #include #include #include #include #include #include #include #include /* ACRY register offsets */ #define ACRY_CTRL1 0x00 #define ACRY_CTRL1_RSA_DMA BIT(1) #define ACRY_CTRL1_RSA_START BIT(0) #define ACRY_CTRL2 0x44 #define ACRY_CTRL3 0x48 #define ACRY_CTRL3_SRAM_AHB_ACCESS BIT(8) #define ACRY_CTRL3_ECC_RSA_MODE_MASK GENMASK(5, 4) #define ACRY_CTRL3_ECC_RSA_MODE_SHIFT 4 #define ACRY_DMA_DRAM_SADDR 0x4c #define ACRY_DMA_DMEM_TADDR 0x50 #define ACRY_DMA_DMEM_TADDR_LEN_MASK GENMASK(15, 0) #define ACRY_DMA_DMEM_TADDR_LEN_SHIFT 0 #define ACRY_RSA_PARAM 0x58 #define ACRY_RSA_PARAM_EXP_MASK GENMASK(31, 16) #define ACRY_RSA_PARAM_EXP_SHIFT 16 #define ACRY_RSA_PARAM_MOD_MASK GENMASK(15, 0) #define ACRY_RSA_PARAM_MOD_SHIFT 0 #define ACRY_RSA_INT_EN 0x3f8 #define ACRY_RSA_INT_EN_RSA_READY BIT(2) #define ACRY_RSA_INT_EN_RSA_CMPLT BIT(1) #define ACRY_RSA_INT_STS 0x3fc #define ACRY_RSA_INT_STS_RSA_READY BIT(2) #define ACRY_RSA_INT_STS_RSA_CMPLT BIT(1) /* misc. constant */ #define ACRY_ECC_MODE 2 #define ACRY_RSA_MODE 3 #define ACRY_CTX_BUFSZ 0x600 struct aspeed_acry { phys_addr_t base; phys_addr_t sram_base; /* internal sram */ struct clk clk; }; static int aspeed_acry_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len, struct key_prop *prop, uint8_t *out) { int i, j; u8 *ctx; u8 *ptr; u32 reg; struct aspeed_acry *acry = dev_get_priv(dev); ctx = memalign(16, ACRY_CTX_BUFSZ); if (!ctx) return -ENOMEM; memset(ctx, 0, ACRY_CTX_BUFSZ); ptr = (u8 *)prop->public_exponent; for (i = prop->exp_len - 1, j = 0; i >= 0; --i) { ctx[j] = ptr[i]; j++; j = (j % 16) ? j : j + 32; } ptr = (u8 *)prop->modulus; for (i = (prop->num_bits >> 3) - 1, j = 0; i >= 0; --i) { ctx[j + 16] = ptr[i]; j++; j = (j % 16) ? j : j + 32; } ptr = (u8 *)sig; for (i = sig_len - 1, j = 0; i >= 0; --i) { ctx[j + 32] = ptr[i]; j++; j = (j % 16) ? j : j + 32; } writel((u32)ctx, acry->base + ACRY_DMA_DRAM_SADDR); reg = (((prop->exp_len << 3) << ACRY_RSA_PARAM_EXP_SHIFT) & ACRY_RSA_PARAM_EXP_MASK) | ((prop->num_bits << ACRY_RSA_PARAM_MOD_SHIFT) & ACRY_RSA_PARAM_MOD_MASK); writel(reg, acry->base + ACRY_RSA_PARAM); reg = (ACRY_CTX_BUFSZ << ACRY_DMA_DMEM_TADDR_LEN_SHIFT) & ACRY_DMA_DMEM_TADDR_LEN_MASK; writel(reg, acry->base + ACRY_DMA_DMEM_TADDR); reg = (ACRY_RSA_MODE << ACRY_CTRL3_ECC_RSA_MODE_SHIFT) & ACRY_CTRL3_ECC_RSA_MODE_MASK; writel(reg, acry->base + ACRY_CTRL3); writel(ACRY_CTRL1_RSA_DMA | ACRY_CTRL1_RSA_START, acry->base + ACRY_CTRL1); /* polling RSA status */ while (1) { reg = readl(acry->base + ACRY_RSA_INT_STS); if ((reg & ACRY_RSA_INT_STS_RSA_READY) && (reg & ACRY_RSA_INT_STS_RSA_CMPLT)) { writel(reg, acry->base + ACRY_RSA_INT_STS); break; } udelay(20); } /* grant SRAM access permission to CPU */ writel(0x0, acry->base + ACRY_CTRL1); writel(ACRY_CTRL3_SRAM_AHB_ACCESS, acry->base + ACRY_CTRL3); udelay(20); for (i = (prop->num_bits / 8) - 1, j = 0; i >= 0; --i) { out[i] = readb(acry->sram_base + (j + 32)); j++; j = (j % 16) ? j : j + 32; } /* return SRAM access permission to ACRY */ writel(0, acry->base + ACRY_CTRL3); free(ctx); return 0; } static int aspeed_acry_probe(struct udevice *dev) { struct aspeed_acry *acry = dev_get_priv(dev); int ret; ret = clk_get_by_index(dev, 0, &acry->clk); if (ret < 0) { debug("Can't get clock for %s: %d\n", dev->name, ret); return ret; } ret = clk_enable(&acry->clk); if (ret) { debug("Failed to enable acry clock (%d)\n", ret); return ret; } acry->base = devfdt_get_addr_index(dev, 0); if (acry->base == FDT_ADDR_T_NONE) { debug("Failed to get acry base\n"); return acry->base; } acry->sram_base = devfdt_get_addr_index(dev, 1); if (acry->sram_base == FDT_ADDR_T_NONE) { debug("Failed to get acry SRAM base\n"); return acry->sram_base; } return ret; } static int aspeed_acry_remove(struct udevice *dev) { struct aspeed_acry *acry = dev_get_priv(dev); clk_disable(&acry->clk); return 0; } static const struct mod_exp_ops aspeed_acry_ops = { .mod_exp = aspeed_acry_mod_exp, }; static const struct udevice_id aspeed_acry_ids[] = { { .compatible = "aspeed,ast2600-acry" }, { } }; U_BOOT_DRIVER(aspeed_acry) = { .name = "aspeed_acry", .id = UCLASS_MOD_EXP, .of_match = aspeed_acry_ids, .probe = aspeed_acry_probe, .remove = aspeed_acry_remove, .priv_auto = sizeof(struct aspeed_acry), .ops = &aspeed_acry_ops, .flags = DM_FLAG_PRE_RELOC, };