| | |
| | | #define BIT(x) (0x1UL << (x)) |
| | | |
| | | FLASH_IDS_T flash_ids = {0}; |
| | | uint8_t ft_chip_info; |
| | | |
| | | static void FMC_TrigErrorHandler(FLCTL_T *fmc) |
| | | { |
| | |
| | | FMC_ReadByte(FLCTL, 0x1000, CMD_DREAD); |
| | | FMC_WriteDisable(FLCTL); |
| | | } |
| | | } |
| | | |
| | | void FMC_ParamsSet(OTP_STRUCT_T *otp) |
| | | { |
| | | ft_chip_info = otp->m.chip_info; |
| | | } |
| | | |
| | | void FMC_GetFlashUniqueId(FLCTL_T *fmc) |
| | |
| | | flash_ids.manufacturer_id = FLCTL_BUFF->X_FL_BUFFER[0]; |
| | | flash_ids.memory_type_id = FLCTL_BUFF->X_FL_BUFFER[1]; |
| | | flash_ids.memory_density_id = FLCTL_BUFF->X_FL_BUFFER[2]; |
| | | |
| | | if (((ft_chip_info & 0x1F) == 0x2) && (flash_ids.manufacturer_id == 0xC4)) { |
| | | flash_ids.memory_density_id = 0x12; |
| | | } |
| | | } |
| | | |
| | | void FMC_SetFlashCapacity(FLCTL_T *fmc) |
| | |
| | | */ |
| | | int FMC_Erase(FLCTL_T *fmc,unsigned int Addr,unsigned char cmd) |
| | | { |
| | | #if FMC_DBG_LOG |
| | | if (cmd == CMD_ERASE_SECTOR) { |
| | | SYS_TEST("Erase Addr: 0x%08x (Sector Erase)\n", Addr); |
| | | } else if (cmd == CMD_ERASE_32K) { |
| | | SYS_TEST("Erase Addr: 0x%08x (BLK32k Erase)\n", Addr); |
| | | } else if (cmd == CMD_ERASE_64K) { |
| | | SYS_TEST("Erase Addr: 0x%08x (BLK64k Erase)\n", Addr); |
| | | } else { |
| | | SYS_TEST("Unhandled Erase CMD, Addr: 0x%08x, CMD: %d\n", Addr, cmd); |
| | | } |
| | | #endif |
| | | |
| | | unsigned char offset = 0; |
| | | unsigned char bytes_num_w; |
| | | |
| | |
| | | fmc->X_FL_TRIG = CMD_TRIG; |
| | | while(fmc->X_FL_TRIG){} |
| | | FMC_TrigErrorHandler(fmc); |
| | | while(FMC_ReadStatusReg(fmc,CMD_READ_STATUS_L) & Write_In_Process_Msk) {} |
| | | // while(FMC_ReadStatusReg(fmc,CMD_READ_STATUS_L) & Write_In_Process_Msk) {} |
| | | return 0; |
| | | } |
| | | |
| | |
| | | if (addr >= FMC_GetFlashCodeAreaSize(fmc)) { |
| | | return -1; |
| | | } |
| | | |
| | | // Ensure we will not touch the flash INFO area |
| | | fmc->X_FL_CONFIG &= ~BIT1; //clear info_en bit |
| | | fmc->X_FL_CONFIG |= BIT2; //set tx_address_transaction bit |
| | | |
| | | return FMC_Erase(fmc,addr,CMD_ERASE_SECTOR); |
| | | } |
| | | |
| | |
| | | || (addr < 0x7000)) { |
| | | return -1; |
| | | } |
| | | |
| | | // Ensure we will not touch the flash INFO area |
| | | fmc->X_FL_CONFIG &= ~BIT1; //clear info_en bit |
| | | fmc->X_FL_CONFIG |= BIT2; //set tx_address_transaction bit |
| | | |
| | | return FMC_Erase(fmc,addr,CMD_ERASE_32K); |
| | | } |
| | | |
| | |
| | | || (addr < 0xF000)) { |
| | | return -1; |
| | | } |
| | | return FMC_Erase(fmc,addr,CMD_ERASE_64K); |
| | | } |
| | | |
| | | /** |
| | | * @brief Erase the whole flash memory. |
| | | * |
| | | * This function is used to erase all data in flash, include |
| | | * Code Area and Info Area. |
| | | * |
| | | * @note This API should only be used when you really know what |
| | | * you are doing. |
| | | * |
| | | * @param fmc: where fmc is a flash peripheral. |
| | | * @retval 0: Success. |
| | | * @retval -1: Fail. |
| | | */ |
| | | int FMC_EraseChip(FLCTL_T *fmc) |
| | | { |
| | | return FMC_Erase(fmc,0x0,CMD_ERASE_CHIP); |
| | | // Ensure we will not touch the flash INFO area |
| | | fmc->X_FL_CONFIG &= ~BIT1; //clear info_en bit |
| | | fmc->X_FL_CONFIG |= BIT2; //set tx_address_transaction bit |
| | | |
| | | return FMC_Erase(fmc,addr,CMD_ERASE_64K); |
| | | } |
| | | |
| | | static void find_special_chunk_in_range(size_t chunk_pattern, uint32_t range_start_sector_idx, uint16_t range_sector_num, |
| | |
| | | return -1; |
| | | } |
| | | |
| | | // Fine 32K blocks from the initial data chunk |
| | | // Find 32K blocks from the initial data chunk |
| | | find_special_chunk_in_range(8, start_phy_sector_idx, sector_num, &block_32k_start_sector_idx, &block_32k_sector_num); |
| | | |
| | | if (block_32k_sector_num == 0) { // No 32k-block found |
| | |
| | | * @brief This function is used to read flash, |
| | | * @param fmc: where fmc is a flash peripheral. |
| | | * @param Addr: where Addr is start address to read |
| | | * @param cmd: where cmd can be CMD_FAST_READ or CMD_NOR_READ |
| | | * @param cmd: where cmd can be \ref CMD_FAST_READ or \ref CMD_DREAD |
| | | * @retval 4byte data |
| | | */ |
| | | unsigned int FMC_ReadWord(FLCTL_T *fmc,unsigned int Addr, unsigned char cmd) |
| | |
| | | * @brief This function is used to read flash, |
| | | * @param fmc: where fmc is a flash peripheral. |
| | | * @param Addr: where Addr is start address to read |
| | | * @param cmd: where cmd can be CMD_FAST_READ or CMD_NOR_READ |
| | | * @param cmd: where cmd can be \ref CMD_FAST_READ or \ref CMD_DREAD |
| | | * @retval 1byte data |
| | | */ |
| | | unsigned char FMC_ReadByte(FLCTL_T *fmc,unsigned int Addr,unsigned char cmd) |
| | |
| | | * @brief This function is used to read a page size (256 bytes) of data from flash |
| | | * @param fmc where fmc is a flash peripheral. |
| | | * @param Addr where Addr is start address to read |
| | | * @param cmd where cmd can be CMD_FAST_READ or CMD_NORM_READ |
| | | * @param cmd where cmd can be \ref CMD_FAST_READ or \ref CMD_DREAD |
| | | * @retval Internal Buffer address |
| | | */ |
| | | unsigned char *FMC_ReadPage(FLCTL_T *fmc,unsigned int Addr,unsigned char cmd) |
| | |
| | | return (unsigned char *)&(FLCTL_BUFF->X_FL_BUFFER[0]); |
| | | } |
| | | |
| | | /** |
| | | * @brief This function is used to read data stream from flash |
| | | * @param fmc where fmc is a flash peripheral. |
| | | * @param Addr where Addr is start address to read |
| | | * @param cmd where cmd can be CMD_FAST_READ or CMD_NORM_READ |
| | | * @param buf where buf is a buffer to store read data |
| | | * @param len where len is data length of bytes to read |
| | | * @retval None |
| | | */ |
| | | int FMC_ReadStream(FLCTL_T *fmc, unsigned int Addr, unsigned char cmd, unsigned char *buf, unsigned int len) |
| | | static int FMC_ReadStreamInternal(FLCTL_T *fmc, unsigned int Addr, unsigned char cmd, unsigned char *buf, unsigned int len) |
| | | { |
| | | unsigned int tmp_addr = Addr; |
| | | unsigned int tmp_size = len; |
| | |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | /** |
| | | * @brief This function is used to read data stream from flash |
| | | * @param fmc where fmc is a flash peripheral. |
| | | * @param Addr where Addr is start address to read |
| | | * @param cmd where cmd can be \ref CMD_FAST_READ or \ref CMD_DREAD |
| | | * @param buf where buf is a buffer to store read data |
| | | * @param len where len is data length of bytes to read |
| | | * @retval None |
| | | */ |
| | | int FMC_ReadStream(FLCTL_T *fmc, unsigned int Addr, unsigned char cmd, unsigned char *buf, unsigned int len) |
| | | { |
| | | // Ensure we will not touch the flash INFO area |
| | | fmc->X_FL_CONFIG &= ~BIT1; //clear info_en bit |
| | | fmc->X_FL_CONFIG |= BIT2; //set tx_address_transaction bit |
| | | |
| | | return FMC_ReadStreamInternal(fmc, Addr, cmd, buf, len); |
| | | } |
| | | /** |
| | | * @brief This function is used to write data to buffer, |
| | |
| | | if (OffsetOfCurrPage + size > 256) |
| | | return -1; |
| | | |
| | | if(FMC_WriteEnable(fmc) == 0) |
| | | return -1; |
| | | |
| | | // Fill the 256-Bytes FMC Write Buffer |
| | | for(size_t i = 0; i < 256; i++) |
| | | if (flash_ids.manufacturer_id == 0x85) |
| | | { |
| | | if ((i >= OffsetOfCurrPage) && (i < OffsetOfCurrPage + size)) |
| | | FLCTL_BUFF->X_FL_BUFFER[i] = *(buf++); |
| | | if (size < 256) |
| | | { |
| | | // Read page back |
| | | FMC_ReadPage(fmc, PageStartAddr, CMD_DREAD); |
| | | // Fill anticipatory data to fmc write buffer |
| | | for (size_t i = 0; i < size; i++) |
| | | { |
| | | FLCTL_BUFF->X_FL_BUFFER[OffsetOfCurrPage + i] = *(buf++); |
| | | } |
| | | // Erase current page |
| | | FMC_Erase(FLCTL, PageStartAddr, CMD_ERASE_PAGE); |
| | | } |
| | | else |
| | | FLCTL_BUFF->X_FL_BUFFER[i] = 0xFF; |
| | | { |
| | | // Fill the 256-Bytes FMC Write Buffer |
| | | for (size_t i = 0; i < 256; i++) |
| | | { |
| | | FLCTL_BUFF->X_FL_BUFFER[i] = *(buf++); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // Fill the 256-Bytes FMC Write Buffer |
| | | for (size_t i = 0; i < 256; i++) |
| | | { |
| | | if ((i >= OffsetOfCurrPage) && (i < OffsetOfCurrPage + size)) |
| | | FLCTL_BUFF->X_FL_BUFFER[i] = *(buf++); |
| | | else |
| | | FLCTL_BUFF->X_FL_BUFFER[i] = 0xFF; |
| | | } |
| | | } |
| | | |
| | | if (FMC_WriteEnable(fmc) == 0) |
| | | return -1; |
| | | |
| | | fmc->X_FL_CTL = (0<<8) | (0x04<<0); |
| | | fmc->X_FL_CONFIG |= 0x1; //pp active |
| | |
| | | return 0; |
| | | } |
| | | |
| | | /** |
| | | * @brief This function is used to write data stream to flash |
| | | * @param fmc where fmc is a flash peripheral |
| | | * @param Addr where Addr is start address to write, can be any valid address |
| | | * @param buf where buf is a buffer to store data to write |
| | | * @param len where len is data length of bytes to write |
| | | * @retval None |
| | | */ |
| | | int FMC_WriteStream(FLCTL_T *fmc, unsigned int Addr, unsigned char *buf, unsigned int len) |
| | | static int FMC_WriteStreamInternal(FLCTL_T *fmc, unsigned int Addr, unsigned char *buf, unsigned int len) |
| | | { |
| | | unsigned int OffsetOfFirstPage = Addr % 256; |
| | | unsigned int WriteSizeInFirstPage = (len < (256 - OffsetOfFirstPage)) ? len : (256 - OffsetOfFirstPage); |
| | |
| | | } |
| | | |
| | | /** |
| | | * @brief This function is used to write data stream to flash |
| | | * @param fmc where fmc is a flash peripheral |
| | | * @param Addr where Addr is start address to write, can be any valid address |
| | | * @param buf where buf is a buffer to store data to write |
| | | * @param len where len is data length of bytes to write |
| | | * @retval None |
| | | */ |
| | | int FMC_WriteStream(FLCTL_T *fmc, unsigned int Addr, unsigned char *buf, unsigned int len) |
| | | { |
| | | // Ensure we will not touch the flash INFO area |
| | | fmc->X_FL_CONFIG &= ~BIT1; //clear info_en bit |
| | | fmc->X_FL_CONFIG |= BIT2; //set tx_address_transaction bit |
| | | |
| | | return FMC_WriteStreamInternal(fmc, Addr, buf, len); |
| | | } |
| | | |
| | | /** |
| | | * @brief This function is used to read data from the flash 4KB INFO area. |
| | | * @param fmc where fmc is a flash peripheral. |
| | | * @param Addr where Addr is start address to read, can be 0 ~ 4095 |
| | | * @param cmd where cmd can be CMD_FAST_READ or CMD_NORM_READ |
| | | * @param cmd where cmd can be \ref CMD_FAST_READ or \ref CMD_DREAD |
| | | * @param buf where buf is a buffer to store read data |
| | | * @param len where len is data length of bytes to read |
| | | * @retval 0 read success |
| | |
| | | fmc->X_FL_CONFIG |= BIT1; //set info_en bit |
| | | fmc->X_FL_CONFIG |= BIT2; //set tx_address_transaction bit |
| | | |
| | | FMC_ReadStream(fmc, Addr, cmd, buf, len); |
| | | FMC_ReadStreamInternal(fmc, Addr, cmd, buf, len); |
| | | |
| | | fmc->X_FL_CONFIG &= ~BIT1; //clear info_en bit |
| | | fmc->X_FL_CONFIG |= BIT2; //set tx_address_transaction bit |
| | |
| | | * @param Addr where Addr is start address to write, can be 0 ~ 4095 |
| | | * @param buf where buf is a buffer to store data to write |
| | | * @param len where len is data length of bytes to write |
| | | * @note [CAUTION!] This is a dangerous API! It may destroy the calibrate |
| | | * data of SoC, do not call this API if you are not sure the actual |
| | | * behavior of it! |
| | | * @retval 0 write success |
| | | * @retval -1 write fail |
| | | */ |
| | |
| | | fmc->X_FL_CONFIG |= BIT1; //set info_en bit |
| | | fmc->X_FL_CONFIG |= BIT2; //set tx_address_transaction bit |
| | | |
| | | FMC_WriteStream(fmc, Addr, buf, len); |
| | | FMC_WriteStreamInternal(fmc, Addr, buf, len); |
| | | |
| | | fmc->X_FL_CONFIG &= ~BIT1; //clear info_en bit |
| | | fmc->X_FL_CONFIG |= BIT2; //set tx_address_transaction bit |
| | |
| | | fmc->X_FL_CONFIG |= BIT1; //set info_en bit |
| | | fmc->X_FL_CONFIG |= BIT2; //set tx_address_transaction bit |
| | | |
| | | ret = FMC_EraseSector(fmc, 0x0); |
| | | ret = FMC_Erase(fmc, 0x0, CMD_ERASE_SECTOR); |
| | | |
| | | fmc->X_FL_CONFIG &= ~BIT1; //clear info_en bit |
| | | fmc->X_FL_CONFIG |= BIT2; //set tx_address_transaction bit |