/* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #include #include #include "flash.h" /****************************************************************************** * * Defines for accesses to the security control in the customer configuration * area in flash top sector. * ******************************************************************************/ #define CCFG_OFFSET_SECURITY CCFG_O_BL_CONFIG #define CCFG_SIZE_SECURITY 0x00000014 /****************************************************************************** * * Default values for security control in customer configuration area in flash * top sector. * ******************************************************************************/ const uint8_t g_ccfg_default_sec[] = { 0xFF, 0xFF, 0xFF, 0xC5, 0xFF, 0xFF, 0xFF, 0xFF, 0xC5, 0xFF, 0xFF, 0xFF, 0xC5, 0xC5, 0xC5, 0xFF, 0xC5, 0xC5, 0xC5, 0xFF }; typedef uint32_t (*flash_prg_pntr_t) (uint8_t *, uint32_t, uint32_t); typedef uint32_t (*flash_sector_erase_pntr_t) (uint32_t); /****************************************************************************** * * Function prototypes for static functions * ******************************************************************************/ static void issue_fsm_command(flash_state_command_t command); static void enable_sectors_for_write(void); static uint32_t scale_cycle_values(uint32_t specified_timing, uint32_t scale_value); static void set_write_mode(void); static void trim_for_write(void); static void set_read_mode(void); /****************************************************************************** * * Erase a flash sector * ******************************************************************************/ uint32_t flash_sector_erase(uint32_t sector_address) { uint32_t error_return; flash_sector_erase_pntr_t func_pntr; /* Call ROM function */ func_pntr = (uint32_t (*)(uint32_t))(ROM_API_FLASH_TABLE[5]); error_return = func_pntr(sector_address); /* Enable standby because ROM function might have disabled it */ HWREGBITW(FLASH_BASE + FLASH_O_CFG, FLASH_CFG_DIS_STANDBY_BITN) = 0; /* Return status of operation. */ return error_return; } /****************************************************************************** * * Erase all unprotected sectors in the flash main bank * ******************************************************************************/ uint32_t flash_bank_erase(bool force_precondition) { uint32_t error_return; uint32_t sector_address; uint32_t reg_val; /* Enable all sectors for erase. */ enable_sectors_for_write(); /* Clear the Status register. */ issue_fsm_command(FAPI_CLEAR_STATUS); /* Enable erase of all sectors and enable precondition if required. */ reg_val = HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE); HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR1) = 0x00000000; HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR2) = 0x00000000; if (force_precondition) HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) |= FLASH_FSM_ST_MACHINE_DO_PRECOND; HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; /* Issue the bank erase command to the FSM. */ issue_fsm_command(FAPI_ERASE_BANK); /* Wait for erase to finish. */ while (flash_check_fsm_for_ready() == FAPI_STATUS_FSM_BUSY) ; /* Update status. */ error_return = flash_check_fsm_for_error(); /* Disable sectors for erase. */ flash_disable_sectors_for_write(); /* Set configured precondition mode since it may have been forced on. */ if (!(reg_val & FLASH_FSM_ST_MACHINE_DO_PRECOND)) { HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) &= ~FLASH_FSM_ST_MACHINE_DO_PRECOND; HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; } /* Program security data to default values in the customer configuration */ /* area within the flash top sector if erase was successful. */ if (error_return == FAPI_STATUS_SUCCESS) { sector_address = FLASHMEM_BASE + flash_size_get() - flash_sector_size_get(); error_return = flash_program((uint8_t *)g_ccfg_default_sec, (sector_address + CCFG_OFFSET_SECURITY), CCFG_SIZE_SECURITY); } /* Return status of operation. */ return error_return; } /****************************************************************************** * * Programs unprotected main bank flash sectors * ******************************************************************************/ uint32_t flash_program(uint8_t *data_buffer, uint32_t address, uint32_t count) { uint32_t error_return; flash_prg_pntr_t func_pntr; /* Call ROM function */ func_pntr = (uint32_t (*)(uint8_t *, uint32_t, uint32_t)) (ROM_API_FLASH_TABLE[6]); error_return = func_pntr(data_buffer, address, count); /* Enable standby because ROM function might have disabled it */ HWREGBITW(FLASH_BASE + FLASH_O_CFG, FLASH_CFG_DIS_STANDBY_BITN) = 0; /* Return status of operation. */ return error_return; } /****************************************************************************** * * Disables all sectors for erase and programming on the active bank * ******************************************************************************/ void flash_disable_sectors_for_write(void) { /* Configure flash back to read mode */ set_read_mode(); /* Disable Level 1 Protection. */ HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS; /* Disable all sectors for erase and programming. */ HWREG(FLASH_BASE + FLASH_O_FBSE) = 0x0000; /* Enable Level 1 Protection. */ HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0; /* Protect sectors from sector erase. */ HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR1) = 0xFFFFFFFF; HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR2) = 0xFFFFFFFF; HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; } /****************************************************************************** * * Issues a command to the Flash State Machine. * ******************************************************************************/ static void issue_fsm_command(flash_state_command_t command) { /* Enable write to FSM register. */ HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; /* Issue FSM command. */ HWREG(FLASH_BASE + FLASH_O_FSM_CMD) = command; /* Start command execute. */ HWREG(FLASH_BASE + FLASH_O_FSM_EXECUTE) = FLASH_CMD_EXEC; /* Disable write to FSM register. */ HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; } /****************************************************************************** * * Enables all sectors for erase and programming on the active bank. * * This function disables the idle reading power reduction mode, selects the * flash bank and enables all sectors for erase and programming on the active * bank. * Sectors may be protected from programming depending on the value of the * FLASH_O_FSM_BSLPx registers. * Sectors may be protected from erase depending on the value of the * FLASH_O_FSM_BSLEx registers. Additional sector erase protection is set by * the FLASH_O_FSM_SECTOR1 register. * ******************************************************************************/ static void enable_sectors_for_write(void) { /* Trim flash module for program/erase operation. */ trim_for_write(); /* Configure flash to write mode */ set_write_mode(); /* Select flash bank. */ HWREG(FLASH_BASE + FLASH_O_FMAC) = 0x00; /* Disable Level 1 Protection. */ HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS; /* Enable all sectors for erase and programming. */ HWREG(FLASH_BASE + FLASH_O_FBSE) = 0xFFFF; /* Enable Level 1 Protection */ HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0; } /****************************************************************************** * * Trims the Flash Bank and Flash Pump for program/erase functionality * * This trimming will make it possible to perform erase and program operations * of the flash. Trim values are loaded from factory configuration area * (referred to as FCGF1). The trimming done by this function is valid until * reset of the flash module. * * Some registers shall be written with a value that is a number of FCLK * cycles. The trim values controlling these registers have a value of * number of half us. FCLK = SysClk / ((RWAIT+1) x 2). * ******************************************************************************/ static void trim_for_write(void) { uint32_t value; uint32_t temp_val; uint32_t fclk_scale; uint32_t rwait; /* Return if flash is already trimmed for program/erase operations. */ if (HWREG(FLASH_BASE + FLASH_O_FWFLAG) & FW_WRT_TRIMMED) return; /* Configure the FSM registers */ /* Enable access to the FSM registers. */ HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; /* Determine the scaling value to be used on timing related trim values. */ /* The value is based on the flash module clock frequency and RWAIT */ rwait = (HWREG(FLASH_BASE + FLASH_O_FRDCTL) & FLASH_FRDCTL_RWAIT_M) >> FLASH_FRDCTL_RWAIT_S; fclk_scale = (16 * FLASH_MODULE_CLK_FREQ) / (rwait + 1); /* Configure Program pulse width bits 15:0. */ /* (FCFG1 offset 0x188 bits 15:0). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_PROG_EP) & FCFG1_FLASH_PROG_EP_PROGRAM_PW_M) >> FCFG1_FLASH_PROG_EP_PROGRAM_PW_S; value = scale_cycle_values(value, fclk_scale); HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PW) = (HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PW) & ~FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_M) | ((value << FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_S) & FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_M); /* Configure Erase pulse width bits 31:0. */ /* (FCFG1 offset 0x18C bits 31:0). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_ERA_PW) & FCFG1_FLASH_ERA_PW_ERASE_PW_M) >> FCFG1_FLASH_ERA_PW_ERASE_PW_S; value = scale_cycle_values(value, fclk_scale); HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PW) = (HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PW) & ~FLASH_FSM_ERA_PW_FSM_ERA_PW_M) | ((value << FLASH_FSM_ERA_PW_FSM_ERA_PW_S) & FLASH_FSM_ERA_PW_FSM_ERA_PW_M); /* Configure no of flash clock cycles from EXECUTEZ going low to the the verify data can be read in the program verify mode bits 7:0. */ /* (FCFG1 offset 0x174 bits 23:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_C_E_P_R) & FCFG1_FLASH_C_E_P_R_PV_ACCESS_M) >> FCFG1_FLASH_C_E_P_R_PV_ACCESS_S; value = scale_cycle_values(value, fclk_scale); HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) = (HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) & ~FLASH_FSM_EX_VAL_EXE_VALD_M) | ((value << FLASH_FSM_EX_VAL_EXE_VALD_S) & FLASH_FSM_EX_VAL_EXE_VALD_M); /* Configure the number of flash clocks from the start of the Read mode at the end of the operations until the FSM clears the BUSY bit in FMSTAT. */ /* (FCFG1 offset 0x178 bits 23:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_P_R_PV) & FCFG1_FLASH_P_R_PV_RH_M) >> FCFG1_FLASH_P_R_PV_RH_S; HWREG(FLASH_BASE + FLASH_O_FSM_RD_H) = (HWREG(FLASH_BASE + FLASH_O_FSM_RD_H) & ~FLASH_FSM_RD_H_RD_H_M) | ((value << FLASH_FSM_RD_H_RD_H_S) & FLASH_FSM_RD_H_RD_H_M); /* Configure Program hold time */ /* (FCFG1 offset 0x178 bits 31:24). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_P_R_PV) & FCFG1_FLASH_P_R_PV_PH_M) >> FCFG1_FLASH_P_R_PV_PH_S; value = scale_cycle_values(value, fclk_scale); HWREG(FLASH_BASE + FLASH_O_FSM_P_OH) = (HWREG(FLASH_BASE + FLASH_O_FSM_P_OH) & ~FLASH_FSM_P_OH_PGM_OH_M) | ((value << FLASH_FSM_P_OH_PGM_OH_S) & FLASH_FSM_P_OH_PGM_OH_M); /* Configure Erase hold time */ /* (FCFG1 offset 0x17C bits 31:24). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_EH_SEQ) & FCFG1_FLASH_EH_SEQ_EH_M) >> FCFG1_FLASH_EH_SEQ_EH_S; value = scale_cycle_values(value, fclk_scale); HWREG(FLASH_BASE + FLASH_O_FSM_ERA_OH) = (HWREG(FLASH_BASE + FLASH_O_FSM_ERA_OH) & ~FLASH_FSM_ERA_OH_ERA_OH_M) | ((value << FLASH_FSM_ERA_OH_ERA_OH_S) & FLASH_FSM_ERA_OH_ERA_OH_M); /* Configure Program verify row switch time */ /* (FCFG1 offset0x178 bits 15:8). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_P_R_PV) & FCFG1_FLASH_P_R_PV_PVH_M) >> FCFG1_FLASH_P_R_PV_PVH_S; value = scale_cycle_values(value, fclk_scale); HWREG(FLASH_BASE + FLASH_O_FSM_PE_VH) = (HWREG(FLASH_BASE + FLASH_O_FSM_PE_VH) & ~FLASH_FSM_PE_VH_PGM_VH_M) | ((value << FLASH_FSM_PE_VH_PGM_VH_S) & FLASH_FSM_PE_VH_PGM_VH_M); /* Configure Program Operation Setup time */ /* (FCFG1 offset 0x170 bits 31:24). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) & FCFG1_FLASH_E_P_PSU_M) >> FCFG1_FLASH_E_P_PSU_S; HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) = (HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) & ~FLASH_FSM_PE_OSU_PGM_OSU_M) | ((value << FLASH_FSM_PE_OSU_PGM_OSU_S) & FLASH_FSM_PE_OSU_PGM_OSU_M); /* Configure Erase Operation Setup time */ /* (FCGF1 offset 0x170 bits 23:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) & FCFG1_FLASH_E_P_ESU_M) >> FCFG1_FLASH_E_P_ESU_S; HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) = (HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) & ~FLASH_FSM_PE_OSU_ERA_OSU_M) | ((value << FLASH_FSM_PE_OSU_ERA_OSU_S) & FLASH_FSM_PE_OSU_ERA_OSU_M); /* Confgure Program Verify Setup time */ /* (FCFG1 offset 0x170 bits 15:8). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) & FCFG1_FLASH_E_P_PVSU_M) >> FCFG1_FLASH_E_P_PVSU_S; HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) = (HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) & ~FLASH_FSM_PE_VSU_PGM_VSU_M) | ((value << FLASH_FSM_PE_VSU_PGM_VSU_S) & FLASH_FSM_PE_VSU_PGM_VSU_M); /* Configure Erase Verify Setup time */ /* (FCFG1 offset 0x170 bits 7:0). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) & FCFG1_FLASH_E_P_EVSU_M) >> FCFG1_FLASH_E_P_EVSU_S; HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) = (HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) & ~FLASH_FSM_PE_VSU_ERA_VSU_M) | ((value << FLASH_FSM_PE_VSU_ERA_VSU_S) & FLASH_FSM_PE_VSU_ERA_VSU_M); /* Configure Addr to EXECUTEZ low setup time */ /* (FCFG1 offset 0x174 bits 15:12). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_C_E_P_R) & FCFG1_FLASH_C_E_P_R_A_EXEZ_SETUP_M) >> FCFG1_FLASH_C_E_P_R_A_EXEZ_SETUP_S; HWREG(FLASH_BASE + FLASH_O_FSM_CMP_VSU) = (HWREG(FLASH_BASE + FLASH_O_FSM_CMP_VSU) & ~FLASH_FSM_CMP_VSU_ADD_EXZ_M) | ((value << FLASH_FSM_CMP_VSU_ADD_EXZ_S) & FLASH_FSM_CMP_VSU_ADD_EXZ_M); /* Configure Voltage Status Count */ /* (FCFG1 offset 0x17C bits 15:12). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_EH_SEQ) & FCFG1_FLASH_EH_SEQ_VSTAT_M) >> FCFG1_FLASH_EH_SEQ_VSTAT_S; HWREG(FLASH_BASE + FLASH_O_FSM_VSTAT) = (HWREG(FLASH_BASE + FLASH_O_FSM_VSTAT) & ~FLASH_FSM_VSTAT_VSTAT_CNT_M) | ((value << FLASH_FSM_VSTAT_VSTAT_CNT_S) & FLASH_FSM_VSTAT_VSTAT_CNT_M); /* Configure Repeat Verify action setup */ /* (FCFG1 offset 0x174 bits 31:24). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_C_E_P_R) & FCFG1_FLASH_C_E_P_R_RVSU_M) >> FCFG1_FLASH_C_E_P_R_RVSU_S; HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) = (HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) & ~FLASH_FSM_EX_VAL_REP_VSU_M) | ((value << FLASH_FSM_EX_VAL_REP_VSU_S) & FLASH_FSM_EX_VAL_REP_VSU_M); /* Configure Maximum Programming Pulses */ /* (FCFG1 offset 0x184 bits 15:0). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_PP) & FCFG1_FLASH_PP_MAX_PP_M) >> FCFG1_FLASH_PP_MAX_PP_S; HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) = (HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) & ~FLASH_FSM_PRG_PUL_MAX_PRG_PUL_M) | ((value << FLASH_FSM_PRG_PUL_MAX_PRG_PUL_S) & FLASH_FSM_PRG_PUL_MAX_PRG_PUL_M); /* Configure Beginning level for VHVCT used during erase modes */ /* (FCFG1 offset 0x180 bits 31:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_E) & FCFG1_FLASH_VHV_E_VHV_E_START_M) >> FCFG1_FLASH_VHV_E_VHV_E_START_S; HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) = (HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) & ~FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_M) | ((value << FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_S) & FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_M); /* Configure Maximum EC Level */ /* (FCFG1 offset 0x2B0 bits 21:18). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) & FCFG1_FLASH_OTP_DATA3_MAX_EC_LEVEL_M) >> FCFG1_FLASH_OTP_DATA3_MAX_EC_LEVEL_S; HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) = (HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) & ~FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_M) | ((value << FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_S) & FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_M); /* Configure Maximum Erase Pulses */ /* (FCFG1 offset 0x188 bits 31:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_PROG_EP) & FCFG1_FLASH_PROG_EP_MAX_EP_M) >> FCFG1_FLASH_PROG_EP_MAX_EP_S; HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) = (HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) & ~FLASH_FSM_ERA_PUL_MAX_ERA_PUL_M) | ((value << FLASH_FSM_ERA_PUL_MAX_ERA_PUL_S) & FLASH_FSM_ERA_PUL_MAX_ERA_PUL_M); /* Configure the VHVCT Step Size. This is the number of erase pulses that must be completed for each level before the FSM increments the CUR_EC_LEVEL to the next higher level. Actual erase pulses per level equals (EC_STEP_SIZE +1). The stepping is only needed for the VHVCT voltage. */ /* (FCFG1 offset 0x2B0 bits 31:23). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) & FCFG1_FLASH_OTP_DATA3_EC_STEP_SIZE_M) >> FCFG1_FLASH_OTP_DATA3_EC_STEP_SIZE_S; HWREG(FLASH_BASE + FLASH_O_FSM_STEP_SIZE) = (HWREG(FLASH_BASE + FLASH_O_FSM_STEP_SIZE) & ~FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_M) | ((value << FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_S) & FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_M); /* Configure the hight of each EC step. This is the number of counts that the CUR_EC_LEVEL will increment when going to a new level. Actual count size equals (EC_STEP_HEIGHT + 1). The stepping applies only to the VHVCT voltage. The read trim value is decremented by 1 before written to the register since actual counts equals (register value + 1). */ /* (FCFG1 offset 0x180 bits 15:0). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_E) & FCFG1_FLASH_VHV_E_VHV_E_STEP_HIGHT_M) >> FCFG1_FLASH_VHV_E_VHV_E_STEP_HIGHT_S; HWREG(FLASH_BASE + FLASH_O_FSM_EC_STEP_HEIGHT) = ((value - 1) & FLASH_FSM_EC_STEP_HEIGHT_EC_STEP_HEIGHT_M); /* Configure Precondition used in erase operations */ /* (FCFG1 offset 0x2B0 bit 22). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) & FCFG1_FLASH_OTP_DATA3_DO_PRECOND_M) >> FCFG1_FLASH_OTP_DATA3_DO_PRECOND_S; HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) = (HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) & ~FLASH_FSM_ST_MACHINE_DO_PRECOND_M) | ((value << FLASH_FSM_ST_MACHINE_DO_PRECOND_S) & FLASH_FSM_ST_MACHINE_DO_PRECOND_M); /* Enable the recommended Good Time function. */ HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) |= FLASH_FSM_ST_MACHINE_ONE_TIME_GOOD; /* Disable write access to FSM registers. */ HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; /* Configure the voltage registers */ /* Unlock voltage registers (0x2080 - 0x2098). */ HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; /* Configure voltage level for the specified pump voltage of high voltage supply input during erase operation VHVCT_E and TRIM13_E */ /* (FCFG1 offset 0x190 bits[3:0] and bits[11:8]). */ temp_val = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV); value = ((temp_val & FCFG1_FLASH_VHV_TRIM13_E_M)>> FCFG1_FLASH_VHV_TRIM13_E_S) << FLASH_FVHVCT1_TRIM13_E_S; value |= ((temp_val & FCFG1_FLASH_VHV_VHV_E_M)>> FCFG1_FLASH_VHV_VHV_E_S) << FLASH_FVHVCT1_VHVCT_E_S; HWREG(FLASH_BASE + FLASH_O_FVHVCT1) = (HWREG(FLASH_BASE + FLASH_O_FVHVCT1) & ~(FLASH_FVHVCT1_TRIM13_E_M | FLASH_FVHVCT1_VHVCT_E_M)) | value; /* Configure voltage level for the specified pump voltage of high voltage supply input during program verify operation VHVCT_PV and TRIM13_PV */ /* (OTP offset 0x194 bits[19:16] and bits[27:24]). */ temp_val = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_PV); value = ((temp_val & FCFG1_FLASH_VHV_PV_TRIM13_PV_M) >> FCFG1_FLASH_VHV_PV_TRIM13_PV_S) << FLASH_FVHVCT1_TRIM13_PV_S; value |= ((temp_val & FCFG1_FLASH_VHV_PV_VHV_PV_M) >> FCFG1_FLASH_VHV_PV_VHV_PV_S) << FLASH_FVHVCT1_VHVCT_PV_S; HWREG(FLASH_BASE + FLASH_O_FVHVCT1) = (HWREG(FLASH_BASE + FLASH_O_FVHVCT1) & ~(FLASH_FVHVCT1_TRIM13_PV_M | FLASH_FVHVCT1_VHVCT_PV_M)) | value; /* Configure voltage level for the specified pump voltage of high voltage supply input during program operation VHVCT_P and TRIM13_P */ /* (FCFG1 offset 0x190 bits[19:16] and bits[27:24]). */ temp_val = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV); value = ((temp_val & FCFG1_FLASH_VHV_TRIM13_P_M) >> FCFG1_FLASH_VHV_TRIM13_P_S) << FLASH_FVHVCT2_TRIM13_P_S; value |= ((temp_val & FCFG1_FLASH_VHV_VHV_P_M) >> FCFG1_FLASH_VHV_VHV_P_S) << FLASH_FVHVCT2_VHVCT_P_S; HWREG(FLASH_BASE + FLASH_O_FVHVCT2) = (HWREG(FLASH_BASE + FLASH_O_FVHVCT2) & ~(FLASH_FVHVCT2_TRIM13_P_M | FLASH_FVHVCT2_VHVCT_P_M)) | value; /* Configure voltage level for the specified pump voltage of wordline power supply for read mode */ /* (FCFG1 offset 0x198 Bits 15:8). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_V) & FCFG1_FLASH_V_V_READ_M) >> FCFG1_FLASH_V_V_READ_S; HWREG(FLASH_BASE + FLASH_O_FVREADCT) = (HWREG(FLASH_BASE + FLASH_O_FVREADCT) & ~FLASH_FVREADCT_VREADCT_M) | ((value << FLASH_FVREADCT_VREADCT_S) & FLASH_FVREADCT_VREADCT_M); /* Configure the voltage level for the VCG 2.5 CT pump voltage */ /* (FCFG1 offset 0x194 bits 15:8). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_PV) & FCFG1_FLASH_VHV_PV_VCG2P5_M) >> FCFG1_FLASH_VHV_PV_VCG2P5_S; HWREG(FLASH_BASE + FLASH_O_FVNVCT) = (HWREG(FLASH_BASE + FLASH_O_FVNVCT) & ~FLASH_FVNVCT_VCG2P5CT_M) | ((value << FLASH_FVNVCT_VCG2P5CT_S) & FLASH_FVNVCT_VCG2P5CT_M); /* Configure the voltage level for the specified pump voltage of high current power input during program operation */ /* (FCFG1 offset 0x198 bits 31:24). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_V) & FCFG1_FLASH_V_VSL_P_M) >> FCFG1_FLASH_V_VSL_P_S; HWREG(FLASH_BASE + FLASH_O_FVSLP) = (HWREG(FLASH_BASE + FLASH_O_FVSLP) & ~FLASH_FVSLP_VSL_P_M) | ((value << FLASH_FVSLP_VSL_P_S) & FLASH_FVSLP_VSL_P_M); /* Configure the voltage level for the specified pump voltage of wordline power supply during programming operations */ /* (OTP offset 0x198 bits 23:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_V) & FCFG1_FLASH_V_VWL_P_M) >> FCFG1_FLASH_V_VWL_P_S; HWREG(FLASH_BASE + FLASH_O_FVWLCT) = (HWREG(FLASH_BASE + FLASH_O_FVWLCT) & ~FLASH_FVWLCT_VWLCT_P_M) | ((value << FLASH_FVWLCT_VWLCT_P_S) & FLASH_FVWLCT_VWLCT_P_M); /* Configure the pump's TRIM_1P7 port pins. */ /* (FCFG1 offset 0x2B0 bits 17:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) & FCFG1_FLASH_OTP_DATA3_TRIM_1P7_M) >> FCFG1_FLASH_OTP_DATA3_TRIM_1P7_S; HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & ~FLASH_FSEQPMP_TRIM_1P7_M) | ((value << FLASH_FSEQPMP_TRIM_1P7_S) & FLASH_FSEQPMP_TRIM_1P7_M); /* Lock the voltage registers. */ HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; /* Set trimmed flag. */ HWREG(FLASH_BASE + FLASH_O_FWLOCK) = 5; HWREG(FLASH_BASE + FLASH_O_FWFLAG) |= FW_WRT_TRIMMED; HWREG(FLASH_BASE + FLASH_O_FWLOCK) = 0; } /****************************************************************************** * * Used to scale the TI OTP values based on the FClk scaling value. * ******************************************************************************/ static uint32_t scale_cycle_values(uint32_t specified_timing, uint32_t scale_value) { uint32_t scaled_value = (specified_timing * scale_value) >> 6; return scaled_value; } /****************************************************************************** * * Used to set flash in read mode. * * Flash is configured with values loaded from OTP dependent on the current * regulator mode. * ******************************************************************************/ static void set_read_mode(void) { uint32_t trim_value; uint32_t value; /* Configure the STANDBY_MODE_SEL, STANDBY_PW_SEL, DIS_STANDBY, DIS_IDLE, VIN_AT_X and VIN_BY_PASS for read mode */ if (HWREG(AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL) & AON_PMCTL_PWRCTL_EXT_REG_MODE) { /* Select trim values for external regulator mode: Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 7) Configure STANDBY_PW_SEL (OTP offset 0x308 bit 6:5) Must be done while the register bit field CONFIG.DIS_STANDBY = 1 */ HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY; trim_value = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4); value = ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_RD_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_RD_S) << FLASH_CFG_STANDBY_MODE_SEL_S; value |= ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_RD_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_RD_S) << FLASH_CFG_STANDBY_PW_SEL_S; /* Configure DIS_STANDBY (OTP offset 0x308 bit 4). Configure DIS_IDLE (OTP offset 0x308 bit 3). */ value |= ((trim_value & (FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_EXT_RD_M | FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_RD_M)) >> FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_RD_S) << FLASH_CFG_DIS_IDLE_S; HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) & ~(FLASH_CFG_STANDBY_MODE_SEL_M | FLASH_CFG_STANDBY_PW_SEL_M | FLASH_CFG_DIS_STANDBY_M | FLASH_CFG_DIS_IDLE_M)) | value; /* Check if sample and hold functionality is disabled. */ if (HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE) { /* Wait for disabled sample and hold functionality to be stable. */ while (!(HWREG(FLASH_BASE+FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS)) ; } /* Configure VIN_AT_X (OTP offset 0x308 bits 2:0) */ value = ((trim_value & FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_RD_M) >> FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_RD_S) << FLASH_FSEQPMP_VIN_AT_X_S; /* Configure VIN_BY_PASS which is dependent on the VIN_AT_X value. If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise VIN_BY_PASS should be 1 */ if (((value & FLASH_FSEQPMP_VIN_AT_X_M) >> FLASH_FSEQPMP_VIN_AT_X_S) != 0x7) value |= FLASH_FSEQPMP_VIN_BY_PASS; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & ~(FLASH_FSEQPMP_VIN_BY_PASS_M | FLASH_FSEQPMP_VIN_AT_X_M)) | value; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; } else { /* Select trim values for internal regulator mode: Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 15) COnfigure STANDBY_PW_SEL (OTP offset 0x308 bit 14:13) Must be done while the register bit field CONFIG.DIS_STANDBY = 1 */ HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY; trim_value = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4); value = ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_RD_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_RD_S) << FLASH_CFG_STANDBY_MODE_SEL_S; value |= ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_RD_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_RD_S) << FLASH_CFG_STANDBY_PW_SEL_S; /* Configure DIS_STANDBY (OTP offset 0x308 bit 12). Configure DIS_IDLE (OTP offset 0x308 bit 11). */ value |= ((trim_value & (FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_INT_RD_M | FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_RD_M)) >> FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_RD_S) << FLASH_CFG_DIS_IDLE_S; HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) & ~(FLASH_CFG_STANDBY_MODE_SEL_M | FLASH_CFG_STANDBY_PW_SEL_M | FLASH_CFG_DIS_STANDBY_M | FLASH_CFG_DIS_IDLE_M)) | value; /* Check if sample and hold functionality is disabled. */ if (HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE) { /* Wait for disabled sample and hold functionality to be stable. */ while (!(HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS)) ; } /* Configure VIN_AT_X (OTP offset 0x308 bits 10:8) */ value = (((trim_value & FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_RD_M) >> FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_RD_S) << FLASH_FSEQPMP_VIN_AT_X_S); /* Configure VIN_BY_PASS which is dependent on the VIN_AT_X value. If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise VIN_BY_PASS should be 1 */ if (((value & FLASH_FSEQPMP_VIN_AT_X_M) >> FLASH_FSEQPMP_VIN_AT_X_S) != 0x7) value |= FLASH_FSEQPMP_VIN_BY_PASS; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & ~(FLASH_FSEQPMP_VIN_BY_PASS_M | FLASH_FSEQPMP_VIN_AT_X_M)) | value; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; } } /****************************************************************************** * * Used to set flash in write mode. * * Flash is configured with values loaded from OTP dependent on the current * regulator mode. * ******************************************************************************/ static void set_write_mode(void) { uint32_t trim_value; uint32_t value; /* Configure the STANDBY_MODE_SEL, STANDBY_PW_SEL, DIS_STANDBY, DIS_IDLE, VIN_AT_X and VIN_BY_PASS for program/erase mode */ if (HWREG(AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL) & AON_PMCTL_PWRCTL_EXT_REG_MODE) { /* Select trim values for external regulator mode: Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 23) Configure STANDBY_PW_SEL (OTP offset 0x308 bit 22:21) Must be done while the register bit field CONFIG.DIS_STANDBY = 1 */ HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY; trim_value = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4); value = ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_WRT_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_WRT_S) << FLASH_CFG_STANDBY_MODE_SEL_S; value |= ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_WRT_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_WRT_S) << FLASH_CFG_STANDBY_PW_SEL_S; /* Configure DIS_STANDBY (OTP offset 0x308 bit 20). Configure DIS_IDLE (OTP offset 0x308 bit 19). */ value |= ((trim_value & (FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_EXT_WRT_M | FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_WRT_M)) >> FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_WRT_S) << FLASH_CFG_DIS_IDLE_S; HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) & ~(FLASH_CFG_STANDBY_MODE_SEL_M | FLASH_CFG_STANDBY_PW_SEL_M | FLASH_CFG_DIS_STANDBY_M | FLASH_CFG_DIS_IDLE_M)) | value; /* Check if sample and hold functionality is disabled. */ if (HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE) { /* Wait for disabled sample and hold functionality to be stable. */ while (!(HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS)) ; } /* Configure VIN_AT_X (OTP offset 0x308 bits 18:16) */ value = ((trim_value & FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_WRT_M) >> FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_WRT_S) << FLASH_FSEQPMP_VIN_AT_X_S; /* Configure VIN_BY_PASS which is dependent on the VIN_AT_X value. If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise VIN_BY_PASS should be 1 */ if (((value & FLASH_FSEQPMP_VIN_AT_X_M) >> FLASH_FSEQPMP_VIN_AT_X_S) != 0x7) value |= FLASH_FSEQPMP_VIN_BY_PASS; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & ~(FLASH_FSEQPMP_VIN_BY_PASS_M | FLASH_FSEQPMP_VIN_AT_X_M)) | value; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; } else { /* Select trim values for internal regulator mode: Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 31) COnfigure STANDBY_PW_SEL (OTP offset 0x308 bit 30:29) Must be done while the register bit field CONFIG.DIS_STANDBY = 1 */ HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY; trim_value = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4); value = ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_WRT_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_WRT_S) << FLASH_CFG_STANDBY_MODE_SEL_S; value |= ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_WRT_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_WRT_S) << FLASH_CFG_STANDBY_PW_SEL_S; /* Configure DIS_STANDBY (OTP offset 0x308 bit 28). Configure DIS_IDLE (OTP offset 0x308 bit 27). */ value |= ((trim_value & (FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_INT_WRT_M | FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_WRT_M)) >> FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_WRT_S) << FLASH_CFG_DIS_IDLE_S; HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) & ~(FLASH_CFG_STANDBY_MODE_SEL_M | FLASH_CFG_STANDBY_PW_SEL_M | FLASH_CFG_DIS_STANDBY_M | FLASH_CFG_DIS_IDLE_M)) | value; /* Check if sample and hold functionality is disabled. */ if (HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE) { /* Wait for disabled sample and hold functionality to be stable. */ while (!(HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS)) ; } /* Configure VIN_AT_X (OTP offset 0x308 bits 26:24) */ value = ((trim_value & FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_WRT_M) >> FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_WRT_S) << FLASH_FSEQPMP_VIN_AT_X_S; /* Configure VIN_BY_PASS which is dependent on the VIN_AT_X value. If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise VIN_BY_PASS should be 1 */ if (((value & FLASH_FSEQPMP_VIN_AT_X_M) >> FLASH_FSEQPMP_VIN_AT_X_S) != 0x7) value |= FLASH_FSEQPMP_VIN_BY_PASS; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & ~(FLASH_FSEQPMP_VIN_BY_PASS_M | FLASH_FSEQPMP_VIN_AT_X_M)) | value; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; } }