xref: /optee_os/core/drivers/crypto/stm32/stm32_cryp.c (revision a9b7c5a89fa33e02f91ae1de6a635c62e9cfc882)
15e64ae67SNicolas Toromanoff // SPDX-License-Identifier: BSD-2-Clause
25e64ae67SNicolas Toromanoff /*
35e64ae67SNicolas Toromanoff  * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
45e64ae67SNicolas Toromanoff  */
55e64ae67SNicolas Toromanoff #include <assert.h>
65e64ae67SNicolas Toromanoff #include <config.h>
78b826c3bSEtienne Carriere #include <drivers/clk.h>
88b826c3bSEtienne Carriere #include <drivers/clk_dt.h>
9047c4fe1SEtienne Carriere #include <drivers/rstctrl.h>
105e64ae67SNicolas Toromanoff #include <initcall.h>
115e64ae67SNicolas Toromanoff #include <io.h>
125e64ae67SNicolas Toromanoff #include <kernel/boot.h>
135e64ae67SNicolas Toromanoff #include <kernel/delay.h>
145e64ae67SNicolas Toromanoff #include <kernel/dt.h>
159e3c57c8SEtienne Carriere #include <kernel/dt_driver.h>
165e64ae67SNicolas Toromanoff #include <kernel/mutex.h>
17299f9bc1SThomas Bourgoin #include <kernel/pm.h>
185e64ae67SNicolas Toromanoff #include <libfdt.h>
195e64ae67SNicolas Toromanoff #include <mm/core_memprot.h>
205e64ae67SNicolas Toromanoff #include <stdint.h>
215e64ae67SNicolas Toromanoff #include <stm32_util.h>
225e64ae67SNicolas Toromanoff #include <string.h>
235e64ae67SNicolas Toromanoff #include <utee_defines.h>
245e64ae67SNicolas Toromanoff #include <util.h>
255e64ae67SNicolas Toromanoff 
265e64ae67SNicolas Toromanoff #include "stm32_cryp.h"
275e64ae67SNicolas Toromanoff #include "common.h"
285e64ae67SNicolas Toromanoff 
295e64ae67SNicolas Toromanoff /* CRYP control register */
305e64ae67SNicolas Toromanoff #define _CRYP_CR			0x0U
315e64ae67SNicolas Toromanoff /* CRYP status register */
325e64ae67SNicolas Toromanoff #define _CRYP_SR			0x04U
335e64ae67SNicolas Toromanoff /* CRYP data input register */
345e64ae67SNicolas Toromanoff #define _CRYP_DIN			0x08U
355e64ae67SNicolas Toromanoff /* CRYP data output register */
365e64ae67SNicolas Toromanoff #define _CRYP_DOUT			0x0CU
375e64ae67SNicolas Toromanoff /* CRYP DMA control register */
385e64ae67SNicolas Toromanoff #define _CRYP_DMACR			0x10U
395e64ae67SNicolas Toromanoff /* CRYP interrupt mask set/clear register */
405e64ae67SNicolas Toromanoff #define _CRYP_IMSCR			0x14U
415e64ae67SNicolas Toromanoff /* CRYP raw interrupt status register */
425e64ae67SNicolas Toromanoff #define _CRYP_RISR			0x18U
435e64ae67SNicolas Toromanoff /* CRYP masked interrupt status register */
445e64ae67SNicolas Toromanoff #define _CRYP_MISR			0x1CU
455e64ae67SNicolas Toromanoff /* CRYP key registers */
465e64ae67SNicolas Toromanoff #define _CRYP_K0LR			0x20U
475e64ae67SNicolas Toromanoff #define _CRYP_K0RR			0x24U
485e64ae67SNicolas Toromanoff #define _CRYP_K1LR			0x28U
495e64ae67SNicolas Toromanoff #define _CRYP_K1RR			0x2CU
505e64ae67SNicolas Toromanoff #define _CRYP_K2LR			0x30U
515e64ae67SNicolas Toromanoff #define _CRYP_K2RR			0x34U
525e64ae67SNicolas Toromanoff #define _CRYP_K3LR			0x38U
535e64ae67SNicolas Toromanoff #define _CRYP_K3RR			0x3CU
545e64ae67SNicolas Toromanoff /* CRYP initialization vector registers */
555e64ae67SNicolas Toromanoff #define _CRYP_IV0LR			0x40U
565e64ae67SNicolas Toromanoff #define _CRYP_IV0RR			0x44U
575e64ae67SNicolas Toromanoff #define _CRYP_IV1LR			0x48U
585e64ae67SNicolas Toromanoff #define _CRYP_IV1RR			0x4CU
595e64ae67SNicolas Toromanoff /* CRYP context swap GCM-CCM registers */
605e64ae67SNicolas Toromanoff #define _CRYP_CSGCMCCM0R		0x50U
615e64ae67SNicolas Toromanoff #define _CRYP_CSGCMCCM1R		0x54U
625e64ae67SNicolas Toromanoff #define _CRYP_CSGCMCCM2R		0x58U
635e64ae67SNicolas Toromanoff #define _CRYP_CSGCMCCM3R		0x5CU
645e64ae67SNicolas Toromanoff #define _CRYP_CSGCMCCM4R		0x60U
655e64ae67SNicolas Toromanoff #define _CRYP_CSGCMCCM5R		0x64U
665e64ae67SNicolas Toromanoff #define _CRYP_CSGCMCCM6R		0x68U
675e64ae67SNicolas Toromanoff #define _CRYP_CSGCMCCM7R		0x6CU
685e64ae67SNicolas Toromanoff /* CRYP context swap GCM registers */
695e64ae67SNicolas Toromanoff #define _CRYP_CSGCM0R			0x70U
705e64ae67SNicolas Toromanoff #define _CRYP_CSGCM1R			0x74U
715e64ae67SNicolas Toromanoff #define _CRYP_CSGCM2R			0x78U
725e64ae67SNicolas Toromanoff #define _CRYP_CSGCM3R			0x7CU
735e64ae67SNicolas Toromanoff #define _CRYP_CSGCM4R			0x80U
745e64ae67SNicolas Toromanoff #define _CRYP_CSGCM5R			0x84U
755e64ae67SNicolas Toromanoff #define _CRYP_CSGCM6R			0x88U
765e64ae67SNicolas Toromanoff #define _CRYP_CSGCM7R			0x8CU
775e64ae67SNicolas Toromanoff /* CRYP hardware configuration register */
785e64ae67SNicolas Toromanoff #define _CRYP_HWCFGR			0x3F0U
795e64ae67SNicolas Toromanoff /* CRYP HW version register */
805e64ae67SNicolas Toromanoff #define _CRYP_VERR			0x3F4U
815e64ae67SNicolas Toromanoff /* CRYP identification */
825e64ae67SNicolas Toromanoff #define _CRYP_IPIDR			0x3F8U
835e64ae67SNicolas Toromanoff /* CRYP HW magic ID */
845e64ae67SNicolas Toromanoff #define _CRYP_MID			0x3FCU
855e64ae67SNicolas Toromanoff 
865e64ae67SNicolas Toromanoff #define CRYP_TIMEOUT_US			1000000U
875e64ae67SNicolas Toromanoff #define TIMEOUT_US_1MS			1000U
8814d68630SThomas Bourgoin #define CRYP_RESET_DELAY_US		U(2)
895e64ae67SNicolas Toromanoff 
905e64ae67SNicolas Toromanoff /* CRYP control register fields */
915e64ae67SNicolas Toromanoff #define _CRYP_CR_RESET_VALUE		0x0U
925e64ae67SNicolas Toromanoff #define _CRYP_CR_NPBLB_MSK		GENMASK_32(23, 20)
935e64ae67SNicolas Toromanoff #define _CRYP_CR_NPBLB_OFF		20U
945e64ae67SNicolas Toromanoff #define _CRYP_CR_GCM_CCMPH_MSK		GENMASK_32(17, 16)
955e64ae67SNicolas Toromanoff #define _CRYP_CR_GCM_CCMPH_OFF		16U
965e64ae67SNicolas Toromanoff #define _CRYP_CR_GCM_CCMPH_INIT		0U
975e64ae67SNicolas Toromanoff #define _CRYP_CR_GCM_CCMPH_HEADER	1U
985e64ae67SNicolas Toromanoff #define _CRYP_CR_GCM_CCMPH_PAYLOAD	2U
995e64ae67SNicolas Toromanoff #define _CRYP_CR_GCM_CCMPH_FINAL	3U
1005e64ae67SNicolas Toromanoff #define _CRYP_CR_CRYPEN			BIT(15)
1015e64ae67SNicolas Toromanoff #define _CRYP_CR_FFLUSH			BIT(14)
1025e64ae67SNicolas Toromanoff #define _CRYP_CR_KEYSIZE_MSK		GENMASK_32(9, 8)
1035e64ae67SNicolas Toromanoff #define _CRYP_CR_KEYSIZE_OFF		8U
1045e64ae67SNicolas Toromanoff #define _CRYP_CR_KSIZE_128		0U
1055e64ae67SNicolas Toromanoff #define _CRYP_CR_KSIZE_192		1U
1065e64ae67SNicolas Toromanoff #define _CRYP_CR_KSIZE_256		2U
1075e64ae67SNicolas Toromanoff #define _CRYP_CR_DATATYPE_MSK		GENMASK_32(7, 6)
1085e64ae67SNicolas Toromanoff #define _CRYP_CR_DATATYPE_OFF		6U
1095e64ae67SNicolas Toromanoff #define _CRYP_CR_DATATYPE_NONE		0U
1105e64ae67SNicolas Toromanoff #define _CRYP_CR_DATATYPE_HALF_WORD	1U
1115e64ae67SNicolas Toromanoff #define _CRYP_CR_DATATYPE_BYTE		2U
1125e64ae67SNicolas Toromanoff #define _CRYP_CR_DATATYPE_BIT		3U
1135e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGOMODE_MSK		(BIT(19) | GENMASK_32(5, 3))
1145e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGOMODE_OFF		3U
1155e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGOMODE_TDES_ECB	0x0U
1165e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGOMODE_TDES_CBC	0x1U
1175e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGOMODE_DES_ECB	0x2U
1185e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGOMODE_DES_CBC	0x3U
1195e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGOMODE_AES_ECB	0x4U
1205e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGOMODE_AES_CBC	0x5U
1215e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGOMODE_AES_CTR	0x6U
1225e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGOMODE_AES		0x7U
1235e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGOMODE_AES_GCM	BIT(16)
1245e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGOMODE_AES_CCM	(BIT(16) | BIT(0))
1255e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGODIR		BIT(2)
1265e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGODIR_ENC		0U
1275e64ae67SNicolas Toromanoff #define _CRYP_CR_ALGODIR_DEC		BIT(2)
1285e64ae67SNicolas Toromanoff 
1295e64ae67SNicolas Toromanoff /* CRYP status register fields */
1305e64ae67SNicolas Toromanoff #define _CRYP_SR_BUSY			BIT(4)
1315e64ae67SNicolas Toromanoff #define _CRYP_SR_OFFU			BIT(3)
1325e64ae67SNicolas Toromanoff #define _CRYP_SR_OFNE			BIT(2)
1335e64ae67SNicolas Toromanoff #define _CRYP_SR_IFNF			BIT(1)
1345e64ae67SNicolas Toromanoff #define _CRYP_SR_IFEM			BIT(0)
1355e64ae67SNicolas Toromanoff 
1365e64ae67SNicolas Toromanoff /* CRYP DMA control register fields */
1375e64ae67SNicolas Toromanoff #define _CRYP_DMACR_DOEN		BIT(1)
1385e64ae67SNicolas Toromanoff #define _CRYP_DMACR_DIEN		BIT(0)
1395e64ae67SNicolas Toromanoff 
1405e64ae67SNicolas Toromanoff /* CRYP interrupt fields */
1415e64ae67SNicolas Toromanoff #define _CRYP_I_OUT			BIT(1)
1425e64ae67SNicolas Toromanoff #define _CRYP_I_IN			BIT(0)
1435e64ae67SNicolas Toromanoff 
1445e64ae67SNicolas Toromanoff /* CRYP hardware configuration register fields */
1455e64ae67SNicolas Toromanoff #define _CRYP_HWCFGR_CFG1_MSK		GENMASK_32(3, 0)
1465e64ae67SNicolas Toromanoff #define _CRYP_HWCFGR_CFG1_OFF		0U
1475e64ae67SNicolas Toromanoff #define _CRYP_HWCFGR_CFG2_MSK		GENMASK_32(7, 4)
1485e64ae67SNicolas Toromanoff #define _CRYP_HWCFGR_CFG2_OFF		4U
1495e64ae67SNicolas Toromanoff #define _CRYP_HWCFGR_CFG3_MSK		GENMASK_32(11, 8)
1505e64ae67SNicolas Toromanoff #define _CRYP_HWCFGR_CFG3_OFF		8U
1515e64ae67SNicolas Toromanoff #define _CRYP_HWCFGR_CFG4_MSK		GENMASK_32(15, 12)
1525e64ae67SNicolas Toromanoff #define _CRYP_HWCFGR_CFG4_OFF		12U
1535e64ae67SNicolas Toromanoff 
1545e64ae67SNicolas Toromanoff /* CRYP HW version register */
1555e64ae67SNicolas Toromanoff #define _CRYP_VERR_MSK			GENMASK_32(7, 0)
1565e64ae67SNicolas Toromanoff #define _CRYP_VERR_OFF			0U
1575e64ae67SNicolas Toromanoff 
1585e64ae67SNicolas Toromanoff /*
1594320f5cfSThomas Bourgoin  * Macro to manage bit manipulation when we work on a local variable
1604320f5cfSThomas Bourgoin  * before writing only once to the hardware register.
1615e64ae67SNicolas Toromanoff  */
1625e64ae67SNicolas Toromanoff #define CLRBITS(v, bits)		((v) &= ~(bits))
1635e64ae67SNicolas Toromanoff #define SETBITS(v, bits)		((v) |= (bits))
1645e64ae67SNicolas Toromanoff 
1655e64ae67SNicolas Toromanoff #define IS_ALGOMODE(cr, mod) \
1665e64ae67SNicolas Toromanoff 	(((cr) & _CRYP_CR_ALGOMODE_MSK) == (_CRYP_CR_ALGOMODE_##mod << \
1675e64ae67SNicolas Toromanoff 					  _CRYP_CR_ALGOMODE_OFF))
1685e64ae67SNicolas Toromanoff 
1695e64ae67SNicolas Toromanoff #define SET_ALGOMODE(mod, cr) \
1705e64ae67SNicolas Toromanoff 	clrsetbits(&(cr), _CRYP_CR_ALGOMODE_MSK, (_CRYP_CR_ALGOMODE_##mod << \
1715e64ae67SNicolas Toromanoff 						  _CRYP_CR_ALGOMODE_OFF))
1725e64ae67SNicolas Toromanoff 
1735e64ae67SNicolas Toromanoff #define GET_ALGOMODE(cr) \
1745e64ae67SNicolas Toromanoff 	(((cr) & _CRYP_CR_ALGOMODE_MSK) >> _CRYP_CR_ALGOMODE_OFF)
1755e64ae67SNicolas Toromanoff 
1765e64ae67SNicolas Toromanoff static struct stm32_cryp_platdata cryp_pdata;
1775e64ae67SNicolas Toromanoff static struct mutex cryp_lock = MUTEX_INITIALIZER;
1785e64ae67SNicolas Toromanoff 
clrsetbits(uint32_t * v,uint32_t mask,uint32_t bits)1795e64ae67SNicolas Toromanoff static void clrsetbits(uint32_t *v, uint32_t mask, uint32_t bits)
1805e64ae67SNicolas Toromanoff {
1815e64ae67SNicolas Toromanoff 	*v = (*v & ~mask) | bits;
1825e64ae67SNicolas Toromanoff }
1835e64ae67SNicolas Toromanoff 
algo_mode_needs_iv(uint32_t cr)1845e64ae67SNicolas Toromanoff static bool algo_mode_needs_iv(uint32_t cr)
1855e64ae67SNicolas Toromanoff {
1865e64ae67SNicolas Toromanoff 	return !IS_ALGOMODE(cr, TDES_ECB) && !IS_ALGOMODE(cr, DES_ECB) &&
1875e64ae67SNicolas Toromanoff 	       !IS_ALGOMODE(cr, AES_ECB);
1885e64ae67SNicolas Toromanoff }
1895e64ae67SNicolas Toromanoff 
algo_mode_is_ecb_cbc(uint32_t cr)1905e64ae67SNicolas Toromanoff static bool algo_mode_is_ecb_cbc(uint32_t cr)
1915e64ae67SNicolas Toromanoff {
1925e64ae67SNicolas Toromanoff 	return GET_ALGOMODE(cr) < _CRYP_CR_ALGOMODE_AES_CTR;
1935e64ae67SNicolas Toromanoff }
1945e64ae67SNicolas Toromanoff 
algo_mode_is_aes(uint32_t cr)1955e64ae67SNicolas Toromanoff static bool algo_mode_is_aes(uint32_t cr)
1965e64ae67SNicolas Toromanoff {
1975e64ae67SNicolas Toromanoff 	return ((cr & _CRYP_CR_ALGOMODE_MSK) >> _CRYP_CR_ALGOMODE_OFF) >=
1985e64ae67SNicolas Toromanoff 	       _CRYP_CR_ALGOMODE_AES_ECB;
1995e64ae67SNicolas Toromanoff }
2005e64ae67SNicolas Toromanoff 
is_decrypt(uint32_t cr)2015e64ae67SNicolas Toromanoff static bool is_decrypt(uint32_t cr)
2025e64ae67SNicolas Toromanoff {
2035e64ae67SNicolas Toromanoff 	return (cr & _CRYP_CR_ALGODIR) == _CRYP_CR_ALGODIR_DEC;
2045e64ae67SNicolas Toromanoff }
2055e64ae67SNicolas Toromanoff 
is_encrypt(uint32_t cr)2065e64ae67SNicolas Toromanoff static bool is_encrypt(uint32_t cr)
2075e64ae67SNicolas Toromanoff {
2085e64ae67SNicolas Toromanoff 	return !is_decrypt(cr);
2095e64ae67SNicolas Toromanoff }
2105e64ae67SNicolas Toromanoff 
does_need_npblb(uint32_t cr)2115e64ae67SNicolas Toromanoff static bool does_need_npblb(uint32_t cr)
2125e64ae67SNicolas Toromanoff {
2135e64ae67SNicolas Toromanoff 	return (IS_ALGOMODE(cr, AES_GCM) && is_encrypt(cr)) ||
2145e64ae67SNicolas Toromanoff 	       (IS_ALGOMODE(cr, AES_CCM) && is_decrypt(cr));
2155e64ae67SNicolas Toromanoff }
2165e64ae67SNicolas Toromanoff 
wait_sr_bits(vaddr_t base,uint32_t bits)2175e64ae67SNicolas Toromanoff static TEE_Result wait_sr_bits(vaddr_t base, uint32_t bits)
2185e64ae67SNicolas Toromanoff {
2195e64ae67SNicolas Toromanoff 	uint64_t timeout_ref = timeout_init_us(CRYP_TIMEOUT_US);
2205e64ae67SNicolas Toromanoff 
2215e64ae67SNicolas Toromanoff 	while ((io_read32(base + _CRYP_SR) & bits) != bits)
2225e64ae67SNicolas Toromanoff 		if (timeout_elapsed(timeout_ref))
2235e64ae67SNicolas Toromanoff 			break;
2245e64ae67SNicolas Toromanoff 
2255e64ae67SNicolas Toromanoff 	if ((io_read32(base + _CRYP_SR) & bits) != bits)
2265e64ae67SNicolas Toromanoff 		return TEE_ERROR_BUSY;
2275e64ae67SNicolas Toromanoff 
2285e64ae67SNicolas Toromanoff 	return TEE_SUCCESS;
2295e64ae67SNicolas Toromanoff }
2305e64ae67SNicolas Toromanoff 
wait_end_busy(vaddr_t base)2315e64ae67SNicolas Toromanoff static TEE_Result wait_end_busy(vaddr_t base)
2325e64ae67SNicolas Toromanoff {
2335e64ae67SNicolas Toromanoff 	uint64_t timeout_ref = timeout_init_us(CRYP_TIMEOUT_US);
2345e64ae67SNicolas Toromanoff 
2355e64ae67SNicolas Toromanoff 	while (io_read32(base + _CRYP_SR) & _CRYP_SR_BUSY)
2365e64ae67SNicolas Toromanoff 		if (timeout_elapsed(timeout_ref))
2375e64ae67SNicolas Toromanoff 			break;
2385e64ae67SNicolas Toromanoff 
2395e64ae67SNicolas Toromanoff 	if (io_read32(base + _CRYP_SR) & _CRYP_SR_BUSY)
2405e64ae67SNicolas Toromanoff 		return TEE_ERROR_BUSY;
2415e64ae67SNicolas Toromanoff 
2425e64ae67SNicolas Toromanoff 	return TEE_SUCCESS;
2435e64ae67SNicolas Toromanoff }
2445e64ae67SNicolas Toromanoff 
wait_end_enable(vaddr_t base)2455e64ae67SNicolas Toromanoff static TEE_Result wait_end_enable(vaddr_t base)
2465e64ae67SNicolas Toromanoff {
2475e64ae67SNicolas Toromanoff 	uint64_t timeout_ref = timeout_init_us(CRYP_TIMEOUT_US);
2485e64ae67SNicolas Toromanoff 
2495e64ae67SNicolas Toromanoff 	while (io_read32(base + _CRYP_CR) & _CRYP_CR_CRYPEN)
2505e64ae67SNicolas Toromanoff 		if (timeout_elapsed(timeout_ref))
2515e64ae67SNicolas Toromanoff 			break;
2525e64ae67SNicolas Toromanoff 
2535e64ae67SNicolas Toromanoff 	if (io_read32(base + _CRYP_CR) & _CRYP_CR_CRYPEN)
2545e64ae67SNicolas Toromanoff 		return TEE_ERROR_BUSY;
2555e64ae67SNicolas Toromanoff 
2565e64ae67SNicolas Toromanoff 	return TEE_SUCCESS;
2575e64ae67SNicolas Toromanoff }
2585e64ae67SNicolas Toromanoff 
write_align_block(struct stm32_cryp_context * ctx,uint32_t * data)2595e64ae67SNicolas Toromanoff static TEE_Result __must_check write_align_block(struct stm32_cryp_context *ctx,
2605e64ae67SNicolas Toromanoff 						 uint32_t *data)
2615e64ae67SNicolas Toromanoff {
2625e64ae67SNicolas Toromanoff 	TEE_Result res = TEE_SUCCESS;
2635e64ae67SNicolas Toromanoff 	unsigned int i = 0;
2645e64ae67SNicolas Toromanoff 
2655e64ae67SNicolas Toromanoff 	res = wait_sr_bits(ctx->base, _CRYP_SR_IFNF);
2665e64ae67SNicolas Toromanoff 	if (res)
2675e64ae67SNicolas Toromanoff 		return res;
2685e64ae67SNicolas Toromanoff 
2695e64ae67SNicolas Toromanoff 	for (i = 0; i < ctx->block_u32; i++) {
2705e64ae67SNicolas Toromanoff 		/* No need to htobe() as we configure the HW to swap bytes */
2715e64ae67SNicolas Toromanoff 		io_write32(ctx->base + _CRYP_DIN, data[i]);
2725e64ae67SNicolas Toromanoff 	}
2735e64ae67SNicolas Toromanoff 
2745e64ae67SNicolas Toromanoff 	return TEE_SUCCESS;
2755e64ae67SNicolas Toromanoff }
2765e64ae67SNicolas Toromanoff 
write_block(struct stm32_cryp_context * ctx,uint8_t * data)2775e64ae67SNicolas Toromanoff static TEE_Result __must_check write_block(struct stm32_cryp_context *ctx,
2785e64ae67SNicolas Toromanoff 					   uint8_t *data)
2795e64ae67SNicolas Toromanoff {
2805e64ae67SNicolas Toromanoff 	if (!IS_ALIGNED_WITH_TYPE(data, uint32_t)) {
2815e64ae67SNicolas Toromanoff 		uint32_t data_u32[MAX_BLOCK_NB_U32] = { 0 };
2825e64ae67SNicolas Toromanoff 
2835e64ae67SNicolas Toromanoff 		memcpy(data_u32, data, ctx->block_u32 * sizeof(uint32_t));
2845e64ae67SNicolas Toromanoff 		return write_align_block(ctx, data_u32);
2855e64ae67SNicolas Toromanoff 	}
2865e64ae67SNicolas Toromanoff 
2875e64ae67SNicolas Toromanoff 	return write_align_block(ctx, (void *)data);
2885e64ae67SNicolas Toromanoff }
2895e64ae67SNicolas Toromanoff 
read_align_block(struct stm32_cryp_context * ctx,uint32_t * data)2905e64ae67SNicolas Toromanoff static TEE_Result __must_check read_align_block(struct stm32_cryp_context *ctx,
2915e64ae67SNicolas Toromanoff 						uint32_t *data)
2925e64ae67SNicolas Toromanoff {
2935e64ae67SNicolas Toromanoff 	TEE_Result res = TEE_SUCCESS;
2945e64ae67SNicolas Toromanoff 	unsigned int i = 0;
2955e64ae67SNicolas Toromanoff 
2965e64ae67SNicolas Toromanoff 	res = wait_sr_bits(ctx->base, _CRYP_SR_OFNE);
2975e64ae67SNicolas Toromanoff 	if (res)
2985e64ae67SNicolas Toromanoff 		return res;
2995e64ae67SNicolas Toromanoff 
3005e64ae67SNicolas Toromanoff 	for (i = 0; i < ctx->block_u32; i++) {
3015e64ae67SNicolas Toromanoff 		/* No need to htobe() as we configure the HW to swap bytes */
3025e64ae67SNicolas Toromanoff 		data[i] = io_read32(ctx->base + _CRYP_DOUT);
3035e64ae67SNicolas Toromanoff 	}
3045e64ae67SNicolas Toromanoff 
3055e64ae67SNicolas Toromanoff 	return TEE_SUCCESS;
3065e64ae67SNicolas Toromanoff }
3075e64ae67SNicolas Toromanoff 
read_block(struct stm32_cryp_context * ctx,uint8_t * data)3085e64ae67SNicolas Toromanoff static TEE_Result __must_check read_block(struct stm32_cryp_context *ctx,
3095e64ae67SNicolas Toromanoff 					  uint8_t *data)
3105e64ae67SNicolas Toromanoff {
3115e64ae67SNicolas Toromanoff 	if (!IS_ALIGNED_WITH_TYPE(data, uint32_t)) {
3125e64ae67SNicolas Toromanoff 		TEE_Result res = TEE_SUCCESS;
3135e64ae67SNicolas Toromanoff 		uint32_t data_u32[MAX_BLOCK_NB_U32] = { 0 };
3145e64ae67SNicolas Toromanoff 
3155e64ae67SNicolas Toromanoff 		res = read_align_block(ctx, data_u32);
3165e64ae67SNicolas Toromanoff 		if (res)
3175e64ae67SNicolas Toromanoff 			return res;
3185e64ae67SNicolas Toromanoff 
3195e64ae67SNicolas Toromanoff 		memcpy(data, data_u32, ctx->block_u32 * sizeof(uint32_t));
3205e64ae67SNicolas Toromanoff 
3215e64ae67SNicolas Toromanoff 		return TEE_SUCCESS;
3225e64ae67SNicolas Toromanoff 	}
3235e64ae67SNicolas Toromanoff 
3245e64ae67SNicolas Toromanoff 	return read_align_block(ctx, (void *)data);
3255e64ae67SNicolas Toromanoff }
3265e64ae67SNicolas Toromanoff 
stm32_cryp_reset(void)32714d68630SThomas Bourgoin static TEE_Result stm32_cryp_reset(void)
32814d68630SThomas Bourgoin {
32914d68630SThomas Bourgoin 	TEE_Result res = TEE_ERROR_GENERIC;
33014d68630SThomas Bourgoin 
33114d68630SThomas Bourgoin 	if (!cryp_pdata.reset)
33214d68630SThomas Bourgoin 		return TEE_SUCCESS;
33314d68630SThomas Bourgoin 
33414d68630SThomas Bourgoin 	res = rstctrl_assert_to(cryp_pdata.reset, TIMEOUT_US_1MS);
33514d68630SThomas Bourgoin 	if (res)
33614d68630SThomas Bourgoin 		return res;
33714d68630SThomas Bourgoin 
33814d68630SThomas Bourgoin 	udelay(CRYP_RESET_DELAY_US);
33914d68630SThomas Bourgoin 
34014d68630SThomas Bourgoin 	return rstctrl_deassert_to(cryp_pdata.reset, TIMEOUT_US_1MS);
34114d68630SThomas Bourgoin }
34214d68630SThomas Bourgoin 
cryp_end(struct stm32_cryp_context * ctx,TEE_Result prev_error)3435e64ae67SNicolas Toromanoff static void cryp_end(struct stm32_cryp_context *ctx, TEE_Result prev_error)
3445e64ae67SNicolas Toromanoff {
34514d68630SThomas Bourgoin 	if (prev_error && stm32_cryp_reset())
346047c4fe1SEtienne Carriere 		panic();
3475e64ae67SNicolas Toromanoff 
3485e64ae67SNicolas Toromanoff 	/* Disable the CRYP peripheral */
3495e64ae67SNicolas Toromanoff 	io_clrbits32(ctx->base + _CRYP_CR, _CRYP_CR_CRYPEN);
3505e64ae67SNicolas Toromanoff }
3515e64ae67SNicolas Toromanoff 
cryp_write_iv(struct stm32_cryp_context * ctx)3525e64ae67SNicolas Toromanoff static void cryp_write_iv(struct stm32_cryp_context *ctx)
3535e64ae67SNicolas Toromanoff {
3545e64ae67SNicolas Toromanoff 	if (algo_mode_needs_iv(ctx->cr)) {
3555e64ae67SNicolas Toromanoff 		unsigned int i = 0;
3565e64ae67SNicolas Toromanoff 
3575e64ae67SNicolas Toromanoff 		/* Restore the _CRYP_IVRx */
3585e64ae67SNicolas Toromanoff 		for (i = 0; i < ctx->block_u32; i++)
3595e64ae67SNicolas Toromanoff 			io_write32(ctx->base + _CRYP_IV0LR + i *
3605e64ae67SNicolas Toromanoff 				   sizeof(uint32_t), ctx->iv[i]);
3615e64ae67SNicolas Toromanoff 	}
3625e64ae67SNicolas Toromanoff }
3635e64ae67SNicolas Toromanoff 
cryp_save_suspend(struct stm32_cryp_context * ctx)3645e64ae67SNicolas Toromanoff static void cryp_save_suspend(struct stm32_cryp_context *ctx)
3655e64ae67SNicolas Toromanoff {
3665e64ae67SNicolas Toromanoff 	unsigned int i = 0;
3675e64ae67SNicolas Toromanoff 
3685e64ae67SNicolas Toromanoff 	if (IS_ALGOMODE(ctx->cr, AES_GCM) || IS_ALGOMODE(ctx->cr, AES_CCM))
3695e64ae67SNicolas Toromanoff 		for (i = 0; i < ARRAY_SIZE(ctx->pm_gcmccm); i++)
3705e64ae67SNicolas Toromanoff 			ctx->pm_gcmccm[i] = io_read32(ctx->base +
3715e64ae67SNicolas Toromanoff 						      _CRYP_CSGCMCCM0R +
3725e64ae67SNicolas Toromanoff 						      i * sizeof(uint32_t));
3735e64ae67SNicolas Toromanoff 
3745e64ae67SNicolas Toromanoff 	if (IS_ALGOMODE(ctx->cr, AES_GCM))
3755e64ae67SNicolas Toromanoff 		for (i = 0; i < ARRAY_SIZE(ctx->pm_gcm); i++)
3765e64ae67SNicolas Toromanoff 			ctx->pm_gcm[i] = io_read32(ctx->base + _CRYP_CSGCM0R +
3775e64ae67SNicolas Toromanoff 						   i * sizeof(uint32_t));
3785e64ae67SNicolas Toromanoff }
3795e64ae67SNicolas Toromanoff 
cryp_restore_suspend(struct stm32_cryp_context * ctx)3805e64ae67SNicolas Toromanoff static void cryp_restore_suspend(struct stm32_cryp_context *ctx)
3815e64ae67SNicolas Toromanoff {
3825e64ae67SNicolas Toromanoff 	unsigned int i = 0;
3835e64ae67SNicolas Toromanoff 
3845e64ae67SNicolas Toromanoff 	if (IS_ALGOMODE(ctx->cr, AES_GCM) || IS_ALGOMODE(ctx->cr, AES_CCM))
3855e64ae67SNicolas Toromanoff 		for (i = 0; i < ARRAY_SIZE(ctx->pm_gcmccm); i++)
3865e64ae67SNicolas Toromanoff 			io_write32(ctx->base + _CRYP_CSGCMCCM0R +
3875e64ae67SNicolas Toromanoff 				   i * sizeof(uint32_t), ctx->pm_gcmccm[i]);
3885e64ae67SNicolas Toromanoff 
3895e64ae67SNicolas Toromanoff 	if (IS_ALGOMODE(ctx->cr, AES_GCM))
3905e64ae67SNicolas Toromanoff 		for (i = 0; i < ARRAY_SIZE(ctx->pm_gcm); i++)
3915e64ae67SNicolas Toromanoff 			io_write32(ctx->base + _CRYP_CSGCM0R +
3925e64ae67SNicolas Toromanoff 				   i * sizeof(uint32_t), ctx->pm_gcm[i]);
3935e64ae67SNicolas Toromanoff }
3945e64ae67SNicolas Toromanoff 
cryp_write_key(struct stm32_cryp_context * ctx)3955e64ae67SNicolas Toromanoff static void cryp_write_key(struct stm32_cryp_context *ctx)
3965e64ae67SNicolas Toromanoff {
3975e64ae67SNicolas Toromanoff 	vaddr_t reg = 0;
3985e64ae67SNicolas Toromanoff 	int i = 0;
3995e64ae67SNicolas Toromanoff 	uint32_t algo = GET_ALGOMODE(ctx->cr);
4005e64ae67SNicolas Toromanoff 
4015e64ae67SNicolas Toromanoff 	if (algo == _CRYP_CR_ALGOMODE_DES_ECB ||
4025e64ae67SNicolas Toromanoff 	    algo == _CRYP_CR_ALGOMODE_DES_CBC)
4035e64ae67SNicolas Toromanoff 		reg = ctx->base + _CRYP_K1RR;
4045e64ae67SNicolas Toromanoff 	else
4055e64ae67SNicolas Toromanoff 		reg = ctx->base + _CRYP_K3RR;
4065e64ae67SNicolas Toromanoff 
4075e64ae67SNicolas Toromanoff 	for (i = ctx->key_size / sizeof(uint32_t) - 1;
4085e64ae67SNicolas Toromanoff 	     i >= 0;
4095e64ae67SNicolas Toromanoff 	     i--, reg -= sizeof(uint32_t))
4105e64ae67SNicolas Toromanoff 		io_write32(reg, ctx->key[i]);
4115e64ae67SNicolas Toromanoff }
4125e64ae67SNicolas Toromanoff 
cryp_prepare_key(struct stm32_cryp_context * ctx)4135e64ae67SNicolas Toromanoff static TEE_Result cryp_prepare_key(struct stm32_cryp_context *ctx)
4145e64ae67SNicolas Toromanoff {
4155e64ae67SNicolas Toromanoff 	TEE_Result res = TEE_SUCCESS;
4165e64ae67SNicolas Toromanoff 
4175e64ae67SNicolas Toromanoff 	/*
4185e64ae67SNicolas Toromanoff 	 * For AES ECB/CBC decryption, key preparation mode must be selected
4195e64ae67SNicolas Toromanoff 	 * to populate the key.
4205e64ae67SNicolas Toromanoff 	 */
4215e64ae67SNicolas Toromanoff 	if (is_decrypt(ctx->cr) && (IS_ALGOMODE(ctx->cr, AES_ECB) ||
4225e64ae67SNicolas Toromanoff 				    IS_ALGOMODE(ctx->cr, AES_CBC))) {
4235e64ae67SNicolas Toromanoff 		/* Select Algomode "prepare key" */
4245e64ae67SNicolas Toromanoff 		io_clrsetbits32(ctx->base + _CRYP_CR, _CRYP_CR_ALGOMODE_MSK,
4255e64ae67SNicolas Toromanoff 				_CRYP_CR_ALGOMODE_AES << _CRYP_CR_ALGOMODE_OFF);
4265e64ae67SNicolas Toromanoff 
4275e64ae67SNicolas Toromanoff 		cryp_write_key(ctx);
4285e64ae67SNicolas Toromanoff 
4295e64ae67SNicolas Toromanoff 		/* Enable CRYP */
4305e64ae67SNicolas Toromanoff 		io_setbits32(ctx->base + _CRYP_CR, _CRYP_CR_CRYPEN);
4315e64ae67SNicolas Toromanoff 
4325e64ae67SNicolas Toromanoff 		res = wait_end_busy(ctx->base);
4335e64ae67SNicolas Toromanoff 		if (res)
4345e64ae67SNicolas Toromanoff 			return res;
4355e64ae67SNicolas Toromanoff 
4365e64ae67SNicolas Toromanoff 		/* Reset 'real' algomode */
4375e64ae67SNicolas Toromanoff 		io_clrsetbits32(ctx->base + _CRYP_CR, _CRYP_CR_ALGOMODE_MSK,
4385e64ae67SNicolas Toromanoff 				ctx->cr & _CRYP_CR_ALGOMODE_MSK);
4395e64ae67SNicolas Toromanoff 	} else {
4405e64ae67SNicolas Toromanoff 		cryp_write_key(ctx);
4415e64ae67SNicolas Toromanoff 	}
4425e64ae67SNicolas Toromanoff 
4435e64ae67SNicolas Toromanoff 	return TEE_SUCCESS;
4445e64ae67SNicolas Toromanoff }
4455e64ae67SNicolas Toromanoff 
save_context(struct stm32_cryp_context * ctx)4465e64ae67SNicolas Toromanoff static TEE_Result save_context(struct stm32_cryp_context *ctx)
4475e64ae67SNicolas Toromanoff {
4485e64ae67SNicolas Toromanoff 	/* Device should not be in a processing phase */
4495e64ae67SNicolas Toromanoff 	if (io_read32(ctx->base + _CRYP_SR) & _CRYP_SR_BUSY)
4505e64ae67SNicolas Toromanoff 		return TEE_ERROR_BAD_STATE;
4515e64ae67SNicolas Toromanoff 
4525e64ae67SNicolas Toromanoff 	/* Disable the CRYP peripheral */
4535e64ae67SNicolas Toromanoff 	io_clrbits32(ctx->base + _CRYP_CR, _CRYP_CR_CRYPEN);
4545e64ae67SNicolas Toromanoff 
4555e64ae67SNicolas Toromanoff 	/* Save CR */
4565e64ae67SNicolas Toromanoff 	ctx->cr = io_read32(ctx->base + _CRYP_CR);
4575e64ae67SNicolas Toromanoff 
4585e64ae67SNicolas Toromanoff 	cryp_save_suspend(ctx);
4595e64ae67SNicolas Toromanoff 
4605e64ae67SNicolas Toromanoff 	/* If algo mode needs to save current IV */
4615e64ae67SNicolas Toromanoff 	if (algo_mode_needs_iv(ctx->cr)) {
4625e64ae67SNicolas Toromanoff 		unsigned int i = 0;
4635e64ae67SNicolas Toromanoff 
4645e64ae67SNicolas Toromanoff 		/* Save IV */
4655e64ae67SNicolas Toromanoff 		for (i = 0; i < ctx->block_u32; i++)
4665e64ae67SNicolas Toromanoff 			ctx->iv[i] = io_read32(ctx->base + _CRYP_IV0LR + i *
4675e64ae67SNicolas Toromanoff 					       sizeof(uint32_t));
4685e64ae67SNicolas Toromanoff 	}
4695e64ae67SNicolas Toromanoff 
4705e64ae67SNicolas Toromanoff 	return TEE_SUCCESS;
4715e64ae67SNicolas Toromanoff }
4725e64ae67SNicolas Toromanoff 
4735e64ae67SNicolas Toromanoff /* To resume the processing of a message */
restore_context(struct stm32_cryp_context * ctx)4745e64ae67SNicolas Toromanoff static TEE_Result restore_context(struct stm32_cryp_context *ctx)
4755e64ae67SNicolas Toromanoff {
4765e64ae67SNicolas Toromanoff 	TEE_Result res = TEE_SUCCESS;
4775e64ae67SNicolas Toromanoff 
4785e64ae67SNicolas Toromanoff 	/* IP should be disabled */
4795e64ae67SNicolas Toromanoff 	if (io_read32(ctx->base + _CRYP_CR) & _CRYP_CR_CRYPEN) {
4805e64ae67SNicolas Toromanoff 		DMSG("Device is still enabled");
4815e64ae67SNicolas Toromanoff 		return TEE_ERROR_BAD_STATE;
4825e64ae67SNicolas Toromanoff 	}
4835e64ae67SNicolas Toromanoff 
4845e64ae67SNicolas Toromanoff 	/* Restore the _CRYP_CR */
4855e64ae67SNicolas Toromanoff 	io_write32(ctx->base + _CRYP_CR, ctx->cr);
4865e64ae67SNicolas Toromanoff 
4875e64ae67SNicolas Toromanoff 	/* Write key and, in case of AES_CBC or AES_ECB decrypt, prepare it */
4885e64ae67SNicolas Toromanoff 	res = cryp_prepare_key(ctx);
4895e64ae67SNicolas Toromanoff 	if (res)
4905e64ae67SNicolas Toromanoff 		return res;
4915e64ae67SNicolas Toromanoff 
4925e64ae67SNicolas Toromanoff 	cryp_restore_suspend(ctx);
4935e64ae67SNicolas Toromanoff 
4945e64ae67SNicolas Toromanoff 	cryp_write_iv(ctx);
4955e64ae67SNicolas Toromanoff 
4965e64ae67SNicolas Toromanoff 	/* Flush internal fifo */
4975e64ae67SNicolas Toromanoff 	io_setbits32(ctx->base + _CRYP_CR, _CRYP_CR_FFLUSH);
4985e64ae67SNicolas Toromanoff 
4995e64ae67SNicolas Toromanoff 	/* Enable the CRYP peripheral */
5005e64ae67SNicolas Toromanoff 	io_setbits32(ctx->base + _CRYP_CR, _CRYP_CR_CRYPEN);
5015e64ae67SNicolas Toromanoff 
5025e64ae67SNicolas Toromanoff 	return TEE_SUCCESS;
5035e64ae67SNicolas Toromanoff }
5045e64ae67SNicolas Toromanoff 
5055e64ae67SNicolas Toromanoff /*
5065e64ae67SNicolas Toromanoff  * Translate a byte index in an array of BE uint32_t into the index of same
5075e64ae67SNicolas Toromanoff  * byte in the corresponding LE uint32_t array.
5085e64ae67SNicolas Toromanoff  */
be_index(size_t index)5095e64ae67SNicolas Toromanoff static size_t be_index(size_t index)
5105e64ae67SNicolas Toromanoff {
5115e64ae67SNicolas Toromanoff 	return (index & ~0x3) + 3 - (index & 0x3);
5125e64ae67SNicolas Toromanoff }
5135e64ae67SNicolas Toromanoff 
ccm_first_context(struct stm32_cryp_context * ctx)5145e64ae67SNicolas Toromanoff static TEE_Result ccm_first_context(struct stm32_cryp_context *ctx)
5155e64ae67SNicolas Toromanoff {
5165e64ae67SNicolas Toromanoff 	TEE_Result res = TEE_SUCCESS;
5175e64ae67SNicolas Toromanoff 	uint32_t b0[AES_BLOCK_NB_U32] = { 0 };
5185e64ae67SNicolas Toromanoff 	uint8_t *iv = (uint8_t *)ctx->iv;
5195e64ae67SNicolas Toromanoff 	size_t l = 0;
5205e64ae67SNicolas Toromanoff 	size_t i = 15;
5215e64ae67SNicolas Toromanoff 
5225e64ae67SNicolas Toromanoff 	/* IP should be disabled */
5235e64ae67SNicolas Toromanoff 	if (io_read32(ctx->base + _CRYP_CR) & _CRYP_CR_CRYPEN)
5245e64ae67SNicolas Toromanoff 		return TEE_ERROR_BAD_STATE;
5255e64ae67SNicolas Toromanoff 
5265e64ae67SNicolas Toromanoff 	/* Write the _CRYP_CR */
5275e64ae67SNicolas Toromanoff 	io_write32(ctx->base + _CRYP_CR, ctx->cr);
5285e64ae67SNicolas Toromanoff 
5295e64ae67SNicolas Toromanoff 	/* Write key */
5305e64ae67SNicolas Toromanoff 	res = cryp_prepare_key(ctx);
5315e64ae67SNicolas Toromanoff 	if (res)
5325e64ae67SNicolas Toromanoff 		return res;
5335e64ae67SNicolas Toromanoff 
5345e64ae67SNicolas Toromanoff 	/* Save full IV that will be b0 */
5355e64ae67SNicolas Toromanoff 	memcpy(b0, iv, sizeof(b0));
5365e64ae67SNicolas Toromanoff 
5375e64ae67SNicolas Toromanoff 	/*
5385e64ae67SNicolas Toromanoff 	 * Update IV to become CTR0/1 before setting it.
5395e64ae67SNicolas Toromanoff 	 * IV is saved as LE uint32_t[4] as expected by hardware,
5405e64ae67SNicolas Toromanoff 	 * but CCM RFC defines bytes to update in a BE array.
5415e64ae67SNicolas Toromanoff 	 */
5425e64ae67SNicolas Toromanoff 	/* Set flag bits to 0 (5 higher bits), keep 3 low bits */
5435e64ae67SNicolas Toromanoff 	iv[be_index(0)] &= 0x7;
5445e64ae67SNicolas Toromanoff 	/* Get size of length field (can be from 2 to 8) */
5455e64ae67SNicolas Toromanoff 	l = iv[be_index(0)] + 1;
5465e64ae67SNicolas Toromanoff 	/* Set Q to 0 */
5475e64ae67SNicolas Toromanoff 	for (i = 15; i >= 15 - l + 1; i--)
5485e64ae67SNicolas Toromanoff 		iv[be_index(i)] = 0;
5495e64ae67SNicolas Toromanoff 	/* Save CTR0 */
5505e64ae67SNicolas Toromanoff 	memcpy(ctx->ctr0_ccm, iv, sizeof(b0));
5515e64ae67SNicolas Toromanoff 	/* Increment Q */
5525e64ae67SNicolas Toromanoff 	iv[be_index(15)] |= 0x1;
5535e64ae67SNicolas Toromanoff 
5545e64ae67SNicolas Toromanoff 	cryp_write_iv(ctx);
5555e64ae67SNicolas Toromanoff 
5565e64ae67SNicolas Toromanoff 	/* Enable the CRYP peripheral */
5575e64ae67SNicolas Toromanoff 	io_setbits32(ctx->base + _CRYP_CR, _CRYP_CR_CRYPEN);
5585e64ae67SNicolas Toromanoff 
5595e64ae67SNicolas Toromanoff 	res = write_align_block(ctx, b0);
5605e64ae67SNicolas Toromanoff 
5615e64ae67SNicolas Toromanoff 	return res;
5625e64ae67SNicolas Toromanoff }
5635e64ae67SNicolas Toromanoff 
do_from_init_to_phase(struct stm32_cryp_context * ctx,uint32_t new_phase)5645e64ae67SNicolas Toromanoff static TEE_Result do_from_init_to_phase(struct stm32_cryp_context *ctx,
5655e64ae67SNicolas Toromanoff 					uint32_t new_phase)
5665e64ae67SNicolas Toromanoff {
5675e64ae67SNicolas Toromanoff 	TEE_Result res = TEE_SUCCESS;
5685e64ae67SNicolas Toromanoff 
5695e64ae67SNicolas Toromanoff 	/*
5705e64ae67SNicolas Toromanoff 	 * We didn't run the init phase yet
5715e64ae67SNicolas Toromanoff 	 * CCM need a specific restore_context phase for the init phase
5725e64ae67SNicolas Toromanoff 	 */
5735e64ae67SNicolas Toromanoff 	if (IS_ALGOMODE(ctx->cr, AES_CCM))
5745e64ae67SNicolas Toromanoff 		res = ccm_first_context(ctx);
5755e64ae67SNicolas Toromanoff 	else
5765e64ae67SNicolas Toromanoff 		res = restore_context(ctx);
5775e64ae67SNicolas Toromanoff 
5785e64ae67SNicolas Toromanoff 	if (res)
5795e64ae67SNicolas Toromanoff 		return res;
5805e64ae67SNicolas Toromanoff 
5815e64ae67SNicolas Toromanoff 	res = wait_end_enable(ctx->base);
5825e64ae67SNicolas Toromanoff 	if (res)
5835e64ae67SNicolas Toromanoff 		return res;
5845e64ae67SNicolas Toromanoff 
5855e64ae67SNicolas Toromanoff 	/* Move to 'new_phase' */
5865e64ae67SNicolas Toromanoff 	io_clrsetbits32(ctx->base + _CRYP_CR, _CRYP_CR_GCM_CCMPH_MSK,
5875e64ae67SNicolas Toromanoff 			new_phase << _CRYP_CR_GCM_CCMPH_OFF);
5885e64ae67SNicolas Toromanoff 
5895e64ae67SNicolas Toromanoff 	/* Enable the CRYP peripheral (init disabled it) */
5905e64ae67SNicolas Toromanoff 	io_setbits32(ctx->base + _CRYP_CR, _CRYP_CR_CRYPEN);
5915e64ae67SNicolas Toromanoff 
5925e64ae67SNicolas Toromanoff 	return TEE_SUCCESS;
5935e64ae67SNicolas Toromanoff }
5945e64ae67SNicolas Toromanoff 
do_from_header_to_phase(struct stm32_cryp_context * ctx,uint32_t new_phase)5955e64ae67SNicolas Toromanoff static TEE_Result do_from_header_to_phase(struct stm32_cryp_context *ctx,
5965e64ae67SNicolas Toromanoff 					  uint32_t new_phase)
5975e64ae67SNicolas Toromanoff {
5985e64ae67SNicolas Toromanoff 	TEE_Result res = TEE_SUCCESS;
5995e64ae67SNicolas Toromanoff 
6005e64ae67SNicolas Toromanoff 	res = restore_context(ctx);
6015e64ae67SNicolas Toromanoff 	if (res)
6025e64ae67SNicolas Toromanoff 		return res;
6035e64ae67SNicolas Toromanoff 
6045e64ae67SNicolas Toromanoff 	if (ctx->extra_size) {
6055e64ae67SNicolas Toromanoff 		/* Manage unaligned header data before moving to next phase */
6065e64ae67SNicolas Toromanoff 		memset((uint8_t *)ctx->extra + ctx->extra_size, 0,
6075e64ae67SNicolas Toromanoff 		       ctx->block_u32 * sizeof(uint32_t) - ctx->extra_size);
6085e64ae67SNicolas Toromanoff 
6095e64ae67SNicolas Toromanoff 		res = write_align_block(ctx, ctx->extra);
6105e64ae67SNicolas Toromanoff 		if (res)
6115e64ae67SNicolas Toromanoff 			return res;
6125e64ae67SNicolas Toromanoff 
6135e64ae67SNicolas Toromanoff 		ctx->assoc_len += (ctx->extra_size) * INT8_BIT;
6145e64ae67SNicolas Toromanoff 		ctx->extra_size = 0;
6155e64ae67SNicolas Toromanoff 	}
6165e64ae67SNicolas Toromanoff 
6175e64ae67SNicolas Toromanoff 	/* Move to 'new_phase' */
6185e64ae67SNicolas Toromanoff 	io_clrsetbits32(ctx->base + _CRYP_CR, _CRYP_CR_GCM_CCMPH_MSK,
6195e64ae67SNicolas Toromanoff 			new_phase << _CRYP_CR_GCM_CCMPH_OFF);
6205e64ae67SNicolas Toromanoff 
6215e64ae67SNicolas Toromanoff 	return TEE_SUCCESS;
6225e64ae67SNicolas Toromanoff }
6235e64ae67SNicolas Toromanoff 
6245e64ae67SNicolas Toromanoff /**
6255e64ae67SNicolas Toromanoff  * @brief Start a AES computation.
6265e64ae67SNicolas Toromanoff  * @param ctx: CRYP process context
6275e64ae67SNicolas Toromanoff  * @param is_dec: true if decryption, false if encryption
6285e64ae67SNicolas Toromanoff  * @param algo: define the algo mode
6295e64ae67SNicolas Toromanoff  * @param key: pointer to key
6305e64ae67SNicolas Toromanoff  * @param key_size: key size
6315e64ae67SNicolas Toromanoff  * @param iv: pointer to initialization vector (unused if algo is ECB)
6325e64ae67SNicolas Toromanoff  * @param iv_size: iv size
6335e64ae67SNicolas Toromanoff  * @note this function doesn't access to hardware but stores in ctx the values
6345e64ae67SNicolas Toromanoff  *
6355e64ae67SNicolas Toromanoff  * @retval TEE_SUCCESS if OK.
6365e64ae67SNicolas Toromanoff  */
stm32_cryp_init(struct stm32_cryp_context * ctx,bool is_dec,enum stm32_cryp_algo_mode algo,const void * key,size_t key_size,const void * iv,size_t iv_size)6375e64ae67SNicolas Toromanoff TEE_Result stm32_cryp_init(struct stm32_cryp_context *ctx, bool is_dec,
6385e64ae67SNicolas Toromanoff 			   enum stm32_cryp_algo_mode algo,
6395e64ae67SNicolas Toromanoff 			   const void *key, size_t key_size, const void *iv,
6405e64ae67SNicolas Toromanoff 			   size_t iv_size)
6415e64ae67SNicolas Toromanoff {
6425e64ae67SNicolas Toromanoff 	unsigned int i = 0;
6435e64ae67SNicolas Toromanoff 	const uint32_t *iv_u32 = NULL;
6445e64ae67SNicolas Toromanoff 	uint32_t local_iv[4] = { 0 };
6455e64ae67SNicolas Toromanoff 	const uint32_t *key_u32 = NULL;
6465e64ae67SNicolas Toromanoff 	uint32_t local_key[8] = { 0 };
6475e64ae67SNicolas Toromanoff 
6485e64ae67SNicolas Toromanoff 	ctx->assoc_len = 0;
6495e64ae67SNicolas Toromanoff 	ctx->load_len = 0;
6505e64ae67SNicolas Toromanoff 	ctx->extra_size = 0;
6515e64ae67SNicolas Toromanoff 	ctx->lock = &cryp_lock;
6525e64ae67SNicolas Toromanoff 
6535e64ae67SNicolas Toromanoff 	ctx->base = io_pa_or_va(&cryp_pdata.base, 1);
6545e64ae67SNicolas Toromanoff 	ctx->cr = _CRYP_CR_RESET_VALUE;
6555e64ae67SNicolas Toromanoff 
6565e64ae67SNicolas Toromanoff 	/* We want buffer to be u32 aligned */
6575e64ae67SNicolas Toromanoff 	if (IS_ALIGNED_WITH_TYPE(key, uint32_t)) {
6585e64ae67SNicolas Toromanoff 		key_u32 = key;
6595e64ae67SNicolas Toromanoff 	} else {
6605e64ae67SNicolas Toromanoff 		memcpy(local_key, key, key_size);
6615e64ae67SNicolas Toromanoff 		key_u32 = local_key;
6625e64ae67SNicolas Toromanoff 	}
6635e64ae67SNicolas Toromanoff 
6645e64ae67SNicolas Toromanoff 	if (IS_ALIGNED_WITH_TYPE(iv, uint32_t)) {
6655e64ae67SNicolas Toromanoff 		iv_u32 = iv;
6665e64ae67SNicolas Toromanoff 	} else {
6675e64ae67SNicolas Toromanoff 		memcpy(local_iv, iv, iv_size);
6685e64ae67SNicolas Toromanoff 		iv_u32 = local_iv;
6695e64ae67SNicolas Toromanoff 	}
6705e64ae67SNicolas Toromanoff 
6715e64ae67SNicolas Toromanoff 	if (is_dec)
6725e64ae67SNicolas Toromanoff 		SETBITS(ctx->cr, _CRYP_CR_ALGODIR);
6735e64ae67SNicolas Toromanoff 	else
6745e64ae67SNicolas Toromanoff 		CLRBITS(ctx->cr, _CRYP_CR_ALGODIR);
6755e64ae67SNicolas Toromanoff 
6765e64ae67SNicolas Toromanoff 	/* Save algo mode */
6775e64ae67SNicolas Toromanoff 	switch (algo) {
6785e64ae67SNicolas Toromanoff 	case STM32_CRYP_MODE_TDES_ECB:
6795e64ae67SNicolas Toromanoff 		SET_ALGOMODE(TDES_ECB, ctx->cr);
6805e64ae67SNicolas Toromanoff 		break;
6815e64ae67SNicolas Toromanoff 	case STM32_CRYP_MODE_TDES_CBC:
6825e64ae67SNicolas Toromanoff 		SET_ALGOMODE(TDES_CBC, ctx->cr);
6835e64ae67SNicolas Toromanoff 		break;
6845e64ae67SNicolas Toromanoff 	case STM32_CRYP_MODE_DES_ECB:
6855e64ae67SNicolas Toromanoff 		SET_ALGOMODE(DES_ECB, ctx->cr);
6865e64ae67SNicolas Toromanoff 		break;
6875e64ae67SNicolas Toromanoff 	case STM32_CRYP_MODE_DES_CBC:
6885e64ae67SNicolas Toromanoff 		SET_ALGOMODE(DES_CBC, ctx->cr);
6895e64ae67SNicolas Toromanoff 		break;
6905e64ae67SNicolas Toromanoff 	case STM32_CRYP_MODE_AES_ECB:
6915e64ae67SNicolas Toromanoff 		SET_ALGOMODE(AES_ECB, ctx->cr);
6925e64ae67SNicolas Toromanoff 		break;
6935e64ae67SNicolas Toromanoff 	case STM32_CRYP_MODE_AES_CBC:
6945e64ae67SNicolas Toromanoff 		SET_ALGOMODE(AES_CBC, ctx->cr);
6955e64ae67SNicolas Toromanoff 		break;
6965e64ae67SNicolas Toromanoff 	case STM32_CRYP_MODE_AES_CTR:
6975e64ae67SNicolas Toromanoff 		SET_ALGOMODE(AES_CTR, ctx->cr);
6985e64ae67SNicolas Toromanoff 		break;
6995e64ae67SNicolas Toromanoff 	case STM32_CRYP_MODE_AES_GCM:
7005e64ae67SNicolas Toromanoff 		SET_ALGOMODE(AES_GCM, ctx->cr);
7015e64ae67SNicolas Toromanoff 		break;
7025e64ae67SNicolas Toromanoff 	case STM32_CRYP_MODE_AES_CCM:
7035e64ae67SNicolas Toromanoff 		SET_ALGOMODE(AES_CCM, ctx->cr);
7045e64ae67SNicolas Toromanoff 		break;
7055e64ae67SNicolas Toromanoff 	default:
7065e64ae67SNicolas Toromanoff 		return TEE_ERROR_BAD_PARAMETERS;
7075e64ae67SNicolas Toromanoff 	}
7085e64ae67SNicolas Toromanoff 
7095e64ae67SNicolas Toromanoff 	/*
7105e64ae67SNicolas Toromanoff 	 * We will use HW Byte swap (_CRYP_CR_DATATYPE_BYTE) for data.
7115e64ae67SNicolas Toromanoff 	 * So we won't need to
7124320f5cfSThomas Bourgoin 	 * TEE_U32_TO_BIG_ENDIAN(data) before write to DIN register
7135e64ae67SNicolas Toromanoff 	 * nor
7144320f5cfSThomas Bourgoin 	 * TEE_U32_FROM_BIG_ENDIAN after reading from DOUT register.
7155e64ae67SNicolas Toromanoff 	 */
7165e64ae67SNicolas Toromanoff 	clrsetbits(&ctx->cr, _CRYP_CR_DATATYPE_MSK,
7175e64ae67SNicolas Toromanoff 		   _CRYP_CR_DATATYPE_BYTE << _CRYP_CR_DATATYPE_OFF);
7185e64ae67SNicolas Toromanoff 
7195e64ae67SNicolas Toromanoff 	/*
7205e64ae67SNicolas Toromanoff 	 * Configure keysize for AES algorithms
7215e64ae67SNicolas Toromanoff 	 * And save block size
7225e64ae67SNicolas Toromanoff 	 */
7235e64ae67SNicolas Toromanoff 	if (algo_mode_is_aes(ctx->cr)) {
7245e64ae67SNicolas Toromanoff 		switch (key_size) {
7255e64ae67SNicolas Toromanoff 		case AES_KEYSIZE_128:
7265e64ae67SNicolas Toromanoff 			clrsetbits(&ctx->cr, _CRYP_CR_KEYSIZE_MSK,
7275e64ae67SNicolas Toromanoff 				   _CRYP_CR_KSIZE_128 << _CRYP_CR_KEYSIZE_OFF);
7285e64ae67SNicolas Toromanoff 			break;
7295e64ae67SNicolas Toromanoff 		case AES_KEYSIZE_192:
7305e64ae67SNicolas Toromanoff 			clrsetbits(&ctx->cr, _CRYP_CR_KEYSIZE_MSK,
7315e64ae67SNicolas Toromanoff 				   _CRYP_CR_KSIZE_192 << _CRYP_CR_KEYSIZE_OFF);
7325e64ae67SNicolas Toromanoff 			break;
7335e64ae67SNicolas Toromanoff 		case AES_KEYSIZE_256:
7345e64ae67SNicolas Toromanoff 			clrsetbits(&ctx->cr, _CRYP_CR_KEYSIZE_MSK,
7355e64ae67SNicolas Toromanoff 				   _CRYP_CR_KSIZE_256 << _CRYP_CR_KEYSIZE_OFF);
7365e64ae67SNicolas Toromanoff 			break;
7375e64ae67SNicolas Toromanoff 		default:
7385e64ae67SNicolas Toromanoff 			return TEE_ERROR_BAD_PARAMETERS;
7395e64ae67SNicolas Toromanoff 		}
7405e64ae67SNicolas Toromanoff 
7415e64ae67SNicolas Toromanoff 		/* And set block size */
7425e64ae67SNicolas Toromanoff 		ctx->block_u32 = AES_BLOCK_NB_U32;
7435e64ae67SNicolas Toromanoff 	} else {
7445e64ae67SNicolas Toromanoff 		/* And set DES/TDES block size */
7455e64ae67SNicolas Toromanoff 		ctx->block_u32 = DES_BLOCK_NB_U32;
7465e64ae67SNicolas Toromanoff 	}
7475e64ae67SNicolas Toromanoff 
7485e64ae67SNicolas Toromanoff 	/* Save key in HW order */
7495e64ae67SNicolas Toromanoff 	ctx->key_size = key_size;
7505e64ae67SNicolas Toromanoff 	for (i = 0; i < key_size / sizeof(uint32_t); i++)
7514320f5cfSThomas Bourgoin 		ctx->key[i] = TEE_U32_TO_BIG_ENDIAN(key_u32[i]);
7525e64ae67SNicolas Toromanoff 
7535e64ae67SNicolas Toromanoff 	/* Save IV */
7545e64ae67SNicolas Toromanoff 	if (algo_mode_needs_iv(ctx->cr)) {
7555e64ae67SNicolas Toromanoff 		if (!iv || iv_size != ctx->block_u32 * sizeof(uint32_t))
7565e64ae67SNicolas Toromanoff 			return TEE_ERROR_BAD_PARAMETERS;
7575e64ae67SNicolas Toromanoff 
7585e64ae67SNicolas Toromanoff 		/*
7595e64ae67SNicolas Toromanoff 		 * We save IV in the byte order expected by the
7605e64ae67SNicolas Toromanoff 		 * IV registers
7615e64ae67SNicolas Toromanoff 		 */
7625e64ae67SNicolas Toromanoff 		for (i = 0; i < ctx->block_u32; i++)
7634320f5cfSThomas Bourgoin 			ctx->iv[i] = TEE_U32_TO_BIG_ENDIAN(iv_u32[i]);
7645e64ae67SNicolas Toromanoff 	}
7655e64ae67SNicolas Toromanoff 
7665e64ae67SNicolas Toromanoff 	/* Reset suspend registers */
7675e64ae67SNicolas Toromanoff 	memset(ctx->pm_gcmccm, 0, sizeof(ctx->pm_gcmccm));
7685e64ae67SNicolas Toromanoff 	memset(ctx->pm_gcm, 0, sizeof(ctx->pm_gcm));
7695e64ae67SNicolas Toromanoff 
7705e64ae67SNicolas Toromanoff 	return TEE_SUCCESS;
7715e64ae67SNicolas Toromanoff }
7725e64ae67SNicolas Toromanoff 
7735e64ae67SNicolas Toromanoff /**
7745e64ae67SNicolas Toromanoff  * @brief Update (or start) a AES authenticate process of
7755e64ae67SNicolas Toromanoff  *        associated data (CCM or GCM).
7765e64ae67SNicolas Toromanoff  * @param ctx: CRYP process context
7775e64ae67SNicolas Toromanoff  * @param data: pointer to associated data
7785e64ae67SNicolas Toromanoff  * @param data_size: data size
7795e64ae67SNicolas Toromanoff  * @retval TEE_SUCCESS if OK.
7805e64ae67SNicolas Toromanoff  */
stm32_cryp_update_assodata(struct stm32_cryp_context * ctx,uint8_t * data,size_t data_size)7815e64ae67SNicolas Toromanoff TEE_Result stm32_cryp_update_assodata(struct stm32_cryp_context *ctx,
7825e64ae67SNicolas Toromanoff 				      uint8_t *data, size_t data_size)
7835e64ae67SNicolas Toromanoff {
7845e64ae67SNicolas Toromanoff 	TEE_Result res = TEE_SUCCESS;
7855e64ae67SNicolas Toromanoff 	unsigned int i = 0;
7865e64ae67SNicolas Toromanoff 	uint32_t previous_phase = 0;
7875e64ae67SNicolas Toromanoff 
7885e64ae67SNicolas Toromanoff 	/* If no associated data, nothing to do */
7895e64ae67SNicolas Toromanoff 	if (!data || !data_size)
7905e64ae67SNicolas Toromanoff 		return TEE_SUCCESS;
7915e64ae67SNicolas Toromanoff 
7925e64ae67SNicolas Toromanoff 	mutex_lock(ctx->lock);
7935e64ae67SNicolas Toromanoff 
7945e64ae67SNicolas Toromanoff 	previous_phase = (ctx->cr & _CRYP_CR_GCM_CCMPH_MSK) >>
7955e64ae67SNicolas Toromanoff 			 _CRYP_CR_GCM_CCMPH_OFF;
7965e64ae67SNicolas Toromanoff 
7975e64ae67SNicolas Toromanoff 	switch (previous_phase) {
7985e64ae67SNicolas Toromanoff 	case _CRYP_CR_GCM_CCMPH_INIT:
7995e64ae67SNicolas Toromanoff 		res = do_from_init_to_phase(ctx, _CRYP_CR_GCM_CCMPH_HEADER);
8005e64ae67SNicolas Toromanoff 		break;
8015e64ae67SNicolas Toromanoff 	case _CRYP_CR_GCM_CCMPH_HEADER:
8025e64ae67SNicolas Toromanoff 		/*
8035e64ae67SNicolas Toromanoff 		 * Function update_assodata was already called.
8045e64ae67SNicolas Toromanoff 		 * We only need to restore the context.
8055e64ae67SNicolas Toromanoff 		 */
8065e64ae67SNicolas Toromanoff 		res = restore_context(ctx);
8075e64ae67SNicolas Toromanoff 		break;
8085e64ae67SNicolas Toromanoff 	default:
8095e64ae67SNicolas Toromanoff 		assert(0);
8105e64ae67SNicolas Toromanoff 		res = TEE_ERROR_BAD_STATE;
8115e64ae67SNicolas Toromanoff 	}
8125e64ae67SNicolas Toromanoff 
8135e64ae67SNicolas Toromanoff 	if (res)
8145e64ae67SNicolas Toromanoff 		goto out;
8155e64ae67SNicolas Toromanoff 
8165e64ae67SNicolas Toromanoff 	/* Manage if remaining data from a previous update_assodata call */
8175e64ae67SNicolas Toromanoff 	if (ctx->extra_size &&
8185e64ae67SNicolas Toromanoff 	    (ctx->extra_size + data_size >=
8195e64ae67SNicolas Toromanoff 	     ctx->block_u32 * sizeof(uint32_t))) {
8205e64ae67SNicolas Toromanoff 		uint32_t block[MAX_BLOCK_NB_U32] = { 0 };
8215e64ae67SNicolas Toromanoff 
8225e64ae67SNicolas Toromanoff 		memcpy(block, ctx->extra, ctx->extra_size);
8235e64ae67SNicolas Toromanoff 		memcpy((uint8_t *)block + ctx->extra_size, data,
8245e64ae67SNicolas Toromanoff 		       ctx->block_u32 * sizeof(uint32_t) - ctx->extra_size);
8255e64ae67SNicolas Toromanoff 
8265e64ae67SNicolas Toromanoff 		res = write_align_block(ctx, block);
8275e64ae67SNicolas Toromanoff 		if (res)
8285e64ae67SNicolas Toromanoff 			goto out;
8295e64ae67SNicolas Toromanoff 
8305e64ae67SNicolas Toromanoff 		i += ctx->block_u32 * sizeof(uint32_t) - ctx->extra_size;
8315e64ae67SNicolas Toromanoff 		ctx->extra_size = 0;
8325e64ae67SNicolas Toromanoff 		ctx->assoc_len += ctx->block_u32 * sizeof(uint32_t) * INT8_BIT;
8335e64ae67SNicolas Toromanoff 	}
8345e64ae67SNicolas Toromanoff 
8355e64ae67SNicolas Toromanoff 	while (data_size - i >= ctx->block_u32 * sizeof(uint32_t)) {
8365e64ae67SNicolas Toromanoff 		res = write_block(ctx, data + i);
8375e64ae67SNicolas Toromanoff 		if (res)
8385e64ae67SNicolas Toromanoff 			goto out;
8395e64ae67SNicolas Toromanoff 
8405e64ae67SNicolas Toromanoff 		/* Process next block */
8415e64ae67SNicolas Toromanoff 		i += ctx->block_u32 * sizeof(uint32_t);
8425e64ae67SNicolas Toromanoff 		ctx->assoc_len += ctx->block_u32 * sizeof(uint32_t) * INT8_BIT;
8435e64ae67SNicolas Toromanoff 	}
8445e64ae67SNicolas Toromanoff 
8455e64ae67SNicolas Toromanoff 	/*
8465e64ae67SNicolas Toromanoff 	 * Manage last block if not a block size multiple:
8475e64ae67SNicolas Toromanoff 	 * Save remaining data to manage them later (potentially with new
8485e64ae67SNicolas Toromanoff 	 * associated data).
8495e64ae67SNicolas Toromanoff 	 */
8505e64ae67SNicolas Toromanoff 	if (i < data_size) {
8515e64ae67SNicolas Toromanoff 		memcpy((uint8_t *)ctx->extra + ctx->extra_size, data + i,
8525e64ae67SNicolas Toromanoff 		       data_size - i);
8535e64ae67SNicolas Toromanoff 		ctx->extra_size += data_size - i;
8545e64ae67SNicolas Toromanoff 	}
8555e64ae67SNicolas Toromanoff 
8565e64ae67SNicolas Toromanoff 	res = save_context(ctx);
8575e64ae67SNicolas Toromanoff out:
8585e64ae67SNicolas Toromanoff 	if (res)
8595e64ae67SNicolas Toromanoff 		cryp_end(ctx, res);
8605e64ae67SNicolas Toromanoff 
8615e64ae67SNicolas Toromanoff 	mutex_unlock(ctx->lock);
8625e64ae67SNicolas Toromanoff 
8635e64ae67SNicolas Toromanoff 	return res;
8645e64ae67SNicolas Toromanoff }
8655e64ae67SNicolas Toromanoff 
8665e64ae67SNicolas Toromanoff /**
8675e64ae67SNicolas Toromanoff  * @brief Update (or start) a AES authenticate and de/encrypt with
8685e64ae67SNicolas Toromanoff  *        payload data (CCM or GCM).
8695e64ae67SNicolas Toromanoff  * @param ctx: CRYP process context
8705e64ae67SNicolas Toromanoff  * @param data_in: pointer to payload
8715e64ae67SNicolas Toromanoff  * @param data_out: pointer where to save de/encrypted payload
8725e64ae67SNicolas Toromanoff  * @param data_size: payload size
8735e64ae67SNicolas Toromanoff  *
8745e64ae67SNicolas Toromanoff  * @retval TEE_SUCCESS if OK.
8755e64ae67SNicolas Toromanoff  */
stm32_cryp_update_load(struct stm32_cryp_context * ctx,uint8_t * data_in,uint8_t * data_out,size_t data_size)8765e64ae67SNicolas Toromanoff TEE_Result stm32_cryp_update_load(struct stm32_cryp_context *ctx,
8775e64ae67SNicolas Toromanoff 				  uint8_t *data_in, uint8_t *data_out,
8785e64ae67SNicolas Toromanoff 				  size_t data_size)
8795e64ae67SNicolas Toromanoff {
8805e64ae67SNicolas Toromanoff 	TEE_Result res = TEE_SUCCESS;
8815e64ae67SNicolas Toromanoff 	unsigned int i = 0;
8825e64ae67SNicolas Toromanoff 	uint32_t previous_phase = 0;
8835e64ae67SNicolas Toromanoff 
8845e64ae67SNicolas Toromanoff 	if (!data_in || !data_size)
8855e64ae67SNicolas Toromanoff 		return TEE_SUCCESS;
8865e64ae67SNicolas Toromanoff 
8875e64ae67SNicolas Toromanoff 	mutex_lock(ctx->lock);
8885e64ae67SNicolas Toromanoff 
8895e64ae67SNicolas Toromanoff 	previous_phase = (ctx->cr & _CRYP_CR_GCM_CCMPH_MSK) >>
8905e64ae67SNicolas Toromanoff 			 _CRYP_CR_GCM_CCMPH_OFF;
8915e64ae67SNicolas Toromanoff 
8925e64ae67SNicolas Toromanoff 	switch (previous_phase) {
8935e64ae67SNicolas Toromanoff 	case _CRYP_CR_GCM_CCMPH_INIT:
8945e64ae67SNicolas Toromanoff 		res = do_from_init_to_phase(ctx, _CRYP_CR_GCM_CCMPH_PAYLOAD);
8955e64ae67SNicolas Toromanoff 		break;
8965e64ae67SNicolas Toromanoff 	case _CRYP_CR_GCM_CCMPH_HEADER:
8975e64ae67SNicolas Toromanoff 		res = do_from_header_to_phase(ctx, _CRYP_CR_GCM_CCMPH_PAYLOAD);
8985e64ae67SNicolas Toromanoff 		break;
8995e64ae67SNicolas Toromanoff 	case _CRYP_CR_GCM_CCMPH_PAYLOAD:
9005e64ae67SNicolas Toromanoff 		/* new update_load call, we only need to restore context */
9015e64ae67SNicolas Toromanoff 		res = restore_context(ctx);
9025e64ae67SNicolas Toromanoff 		break;
9035e64ae67SNicolas Toromanoff 	default:
9045e64ae67SNicolas Toromanoff 		assert(0);
9055e64ae67SNicolas Toromanoff 		res = TEE_ERROR_BAD_STATE;
9065e64ae67SNicolas Toromanoff 	}
9075e64ae67SNicolas Toromanoff 
9085e64ae67SNicolas Toromanoff 	if (res)
9095e64ae67SNicolas Toromanoff 		goto out;
9105e64ae67SNicolas Toromanoff 
9115e64ae67SNicolas Toromanoff 	/* Manage if incomplete block from a previous update_load call */
9125e64ae67SNicolas Toromanoff 	if (ctx->extra_size &&
9135e64ae67SNicolas Toromanoff 	    (ctx->extra_size + data_size >=
9145e64ae67SNicolas Toromanoff 	     ctx->block_u32 * sizeof(uint32_t))) {
9155e64ae67SNicolas Toromanoff 		uint32_t block_out[MAX_BLOCK_NB_U32] = { 0 };
9165e64ae67SNicolas Toromanoff 
9175e64ae67SNicolas Toromanoff 		memcpy((uint8_t *)ctx->extra + ctx->extra_size, data_in + i,
9185e64ae67SNicolas Toromanoff 		       ctx->block_u32 * sizeof(uint32_t) - ctx->extra_size);
9195e64ae67SNicolas Toromanoff 
9205e64ae67SNicolas Toromanoff 		res = write_align_block(ctx, ctx->extra);
9215e64ae67SNicolas Toromanoff 		if (res)
9225e64ae67SNicolas Toromanoff 			goto out;
9235e64ae67SNicolas Toromanoff 
9245e64ae67SNicolas Toromanoff 		res = read_align_block(ctx, block_out);
9255e64ae67SNicolas Toromanoff 		if (res)
9265e64ae67SNicolas Toromanoff 			goto out;
9275e64ae67SNicolas Toromanoff 
9285e64ae67SNicolas Toromanoff 		memcpy(data_out + i, (uint8_t *)block_out + ctx->extra_size,
9295e64ae67SNicolas Toromanoff 		       ctx->block_u32 * sizeof(uint32_t) - ctx->extra_size);
9305e64ae67SNicolas Toromanoff 
9315e64ae67SNicolas Toromanoff 		i += ctx->block_u32 * sizeof(uint32_t) - ctx->extra_size;
9325e64ae67SNicolas Toromanoff 		ctx->extra_size = 0;
9335e64ae67SNicolas Toromanoff 
9345e64ae67SNicolas Toromanoff 		ctx->load_len += ctx->block_u32 * sizeof(uint32_t) * INT8_BIT;
9355e64ae67SNicolas Toromanoff 	}
9365e64ae67SNicolas Toromanoff 
9375e64ae67SNicolas Toromanoff 	while (data_size - i >= ctx->block_u32 * sizeof(uint32_t)) {
9385e64ae67SNicolas Toromanoff 		res = write_block(ctx, data_in + i);
9395e64ae67SNicolas Toromanoff 		if (res)
9405e64ae67SNicolas Toromanoff 			goto out;
9415e64ae67SNicolas Toromanoff 
9425e64ae67SNicolas Toromanoff 		res = read_block(ctx, data_out + i);
9435e64ae67SNicolas Toromanoff 		if (res)
9445e64ae67SNicolas Toromanoff 			goto out;
9455e64ae67SNicolas Toromanoff 
9465e64ae67SNicolas Toromanoff 		/* Process next block */
9475e64ae67SNicolas Toromanoff 		i += ctx->block_u32 * sizeof(uint32_t);
9485e64ae67SNicolas Toromanoff 		ctx->load_len += ctx->block_u32 * sizeof(uint32_t) * INT8_BIT;
9495e64ae67SNicolas Toromanoff 	}
9505e64ae67SNicolas Toromanoff 
9515e64ae67SNicolas Toromanoff 	res = save_context(ctx);
9525e64ae67SNicolas Toromanoff 	if (res)
9535e64ae67SNicolas Toromanoff 		goto out;
9545e64ae67SNicolas Toromanoff 
9555e64ae67SNicolas Toromanoff 	/*
9565e64ae67SNicolas Toromanoff 	 * Manage last block if not a block size multiple
9575e64ae67SNicolas Toromanoff 	 * We saved context,
9585e64ae67SNicolas Toromanoff 	 * Complete block with 0 and send to CRYP to get {en,de}crypted data
9595e64ae67SNicolas Toromanoff 	 * Store data to resend as last block in final()
9605e64ae67SNicolas Toromanoff 	 * or to complete next update_load() to get correct tag.
9615e64ae67SNicolas Toromanoff 	 */
9625e64ae67SNicolas Toromanoff 	if (i < data_size) {
9635e64ae67SNicolas Toromanoff 		uint32_t block_out[MAX_BLOCK_NB_U32] = { 0 };
9645e64ae67SNicolas Toromanoff 		size_t prev_extra_size = ctx->extra_size;
9655e64ae67SNicolas Toromanoff 
9665e64ae67SNicolas Toromanoff 		/* Re-enable the CRYP peripheral */
9675e64ae67SNicolas Toromanoff 		io_setbits32(ctx->base + _CRYP_CR, _CRYP_CR_CRYPEN);
9685e64ae67SNicolas Toromanoff 
9695e64ae67SNicolas Toromanoff 		memcpy((uint8_t *)ctx->extra + ctx->extra_size, data_in + i,
9705e64ae67SNicolas Toromanoff 		       data_size - i);
9715e64ae67SNicolas Toromanoff 		ctx->extra_size += data_size - i;
9725e64ae67SNicolas Toromanoff 		memset((uint8_t *)ctx->extra + ctx->extra_size, 0,
9735e64ae67SNicolas Toromanoff 		       ctx->block_u32 * sizeof(uint32_t) - ctx->extra_size);
9745e64ae67SNicolas Toromanoff 
9755e64ae67SNicolas Toromanoff 		res = write_align_block(ctx, ctx->extra);
9765e64ae67SNicolas Toromanoff 		if (res)
9775e64ae67SNicolas Toromanoff 			goto out;
9785e64ae67SNicolas Toromanoff 
9795e64ae67SNicolas Toromanoff 		res = read_align_block(ctx, block_out);
9805e64ae67SNicolas Toromanoff 		if (res)
9815e64ae67SNicolas Toromanoff 			goto out;
9825e64ae67SNicolas Toromanoff 
9835e64ae67SNicolas Toromanoff 		memcpy(data_out + i, (uint8_t *)block_out + prev_extra_size,
9845e64ae67SNicolas Toromanoff 		       data_size - i);
9855e64ae67SNicolas Toromanoff 
9865e64ae67SNicolas Toromanoff 		/* Disable the CRYP peripheral */
9875e64ae67SNicolas Toromanoff 		io_clrbits32(ctx->base + _CRYP_CR, _CRYP_CR_CRYPEN);
9885e64ae67SNicolas Toromanoff 	}
9895e64ae67SNicolas Toromanoff 
9905e64ae67SNicolas Toromanoff out:
9915e64ae67SNicolas Toromanoff 	if (res)
9925e64ae67SNicolas Toromanoff 		cryp_end(ctx, res);
9935e64ae67SNicolas Toromanoff 
9945e64ae67SNicolas Toromanoff 	mutex_unlock(ctx->lock);
9955e64ae67SNicolas Toromanoff 
9965e64ae67SNicolas Toromanoff 	return res;
9975e64ae67SNicolas Toromanoff }
9985e64ae67SNicolas Toromanoff 
9995e64ae67SNicolas Toromanoff /**
10005e64ae67SNicolas Toromanoff  * @brief Get authentication tag for AES authenticated algorithms (CCM or GCM).
10015e64ae67SNicolas Toromanoff  * @param ctx: CRYP process context
10025e64ae67SNicolas Toromanoff  * @param tag: pointer where to save the tag
10035e64ae67SNicolas Toromanoff  * @param data_size: tag size
10045e64ae67SNicolas Toromanoff  *
10055e64ae67SNicolas Toromanoff  * @retval TEE_SUCCESS if OK.
10065e64ae67SNicolas Toromanoff  */
stm32_cryp_final(struct stm32_cryp_context * ctx,uint8_t * tag,size_t tag_size)10075e64ae67SNicolas Toromanoff TEE_Result stm32_cryp_final(struct stm32_cryp_context *ctx, uint8_t *tag,
10085e64ae67SNicolas Toromanoff 			    size_t tag_size)
10095e64ae67SNicolas Toromanoff {
10105e64ae67SNicolas Toromanoff 	TEE_Result res = TEE_SUCCESS;
10115e64ae67SNicolas Toromanoff 	uint32_t tag_u32[4] = { 0 };
10125e64ae67SNicolas Toromanoff 	uint32_t previous_phase = 0;
10135e64ae67SNicolas Toromanoff 
10145e64ae67SNicolas Toromanoff 	mutex_lock(ctx->lock);
10155e64ae67SNicolas Toromanoff 
10165e64ae67SNicolas Toromanoff 	previous_phase = (ctx->cr & _CRYP_CR_GCM_CCMPH_MSK) >>
10175e64ae67SNicolas Toromanoff 			 _CRYP_CR_GCM_CCMPH_OFF;
10185e64ae67SNicolas Toromanoff 
10195e64ae67SNicolas Toromanoff 	switch (previous_phase) {
10205e64ae67SNicolas Toromanoff 	case _CRYP_CR_GCM_CCMPH_INIT:
10215e64ae67SNicolas Toromanoff 		res = do_from_init_to_phase(ctx, _CRYP_CR_GCM_CCMPH_FINAL);
10225e64ae67SNicolas Toromanoff 		break;
10235e64ae67SNicolas Toromanoff 	case _CRYP_CR_GCM_CCMPH_HEADER:
10245e64ae67SNicolas Toromanoff 		res = do_from_header_to_phase(ctx, _CRYP_CR_GCM_CCMPH_FINAL);
10255e64ae67SNicolas Toromanoff 		break;
10265e64ae67SNicolas Toromanoff 	case _CRYP_CR_GCM_CCMPH_PAYLOAD:
10275e64ae67SNicolas Toromanoff 		res = restore_context(ctx);
10285e64ae67SNicolas Toromanoff 		if (res)
10295e64ae67SNicolas Toromanoff 			break;
10305e64ae67SNicolas Toromanoff 
10315e64ae67SNicolas Toromanoff 		/* Manage if incomplete block from a previous update_load() */
10325e64ae67SNicolas Toromanoff 		if (ctx->extra_size) {
10335e64ae67SNicolas Toromanoff 			uint32_t block_out[MAX_BLOCK_NB_U32] = { 0 };
10345e64ae67SNicolas Toromanoff 			size_t sz = ctx->block_u32 * sizeof(uint32_t) -
10355e64ae67SNicolas Toromanoff 				    ctx->extra_size;
10365e64ae67SNicolas Toromanoff 
10375e64ae67SNicolas Toromanoff 			if (does_need_npblb(ctx->cr)) {
10385e64ae67SNicolas Toromanoff 				io_clrsetbits32(ctx->base + _CRYP_CR,
10395e64ae67SNicolas Toromanoff 						_CRYP_CR_NPBLB_MSK,
10405e64ae67SNicolas Toromanoff 						sz << _CRYP_CR_NPBLB_OFF);
10415e64ae67SNicolas Toromanoff 			}
10425e64ae67SNicolas Toromanoff 
10435e64ae67SNicolas Toromanoff 			memset((uint8_t *)ctx->extra + ctx->extra_size, 0, sz);
10445e64ae67SNicolas Toromanoff 
10455e64ae67SNicolas Toromanoff 			res = write_align_block(ctx, ctx->extra);
10465e64ae67SNicolas Toromanoff 			if (res)
10475e64ae67SNicolas Toromanoff 				break;
10485e64ae67SNicolas Toromanoff 
10495e64ae67SNicolas Toromanoff 			/* Don't care {en,de}crypted data, already saved */
10505e64ae67SNicolas Toromanoff 			res = read_align_block(ctx, block_out);
10515e64ae67SNicolas Toromanoff 			if (res)
10525e64ae67SNicolas Toromanoff 				break;
10535e64ae67SNicolas Toromanoff 
10545e64ae67SNicolas Toromanoff 			ctx->load_len += (ctx->extra_size * INT8_BIT);
10555e64ae67SNicolas Toromanoff 			ctx->extra_size = 0;
10565e64ae67SNicolas Toromanoff 		}
10575e64ae67SNicolas Toromanoff 
10585e64ae67SNicolas Toromanoff 		/* Move to final phase */
10595e64ae67SNicolas Toromanoff 		io_clrsetbits32(ctx->base + _CRYP_CR, _CRYP_CR_GCM_CCMPH_MSK,
10605e64ae67SNicolas Toromanoff 				_CRYP_CR_GCM_CCMPH_FINAL <<
10615e64ae67SNicolas Toromanoff 				_CRYP_CR_GCM_CCMPH_OFF);
10625e64ae67SNicolas Toromanoff 		break;
10635e64ae67SNicolas Toromanoff 	default:
10645e64ae67SNicolas Toromanoff 		assert(0);
10655e64ae67SNicolas Toromanoff 		res = TEE_ERROR_BAD_STATE;
10665e64ae67SNicolas Toromanoff 	}
10675e64ae67SNicolas Toromanoff 
10685e64ae67SNicolas Toromanoff 	if (res)
10695e64ae67SNicolas Toromanoff 		goto out;
10705e64ae67SNicolas Toromanoff 
10715e64ae67SNicolas Toromanoff 	if (IS_ALGOMODE(ctx->cr, AES_GCM)) {
10725e64ae67SNicolas Toromanoff 		/* No need to htobe() as we configure the HW to swap bytes */
10735e64ae67SNicolas Toromanoff 		io_write32(ctx->base + _CRYP_DIN, 0U);
10745e64ae67SNicolas Toromanoff 		io_write32(ctx->base + _CRYP_DIN, ctx->assoc_len);
10755e64ae67SNicolas Toromanoff 		io_write32(ctx->base + _CRYP_DIN, 0U);
10765e64ae67SNicolas Toromanoff 		io_write32(ctx->base + _CRYP_DIN, ctx->load_len);
10775e64ae67SNicolas Toromanoff 	} else if (IS_ALGOMODE(ctx->cr, AES_CCM)) {
10785e64ae67SNicolas Toromanoff 		/* No need to htobe() in this phase */
10795e64ae67SNicolas Toromanoff 		res = write_align_block(ctx, ctx->ctr0_ccm);
10805e64ae67SNicolas Toromanoff 		if (res)
10815e64ae67SNicolas Toromanoff 			goto out;
10825e64ae67SNicolas Toromanoff 	}
10835e64ae67SNicolas Toromanoff 
10845e64ae67SNicolas Toromanoff 	res = read_align_block(ctx, tag_u32);
10855e64ae67SNicolas Toromanoff 	if (res)
10865e64ae67SNicolas Toromanoff 		goto out;
10875e64ae67SNicolas Toromanoff 
10885e64ae67SNicolas Toromanoff 	memcpy(tag, tag_u32, MIN(sizeof(tag_u32), tag_size));
10895e64ae67SNicolas Toromanoff 
10905e64ae67SNicolas Toromanoff out:
10915e64ae67SNicolas Toromanoff 	cryp_end(ctx, res);
10925e64ae67SNicolas Toromanoff 	mutex_unlock(ctx->lock);
10935e64ae67SNicolas Toromanoff 
10945e64ae67SNicolas Toromanoff 	return res;
10955e64ae67SNicolas Toromanoff }
10965e64ae67SNicolas Toromanoff 
10975e64ae67SNicolas Toromanoff /**
10985e64ae67SNicolas Toromanoff  * @brief Update (or start) a de/encrypt process.
10995e64ae67SNicolas Toromanoff  * @param ctx: CRYP process context
11005e64ae67SNicolas Toromanoff  * @param last_block: true if last payload data block
11015e64ae67SNicolas Toromanoff  * @param data_in: pointer to payload
11025e64ae67SNicolas Toromanoff  * @param data_out: pointer where to save de/encrypted payload
11035e64ae67SNicolas Toromanoff  * @param data_size: payload size
11045e64ae67SNicolas Toromanoff  *
11055e64ae67SNicolas Toromanoff  * @retval TEE_SUCCESS if OK.
11065e64ae67SNicolas Toromanoff  */
stm32_cryp_update(struct stm32_cryp_context * ctx,bool last_block,uint8_t * data_in,uint8_t * data_out,size_t data_size)11075e64ae67SNicolas Toromanoff TEE_Result stm32_cryp_update(struct stm32_cryp_context *ctx, bool last_block,
11085e64ae67SNicolas Toromanoff 			     uint8_t *data_in, uint8_t *data_out,
11095e64ae67SNicolas Toromanoff 			     size_t data_size)
11105e64ae67SNicolas Toromanoff {
11115e64ae67SNicolas Toromanoff 	TEE_Result res = TEE_SUCCESS;
11125e64ae67SNicolas Toromanoff 	unsigned int i = 0;
11135e64ae67SNicolas Toromanoff 
11145e64ae67SNicolas Toromanoff 	mutex_lock(ctx->lock);
11155e64ae67SNicolas Toromanoff 
11165e64ae67SNicolas Toromanoff 	/*
11175e64ae67SNicolas Toromanoff 	 * In CBC and ECB encryption we need to manage specifically last
11185e64ae67SNicolas Toromanoff 	 * 2 blocks if total size in not aligned to a block size.
11195e64ae67SNicolas Toromanoff 	 * Currently return TEE_ERROR_NOT_IMPLEMENTED. Moreover as we need to
11205e64ae67SNicolas Toromanoff 	 * know last 2 blocks, if unaligned and call with less than two blocks,
11215e64ae67SNicolas Toromanoff 	 * return TEE_ERROR_BAD_STATE.
11225e64ae67SNicolas Toromanoff 	 */
11235e64ae67SNicolas Toromanoff 	if (last_block && algo_mode_is_ecb_cbc(ctx->cr) &&
11245e64ae67SNicolas Toromanoff 	    is_encrypt(ctx->cr) &&
112576d6685eSEtienne Carriere 	    (ROUNDDOWN2(data_size, ctx->block_u32 * sizeof(uint32_t)) !=
11265e64ae67SNicolas Toromanoff 	     data_size)) {
11275e64ae67SNicolas Toromanoff 		if (data_size < ctx->block_u32 * sizeof(uint32_t) * 2) {
11285e64ae67SNicolas Toromanoff 			/*
11295e64ae67SNicolas Toromanoff 			 * If CBC, size of the last part should be at
11305e64ae67SNicolas Toromanoff 			 * least 2*BLOCK_SIZE
11315e64ae67SNicolas Toromanoff 			 */
11325e64ae67SNicolas Toromanoff 			EMSG("Unexpected last block size");
11335e64ae67SNicolas Toromanoff 			res = TEE_ERROR_BAD_STATE;
11345e64ae67SNicolas Toromanoff 			goto out;
11355e64ae67SNicolas Toromanoff 		}
11365e64ae67SNicolas Toromanoff 		/*
11375e64ae67SNicolas Toromanoff 		 * Moreover the ECB/CBC specific padding for encrypt is not
11385e64ae67SNicolas Toromanoff 		 * yet implemented, and not used in OPTEE
11395e64ae67SNicolas Toromanoff 		 */
11405e64ae67SNicolas Toromanoff 		res = TEE_ERROR_NOT_IMPLEMENTED;
11415e64ae67SNicolas Toromanoff 		goto out;
11425e64ae67SNicolas Toromanoff 	}
11435e64ae67SNicolas Toromanoff 
11445e64ae67SNicolas Toromanoff 	/* Manage remaining CTR mask from previous update call */
11455e64ae67SNicolas Toromanoff 	if (IS_ALGOMODE(ctx->cr, AES_CTR) && ctx->extra_size) {
11465e64ae67SNicolas Toromanoff 		unsigned int j = 0;
11475e64ae67SNicolas Toromanoff 		uint8_t *mask = (uint8_t *)ctx->extra;
11485e64ae67SNicolas Toromanoff 
11495e64ae67SNicolas Toromanoff 		for (j = 0; j < ctx->extra_size && i < data_size; j++, i++)
11505e64ae67SNicolas Toromanoff 			data_out[i] = data_in[i] ^ mask[j];
11515e64ae67SNicolas Toromanoff 
11525e64ae67SNicolas Toromanoff 		if (j != ctx->extra_size) {
11535e64ae67SNicolas Toromanoff 			/*
11545e64ae67SNicolas Toromanoff 			 * We didn't consume all saved mask,
11555e64ae67SNicolas Toromanoff 			 * but no more data.
11565e64ae67SNicolas Toromanoff 			 */
11575e64ae67SNicolas Toromanoff 
11585e64ae67SNicolas Toromanoff 			/* We save remaining mask and its new size */
1159*a9b7c5a8SEtienne Carriere 			memmove(ctx->extra, (uint8_t *)ctx->extra + j,
11605e64ae67SNicolas Toromanoff 				ctx->extra_size - j);
11615e64ae67SNicolas Toromanoff 			ctx->extra_size -= j;
11625e64ae67SNicolas Toromanoff 
11635e64ae67SNicolas Toromanoff 			/*
11645e64ae67SNicolas Toromanoff 			 * We don't need to save HW context we didn't
11655e64ae67SNicolas Toromanoff 			 * modify HW state.
11665e64ae67SNicolas Toromanoff 			 */
11675e64ae67SNicolas Toromanoff 			res = TEE_SUCCESS;
11685e64ae67SNicolas Toromanoff 			goto out;
11695e64ae67SNicolas Toromanoff 		}
11705e64ae67SNicolas Toromanoff 
11715e64ae67SNicolas Toromanoff 		/* All extra mask consumed */
11725e64ae67SNicolas Toromanoff 		ctx->extra_size = 0;
11735e64ae67SNicolas Toromanoff 	}
11745e64ae67SNicolas Toromanoff 
11755e64ae67SNicolas Toromanoff 	res = restore_context(ctx);
11765e64ae67SNicolas Toromanoff 	if (res)
11775e64ae67SNicolas Toromanoff 		goto out;
11785e64ae67SNicolas Toromanoff 
11795e64ae67SNicolas Toromanoff 	while (data_size - i >= ctx->block_u32 * sizeof(uint32_t)) {
11805e64ae67SNicolas Toromanoff 		/*
11815e64ae67SNicolas Toromanoff 		 * We only write/read one block at a time
11825e64ae67SNicolas Toromanoff 		 * but CRYP use a in (and out) FIFO of 8 * uint32_t
11835e64ae67SNicolas Toromanoff 		 */
11845e64ae67SNicolas Toromanoff 		res = write_block(ctx, data_in + i);
11855e64ae67SNicolas Toromanoff 		if (res)
11865e64ae67SNicolas Toromanoff 			goto out;
11875e64ae67SNicolas Toromanoff 
11885e64ae67SNicolas Toromanoff 		res = read_block(ctx, data_out + i);
11895e64ae67SNicolas Toromanoff 		if (res)
11905e64ae67SNicolas Toromanoff 			goto out;
11915e64ae67SNicolas Toromanoff 
11925e64ae67SNicolas Toromanoff 		/* Process next block */
11935e64ae67SNicolas Toromanoff 		i += ctx->block_u32 * sizeof(uint32_t);
11945e64ae67SNicolas Toromanoff 	}
11955e64ae67SNicolas Toromanoff 
11965e64ae67SNicolas Toromanoff 	/* Manage last block if not a block size multiple */
11975e64ae67SNicolas Toromanoff 	if (i < data_size) {
11985e64ae67SNicolas Toromanoff 		uint32_t block_in[MAX_BLOCK_NB_U32] = { 0 };
11995e64ae67SNicolas Toromanoff 		uint32_t block_out[MAX_BLOCK_NB_U32] = { 0 };
12005e64ae67SNicolas Toromanoff 
12015e64ae67SNicolas Toromanoff 		if (!IS_ALGOMODE(ctx->cr, AES_CTR)) {
12025e64ae67SNicolas Toromanoff 			/*
12035e64ae67SNicolas Toromanoff 			 * Other algorithm than CTR can manage only multiple
12045e64ae67SNicolas Toromanoff 			 * of block_size.
12055e64ae67SNicolas Toromanoff 			 */
12065e64ae67SNicolas Toromanoff 			res = TEE_ERROR_BAD_PARAMETERS;
12075e64ae67SNicolas Toromanoff 			goto out;
12085e64ae67SNicolas Toromanoff 		}
12095e64ae67SNicolas Toromanoff 
12105e64ae67SNicolas Toromanoff 		/*
12115e64ae67SNicolas Toromanoff 		 * For CTR we save the generated mask to use it at next
12125e64ae67SNicolas Toromanoff 		 * update call.
12135e64ae67SNicolas Toromanoff 		 */
12145e64ae67SNicolas Toromanoff 		memcpy(block_in, data_in + i, data_size - i);
12155e64ae67SNicolas Toromanoff 
12165e64ae67SNicolas Toromanoff 		res = write_align_block(ctx, block_in);
12175e64ae67SNicolas Toromanoff 		if (res)
12185e64ae67SNicolas Toromanoff 			goto out;
12195e64ae67SNicolas Toromanoff 
12205e64ae67SNicolas Toromanoff 		res = read_align_block(ctx, block_out);
12215e64ae67SNicolas Toromanoff 		if (res)
12225e64ae67SNicolas Toromanoff 			goto out;
12235e64ae67SNicolas Toromanoff 
12245e64ae67SNicolas Toromanoff 		memcpy(data_out + i, block_out, data_size - i);
12255e64ae67SNicolas Toromanoff 
12265e64ae67SNicolas Toromanoff 		/* Save mask for possibly next call */
12275e64ae67SNicolas Toromanoff 		ctx->extra_size = ctx->block_u32 * sizeof(uint32_t) -
12285e64ae67SNicolas Toromanoff 			(data_size - i);
12295e64ae67SNicolas Toromanoff 		memcpy(ctx->extra, (uint8_t *)block_out + data_size - i,
12305e64ae67SNicolas Toromanoff 		       ctx->extra_size);
12315e64ae67SNicolas Toromanoff 	}
12325e64ae67SNicolas Toromanoff 
12335e64ae67SNicolas Toromanoff 	if (!last_block)
12345e64ae67SNicolas Toromanoff 		res = save_context(ctx);
12355e64ae67SNicolas Toromanoff 
12365e64ae67SNicolas Toromanoff out:
12375e64ae67SNicolas Toromanoff 	/* If last block or error, end of CRYP process */
12385e64ae67SNicolas Toromanoff 	if (last_block || res)
12395e64ae67SNicolas Toromanoff 		cryp_end(ctx, res);
12405e64ae67SNicolas Toromanoff 
12415e64ae67SNicolas Toromanoff 	mutex_unlock(ctx->lock);
12425e64ae67SNicolas Toromanoff 
12435e64ae67SNicolas Toromanoff 	return res;
12445e64ae67SNicolas Toromanoff }
12455e64ae67SNicolas Toromanoff 
stm32_cryp_pm(enum pm_op op,uint32_t pm_hint,const struct pm_callback_handle * hdl __unused)1246299f9bc1SThomas Bourgoin static TEE_Result stm32_cryp_pm(enum pm_op op, uint32_t pm_hint,
1247299f9bc1SThomas Bourgoin 				const struct pm_callback_handle *hdl __unused)
1248299f9bc1SThomas Bourgoin {
1249299f9bc1SThomas Bourgoin 	switch (op) {
1250299f9bc1SThomas Bourgoin 	case PM_OP_SUSPEND:
1251299f9bc1SThomas Bourgoin 		clk_disable(cryp_pdata.clock);
1252299f9bc1SThomas Bourgoin 		return TEE_SUCCESS;
1253299f9bc1SThomas Bourgoin 	case PM_OP_RESUME:
1254299f9bc1SThomas Bourgoin 		if (clk_enable(cryp_pdata.clock))
1255299f9bc1SThomas Bourgoin 			panic();
1256299f9bc1SThomas Bourgoin 
1257299f9bc1SThomas Bourgoin 		if (PM_HINT_IS_STATE(pm_hint, CONTEXT) && stm32_cryp_reset())
1258299f9bc1SThomas Bourgoin 			panic();
1259299f9bc1SThomas Bourgoin 
1260299f9bc1SThomas Bourgoin 		return TEE_SUCCESS;
1261299f9bc1SThomas Bourgoin 	default:
1262299f9bc1SThomas Bourgoin 		/* Unexpected PM operation */
1263299f9bc1SThomas Bourgoin 		assert(0);
1264299f9bc1SThomas Bourgoin 		return TEE_ERROR_NOT_IMPLEMENTED;
1265299f9bc1SThomas Bourgoin 	}
1266299f9bc1SThomas Bourgoin }
1267299f9bc1SThomas Bourgoin DECLARE_KEEP_PAGER(stm32_cryp_pm);
1268299f9bc1SThomas Bourgoin 
stm32_cryp_probe(const void * fdt,int node,const void * compt_data __unused)12698b826c3bSEtienne Carriere static TEE_Result stm32_cryp_probe(const void *fdt, int node,
12708b826c3bSEtienne Carriere 				   const void *compt_data __unused)
12715e64ae67SNicolas Toromanoff {
12728b826c3bSEtienne Carriere 	TEE_Result res = TEE_SUCCESS;
12735e64ae67SNicolas Toromanoff 	struct dt_node_info dt_cryp = { };
12748b826c3bSEtienne Carriere 	struct rstctrl *rstctrl = NULL;
12758b826c3bSEtienne Carriere 	struct clk *clk = NULL;
12765e64ae67SNicolas Toromanoff 
1277f354a5d8SGatien Chevallier 	fdt_fill_device_info(fdt, &dt_cryp, node);
12785e64ae67SNicolas Toromanoff 
12798b826c3bSEtienne Carriere 	if (dt_cryp.reg == DT_INFO_INVALID_REG ||
12808b826c3bSEtienne Carriere 	    dt_cryp.reg_size == DT_INFO_INVALID_REG_SIZE)
1281047c4fe1SEtienne Carriere 		panic();
12825e64ae67SNicolas Toromanoff 
12838b826c3bSEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 0, &clk);
12848b826c3bSEtienne Carriere 	if (res)
12858b826c3bSEtienne Carriere 		return res;
12865e64ae67SNicolas Toromanoff 
12878b826c3bSEtienne Carriere 	res = rstctrl_dt_get_by_index(fdt, node, 0, &rstctrl);
12881d8b1184SThomas Bourgoin 	if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND)
12898b826c3bSEtienne Carriere 		return res;
12905e64ae67SNicolas Toromanoff 
12918b826c3bSEtienne Carriere 	cryp_pdata.clock = clk;
12928b826c3bSEtienne Carriere 	cryp_pdata.reset = rstctrl;
12938b826c3bSEtienne Carriere 	cryp_pdata.base.pa = dt_cryp.reg;
12948b826c3bSEtienne Carriere 
12958b826c3bSEtienne Carriere 	io_pa_or_va_secure(&cryp_pdata.base, dt_cryp.reg_size);
12968b826c3bSEtienne Carriere 	if (!cryp_pdata.base.va)
1297d1a9c68bSEtienne Carriere 		panic();
12985e64ae67SNicolas Toromanoff 
12998b826c3bSEtienne Carriere 	if (clk_enable(cryp_pdata.clock))
13008b826c3bSEtienne Carriere 		panic();
13015e64ae67SNicolas Toromanoff 
130214d68630SThomas Bourgoin 	if (stm32_cryp_reset())
13035e64ae67SNicolas Toromanoff 		panic();
13045e64ae67SNicolas Toromanoff 
1305fa8cb7a8SNicolas Toromanoff 	if (IS_ENABLED(CFG_CRYPTO_DRV_AUTHENC)) {
1306fa8cb7a8SNicolas Toromanoff 		res = stm32_register_authenc();
1307fa8cb7a8SNicolas Toromanoff 		if (res) {
1308fa8cb7a8SNicolas Toromanoff 			EMSG("Failed to register to authenc: %#"PRIx32, res);
1309fa8cb7a8SNicolas Toromanoff 			panic();
1310fa8cb7a8SNicolas Toromanoff 		}
1311fa8cb7a8SNicolas Toromanoff 	}
1312fa8cb7a8SNicolas Toromanoff 
13135e64ae67SNicolas Toromanoff 	if (IS_ENABLED(CFG_CRYPTO_DRV_CIPHER)) {
13144320f5cfSThomas Bourgoin 		res = stm32_register_cipher(CRYP_IP);
13155e64ae67SNicolas Toromanoff 		if (res) {
13165e64ae67SNicolas Toromanoff 			EMSG("Failed to register to cipher: %#"PRIx32, res);
13175e64ae67SNicolas Toromanoff 			panic();
13185e64ae67SNicolas Toromanoff 		}
13195e64ae67SNicolas Toromanoff 	}
13205e64ae67SNicolas Toromanoff 
1321299f9bc1SThomas Bourgoin 	register_pm_core_service_cb(stm32_cryp_pm, NULL, "stm32-cryp");
1322299f9bc1SThomas Bourgoin 
13235e64ae67SNicolas Toromanoff 	return TEE_SUCCESS;
13245e64ae67SNicolas Toromanoff }
13255e64ae67SNicolas Toromanoff 
13268b826c3bSEtienne Carriere static const struct dt_device_match stm32_cryp_match_table[] = {
13278b826c3bSEtienne Carriere 	{ .compatible = "st,stm32mp1-cryp" },
13288b826c3bSEtienne Carriere 	{ }
13298b826c3bSEtienne Carriere };
13308b826c3bSEtienne Carriere 
13318b826c3bSEtienne Carriere DEFINE_DT_DRIVER(stm32_cryp_dt_driver) = {
13328b826c3bSEtienne Carriere 	.name = "stm32-cryp",
13338b826c3bSEtienne Carriere 	.match_table = stm32_cryp_match_table,
13348b826c3bSEtienne Carriere 	.probe = stm32_cryp_probe,
13358b826c3bSEtienne Carriere };
1336