blob: 2bf96ac9fa8a7f3c3a44e46b2e3c113011d72c8c [file] [log] [blame]
Amol Jadi7d3ad062013-01-04 15:30:19 -08001/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -08002
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
Amol Jadi7d3ad062013-01-04 15:30:19 -080012 * * Neither the name of The Linux Foundation nor the names of its
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -080013 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <string.h>
30#include <endian.h>
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -080031#include <debug.h>
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -080032#include <reg.h>
33#include <platform/iomap.h>
34#include "crypto_eng.h"
35#include "crypto_hash.h"
36
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -080037/*
38 * Function to reset the crypto engine.
39 */
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -080040
41void crypto_eng_reset(void)
42{
Channagoud Kadabi56cd9662012-05-04 13:32:51 +053043#if ASYNC_RESET_CE
44 ce_async_reset();
45#else
Ajay Dudanib01e5062011-12-03 23:23:42 -080046 wr_ce(SW_RST, CRYPTO3_CONFIG);
Channagoud Kadabi9268f4c2012-04-27 11:31:04 +053047 dmb();
Channagoud Kadabi56cd9662012-05-04 13:32:51 +053048#endif
49 return;
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -080050}
51
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -080052/*
53 * Function to initialize the crypto engine for a new session. It enables the
54 * auto shutdown feature of CRYPTO3 and mask various interrupts since we use
55 * polling. We are not using DMOV now.
56 */
57
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -080058void crypto_eng_init(void)
59{
Ajay Dudanib01e5062011-12-03 23:23:42 -080060 unsigned int val;
61 val = (AUTO_SHUTDOWN_EN | MASK_ERR_INTR | MASK_AUTH_DONE_INTR |
62 MASK_DIN_INTR | MASK_DOUT_INTR | HIGH_SPD_IN_EN_N |
63 HIGH_SPD_OUT_EN_N | HIGH_SPD_HASH_EN_N);
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -080064
Ajay Dudanib01e5062011-12-03 23:23:42 -080065 wr_ce(val, CRYPTO3_CONFIG);
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -080066}
67
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -080068/*
69 * Function to set various SHAx registers in CRYPTO3 based on algorithm type.
70 */
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -080071
Ajay Dudanib01e5062011-12-03 23:23:42 -080072void
73crypto_set_sha_ctx(void *ctx_ptr, unsigned int bytes_to_write,
74 crypto_auth_alg_type auth_alg, bool first, bool last)
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -080075{
Ajay Dudanib01e5062011-12-03 23:23:42 -080076 crypto_SHA1_ctx *sha1_ctx = (crypto_SHA1_ctx *) ctx_ptr;
77 crypto_SHA256_ctx *sha256_ctx = (crypto_SHA256_ctx *) ctx_ptr;
78 unsigned int i = 0;
79 unsigned int iv_len = 0;
80 unsigned int *auth_iv;
81 unsigned int seg_cfg_val;
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -080082
Ajay Dudanib01e5062011-12-03 23:23:42 -080083 seg_cfg_val = SEG_CFG_AUTH_ALG_SHA;
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -080084
Ajay Dudanib01e5062011-12-03 23:23:42 -080085 if (auth_alg == CRYPTO_AUTH_ALG_SHA1) {
86 seg_cfg_val |= SEG_CFG_AUTH_SIZE_SHA1;
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -080087
Ajay Dudanib01e5062011-12-03 23:23:42 -080088 if ((first) || ((sha1_ctx->saved_buff_indx != 0) &&
89 (sha1_ctx->auth_bytecnt[0] != 0
90 || sha1_ctx->auth_bytecnt[1] != 0))) {
91 seg_cfg_val |= SEG_CFG_FIRST;
92 }
93 if (last) {
94 seg_cfg_val |= SEG_CFG_LAST;
95 }
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -080096
Ajay Dudanib01e5062011-12-03 23:23:42 -080097 iv_len = SHA1_INIT_VECTOR_SIZE;
98 auth_iv = sha1_ctx->auth_iv;
99 } else if (auth_alg == CRYPTO_AUTH_ALG_SHA256) {
100 seg_cfg_val |= SEG_CFG_AUTH_SIZE_SHA256;
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800101
Ajay Dudanib01e5062011-12-03 23:23:42 -0800102 if ((first) || ((sha256_ctx->saved_buff_indx != 0) &&
103 (sha256_ctx->auth_bytecnt[0] != 0
104 || sha256_ctx->auth_bytecnt[1] != 0))) {
105 seg_cfg_val |= SEG_CFG_FIRST;
106 }
107 if (last) {
108 seg_cfg_val |= SEG_CFG_LAST;
109 }
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800110
Ajay Dudanib01e5062011-12-03 23:23:42 -0800111 iv_len = SHA256_INIT_VECTOR_SIZE;
112 auth_iv = sha256_ctx->auth_iv;
113 } else {
114 dprintf(CRITICAL,
115 "crypto_set_sha_ctx invalid auth algorithm\n");
116 return;
117 }
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800118
Ajay Dudanib01e5062011-12-03 23:23:42 -0800119 for (i = 0; i < iv_len; i++) {
120 wr_ce(*(auth_iv + i), CRYPTO3_AUTH_IVn(i));
121 }
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800122
Ajay Dudanib01e5062011-12-03 23:23:42 -0800123 wr_ce(seg_cfg_val, CRYPTO3_SEG_CFG);
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800124
Ajay Dudanib01e5062011-12-03 23:23:42 -0800125 /* Typecast with crypto_SHA1_ctx because offset of auth_bytecnt in both
126 crypto_SHA1_ctx and crypto_SHA256_ctx are same */
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800127
Ajay Dudanib01e5062011-12-03 23:23:42 -0800128 wr_ce(((crypto_SHA1_ctx *) ctx_ptr)->auth_bytecnt[0],
129 CRYPTO3_AUTH_BYTECNTn(0));
130 wr_ce(((crypto_SHA1_ctx *) ctx_ptr)->auth_bytecnt[1],
131 CRYPTO3_AUTH_BYTECNTn(1));
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800132
Ajay Dudanib01e5062011-12-03 23:23:42 -0800133 wr_ce((bytes_to_write << AUTH_SEG_CFG_AUTH_SIZE), CRYPTO3_AUTH_SEG_CFG);
134 wr_ce(bytes_to_write, CRYPTO3_SEG_SIZE);
135 wr_ce(GOPROC_GO, CRYPTO3_GOPROC);
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800136
Ajay Dudanib01e5062011-12-03 23:23:42 -0800137 return;
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800138}
139
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800140/*
141 * Function to send data to CRYPTO3. This is non-DMOV implementation and uses
142 * polling to send the requested amount of data.
143 */
144
Ajay Dudanib01e5062011-12-03 23:23:42 -0800145void
146crypto_send_data(void *ctx_ptr, unsigned char *data_ptr,
147 unsigned int buff_size, unsigned int bytes_to_write,
148 unsigned int *ret_status)
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800149{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800150 crypto_SHA1_ctx *sha1_ctx = (crypto_SHA1_ctx *) ctx_ptr;
151 unsigned int bytes_left = 0;
152 unsigned int i = 0;
153 unsigned int ce_status = 0;
154 unsigned int ce_err_bmsk = 0;
155 unsigned int is_not_aligned = FALSE;
156 unsigned char data[4];
157 unsigned char *buff_ptr = data_ptr;
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800158
Ajay Dudanib01e5062011-12-03 23:23:42 -0800159 /* Check if the buff_ptr is aligned */
160 if (!(IS_ALIGNED(buff_ptr))) {
161 is_not_aligned = TRUE;
162 }
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800163
Ajay Dudanib01e5062011-12-03 23:23:42 -0800164 /* Fill the saved_buff with data from buff_ptr. First we have to write
165 all the data from the saved_buff and then we will write data from
166 buff_ptr. We will update bytes_left and buff_ptr in the while loop
167 once are done writing all the data from saved_buff. */
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800168
Ajay Dudanib01e5062011-12-03 23:23:42 -0800169 if (sha1_ctx->saved_buff_indx != 0) {
170 memcpy(sha1_ctx->saved_buff + sha1_ctx->saved_buff_indx,
171 buff_ptr,
172 (((buff_size + sha1_ctx->saved_buff_indx) <=
173 CRYPTO_SHA_BLOCK_SIZE)
174 ? buff_size : (CRYPTO_SHA_BLOCK_SIZE -
175 sha1_ctx->saved_buff_indx)));
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800176
Ajay Dudanib01e5062011-12-03 23:23:42 -0800177 if (bytes_to_write >= CRYPTO_SHA_BLOCK_SIZE) {
178 bytes_left = CRYPTO_SHA_BLOCK_SIZE;
179 } else {
180 bytes_left = bytes_to_write;
181 }
182 } else {
183 bytes_left = bytes_to_write;
184 }
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800185
Ajay Dudanib01e5062011-12-03 23:23:42 -0800186 /* Error bitmask to check crypto engine status */
187 ce_err_bmsk = (SW_ERR | DIN_RDY | DIN_SIZE_AVAIL);
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800188
Ajay Dudanib01e5062011-12-03 23:23:42 -0800189 while (bytes_left >= 4) {
190 ce_status = rd_ce(CRYPTO3_STATUS);
191 ce_status &= ce_err_bmsk;
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800192
Ajay Dudanib01e5062011-12-03 23:23:42 -0800193 if (ce_status & SW_ERR) {
194 /* If there is SW_ERR, reset the engine */
195 crypto_eng_reset();
196 *ret_status = CRYPTO_ERR_FAIL;
197 dprintf(CRITICAL, "crypto_send_data sw error\n");
198 return;
199 }
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800200
Ajay Dudanib01e5062011-12-03 23:23:42 -0800201 /* We can write data now - 4 bytes at a time in network byte order */
202 if ((ce_status & DIN_RDY)
203 && ((ce_status & DIN_SIZE_AVAIL) >= 4)) {
204 if (sha1_ctx->saved_buff_indx != 0) {
205 /* Write from saved_buff */
206 wr_ce(htonl
207 (*
208 ((unsigned int *)(sha1_ctx->saved_buff) +
209 i)), CRYPTO3_DATA_IN);
210 } else {
211 if (!is_not_aligned) {
212 /* Write from buff_ptr aligned */
213 wr_ce(htonl
214 (*((unsigned int *)buff_ptr + i)),
215 CRYPTO3_DATA_IN);
216 } else {
217 /* If buff_ptr is not aligned write byte by byte */
218 data[0] = *(buff_ptr + i);
219 data[1] = *(buff_ptr + i + 1);
220 data[2] = *(buff_ptr + i + 2);
221 data[3] = *(buff_ptr + i + 3);
222 /* i will incremented by 1 in outside block */
223 i += 3;
224 wr_ce(htonl(*(unsigned int *)data),
225 CRYPTO3_DATA_IN);
226 memset(data, 0, 4);
227 }
228 }
229 i++;
230 bytes_left -= 4;
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800231
Ajay Dudanib01e5062011-12-03 23:23:42 -0800232 /* Check if we have written from saved_buff. Adjust buff_ptr and
233 bytes_left accordingly */
234 if ((sha1_ctx->saved_buff_indx != 0)
235 && (bytes_left == 0)
236 && (bytes_to_write > CRYPTO_SHA_BLOCK_SIZE)) {
237 bytes_left =
238 (bytes_to_write - CRYPTO_SHA_BLOCK_SIZE);
239 buff_ptr =
240 (unsigned char *)((unsigned char *)data_ptr
241 + CRYPTO_SHA_BLOCK_SIZE -
242 sha1_ctx->
243 saved_buff_indx);
244 i = 0;
245 sha1_ctx->saved_buff_indx = 0;
246 if (!(IS_ALIGNED(buff_ptr))) {
247 is_not_aligned = TRUE;
248 }
249 }
250 }
251 }
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800252
Ajay Dudanib01e5062011-12-03 23:23:42 -0800253 /* We might have bytes_left < 4. Write them now if available */
254 if (bytes_left) {
255 memset(data, 0, sizeof(unsigned int));
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800256
Ajay Dudanib01e5062011-12-03 23:23:42 -0800257 if (sha1_ctx->saved_buff_indx)
258 buff_ptr = (sha1_ctx->saved_buff + bytes_to_write - 1);
259 else
260 buff_ptr =
261 (((unsigned char *)data_ptr) + buff_size - 1);
Subbaraman Narayanamurthy22d53c62011-04-12 18:15:50 -0700262
Ajay Dudanib01e5062011-12-03 23:23:42 -0800263 for (i = 0; i < bytes_left; i++) {
264 data[3 - i] = *(buff_ptr - bytes_left + i + 1);
265 }
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800266
Ajay Dudanib01e5062011-12-03 23:23:42 -0800267 ce_status = rd_ce(CRYPTO3_STATUS);
268 ce_status &= ce_err_bmsk;
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800269
Ajay Dudanib01e5062011-12-03 23:23:42 -0800270 if (ce_status & SW_ERR) {
271 crypto_eng_reset();
272 *ret_status = CRYPTO_ERR_FAIL;
273 dprintf(CRITICAL, "crypto_send_data sw error 2\n");
274 return;
275 }
276 if ((ce_status & DIN_RDY)
277 && ((ce_status & DIN_SIZE_AVAIL) >= 4)) {
278 wr_ce(*(unsigned int *)data, CRYPTO3_DATA_IN);
279 }
280 }
281 *ret_status = CRYPTO_ERR_NONE;
282 return;
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800283}
284
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800285/*
286 * Function to get digest from CRYPTO3. We poll for AUTH_DONE from CRYPTO3.
287 */
288
Ajay Dudanib01e5062011-12-03 23:23:42 -0800289void
290crypto_get_digest(unsigned char *digest_ptr, unsigned int *ret_status,
291 crypto_auth_alg_type auth_alg, bool last)
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800292{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800293 unsigned int ce_status = 0;
294 unsigned int ce_err_bmsk = (AUTH_DONE | SW_ERR);
295 unsigned int i = 0;
296 unsigned int digest_len = 0;
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800297
Ajay Dudanib01e5062011-12-03 23:23:42 -0800298 do {
299 ce_status = rd_ce(CRYPTO3_STATUS);
300 ce_status &= ce_err_bmsk;
301 }
302 while (ce_status == 0);
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800303
Ajay Dudanib01e5062011-12-03 23:23:42 -0800304 if (ce_status & SW_ERR) {
305 crypto_eng_reset();
306 *ret_status = CRYPTO_ERR_FAIL;
307 dprintf(CRITICAL, "crypto_get_digest sw error\n");
308 return;
309 }
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800310
Ajay Dudanib01e5062011-12-03 23:23:42 -0800311 /* Digest length depends on auth_alg */
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800312
Ajay Dudanib01e5062011-12-03 23:23:42 -0800313 if (auth_alg == CRYPTO_AUTH_ALG_SHA1) {
314 digest_len = SHA1_INIT_VECTOR_SIZE;
315 } else if (auth_alg == CRYPTO_AUTH_ALG_SHA256) {
316 digest_len = SHA256_INIT_VECTOR_SIZE;
317 }
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800318
Ajay Dudanib01e5062011-12-03 23:23:42 -0800319 /* Retrieve digest from CRYPTO3 */
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800320
Ajay Dudanib01e5062011-12-03 23:23:42 -0800321 for (i = 0; i < digest_len; i++) {
322 unsigned int auth_iv = rd_ce(CRYPTO3_AUTH_IVn(i));
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800323
Ajay Dudanib01e5062011-12-03 23:23:42 -0800324 if (last) {
325 *((unsigned int *)digest_ptr + i) = htonl(auth_iv);
326 } else {
327 *((unsigned int *)digest_ptr + i) = auth_iv;
328 }
329 }
330 *ret_status = CRYPTO_ERR_NONE;
331 return;
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800332}
333
Subbaraman Narayanamurthy8fcccbd2011-01-28 13:26:00 -0800334/* Function to restore auth_bytecnt registers for ctx_ptr */
335
336void crypto_get_ctx(void *ctx_ptr)
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800337{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800338 ((crypto_SHA1_ctx *) ctx_ptr)->auth_bytecnt[0] =
339 rd_ce(CRYPTO3_AUTH_BYTECNTn(0));
340 ((crypto_SHA1_ctx *) ctx_ptr)->auth_bytecnt[1] =
341 rd_ce(CRYPTO3_AUTH_BYTECNTn(1));
342 return;
Subbaraman Narayanamurthy9b7276c2011-01-25 17:25:30 -0800343}
Amol Jadi7d3ad062013-01-04 15:30:19 -0800344
345/* Returns the max authentication block size */
346uint32_t crypto_get_max_auth_blk_size()
347{
348 return 0xFA00;
349}