diff options
author | Pascal van Leeuwen <pvanleeuwen@insidesecure.com> | 2019-08-19 10:40:26 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2019-08-30 04:05:28 -0400 |
commit | f6cc45c854da0c964d1541712bb3326c72020a1c (patch) | |
tree | 17d34f77cd452ea42959f91c16422b3b318cafdc | |
parent | 625f269a5a7a3643771320387e474bd0a61d9654 (diff) |
crypto: inside-secure - add support for using the EIP197 without vendor firmware
Until now, the inside-secure driver required a set of firmware images
supplied by the silicon vendor, typically under NDA, to be present in
/lib/firmware/inside-secure in order to be able to function.
This patch removes the dependence on this official vendor firmware by
falling back to generic "mini" FW - developed specifically for this
driver - that can be provided under GPL 2.0 through linux-firmwares.
Signed-off-by: Pascal van Leeuwen <pvanleeuwen@verimatrix.com>
Acked-by: Antoine Tenart <antoine.tenart@bootlin.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | drivers/crypto/inside-secure/safexcel.c | 194 | ||||
-rw-r--r-- | drivers/crypto/inside-secure/safexcel.h | 12 |
2 files changed, 161 insertions, 45 deletions
diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index dfe22d2d7161..e12a2a3a5422 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c | |||
@@ -108,44 +108,143 @@ static void eip197_trc_cache_init(struct safexcel_crypto_priv *priv) | |||
108 | writel(val, priv->base + EIP197_TRC_PARAMS); | 108 | writel(val, priv->base + EIP197_TRC_PARAMS); |
109 | } | 109 | } |
110 | 110 | ||
111 | static void eip197_write_firmware(struct safexcel_crypto_priv *priv, | 111 | static void eip197_init_firmware(struct safexcel_crypto_priv *priv) |
112 | const struct firmware *fw, int pe, u32 ctrl, | ||
113 | u32 prog_en) | ||
114 | { | 112 | { |
115 | const u32 *data = (const u32 *)fw->data; | 113 | int pe, i; |
116 | u32 val; | 114 | u32 val; |
117 | int i; | ||
118 | 115 | ||
119 | /* Reset the engine to make its program memory accessible */ | 116 | for (pe = 0; pe < priv->config.pes; pe++) { |
120 | writel(EIP197_PE_ICE_x_CTRL_SW_RESET | | 117 | /* Configure the token FIFO's */ |
121 | EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR | | 118 | writel(3, EIP197_PE(priv) + EIP197_PE_ICE_PUTF_CTRL(pe)); |
122 | EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR, | 119 | writel(0, EIP197_PE(priv) + EIP197_PE_ICE_PPTF_CTRL(pe)); |
123 | EIP197_PE(priv) + ctrl); | 120 | |
121 | /* Clear the ICE scratchpad memory */ | ||
122 | val = readl(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe)); | ||
123 | val |= EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_TIMER | | ||
124 | EIP197_PE_ICE_SCRATCH_CTRL_TIMER_EN | | ||
125 | EIP197_PE_ICE_SCRATCH_CTRL_SCRATCH_ACCESS | | ||
126 | EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_ACCESS; | ||
127 | writel(val, EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe)); | ||
128 | |||
129 | /* clear the scratchpad RAM using 32 bit writes only */ | ||
130 | for (i = 0; i < EIP197_NUM_OF_SCRATCH_BLOCKS; i++) | ||
131 | writel(0, EIP197_PE(priv) + | ||
132 | EIP197_PE_ICE_SCRATCH_RAM(pe) + (i<<2)); | ||
133 | |||
134 | /* Reset the IFPP engine to make its program mem accessible */ | ||
135 | writel(EIP197_PE_ICE_x_CTRL_SW_RESET | | ||
136 | EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR | | ||
137 | EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR, | ||
138 | EIP197_PE(priv) + EIP197_PE_ICE_FPP_CTRL(pe)); | ||
139 | |||
140 | /* Reset the IPUE engine to make its program mem accessible */ | ||
141 | writel(EIP197_PE_ICE_x_CTRL_SW_RESET | | ||
142 | EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR | | ||
143 | EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR, | ||
144 | EIP197_PE(priv) + EIP197_PE_ICE_PUE_CTRL(pe)); | ||
145 | |||
146 | /* Enable access to all IFPP program memories */ | ||
147 | writel(EIP197_PE_ICE_RAM_CTRL_FPP_PROG_EN, | ||
148 | EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); | ||
149 | } | ||
150 | |||
151 | } | ||
124 | 152 | ||
125 | /* Enable access to the program memory */ | 153 | static int eip197_write_firmware(struct safexcel_crypto_priv *priv, |
126 | writel(prog_en, EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); | 154 | const struct firmware *fw) |
155 | { | ||
156 | const u32 *data = (const u32 *)fw->data; | ||
157 | int i; | ||
127 | 158 | ||
128 | /* Write the firmware */ | 159 | /* Write the firmware */ |
129 | for (i = 0; i < fw->size / sizeof(u32); i++) | 160 | for (i = 0; i < fw->size / sizeof(u32); i++) |
130 | writel(be32_to_cpu(data[i]), | 161 | writel(be32_to_cpu(data[i]), |
131 | priv->base + EIP197_CLASSIFICATION_RAMS + i * sizeof(u32)); | 162 | priv->base + EIP197_CLASSIFICATION_RAMS + i * sizeof(u32)); |
132 | 163 | ||
133 | /* Disable access to the program memory */ | 164 | /* Exclude final 2 NOPs from size */ |
134 | writel(0, EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); | 165 | return i - EIP197_FW_TERMINAL_NOPS; |
166 | } | ||
167 | |||
168 | /* | ||
169 | * If FW is actual production firmware, then poll for its initialization | ||
170 | * to complete and check if it is good for the HW, otherwise just return OK. | ||
171 | */ | ||
172 | static bool poll_fw_ready(struct safexcel_crypto_priv *priv, int fpp) | ||
173 | { | ||
174 | int pe, pollcnt; | ||
175 | u32 base, pollofs; | ||
176 | |||
177 | if (fpp) | ||
178 | pollofs = EIP197_FW_FPP_READY; | ||
179 | else | ||
180 | pollofs = EIP197_FW_PUE_READY; | ||
135 | 181 | ||
136 | /* Release engine from reset */ | 182 | for (pe = 0; pe < priv->config.pes; pe++) { |
137 | val = readl(EIP197_PE(priv) + ctrl); | 183 | base = EIP197_PE_ICE_SCRATCH_RAM(pe); |
138 | val &= ~EIP197_PE_ICE_x_CTRL_SW_RESET; | 184 | pollcnt = EIP197_FW_START_POLLCNT; |
139 | writel(val, EIP197_PE(priv) + ctrl); | 185 | while (pollcnt && |
186 | (readl_relaxed(EIP197_PE(priv) + base + | ||
187 | pollofs) != 1)) { | ||
188 | pollcnt--; | ||
189 | } | ||
190 | if (!pollcnt) { | ||
191 | dev_err(priv->dev, "FW(%d) for PE %d failed to start\n", | ||
192 | fpp, pe); | ||
193 | return false; | ||
194 | } | ||
195 | } | ||
196 | return true; | ||
197 | } | ||
198 | |||
199 | static bool eip197_start_firmware(struct safexcel_crypto_priv *priv, | ||
200 | int ipuesz, int ifppsz, int minifw) | ||
201 | { | ||
202 | int pe; | ||
203 | u32 val; | ||
204 | |||
205 | for (pe = 0; pe < priv->config.pes; pe++) { | ||
206 | /* Disable access to all program memory */ | ||
207 | writel(0, EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); | ||
208 | |||
209 | /* Start IFPP microengines */ | ||
210 | if (minifw) | ||
211 | val = 0; | ||
212 | else | ||
213 | val = EIP197_PE_ICE_UENG_START_OFFSET((ifppsz - 1) & | ||
214 | EIP197_PE_ICE_UENG_INIT_ALIGN_MASK) | | ||
215 | EIP197_PE_ICE_UENG_DEBUG_RESET; | ||
216 | writel(val, EIP197_PE(priv) + EIP197_PE_ICE_FPP_CTRL(pe)); | ||
217 | |||
218 | /* Start IPUE microengines */ | ||
219 | if (minifw) | ||
220 | val = 0; | ||
221 | else | ||
222 | val = EIP197_PE_ICE_UENG_START_OFFSET((ipuesz - 1) & | ||
223 | EIP197_PE_ICE_UENG_INIT_ALIGN_MASK) | | ||
224 | EIP197_PE_ICE_UENG_DEBUG_RESET; | ||
225 | writel(val, EIP197_PE(priv) + EIP197_PE_ICE_PUE_CTRL(pe)); | ||
226 | } | ||
227 | |||
228 | /* For miniFW startup, there is no initialization, so always succeed */ | ||
229 | if (minifw) | ||
230 | return true; | ||
231 | |||
232 | /* Wait until all the firmwares have properly started up */ | ||
233 | if (!poll_fw_ready(priv, 1)) | ||
234 | return false; | ||
235 | if (!poll_fw_ready(priv, 0)) | ||
236 | return false; | ||
237 | |||
238 | return true; | ||
140 | } | 239 | } |
141 | 240 | ||
142 | static int eip197_load_firmwares(struct safexcel_crypto_priv *priv) | 241 | static int eip197_load_firmwares(struct safexcel_crypto_priv *priv) |
143 | { | 242 | { |
144 | const char *fw_name[] = {"ifpp.bin", "ipue.bin"}; | 243 | const char *fw_name[] = {"ifpp.bin", "ipue.bin"}; |
145 | const struct firmware *fw[FW_NB]; | 244 | const struct firmware *fw[FW_NB]; |
146 | char fw_path[31], *dir = NULL; | 245 | char fw_path[37], *dir = NULL; |
147 | int i, j, ret = 0, pe; | 246 | int i, j, ret = 0, pe; |
148 | u32 val; | 247 | int ipuesz, ifppsz, minifw = 0; |
149 | 248 | ||
150 | if (priv->version == EIP197D_MRVL) | 249 | if (priv->version == EIP197D_MRVL) |
151 | dir = "eip197d"; | 250 | dir = "eip197d"; |
@@ -155,51 +254,56 @@ static int eip197_load_firmwares(struct safexcel_crypto_priv *priv) | |||
155 | else | 254 | else |
156 | return -ENODEV; | 255 | return -ENODEV; |
157 | 256 | ||
257 | retry_fw: | ||
158 | for (i = 0; i < FW_NB; i++) { | 258 | for (i = 0; i < FW_NB; i++) { |
159 | snprintf(fw_path, 31, "inside-secure/%s/%s", dir, fw_name[i]); | 259 | snprintf(fw_path, 37, "inside-secure/%s/%s", dir, fw_name[i]); |
160 | ret = request_firmware(&fw[i], fw_path, priv->dev); | 260 | ret = firmware_request_nowarn(&fw[i], fw_path, priv->dev); |
161 | if (ret) { | 261 | if (ret) { |
162 | if (priv->version != EIP197B_MRVL) | 262 | if (minifw || priv->version != EIP197B_MRVL) |
163 | goto release_fw; | 263 | goto release_fw; |
164 | 264 | ||
165 | /* Fallback to the old firmware location for the | 265 | /* Fallback to the old firmware location for the |
166 | * EIP197b. | 266 | * EIP197b. |
167 | */ | 267 | */ |
168 | ret = request_firmware(&fw[i], fw_name[i], priv->dev); | 268 | ret = firmware_request_nowarn(&fw[i], fw_name[i], |
169 | if (ret) { | 269 | priv->dev); |
170 | dev_err(priv->dev, | 270 | if (ret) |
171 | "Failed to request firmware %s (%d)\n", | ||
172 | fw_name[i], ret); | ||
173 | goto release_fw; | 271 | goto release_fw; |
174 | } | ||
175 | } | 272 | } |
176 | } | 273 | } |
177 | 274 | ||
178 | for (pe = 0; pe < priv->config.pes; pe++) { | 275 | eip197_init_firmware(priv); |
179 | /* Clear the scratchpad memory */ | ||
180 | val = readl(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe)); | ||
181 | val |= EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_TIMER | | ||
182 | EIP197_PE_ICE_SCRATCH_CTRL_TIMER_EN | | ||
183 | EIP197_PE_ICE_SCRATCH_CTRL_SCRATCH_ACCESS | | ||
184 | EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_ACCESS; | ||
185 | writel(val, EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe)); | ||
186 | 276 | ||
187 | memset_io(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_RAM(pe), 0, | 277 | ifppsz = eip197_write_firmware(priv, fw[FW_IFPP]); |
188 | EIP197_NUM_OF_SCRATCH_BLOCKS * sizeof(u32)); | ||
189 | 278 | ||
190 | eip197_write_firmware(priv, fw[FW_IFPP], pe, | 279 | /* Enable access to IPUE program memories */ |
191 | EIP197_PE_ICE_FPP_CTRL(pe), | 280 | for (pe = 0; pe < priv->config.pes; pe++) |
192 | EIP197_PE_ICE_RAM_CTRL_FPP_PROG_EN); | 281 | writel(EIP197_PE_ICE_RAM_CTRL_PUE_PROG_EN, |
282 | EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); | ||
193 | 283 | ||
194 | eip197_write_firmware(priv, fw[FW_IPUE], pe, | 284 | ipuesz = eip197_write_firmware(priv, fw[FW_IPUE]); |
195 | EIP197_PE_ICE_PUE_CTRL(pe), | 285 | |
196 | EIP197_PE_ICE_RAM_CTRL_PUE_PROG_EN); | 286 | if (eip197_start_firmware(priv, ipuesz, ifppsz, minifw)) { |
287 | dev_dbg(priv->dev, "Firmware loaded successfully"); | ||
288 | return 0; | ||
197 | } | 289 | } |
198 | 290 | ||
291 | ret = -ENODEV; | ||
292 | |||
199 | release_fw: | 293 | release_fw: |
200 | for (j = 0; j < i; j++) | 294 | for (j = 0; j < i; j++) |
201 | release_firmware(fw[j]); | 295 | release_firmware(fw[j]); |
202 | 296 | ||
297 | if (!minifw) { | ||
298 | /* Retry with minifw path */ | ||
299 | dev_dbg(priv->dev, "Firmware set not (fully) present or init failed, falling back to BCLA mode\n"); | ||
300 | dir = "eip197_minifw"; | ||
301 | minifw = 1; | ||
302 | goto retry_fw; | ||
303 | } | ||
304 | |||
305 | dev_dbg(priv->dev, "Firmware load failed.\n"); | ||
306 | |||
203 | return ret; | 307 | return ret; |
204 | } | 308 | } |
205 | 309 | ||
diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h index 2db2a9636eb7..33e5f663c249 100644 --- a/drivers/crypto/inside-secure/safexcel.h +++ b/drivers/crypto/inside-secure/safexcel.h | |||
@@ -136,8 +136,10 @@ | |||
136 | #define EIP197_PE_IN_TBUF_THRES(n) (0x0100 + (0x2000 * (n))) | 136 | #define EIP197_PE_IN_TBUF_THRES(n) (0x0100 + (0x2000 * (n))) |
137 | #define EIP197_PE_ICE_SCRATCH_RAM(n) (0x0800 + (0x2000 * (n))) | 137 | #define EIP197_PE_ICE_SCRATCH_RAM(n) (0x0800 + (0x2000 * (n))) |
138 | #define EIP197_PE_ICE_PUE_CTRL(n) (0x0c80 + (0x2000 * (n))) | 138 | #define EIP197_PE_ICE_PUE_CTRL(n) (0x0c80 + (0x2000 * (n))) |
139 | #define EIP197_PE_ICE_PUTF_CTRL(n) (0x0d00 + (0x2000 * (n))) | ||
139 | #define EIP197_PE_ICE_SCRATCH_CTRL(n) (0x0d04 + (0x2000 * (n))) | 140 | #define EIP197_PE_ICE_SCRATCH_CTRL(n) (0x0d04 + (0x2000 * (n))) |
140 | #define EIP197_PE_ICE_FPP_CTRL(n) (0x0d80 + (0x2000 * (n))) | 141 | #define EIP197_PE_ICE_FPP_CTRL(n) (0x0d80 + (0x2000 * (n))) |
142 | #define EIP197_PE_ICE_PPTF_CTRL(n) (0x0e00 + (0x2000 * (n))) | ||
141 | #define EIP197_PE_ICE_RAM_CTRL(n) (0x0ff0 + (0x2000 * (n))) | 143 | #define EIP197_PE_ICE_RAM_CTRL(n) (0x0ff0 + (0x2000 * (n))) |
142 | #define EIP197_PE_EIP96_TOKEN_CTRL(n) (0x1000 + (0x2000 * (n))) | 144 | #define EIP197_PE_EIP96_TOKEN_CTRL(n) (0x1000 + (0x2000 * (n))) |
143 | #define EIP197_PE_EIP96_FUNCTION_EN(n) (0x1004 + (0x2000 * (n))) | 145 | #define EIP197_PE_EIP96_FUNCTION_EN(n) (0x1004 + (0x2000 * (n))) |
@@ -228,6 +230,11 @@ | |||
228 | #define EIP197_DxE_THR_CTRL_EN BIT(30) | 230 | #define EIP197_DxE_THR_CTRL_EN BIT(30) |
229 | #define EIP197_DxE_THR_CTRL_RESET_PE BIT(31) | 231 | #define EIP197_DxE_THR_CTRL_RESET_PE BIT(31) |
230 | 232 | ||
233 | /* EIP197_PE_ICE_PUE/FPP_CTRL */ | ||
234 | #define EIP197_PE_ICE_UENG_START_OFFSET(n) ((n) << 16) | ||
235 | #define EIP197_PE_ICE_UENG_INIT_ALIGN_MASK 0x7ff0 | ||
236 | #define EIP197_PE_ICE_UENG_DEBUG_RESET BIT(3) | ||
237 | |||
231 | /* EIP197_HIA_AIC_G_ENABLED_STAT */ | 238 | /* EIP197_HIA_AIC_G_ENABLED_STAT */ |
232 | #define EIP197_G_IRQ_DFE(n) BIT((n) << 1) | 239 | #define EIP197_G_IRQ_DFE(n) BIT((n) << 1) |
233 | #define EIP197_G_IRQ_DSE(n) BIT(((n) << 1) + 1) | 240 | #define EIP197_G_IRQ_DSE(n) BIT(((n) << 1) + 1) |
@@ -503,6 +510,11 @@ struct safexcel_command_desc { | |||
503 | * Internal structures & functions | 510 | * Internal structures & functions |
504 | */ | 511 | */ |
505 | 512 | ||
513 | #define EIP197_FW_TERMINAL_NOPS 2 | ||
514 | #define EIP197_FW_START_POLLCNT 16 | ||
515 | #define EIP197_FW_PUE_READY 0x14 | ||
516 | #define EIP197_FW_FPP_READY 0x18 | ||
517 | |||
506 | enum eip197_fw { | 518 | enum eip197_fw { |
507 | FW_IFPP = 0, | 519 | FW_IFPP = 0, |
508 | FW_IPUE, | 520 | FW_IPUE, |