/** @file crypto.c @ingroup @note Copyright Novatek Microelectronics Corp. 2019. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. */ #include #include #include #include #include #include #include #define CRYPTO_SETREG(ofs,value) OUTW(IOADDR_CRYPTO_REG_BASE+(ofs),(value)) #define CRYPTO_GETREG(ofs) INW(IOADDR_CRYPTO_REG_BASE+(ofs)) #define CRYPTO_REG_BASE_ADDR IOADDR_CRYPTO_REG_BASE #define CLOCK_GEN_REG_BASE_ADDR IOADDR_CG_REG_BASE #define CLOCK_GEN_PLL_PWR_REG (CLOCK_GEN_REG_BASE_ADDR + 0x00) #define CLOCK_GEN_PLL_STS_REG (CLOCK_GEN_REG_BASE_ADDR + 0x04) #define CLOCK_GEN_ENABLE_REG0 (CLOCK_GEN_REG_BASE_ADDR + 0x70) #define CKGEN_PLLEN_PLL2 (0x01 << 2) // PLL2: for Secure boot #define CRYPTO_DMA_CONFIG_REG_OFS 0x08 #define CRYPTO_DMA_STS_REG_OFS 0x0C #define CRYPTO_SRC_ADDR_REG_OFS 0x50 #define CRYPTO_DST_ADDR_REG_OFS 0xA4 #define CRYPTO_DMA_CONTROL_REG_OFS 0x04 #define CRYPTO_KEY000_REG_OFS 0x30 #define CRYPTO_KEY032_REG_OFS 0x34 #define CRYPTO_KEY064_REG_OFS 0x38 #define CRYPTO_KEY096_REG_OFS 0x3C // Crypto #define CRYPTO_CONFREG_SWRST (1<<0) #define CRYPTO_CONFREG_CRYPTO_EN (1<<1) #define CRYPTO_CONFREG_AES128 (2<<4) #define CRYPTO_CONFREG_DECRYPT (1<<8) #define CRYPTO_PIO_DONE (1<<0) #define dma_getPhyAddr(addr) ((((UINT32)(addr))>=0x60000000UL)?((UINT32)(addr)-0x60000000UL):(UINT32)(addr)) #define SCE_DES_TABLE_NUM (40) //8(header DesTab) + 32(addr DesTab) #define SCE_DES_WORD_SIZE (4) //1 DesTab = 4 word #define SCE_DES_IV_OFS (8) #define SCE_DES_CNT_OFS (12) #define SCE_DES_HAEDER_OFS (16) #define SCE_DES_CV_OFS (20) #define SCE_DES_S0_OFS (24) #define SCE_DES_GHASH_OFS (28) #define SCE_DES_BLOCK_CFG_OFS (32) #define SCE_DMA_COUNT (1) #define ROM_AES_SIZE (16) #define _ALIGNED(x) __attribute__((aligned(x))) static _ALIGNED(32) u32 vuiSCE_DesTab[SCE_DES_TABLE_NUM*SCE_DES_WORD_SIZE]; #define OUTREG32(x, y) writel(y, x) //(*((volatile UINT32*)(x)) = (y)) ///< Write 32bits IO register #define INREG32(x) readl(x) #define SETREG32(x, y) OUTREG32((x), INREG32(x) | (y)) ///< Set 32bits IO register #define CLRREG32(x, y) OUTREG32((x), INREG32(x) & ~(y)) ///< Clear 32bits IO register #define dma_getPhyAddr(addr) ((((UINT32)(addr))>=0x60000000UL)?((UINT32)(addr)-0x60000000UL):(UINT32)(addr)) #ifndef CHKPNT #define CHKPNT printf("\033[37mCHK: %d, %s\033[0m\r\n", __LINE__, __func__) #endif #ifndef DBGD #define DBGD(x) printf("\033[0;35m%s=%d\033[0m\r\n", #x, x) #endif #ifndef DBGH #define DBGH(x) printf("\033[0;35m%s=0x%08X\033[0m\r\n", #x, x) #endif #ifndef DBG_DUMP #define DBG_DUMP(fmtstr, args...) printf(fmtstr, ##args) #endif #ifndef DBG_ERR #define DBG_ERR(fmtstr, args...) printf("\033[0;31mERR:%s() \033[0m" fmtstr, __func__, ##args) #endif #ifndef DBG_WRN #define DBG_WRN(fmtstr, args...) printf("\033[0;33mWRN:%s() \033[0m" fmtstr, __func__, ##args) #endif #if 0 #define DBG_IND(fmtstr, args...) printf("%s(): " fmtstr, __func__, ##args) #else #ifndef DBG_IND #define DBG_IND(fmtstr, args...) #endif #endif static u32 crypto_set_mode(u32 uiMode, u32 uiOPMode, u32 uiType) { if (uiMode != CRYPTO_AES) { return -1; } if (uiOPMode >= CRYPTO_OPMODE_NUM) { return -1; } //OUTREG32(CRYPRO_REG_BASE_ADDR, /*(1 << 9) | */(uiMode<<4) | (uiType << 8) | CRYPTO_CONFREG_CRYPTO_EN/* | CRYPTO_CONFREG_SWRST*/); // big endian, descrypt, AES-128, sw-reset OUTREG32(CRYPTO_REG_BASE_ADDR, CRYPTO_CONFREG_CRYPTO_EN); // big endian, descrypt, AES-128, sw-reset return 0; } //Enable Crypto engine clock SETREG32(CLOCK_GEN_REG_BASE_ADDR + 0x80, (0x01 << 23));// uart_putSystemUARTStr("keyoffset=");// uart_putSystemUARTStr(Dec2HexStr(key_offset));// uart_putSystemUARTStr("\r\n"); OUTREG32(CRYPRO_REG_BASE_ADDR+0x30, 0x13141516); OUTREG32(CRYPRO_REG_BASE_ADDR+0x34, 0x09101112); OUTREG32(CRYPRO_REG_BASE_ADDR+0x38, 0x05060708); OUTREG32(CRYPRO_REG_BASE_ADDR+0x3C, 0x01020304); OUTREG32(CRYPRO_REG_BASE_ADDR, (1<<9)|(1<<8)|(2<<1)|(1<<0)); // big endian, descrypt, AES-128, sw-reset// OUTREG32(CRYPRO_REG_BASE_ADDR, (0<<9)|(1<<8)|(2<<1)|(1<<0)); // little endian, descrypt, AES-128, sw-reset while (1) // wait sw reset clear { uiReg = INREG32(CRYPRO_REG_BASE_ADDR); if ((uiReg & (1<<0)) == 0) break; } static void crypto_dma_enable(u32 uiMode, u32 uiOPMode, u32 uiType, u32 SrcAddr, u32 DstAddr, u32 Len) { u64 uiReg; u32 header_config=0; u32 block_config =0; //clear DMA interrupt status uiReg = CRYPTO_GETREG(CRYPTO_DMA_STS_REG_OFS); CRYPTO_SETREG(CRYPTO_DMA_STS_REG_OFS, uiReg); //Disable interrupt enable CRYPTO_SETREG(CRYPTO_DMA_CONFIG_REG_OFS, 0x0); memset((void*)&vuiSCE_DesTab[0], 0, SCE_DES_TABLE_NUM*SCE_DES_WORD_SIZE*4); //Configure DMA buffer address and size header_config = (u32)((1 << 12 ) |((uiOPMode) << 8 ) | (uiMode << 4 ) | uiType); //Flush cache vuiSCE_DesTab[SCE_DES_HAEDER_OFS] = (u32)header_config; block_config = 0; vuiSCE_DesTab[SCE_DES_BLOCK_CFG_OFS] = dma_getPhyAddr(SrcAddr); vuiSCE_DesTab[SCE_DES_BLOCK_CFG_OFS+1] = dma_getPhyAddr(DstAddr); vuiSCE_DesTab[SCE_DES_BLOCK_CFG_OFS+2] = Len; block_config = (u32)(1); vuiSCE_DesTab[SCE_DES_BLOCK_CFG_OFS+3] = block_config; flush_dcache_range((ulong)&vuiSCE_DesTab[0], (ulong)&vuiSCE_DesTab[0] + roundup(SCE_DES_TABLE_NUM *SCE_DES_WORD_SIZE*4, ARCH_DMA_MINALIGN)); flush_dcache_range(SrcAddr, SrcAddr + roundup(Len, ARCH_DMA_MINALIGN)); invalidate_dcache_range(DstAddr, DstAddr + roundup(Len, ARCH_DMA_MINALIGN)); CRYPTO_SETREG(CRYPTO_SRC_ADDR_REG_OFS, dma_getPhyAddr((UINT32)&vuiSCE_DesTab[0])); //Set DMA Enable CRYPTO_SETREG(CRYPTO_DMA_CONTROL_REG_OFS, (0x1<<4)); while (!(CRYPTO_GETREG(CRYPTO_DMA_STS_REG_OFS) & (0x1<<4))); CRYPTO_SETREG(CRYPTO_DMA_STS_REG_OFS, (0x1<<4)); } s32 crypto_data_operation(EFUSE_OTP_KEY_SET_FIELD key_set, CRYPT_OP crypt_op_param) { UINT32 reg; s32 ret; reg = INREG32(CLOCK_GEN_REG_BASE_ADDR + 0x4); if((reg & CKGEN_PLLEN_PLL2) != CKGEN_PLLEN_PLL2) { SETREG32(CLOCK_GEN_PLL_PWR_REG, CKGEN_PLLEN_PLL2); while (1) // wait PLL2 enabled { if (INREG32(CLOCK_GEN_PLL_STS_REG) & (CKGEN_PLLEN_PLL2)) { break; } } } SETREG32(CLOCK_GEN_ENABLE_REG0, (0x01 << 31)); ret = crypto_set_mode(CRYPTO_AES, crypt_op_param.op_mode, crypt_op_param.en_de_crypt); if (ret < 0) { return ret; } otp_set_key_destination(key_set); crypto_dma_enable(CRYPTO_AES, crypt_op_param.op_mode, crypt_op_param.en_de_crypt, crypt_op_param.src_addr, crypt_op_param.dst_addr, crypt_op_param.length); CLRREG32(CLOCK_GEN_ENABLE_REG0, (0x01 << 31)); return 0; } //CRYPTO_AES, crypt_op_param.op_mode, crypt_op_param.en_de_crypt, CRYPTO_DMA); static void crypto_setKey(u8 *ucKey) { u8 *u32_key = ucKey; CRYPTO_SETREG(CRYPTO_KEY000_REG_OFS, *(u32 *)(u32_key + 0)); CRYPTO_SETREG(CRYPTO_KEY032_REG_OFS, *(u32 *)(u32_key + 4)); CRYPTO_SETREG(CRYPTO_KEY064_REG_OFS, *(u32 *)(u32_key + 8)); CRYPTO_SETREG(CRYPTO_KEY096_REG_OFS, *(u32 *)(u32_key + 12)); } s32 crypto_data_operation_by_key(UINT8 * key, CRYPT_OP crypt_op_param) { s32 ret; UINT32 reg; reg = INREG32(CLOCK_GEN_REG_BASE_ADDR + 0x4); if((reg & CKGEN_PLLEN_PLL2) != CKGEN_PLLEN_PLL2) { SETREG32(CLOCK_GEN_PLL_PWR_REG, CKGEN_PLLEN_PLL2); while (1) // wait PLL2 enabled { if (INREG32(CLOCK_GEN_PLL_STS_REG) & (CKGEN_PLLEN_PLL2)) { break; } } } SETREG32(CLOCK_GEN_ENABLE_REG0, (0x01 << 31)); ret = crypto_set_mode(CRYPTO_AES, crypt_op_param.op_mode, crypt_op_param.en_de_crypt); if (ret < 0) { return ret; } crypto_setKey(key); crypto_dma_enable(CRYPTO_AES, crypt_op_param.op_mode, crypt_op_param.en_de_crypt, crypt_op_param.src_addr, crypt_op_param.dst_addr, crypt_op_param.length); CLRREG32(CLOCK_GEN_ENABLE_REG0, (0x01 << 31)); return 0; }