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