blob: 4b70d89def743ad5216849e0447b601cd3c39429 [file] [log] [blame]
Chia-Wei Wang3477d922024-10-14 17:56:20 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright 2024 ASPEED Technology Inc.
4 */
5#include <asm/io.h>
6#include <config.h>
7#include <crypto/ecdsa-uclass.h>
8#include <dm.h>
9#include <linux/bitfield.h>
10#include <linux/bitops.h>
11#include <linux/iopoll.h>
12#include <malloc.h>
13#include <u-boot/ecdsa.h>
14
15/* SCU register offsets */
16#define SCU1_CPTRA 0x130
17#define SCU1_CPTRA_RDY_FOR_RT BIT(18)
18
19/* CPTRA MBOX register offsets */
20#define CPTRA_MBOX_LOCK 0x00
21#define CPTRA_MBOX_USER 0x04
22#define CPTRA_MBOX_CMD 0x08
23#define CPTRA_MBOX_DLEN 0x0c
24#define CPTRA_MBOX_DATAIN 0x10
25#define CPTRA_MBOX_DATAOUT 0x14
26#define CPTRA_MBOX_EXEC 0x18
27#define CPTRA_MBOX_STS 0x1c
28#define CPTRA_MBOX_STS_SOC_LOCK BIT(9)
29#define CPTRA_MBOX_STS_FSM_PS GENMASK(8, 6)
30#define CPTRA_MBOX_STS_PS GENMASK(3, 0)
31#define CPTRA_MBOX_UNLOCK 0x20
32
33#define CPTRA_ECDSA_SIG_LEN 96 /* ECDSA384 */
34#define CPTRA_ECDSA_SHA_LEN 48 /* SHA384 */
35
36#define CPTRA_MBCMD_ECDSA384_SIGNATURE_VERIFY 0x53494756
37
38enum cptra_mbox_sts {
39 CPTRA_MBSTS_CMD_BUSY,
40 CPTRA_MBSTS_DATA_READY,
41 CPTRA_MBSTS_CMD_COMPLETE,
42 CPTRA_MBSTS_CMD_FAILURE,
43};
44
45enum cptra_mbox_fsm {
46 CPTRA_MBFSM_IDLE,
47 CPTRA_MBFSM_RDY_FOR_CMD,
48 CPTRA_MBFSM_RDY_FOR_DLEN,
49 CPTRA_MBFSM_RDY_FOR_DATA,
50 CPTRA_MBFSM_EXEC_UC,
51 CPTRA_MBFSM_EXEC_SOC,
52 CPTRA_MBFSM_ERROR,
53};
54
55struct cptra_ecdsa {
56 void *regs;
57};
58
59static uint32_t mbox_csum(uint32_t csum, uint8_t *data, uint32_t dlen)
60{
61 uint32_t i;
62
63 for (i = 0; i < dlen; ++i)
64 csum -= data[i];
65
66 return csum;
67}
68
69static int cptra_ecdsa_verify(struct udevice *dev, const struct ecdsa_public_key *pubkey,
70 const void *hash, size_t hash_len,
71 const void *signature, size_t sig_len)
72{
73 struct cptra_ecdsa *ce;
74 uint8_t *x, *y, *r, *s;
75 uint32_t cmd, csum;
76 uint32_t reg, sts;
77 uint32_t *p32;
78 int i;
79
80 if (hash_len != CPTRA_ECDSA_SHA_LEN || sig_len != CPTRA_ECDSA_SIG_LEN)
81 return -EINVAL;
82
83 if ((strcmp(pubkey->curve_name, "secp384r1") && strcmp(pubkey->curve_name, "prime384v1")) ||
84 pubkey->size_bits != ((CPTRA_ECDSA_SIG_LEN / 2) << 3))
85 return -EINVAL;
86
87 ce = dev_get_priv(dev);
88
89 /* get CPTRA MBOX lock */
90 if (readl_poll_timeout(ce->regs + CPTRA_MBOX_LOCK, reg, reg == 0, 1000000))
91 return -EBUSY;
92
93 /* check MBOX is ready for command */
94 sts = readl(ce->regs + CPTRA_MBOX_STS);
95 if (FIELD_GET(CPTRA_MBOX_STS_FSM_PS, sts) != CPTRA_MBFSM_RDY_FOR_CMD)
96 return -EACCES;
97
98 /* init mbox parameters */
99 cmd = CPTRA_MBCMD_ECDSA384_SIGNATURE_VERIFY;
100 csum = 0;
101 x = (uint8_t *)pubkey->x;
102 y = (uint8_t *)pubkey->y;
103 r = (uint8_t *)signature;
104 s = (uint8_t *)signature + (CPTRA_ECDSA_SIG_LEN / 2);
105
106 /* calculate checksum */
107 csum = mbox_csum(csum, (uint8_t *)&cmd, sizeof(cmd));
108 csum = mbox_csum(csum, x, CPTRA_ECDSA_SIG_LEN / 2);
109 csum = mbox_csum(csum, y, CPTRA_ECDSA_SIG_LEN / 2);
110 csum = mbox_csum(csum, r, CPTRA_ECDSA_SIG_LEN / 2);
111 csum = mbox_csum(csum, s, CPTRA_ECDSA_SIG_LEN / 2);
112
113 /* write command, data length */
114 writel(cmd, ce->regs + CPTRA_MBOX_CMD);
115 writel(sizeof(csum) + (CPTRA_ECDSA_SIG_LEN << 1), ce->regs + CPTRA_MBOX_DLEN);
116
117 /* write ECDSA384_SIGNATURE_VERIFY command parameters */
118 writel(csum, ce->regs + CPTRA_MBOX_DATAIN);
119
120 for (i = 0, p32 = (uint32_t *)x; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i)
121 writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN);
122
123 for (i = 0, p32 = (uint32_t *)y; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i)
124 writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN);
125
126 for (i = 0, p32 = (uint32_t *)r; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i)
127 writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN);
128
129 for (i = 0, p32 = (uint32_t *)s; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i)
130 writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN);
131
132 /* trigger mbox command */
133 writel(0x1, ce->regs + CPTRA_MBOX_EXEC);
134
135 /* poll for result */
136 while (1) {
137 sts = FIELD_GET(CPTRA_MBOX_STS_PS, readl(ce->regs + CPTRA_MBOX_STS));
138 if (sts != CPTRA_MBSTS_CMD_BUSY)
139 break;
140 }
141
142 /* unlock mbox */
143 writel(0x0, ce->regs + CPTRA_MBOX_EXEC);
144
145 return (sts == CPTRA_MBSTS_CMD_FAILURE) ? sts : 0;
146}
147
148static int cptra_ecdsa_probe(struct udevice *dev)
149{
150 struct cptra_ecdsa *ce = dev_get_priv(dev);
151
152 ce->regs = (void *)devfdt_get_addr(dev);
153 if (ce->regs == (void *)FDT_ADDR_T_NONE) {
154 debug("cannot map Caliptra mailbox registers\n");
155 return -EINVAL;
156 }
157
158 return 0;
159}
160
161static int cptra_ecdsa_remove(struct udevice *dev)
162{
163 return 0;
164}
165
166static const struct ecdsa_ops cptra_ecdsa_ops = {
167 .verify = cptra_ecdsa_verify,
168};
169
170static const struct udevice_id cptra_ecdsa_ids[] = {
171 { .compatible = "aspeed,ast2700-cptra-ecdsa" },
172 { }
173};
174
175U_BOOT_DRIVER(aspeed_cptra_ecdsa) = {
176 .name = "aspeed_cptra_ecdsa",
177 .id = UCLASS_ECDSA,
178 .of_match = cptra_ecdsa_ids,
179 .ops = &cptra_ecdsa_ops,
180 .probe = cptra_ecdsa_probe,
181 .remove = cptra_ecdsa_remove,
182 .priv_auto = sizeof(struct cptra_ecdsa),
183 .flags = DM_FLAG_PRE_RELOC,
184};