/* * Copyright (c) 2022 OpenLuat & AirM2M * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "bl_inc.h" #ifdef __RUN_IN_RAM__ #define __disable_irq() #define __disable_fault_irq() #define __enable_fault_irq() #define __enable_irq() #endif void __FUNC_IN_RAM__ CACHE_EncryptInit(uint8_t *key, uint8_t *iv, uint32_t start, uint32_t end) { int i; uint32_t ckey[4]; uint32_t civ[4]; for(i = 0; i < 4; i++) { ckey[3 - i] = BytesGetBe32(key + i * 4); civ[3 - i] = BytesGetBe32(iv + i * 4); } __disable_irq(); for (i = 0; i < 5000; i++) { if (CACHE->CACHE_CS & CACHE_IS_BUSY) //cache正在从Flash中取指 { continue; } break; } CACHE->CACHE_CS = 0x00000000 + CACHE_KEY_GEN; //密钥生成模式 CACHE->CACHE_I3 = civ[3]; CACHE->CACHE_I2 = civ[2]; CACHE->CACHE_I1 = civ[1]; CACHE->CACHE_I0 = civ[0]; CACHE->CACHE_K3 = ckey[3]; CACHE->CACHE_K2 = ckey[2]; CACHE->CACHE_K1 = ckey[1]; CACHE->CACHE_K0 = ckey[0]; CACHE->CACHE_CS |= CACHE_KEY_GEN_START; for (i = 0; i < 10000; i++) { if((CACHE->CACHE_CS & CACHE_KEY_GEN_START) == 0) { break; } } CACHE->CACHE_CS = 0; CACHE->CACHE_SADDR = start; CACHE->CACHE_EADDR = end; CACHE->CACHE_CONFIG = 0xA5A50055; __enable_irq(); } void __FUNC_IN_RAM__ CACHE_CleanAll(CACHE_TypeDef *Cache) { while (Cache->CACHE_CS & CACHE_IS_BUSY); Cache->CACHE_REF = CACHE_REFRESH_ALLTAG; Cache->CACHE_REF |= CACHE_REFRESH; while ((Cache->CACHE_REF & CACHE_REFRESH)); } #ifdef __RUN_IN_RAM__ typedef struct { uint8_t Instruction; QSPI_BusModeTypeDef BusMode; QSPI_CmdFormatTypeDef CmdFormat; uint32_t Address; uint32_t WrData; uint32_t RdData; }FLASH_CommandTypeDef; #define QSPI_FIFO_NUM 32 #define FLASH_QSPI_TIMEOUT_DEFAULT_CNT (19000) //18944 #define FLASH_QSPI_ACCESS_REQ_ENABLE (0x00000001U) #define FLASH_QSPI_FLASH_READY_ENABLE (0x0000006BU) static int32_t prvQSPI_Command(FLASH_CommandTypeDef *cmd, int32_t timeout) { int32_t i; int32_t status = -ERROR_OPERATION_FAILED; QSPI->REG_WDATA = cmd->WrData; QSPI->ADDRES = (QSPI->ADDRES & ~QUADSPI_ADDRESS_ADR) | (cmd->Address << 8); QSPI->FCU_CMD = (QSPI->FCU_CMD & ~(QUADSPI_FCU_CMD_CODE | QUADSPI_FCU_CMD_BUS_MODE | QUADSPI_FCU_CMD_CMD_FORMAT | QUADSPI_FCU_CMD_ACCESS_REQ)) | ((cmd->Instruction << 24) |((uint32_t)( cmd->BusMode<< 8)) |((uint32_t)( cmd->CmdFormat << 4))| (FLASH_QSPI_ACCESS_REQ_ENABLE)); //Wait For CMD done for (i = 0; i < timeout; i += 4) { if (QSPI->INT_RAWSTATUS & QUADSPI_INT_RAWSTATUS_DONE_IR) { QSPI->INT_CLEAR = QUADSPI_INT_CLEAR_DONE; status = ERROR_NONE; break; } } cmd->RdData = QSPI->REG_RDATA; return status; } static int32_t prvQSPI_WriteEnable(QSPI_BusModeTypeDef bus_mode) { FLASH_CommandTypeDef sCommand; sCommand.Instruction = SPIFLASH_CMD_WREN; sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8; if (QSPI_BUSMODE_444 == bus_mode) { sCommand.BusMode = QSPI_BUSMODE_444; } else { sCommand.BusMode = QSPI_BUSMODE_111; } if (prvQSPI_Command(&sCommand, FLASH_QSPI_TIMEOUT_DEFAULT_CNT)) { return -ERROR_OPERATION_FAILED; } return ERROR_NONE; } //PP,QPP,Sector Erase,Block Erase, Chip Erase, Write Status Reg, Erase Security Reg int32_t prvQSPI_IsBusy(QSPI_BusModeTypeDef bus_mode) { FLASH_CommandTypeDef sCommand; sCommand.Instruction = SPIFLASH_CMD_RDSR; sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_RREG8; if (QSPI_BUSMODE_444 == bus_mode) { sCommand.BusMode = QSPI_BUSMODE_444; } else { sCommand.BusMode = QSPI_BUSMODE_111; } if (prvQSPI_Command(&sCommand, FLASH_QSPI_TIMEOUT_DEFAULT_CNT)) { return -ERROR_OPERATION_FAILED; } if (sCommand.RdData & BIT0) { return -ERROR_DEVICE_BUSY; } return ERROR_NONE; } int32_t Flash_EraseStart(uint32_t Address, uint8_t IsBlock) { FLASH_CommandTypeDef sCommand; Address &= (uint32_t)(0x00FFFFFF); while (CACHE->CACHE_CS & CACHE_IS_BUSY); sCommand.BusMode = QSPI_BUSMODE_111; sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24; if (prvQSPI_WriteEnable(sCommand.BusMode) != 0) { return -ERROR_OPERATION_FAILED; } if (IsBlock) { sCommand.Instruction = SPIFLASH_CMD_BE; } else { sCommand.Instruction = SPIFLASH_CMD_SE; } sCommand.Address = Address; if (prvQSPI_Command(&sCommand, FLASH_QSPI_TIMEOUT_DEFAULT_CNT)) { return -ERROR_OPERATION_FAILED; } return ERROR_NONE; } int32_t Flash_CheckBusy(void) { return prvQSPI_IsBusy(QSPI_BUSMODE_111); } #endif #if 0 int32_t __FUNC_IN_RAM__ Flash_Program(uint32_t Address, const uint8_t *pBuf, uint32_t Len) { FLASH_CommandTypeDef sCommand; uint32_t FinishLen = 0, DummyLen, ProgramLen, i; int32_t status; uint32_t PageData[64]; /* Initialize the adress variables */ sCommand.Instruction = QUAD_INPUT_PAGE_PROG_CMD; sCommand.BusMode = QSPI_BUSMODE_114; sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24_PDAT; Address &= 0x00ffffff; while(FinishLen < Len) { if (prvQSPI_WriteEnable(QSPI_BUSMODE_111)) { return -ERROR_OPERATION_FAILED; } #if (defined __FLASH_DISABLE_IRQ__) __disable_irq(); ProgramLen = ((Len - FinishLen) > 4)?4:(Len - FinishLen); #else ProgramLen = ((Len - FinishLen) > QSPI_FIFO_NUM)?QSPI_FIFO_NUM:(Len - FinishLen); #endif for(i = 0; i < ProgramLen; i+=4) { PageData[i >> 2] = BytesGetLe32(pBuf + i); } QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_TFFH; QSPI->BYTE_NUM = (ProgramLen << 16); sCommand.Address = Address + FinishLen; DummyLen = 0; while((DummyLen < ProgramLen) && !(QSPI->FIFO_CNTL & QUADSPI_FIFO_CNTL_TFFL)) { QSPI->WR_FIFO = PageData[DummyLen >> 2]; DummyLen += 4; } QSPI->ADDRES = (QSPI->ADDRES & ~QUADSPI_ADDRESS_ADR) | (sCommand.Address << 8); QSPI->FCU_CMD = (QSPI->FCU_CMD & ~(QUADSPI_FCU_CMD_CODE | QUADSPI_FCU_CMD_BUS_MODE | QUADSPI_FCU_CMD_CMD_FORMAT | QUADSPI_FCU_CMD_ACCESS_REQ)) | ((sCommand.Instruction << 24) |((uint32_t)( sCommand.BusMode<< 8)) |((uint32_t)( sCommand.CmdFormat << 4))| (FLASH_QSPI_ACCESS_REQ_ENABLE)); while(DummyLen < ProgramLen) { while(QSPI->FIFO_CNTL & QUADSPI_FIFO_CNTL_TFFL) { } QSPI->WR_FIFO = PageData[DummyLen >> 2]; DummyLen += 4; } // DBG("%u", DummyLen); status = -ERROR_OPERATION_FAILED; for (i = 0; i < FLASH_QSPI_TIMEOUT_DEFAULT_CNT; i += 4) { if (QSPI->INT_RAWSTATUS & QUADSPI_INT_RAWSTATUS_DONE_IR) { QSPI->INT_CLEAR = QUADSPI_INT_CLEAR_DONE; status = ERROR_NONE; break; } } if (status) { #if (defined __FLASH_DISABLE_IRQ__) CACHE_CleanAll(CACHE); __enable_irq(); #endif return status; } while (prvQSPI_IsBusy(QSPI_BUSMODE_111)); #if (defined __FLASH_DISABLE_IRQ__) __enable_irq(); #endif FinishLen += ProgramLen; } #if (defined __FLASH_DISABLE_IRQ__) CACHE_CleanAll(CACHE); #endif return ERROR_NONE; } #endif /** * @brief Flash Erase Sector. * @param sectorAddress: The sector address to be erased * @retval FLASH Status: The returned value can be: QSPI_STATUS_ERROR, QSPI_STATUS_OK */ uint8_t FLASH_EraseSector(uint32_t sectorAddress) { uint8_t ret; __disable_irq(); //__disable_fault_irq(); ret = ROM_QSPI_EraseSector(NULL, sectorAddress); //__enable_fault_irq(); __enable_irq(); return ret; } /** * @brief Flash Program Interface. * @param addr: specifies the address to be programmed. * @param size: specifies the size to be programmed. * @param buffer: pointer to the data to be programmed, need word aligned * @retval FLASH Status: The returned value can be: QSPI_STATUS_ERROR, QSPI_STATUS_OK */ uint8_t FLASH_ProgramPage(uint32_t addr, uint32_t size, uint8_t *buffer) { uint8_t ret; QSPI_CommandTypeDef cmdType; cmdType.Instruction = QUAD_INPUT_PAGE_PROG_CMD; cmdType.BusMode = QSPI_BUSMODE_114; cmdType.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24_PDAT; __disable_irq(); //__disable_fault_irq(); ret = ROM_QSPI_ProgramPage(&cmdType, DMA_Channel_1, addr, size, buffer); //__enable_fault_irq(); __enable_irq(); return ret; } int32_t Flash_Erase(uint32_t Address, uint32_t Length) { uint32_t TotalLen = 0; QSPI_CommandTypeDef sCommand; sCommand.BusMode = QSPI_BUSMODE_111; sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24; uint32_t FlashAddress, DummyLen; uint8_t ret; while (TotalLen < Length) { FlashAddress = Address + TotalLen; DummyLen = Length - TotalLen; if (!(FlashAddress & SPI_FLASH_BLOCK_MASK) && (DummyLen >= SPI_FLASH_BLOCK_SIZE)) { sCommand.Instruction = SPIFLASH_CMD_BE; TotalLen += SPI_FLASH_BLOCK_SIZE; } else { sCommand.Instruction = SPIFLASH_CMD_SE; TotalLen += SPI_FLASH_SECTOR_SIZE; } __disable_irq(); //__disable_fault_irq(); ret = ROM_QSPI_EraseSector(&sCommand, FlashAddress); //__enable_fault_irq(); __enable_irq(); } CACHE_CleanAll(CACHE); return ERROR_NONE; } int32_t Flash_Program(uint32_t Address, const uint8_t *pBuf, uint32_t Len) { uint32_t size = (Len + (4 - 1)) & (~(4 - 1)); uint32_t Pos = 0; uint8_t ret; QSPI_CommandTypeDef cmdType; cmdType.Instruction = QUAD_INPUT_PAGE_PROG_CMD; cmdType.BusMode = QSPI_BUSMODE_114; cmdType.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24_PDAT; while(Pos < size) { if ((size - Pos) > __FLASH_PAGE_SIZE__) { __disable_irq(); //__disable_fault_irq(); ret = ROM_QSPI_ProgramPage(&cmdType, DMA_Channel_1, Address + Pos, __FLASH_PAGE_SIZE__, pBuf + Pos); //__enable_fault_irq(); __enable_irq(); Pos += __FLASH_PAGE_SIZE__; } else { __disable_irq(); //__disable_fault_irq(); ret = ROM_QSPI_ProgramPage(&cmdType, DMA_Channel_1, Address + Pos, (size - Pos), pBuf + Pos); //__enable_fault_irq(); __enable_irq(); Pos += (size - Pos); } } CACHE_CleanAll(CACHE); return ERROR_NONE; } #if 0 int Flash_EraseSector(uint32_t address, uint8_t NeedCheck) { uint8_t buf[__FLASH_PAGE_SIZE__]; uint32_t i; uint8_t retry = 1; void *res; memset(buf, 0xff, __FLASH_PAGE_SIZE__); BL_ERASESECTOR_AGAIN: FLASH_EraseSector(address); #if (defined __BUILD_OS__) || (defined __BUILD_APP__) CACHE_CleanAll(CACHE); #endif if (!NeedCheck) return ERROR_NONE; for(i = 0; i < 4096; i+=__FLASH_PAGE_SIZE__) { res = memcmp(address + i, buf, __FLASH_PAGE_SIZE__); if (res) { DBG_INFO("%x", res); if (retry) { retry = 0; goto BL_ERASESECTOR_AGAIN; } else { return -1; } } } return 0; } int Flash_ProgramData(uint32_t address, uint32_t *Data, uint32_t Len, uint8_t NeedCheck) { void *res; uint32_t size = (Len + (4 - 1)) & (~(4 - 1)); FLASH_ProgramPage(address, size, Data); #if (defined __BUILD_OS__) || (defined __BUILD_APP__) CACHE_CleanAll(CACHE); #endif if (!NeedCheck) return ERROR_NONE; res = memcmp(address, Data, Len); if (res) { DBG_INFO("%x", res); FLASH_ProgramPage(address, size, Data); #if (defined __BUILD_OS__) || (defined __BUILD_APP__) CACHE_CleanAll(CACHE); #endif res = memcmp(address, Data, size); if (res) { DBG_INFO("%x", res); return -1; } } return 0; } #endif