// Copyright 2020-2021 Beken // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include #include #include "flash_driver.h" #include "flash_hal.h" #include "sys_driver.h" #include "driver/flash_partition.h" #include #include "flash_bypass.h" #if (CONFIG_SOC_BK7236XX) || (CONFIG_SOC_BK7239XX) #include "partitions_gen.h" #endif #ifdef CONFIG_FREERTOS_SMP #include "spinlock.h" static SPINLOCK_SECTION volatile spinlock_t flash_spin_lock = SPIN_LOCK_INIT; #endif // CONFIG_FREERTOS_SMP typedef struct { flash_hal_t hal; uint32_t flash_id; uint32_t flash_status_reg_val; uint32_t flash_line_mode; const flash_config_t * flash_cfg; } flash_driver_t; typedef struct { uint32_t reg16; uint32_t reg17; } flash_ctrl_context_t; #define FLASH_GET_PROTECT_CFG(cfg) ((cfg) & FLASH_STATUS_REG_PROTECT_MASK) #define FLASH_GET_CMP_CFG(cfg) (((cfg) >> FLASH_STATUS_REG_PROTECT_OFFSET) & FLASH_STATUS_REG_PROTECT_MASK) #define FLASH_RETURN_ON_DRIVER_NOT_INIT() do {\ if (!s_flash_is_init) {\ return BK_ERR_FLASH_NOT_INIT;\ }\ } while(0) #define FLASH_RETURN_ON_WRITE_ADDR_OUT_OF_RANGE(addr, len) do {\ if ((addr >= s_flash.flash_cfg->flash_size) ||\ (len > s_flash.flash_cfg->flash_size) ||\ ((addr + len) > s_flash.flash_cfg->flash_size)) {\ FLASH_LOGW("write error[addr:0x%x len:0x%x]\r\n", addr, len);\ return BK_ERR_FLASH_ADDR_OUT_OF_RANGE;\ }\ } while(0) static const flash_config_t flash_config[] = { /* flash_id, flash_size, status_reg_size, line_mode, cmp_post, protect_post, protect_mask, protect_all, protect_none, unprotect_last_block. quad_en_post, quad_en_val, coutinuous_read_mode_bits_val */ {0x1C7016, FLASH_SIZE_4M, 1, FLASH_LINE_MODE_FOUR, 0, 2, 0x1F, 0x1F, 0x00, 0x01B, 9, 1, 0xA5, }, //en_25qh32b {0x1C7015, FLASH_SIZE_2M, 1, FLASH_LINE_MODE_FOUR, 0, 2, 0x1F, 0x1F, 0x00, 0x0d, 9, 1, 0xA5, }, //en_25qh16b {0x0B4014, FLASH_SIZE_1M, 2, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x101, 9, 1, 0xA0, }, //xtx_25f08b {0x0B4015, FLASH_SIZE_2M, 2, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x101, 9, 1, 0xA0, }, //xtx_25f16b {0x0B4016, FLASH_SIZE_4M, 2, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x101, 9, 1, 0xA0, }, //xtx_25f32b {0x0B4017, FLASH_SIZE_8M, 2, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x05, 0x00, 0x109, 9, 1, 0xA0, }, //xtx_25f64b {0x0B6017, FLASH_SIZE_8M, 2, FLASH_LINE_MODE_FOUR, 0, 2, 0x0F, 0x0F, 0x00, 0x00E, 9, 1, 0xA0, }, //xt_25q64d {0x0B6018, FLASH_SIZE_16M, 2, FLASH_LINE_MODE_FOUR, 0, 2, 0x0F, 0x0F, 0x00, 0x00E, 9, 1, 0xA0, }, //xt_25q128d {0x0B4018, FLASH_SIZE_16M, 2, FLASH_LINE_MODE_FOUR, 0, 2, 0x0F, 0x0F, 0x00, 0x00E, 9, 1, 0xA0, }, //xt_25F128F-W {0x0E4016, FLASH_SIZE_4M, 2, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x101, 9, 1, 0xA0, }, //xtx_FT25H32 {0x1C4116, FLASH_SIZE_4M, 1, FLASH_LINE_MODE_FOUR, 0, 2, 0x1F, 0x1F, 0x00, 0x00E, 9, 1, 0xA0, }, //en_25qe32a(not support 4 line) {0x5E5018, FLASH_SIZE_16M, 1, FLASH_LINE_MODE_FOUR, 0, 2, 0x0F, 0x0F, 0x00, 0x00E, 9, 1, 0xA0, }, //zb_25lq128c {0xC84015, FLASH_SIZE_2M, 2, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x101, 9, 1, 0xA0, }, //gd_25q16c {0xC84017, FLASH_SIZE_8M, 1, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x101, 9, 1, 0xA0, }, //gd_25q16c {0xC84016, FLASH_SIZE_4M, 3, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x00E, 9, 1, 0xA0, }, //gd_25q32c {0xC86018, FLASH_SIZE_16M, 2, FLASH_LINE_MODE_FOUR, 0, 2, 0x0F, 0x0F, 0x00, 0x00E, 9, 1, 0xA0, }, //gd_25lq128e {0xC86515, FLASH_SIZE_2M, 2, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x101, 9, 1, 0xA0, }, //gd_25w16e {0xC86516, FLASH_SIZE_4M, 2, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x00E, 9, 1, 0xA0, }, //gd_25wq32e {0xEF4016, FLASH_SIZE_4M, 2, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x101, 9, 1, 0xA0, }, //w_25q32(bfj) {0x204118, FLASH_SIZE_16M, 2, FLASH_LINE_MODE_FOUR, 0, 2, 0x0F, 0x0F, 0x00, 0x00E, 9, 1, 0xA0, }, //xm_25qu128c {0x204016, FLASH_SIZE_4M, 2, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x101, 9, 1, 0xA0, }, //xmc_25qh32b {0xC22315, FLASH_SIZE_2M, 1, FLASH_LINE_MODE_FOUR, 0, 2, 0x0F, 0x0F, 0x00, 0x00E, 6, 1, 0xA5, }, //mx_25v16b {0xEB6015, FLASH_SIZE_2M, 2, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x101, 9, 1, 0xA0, }, //zg_th25q16b {0xC86517, FLASH_SIZE_8M, 2, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x00E, 9, 1, 0xA0, }, //gd_25Q32E {0xCD6017, FLASH_SIZE_8M, 3, FLASH_LINE_MODE_FOUR, 14, 2, 0x1F, 0x1F, 0x00, 0x00E, 9, 1, 0xA0, }, //th_25q64ha {0x000000, FLASH_SIZE_4M, 2, FLASH_LINE_MODE_TWO, 0, 2, 0x1F, 0x00, 0x00, 0x000, 0, 0, 0x00, }, //default }; static flash_driver_t s_flash = {0}; static bool s_flash_is_init = false; // static flash_ctrl_context_t flash_ctrl_context; #if (CONFIG_SOC_BK7256XX) static uint32_t s_hold_low_speed_status = 0; #endif extern bk_err_t mb_flash_ipc_init(void); extern bk_err_t mb_flash_op_prepare(void); extern bk_err_t mb_flash_op_finish(void); extern bk_err_t bk_flash_partition_write_perm_check_by_addr(uint32_t addr, uint32_t size, uint32_t magic_code); extern int xTaskResumeAll( void ); extern void vTaskSuspendAll( void ); static inline uint32_t flash_enter_critical() { uint32_t flags = rtos_disable_int(); #ifdef CONFIG_FREERTOS_SMP spin_lock(&flash_spin_lock); #endif // CONFIG_FREERTOS_SMP return flags; } static inline void flash_exit_critical(uint32_t flags) { #ifdef CONFIG_FREERTOS_SMP spin_unlock(&flash_spin_lock); #endif // CONFIG_FREERTOS_SMP rtos_enable_int(flags); } #if 1 #ifdef CONFIG_FREERTOS_SMP static beken_mutex_t s_flash_mutex = NULL; #endif static void flash_lock_init(void) { #ifdef CONFIG_FREERTOS_SMP int ret = rtos_init_mutex(&s_flash_mutex); BK_ASSERT(kNoErr == ret); /* ASSERT VERIFIED */ #endif } #if 0 static void flash_lock_deinit(void) { int ret = rtos_deinit_mutex(&s_flash_mutex); BK_ASSERT(kNoErr == ret); /* ASSERT VERIFIED */ } #endif static void flash_lock(void) { if(rtos_is_in_interrupt_context() || rtos_local_irq_disabled()) { return; } #ifdef CONFIG_FREERTOS_SMP rtos_lock_mutex(&s_flash_mutex); #endif vTaskSuspendAll(); mb_flash_op_prepare(); } static void flash_unlock(void) { if(rtos_is_in_interrupt_context() || rtos_local_irq_disabled()) { return; } mb_flash_op_finish(); xTaskResumeAll(); #ifdef CONFIG_FREERTOS_SMP rtos_unlock_mutex(&s_flash_mutex); #endif } #endif static void flash_get_current_config(void) { bool cfg_success = false; for (uint32_t i = 0; i < (ARRAY_SIZE(flash_config) - 1); i++) { if (s_flash.flash_id == flash_config[i].flash_id) { s_flash.flash_cfg = &flash_config[i]; cfg_success = true; break; } } if (!cfg_success) { s_flash.flash_cfg = &flash_config[ARRAY_SIZE(flash_config) - 1]; for(int i = 0; i < 10; i++) { FLASH_LOGE("This flash is not identified, choose default config\r\n"); } } } static uint32_t flash_read_status_reg(void) { uint32_t status_reg;; uint32_t int_level = flash_enter_critical(); status_reg = flash_hal_read_status_reg(&s_flash.hal, s_flash.flash_cfg->status_reg_size); flash_exit_critical(int_level); return status_reg; } static void flash_write_status_reg(uint32_t status_reg_val) { uint32_t int_level = flash_enter_critical(); s_flash.flash_status_reg_val = status_reg_val; flash_hal_write_status_reg(&s_flash.hal, s_flash.flash_cfg->status_reg_size, status_reg_val); flash_exit_critical(int_level); } static uint32_t flash_get_id(void) { uint32_t flash_id;; uint32_t int_level = flash_enter_critical(); flash_id = flash_hal_get_id(&s_flash.hal); flash_exit_critical(int_level); return flash_id; } static uint32_t flash_get_protect_cfg(flash_protect_type_t type) { switch (type) { case FLASH_PROTECT_NONE: return FLASH_GET_PROTECT_CFG(s_flash.flash_cfg->protect_none); case FLASH_PROTECT_ALL: return FLASH_GET_PROTECT_CFG(s_flash.flash_cfg->protect_all); case FLASH_UNPROTECT_LAST_BLOCK: return FLASH_GET_PROTECT_CFG(s_flash.flash_cfg->unprotect_last_block); default: return FLASH_GET_PROTECT_CFG(s_flash.flash_cfg->protect_all); } } static void flash_set_protect_cfg(uint32_t *status_reg_val, uint32_t new_protect_cfg) { *status_reg_val &= ~(s_flash.flash_cfg->protect_mask << s_flash.flash_cfg->protect_post); *status_reg_val |= ((new_protect_cfg & s_flash.flash_cfg->protect_mask) << s_flash.flash_cfg->protect_post); } static uint32_t flash_get_cmp_cfg(flash_protect_type_t type) { switch (type) { case FLASH_PROTECT_NONE: return FLASH_GET_CMP_CFG(s_flash.flash_cfg->protect_none); case FLASH_PROTECT_ALL: return FLASH_GET_CMP_CFG(s_flash.flash_cfg->protect_all); case FLASH_UNPROTECT_LAST_BLOCK: return FLASH_GET_CMP_CFG(s_flash.flash_cfg->unprotect_last_block); default: return FLASH_GET_CMP_CFG(s_flash.flash_cfg->protect_all); } } static void flash_set_cmp_cfg(uint32_t *status_reg_val, uint32_t new_cmp_cfg) { *status_reg_val &= ~(FLASH_CMP_MASK << s_flash.flash_cfg->cmp_post); *status_reg_val |= ((new_cmp_cfg & FLASH_CMP_MASK) << s_flash.flash_cfg->cmp_post); } static bool flash_is_need_update_status_reg(uint32_t protect_cfg, uint32_t cmp_cfg, uint32_t status_reg_val) { uint32_t cur_protect_val_in_status_reg = (status_reg_val >> s_flash.flash_cfg->protect_post) & s_flash.flash_cfg->protect_mask; uint32_t cur_cmp_val_in_status_reg = (status_reg_val >> s_flash.flash_cfg->cmp_post) & FLASH_CMP_MASK; if (cur_protect_val_in_status_reg != protect_cfg || cur_cmp_val_in_status_reg != cmp_cfg) { return true; } else { return false; } } static flash_protect_type_t flash_get_protect_type(uint32_t sr_value) { uint32_t type = 0; uint16_t protect_value = 0; uint16_t cmp; protect_value = sr_value >> s_flash.flash_cfg->protect_post; protect_value = protect_value & s_flash.flash_cfg->protect_mask; cmp = (sr_value >> s_flash.flash_cfg->cmp_post) & FLASH_CMP_MASK; protect_value |= cmp << FLASH_STATUS_REG_PROTECT_OFFSET; if (protect_value == s_flash.flash_cfg->protect_all) type = FLASH_PROTECT_ALL; else if (protect_value == s_flash.flash_cfg->protect_none) type = FLASH_PROTECT_NONE; else if (protect_value == s_flash.flash_cfg->unprotect_last_block) type = FLASH_UNPROTECT_LAST_BLOCK; else type = FLASH_PROTECT_ALL; // FLASH_UNPROTECT_LAST_BLOCK ??? return type; } static void flash_set_protect_type(flash_protect_type_t type) { uint32_t protect_cfg; uint32_t cmp_cfg; uint32_t status_reg = s_flash.flash_status_reg_val; protect_cfg = flash_get_protect_cfg(type); cmp_cfg = flash_get_cmp_cfg(type); #if CONFIG_FLASH_SUPPORT_MULTI_PE /* multiple process element. (multi-cores or SPE/NSPE) */ status_reg = flash_read_status_reg(); #endif #if CONFIG_FLASH_WRITE_STATUS_VOLATILE flash_hal_set_volatile_status_write(&s_flash.hal); #endif if (flash_is_need_update_status_reg(protect_cfg, cmp_cfg, status_reg)) { flash_set_protect_cfg(&status_reg, protect_cfg); flash_set_cmp_cfg(&status_reg, cmp_cfg); //FLASH_LOGD("write status reg:%x, status_reg_size:%d\r\n", status_reg, s_flash.flash_cfg->status_reg_size); flash_write_status_reg(status_reg); } } static void flash_set_qe(void) { uint32_t status_reg = s_flash.flash_status_reg_val; #if CONFIG_FLASH_SUPPORT_MULTI_PE status_reg = flash_read_status_reg(); #endif if (((status_reg >> s_flash.flash_cfg->quad_en_post) & 0x01) == s_flash.flash_cfg->quad_en_val) { return; } if (1 == s_flash.flash_cfg->quad_en_val) status_reg |= (1 << s_flash.flash_cfg->quad_en_post); else status_reg &= ~(1 << s_flash.flash_cfg->quad_en_post); flash_write_status_reg(status_reg); } static void flash_read_common(uint8_t *buffer, uint32_t address, uint32_t len) { uint32_t addr = address & (~FLASH_ADDRESS_MASK); uint32_t buf[FLASH_BUFFER_LEN] = {0}; uint8_t *pb = (uint8_t *)&buf[0]; if (len == 0) { return; } while (len) { uint32_t int_level = flash_enter_critical(); flash_hal_set_op_cmd_read(&s_flash.hal, addr); addr += FLASH_BYTES_CNT; for (uint32_t i = 0; i < FLASH_BUFFER_LEN; i++) { buf[i] = flash_hal_read_data(&s_flash.hal); } flash_exit_critical(int_level); for (uint32_t i = address % FLASH_BYTES_CNT; i < FLASH_BYTES_CNT; i++) { *buffer++ = pb[i]; address++; len--; if (len == 0) { break; } } } } static void flash_read_word_common(uint32_t *buffer, uint32_t address, uint32_t len) { uint32_t addr = address & (~FLASH_ADDRESS_MASK); uint32_t buf[FLASH_BUFFER_LEN] = {0}; //nt8_t *pb = (uint8_t *)&buf[0]; uint32_t *pb = (uint32_t *)&buf[0]; if (len == 0) { return; } while (len) { uint32_t int_level = flash_enter_critical(); flash_hal_set_op_cmd_read(&s_flash.hal, addr); addr += FLASH_BYTES_CNT; for (uint32_t i = 0; i < FLASH_BUFFER_LEN; i++) { buf[i] = flash_hal_read_data(&s_flash.hal); } flash_exit_critical(int_level); for (uint32_t i = address % (FLASH_BYTES_CNT/4); i < (FLASH_BYTES_CNT/4); i++) { *buffer++ = pb[i]; address++; len--; if (len == 0) { break; } } } } static bk_err_t flash_write_common(const uint8_t *buffer, uint32_t address, uint32_t len) { uint32_t buf[FLASH_BUFFER_LEN]; uint8_t *pb = (uint8_t *)&buf[0]; uint32_t addr = address & (~FLASH_ADDRESS_MASK); FLASH_RETURN_ON_WRITE_ADDR_OUT_OF_RANGE(addr, len); while (len) { os_memset(pb, 0xFF, FLASH_BYTES_CNT); for (uint32_t i = address % FLASH_BYTES_CNT; i < FLASH_BYTES_CNT; i++) { pb[i] = *buffer++; address++; len--; if (len == 0) { break; } } uint32_t int_level = flash_enter_critical(); flash_hal_wait_op_done(&s_flash.hal); for (uint32_t i = 0; i < FLASH_BUFFER_LEN; i++) { flash_hal_write_data(&s_flash.hal, buf[i]); } flash_hal_set_op_cmd_write(&s_flash.hal, addr); flash_exit_critical(int_level); addr += FLASH_BYTES_CNT; } return BK_OK; } static bk_err_t flash_erase_block(uint32_t address, int type) { uint32_t int_level = flash_enter_critical(); flash_hal_erase_block(&s_flash.hal, address, type); flash_exit_critical(int_level); return BK_OK; } static flash_line_mode_t flash_set_line_mode(flash_line_mode_t line_mode) { uint32_t int_level = flash_enter_critical(); flash_line_mode_t new_line_mode; flash_line_mode_t old_line_mode = s_flash.flash_line_mode; #if CONFIG_FLASH_QUAD_ENABLE if ( (FLASH_LINE_MODE_FOUR == line_mode) && (FLASH_LINE_MODE_FOUR == s_flash.flash_cfg->line_mode) ) { new_line_mode = FLASH_LINE_MODE_FOUR; } else #endif { new_line_mode = FLASH_LINE_MODE_TWO; } if(new_line_mode == old_line_mode) { flash_exit_critical(int_level); return old_line_mode; } flash_hal_clear_qwfr(&s_flash.hal); // cmd CRMR (coutinuous_read_mode reset), quit QPI mode. #if CONFIG_SOC_BK7236XX sys_drv_set_sys2flsh_2wire(0); #endif if (FLASH_LINE_MODE_FOUR == new_line_mode) { flash_hal_set_quad_m_value(&s_flash.hal, s_flash.flash_cfg->coutinuous_read_mode_bits_val); flash_set_qe(); flash_hal_set_mode(&s_flash.hal, FLASH_MODE_QUAD); // enter QPI mode. } else { flash_hal_set_mode(&s_flash.hal, FLASH_MODE_DUAL); } s_flash.flash_line_mode = new_line_mode; #if CONFIG_SOC_BK7236XX sys_drv_set_sys2flsh_2wire(1); #endif flash_exit_critical(int_level); return old_line_mode; } flash_line_mode_t bk_flash_get_line_mode(void) { return s_flash.flash_cfg->line_mode; } bk_err_t bk_flash_set_line_mode(flash_line_mode_t line_mode) { return BK_OK; (void)line_mode; } bk_err_t bk_flash_driver_init(void) { if (s_flash_is_init) { return BK_OK; } bk_err_t ret_code = mb_flash_ipc_init(); /* used for projects with LCD. */ if(ret_code != BK_OK) return ret_code; #if (CONFIG_CPU_CNT > 1) extern bk_err_t bk_flash_svr_init(void); ret_code = bk_flash_svr_init(); if(ret_code != BK_OK) { BK_LOGE("Flash", "flash svr create failed %d.\r\n", ret_code); } #endif os_memset(&s_flash, 0, sizeof(s_flash)); flash_hal_init(&s_flash.hal); #if (0 == CONFIG_JTAG) flash_hal_disable_cpu_data_wr(&s_flash.hal); #endif // s_flash.flash_line_mode = 0; flash_set_line_mode(FLASH_LINE_MODE_TWO); s_flash.flash_id = flash_get_id(); FLASH_LOGI("id=0x%x\r\n", s_flash.flash_id); flash_get_current_config(); flash_hal_set_quad_m_value(&s_flash.hal, s_flash.flash_cfg->coutinuous_read_mode_bits_val); s_flash.flash_status_reg_val = flash_read_status_reg(); flash_set_protect_type(FLASH_UNPROTECT_LAST_BLOCK); flash_set_line_mode(s_flash.flash_cfg->line_mode); flash_hal_set_default_clk(&s_flash.hal); #if (CONFIG_SOC_BK7256XX) #if CONFIG_ATE_TEST bk_flash_clk_switch(FLASH_SPEED_LOW, 0); #else bk_flash_clk_switch(FLASH_SPEED_HIGH, 0); #endif #endif #if (CONFIG_SOC_BK7236XX) || (CONFIG_SOC_BK7239XX) #if (CONFIG_SOC_BK7236N) || (CONFIG_SOC_BK7239XX) if((s_flash.flash_id >> FLASH_ManuFacID_POSI) == FLASH_ManuFacID_GD || (s_flash.flash_id >> FLASH_ManuFacID_POSI) == FLASH_ManuFacID_TH) { if((2 != sys_drv_flash_get_clk_sel()) || (0 != sys_drv_flash_get_clk_div())) { sys_drv_flash_set_clk_div(0); // 80M div 1 = 80M sys_drv_flash_cksel(2); } } else { if((0 != sys_drv_flash_get_clk_sel()) || (0 != sys_drv_flash_get_clk_div())) { sys_drv_flash_set_clk_div(0); // XTAL= 40M sys_drv_flash_cksel(0); } } #else if((s_flash.flash_id >> FLASH_ManuFacID_POSI) == FLASH_ManuFacID_GD || (s_flash.flash_id >> FLASH_ManuFacID_POSI) == FLASH_ManuFacID_TH) { if((1 != sys_drv_flash_get_clk_sel()) || (1 != sys_drv_flash_get_clk_div())) { #if (CONFIG_FLASH_CLK_120M) sys_drv_flash_set_clk_div(0); // dpll div 4 = 120M #else sys_drv_flash_set_clk_div(1); // dpll div 6 = 80M #endif sys_drv_flash_cksel(1); } } else { if((1 != sys_drv_flash_get_clk_sel()) || (3 != sys_drv_flash_get_clk_div())) { sys_drv_flash_set_clk_div(3); // dpll div 10 = 48M sys_drv_flash_cksel(1); } } #endif sys_drv_set_sys2flsh_2wire(1); #endif flash_lock_init(); s_flash_is_init = true; #if CONFIG_FLASH_TEST // int bk_flash_register_cli_test_feature(void); // int bk_flash_wr_register_cli_test_feature(void); // bk_flash_register_cli_test_feature(); // bk_flash_wr_register_cli_test_feature(); #endif #if CONFIG_FLASH_API_TEST int bk_flash_api_register_cli_test_feature(void); bk_flash_api_register_cli_test_feature(); #endif return BK_OK; } bk_err_t bk_flash_driver_deinit(void) { if (!s_flash_is_init) { return BK_OK; } s_flash_is_init = false; return BK_OK; } static bk_err_t flash_erase_no_lock(uint32_t address, int cmd) { if (address >= s_flash.flash_cfg->flash_size) { FLASH_LOGW("erase error:invalid address 0x%x\r\n", address); return BK_ERR_FLASH_ADDR_OUT_OF_RANGE; } uint32_t erase_size = 0; if(cmd == FLASH_OP_CMD_SE) erase_size = FLASH_SECTOR_SIZE; else if(cmd == FLASH_OP_CMD_BE1) erase_size = FLASH_BLOCK32_SIZE; else if(cmd == FLASH_OP_CMD_BE2) erase_size = FLASH_BLOCK_SIZE; else return BK_FAIL; uint32_t erase_addr = address & (~(erase_size - 1)); bk_err_t ret_val = BK_FAIL; flash_line_mode_t old_line_mode = flash_set_line_mode(FLASH_LINE_MODE_TWO); uint32_t status_reg = s_flash.flash_status_reg_val; #if CONFIG_FLASH_SUPPORT_MULTI_PE status_reg = flash_read_status_reg(); #endif flash_protect_type_t partition_type = flash_get_protect_type(status_reg); if(bk_flash_partition_write_perm_check_by_addr(erase_addr, erase_size, FLASH_API_MAGIC_CODE) == BK_OK) { flash_set_protect_type(FLASH_PROTECT_NONE); if(bk_flash_partition_write_perm_check_by_addr(erase_addr, erase_size, FLASH_API_MAGIC_CODE) == BK_OK) ret_val = flash_erase_block(address, cmd); } flash_set_protect_type(partition_type); flash_set_line_mode(old_line_mode); return ret_val; } bk_err_t bk_flash_erase_sector(uint32_t address) { if (address >= s_flash.flash_cfg->flash_size) { FLASH_LOGW("erase error:invalid address 0x%x\r\n", address); return BK_ERR_FLASH_ADDR_OUT_OF_RANGE; } flash_lock(); bk_err_t ret_val = flash_erase_no_lock(address, FLASH_OP_CMD_SE); flash_unlock(); return ret_val; } bk_err_t bk_flash_erase_32k(uint32_t address) { if (address >= s_flash.flash_cfg->flash_size) { FLASH_LOGW("erase error:invalid address 0x%x\r\n", address); return BK_ERR_FLASH_ADDR_OUT_OF_RANGE; } flash_lock(); bk_err_t ret_val = flash_erase_no_lock(address, FLASH_OP_CMD_BE1); flash_unlock(); return ret_val; } bk_err_t bk_flash_erase_block(uint32_t address) { if (address >= s_flash.flash_cfg->flash_size) { FLASH_LOGW("erase error:invalid address 0x%x\r\n", address); return BK_ERR_FLASH_ADDR_OUT_OF_RANGE; } flash_lock(); bk_err_t ret_val = flash_erase_no_lock(address, FLASH_OP_CMD_BE2); flash_unlock(); return ret_val; } bk_err_t bk_flash_read_bytes(uint32_t address, uint8_t *user_buf, uint32_t size) { if (address >= s_flash.flash_cfg->flash_size) { FLASH_LOGW("read error:invalid address 0x%x\r\n", address); return BK_ERR_FLASH_ADDR_OUT_OF_RANGE; } flash_read_common(user_buf, address, size); return BK_OK; } bk_err_t bk_flash_read_word(uint32_t address, uint32_t *user_buf, uint32_t size) { if (address >= s_flash.flash_cfg->flash_size) { FLASH_LOGW("read error:invalid address 0x%x\r\n", address); return BK_ERR_FLASH_ADDR_OUT_OF_RANGE; } flash_read_word_common(user_buf, address, size); return BK_OK; } static bk_err_t flash_write_no_lock(uint32_t address, const uint8_t *user_buf, uint32_t size) { if (address >= s_flash.flash_cfg->flash_size) { FLASH_LOGW("write error:invalid address 0x%x\r\n", address); return BK_ERR_FLASH_ADDR_OUT_OF_RANGE; } bk_err_t ret_val = BK_FAIL; flash_line_mode_t old_line_mode = flash_set_line_mode(FLASH_LINE_MODE_TWO); uint32_t status_reg = s_flash.flash_status_reg_val; #if CONFIG_FLASH_SUPPORT_MULTI_PE status_reg = flash_read_status_reg(); #endif flash_protect_type_t partition_type = flash_get_protect_type(status_reg); if(bk_flash_partition_write_perm_check_by_addr(address, size, FLASH_API_MAGIC_CODE) == BK_OK) { flash_set_protect_type(FLASH_PROTECT_NONE); if(bk_flash_partition_write_perm_check_by_addr(address, size, FLASH_API_MAGIC_CODE) == BK_OK) ret_val = flash_write_common(user_buf, address, size); } flash_set_protect_type(partition_type); flash_set_line_mode(old_line_mode); return ret_val; } bk_err_t bk_flash_write_bytes(uint32_t address, const uint8_t *user_buf, uint32_t size) { if (address >= s_flash.flash_cfg->flash_size) { FLASH_LOGW("write error:invalid address 0x%x\r\n", address); return BK_ERR_FLASH_ADDR_OUT_OF_RANGE; } flash_lock(); bk_err_t ret_val = flash_write_no_lock(address, user_buf, size); flash_unlock(); return ret_val; } uint32_t bk_flash_get_id(void) { return s_flash.flash_id; } bk_err_t bk_flash_set_clk_dpll(void) { sys_drv_flash_set_dpll(); flash_hal_set_clk_dpll(&s_flash.hal); return BK_OK; } bk_err_t bk_flash_set_clk_dco(void) { sys_drv_flash_set_dco(); bool ate_enabled = ate_is_enabled(); flash_hal_set_clk_dco(&s_flash.hal, ate_enabled); return BK_OK; } #if (CONFIG_SOC_BK7256XX) bk_err_t bk_flash_set_clk(flash_clk_src_t flash_src_clk, uint8_t flash_dpll_div) { if ((FLASH_CLK_DPLL == flash_src_clk) && (flash_dpll_div == 0)) { FLASH_LOGE("flash 120M clock not support.\r\n"); return BK_FAIL; } if (FLASH_CLK_APLL == flash_src_clk) { FLASH_LOGE("flash apll clock not support.\r\n"); return BK_FAIL; } uint32_t int_level = flash_enter_critical(); if((sys_drv_flash_get_clk_sel() == flash_src_clk) && (sys_drv_flash_get_clk_div() == flash_dpll_div)) { flash_exit_critical(int_level); return BK_OK; } if (FLASH_CLK_DPLL == flash_src_clk) { sys_drv_flash_set_clk_div(flash_dpll_div); } sys_drv_flash_cksel(flash_src_clk); flash_exit_critical(int_level); return BK_OK; } bk_err_t bk_flash_clk_switch(uint32_t flash_speed_type, uint32_t modules) { uint32_t int_level = flash_enter_critical(); int chip_id = 0; switch (flash_speed_type) { case FLASH_SPEED_LOW: s_hold_low_speed_status |= modules; FLASH_LOGD("%s: set low, 0x%x 0x%x\r\n", __func__, s_hold_low_speed_status, modules); if (s_hold_low_speed_status) { bk_flash_set_clk(FLASH_CLK_XTAL, FLASH_DPLL_DIV_VALUE_TEN); } break; case FLASH_SPEED_HIGH: s_hold_low_speed_status &= ~(modules); FLASH_LOGD("%s: clear low bit, 0x%x 0x%x\r\n", __func__, s_hold_low_speed_status, modules); if (0 == s_hold_low_speed_status) { chip_id = bk_get_hardware_chip_id_version(); //chipC version with GD flash switch to 80M for peformance if ((chip_id == CHIP_VERSION_C) && ((s_flash.flash_id >> FLASH_ManuFacID_POSI) == FLASH_ManuFacID_GD)) { bk_flash_set_clk(FLASH_CLK_DPLL, FLASH_DPLL_DIV_VALUE_SIX); } else { bk_flash_set_clk(FLASH_CLK_DPLL, FLASH_DPLL_DIV_VALUE_TEN); } } break; } flash_exit_critical(int_level); return BK_OK; } #endif #if CONFIG_FLASH_TEST bk_err_t bk_flash_write_enable(void) { return BK_OK; } bk_err_t bk_flash_write_disable(void) { return BK_OK; } uint16_t bk_flash_read_status_reg(void) { #if CONFIG_FLASH_SUPPORT_MULTI_PE flash_line_mode_t old_line_mode = flash_set_line_mode(FLASH_LINE_MODE_TWO); uint16_t sr_data = flash_read_status_reg(); flash_set_line_mode(old_line_mode); return sr_data; #else return s_flash.flash_status_reg_val; #endif } bk_err_t bk_flash_write_status_reg(uint16_t status_reg_data) { #if 0 flash_line_mode_t old_line_mode = flash_set_line_mode(FLASH_LINE_MODE_TWO); flash_write_status_reg(status_reg_data); flash_set_line_mode(old_line_mode); #endif return BK_OK; } uint32_t bk_flash_get_crc_err_num(void) { return flash_hal_get_crc_err_num(&s_flash.hal); } #endif flash_protect_type_t bk_flash_get_protect_type(void) { return FLASH_PROTECT_ALL; } bk_err_t bk_flash_set_protect_type(flash_protect_type_t type) { return BK_OK; } bool bk_flash_is_driver_inited() { return s_flash_is_init; } uint32_t bk_flash_get_current_total_size(void) { return s_flash.flash_cfg->flash_size; } bk_err_t bk_flash_register_ps_suspend_callback(flash_ps_callback_t ps_suspend_cb) { return BK_OK; } bk_err_t bk_flash_register_ps_resume_callback(flash_ps_callback_t ps_resume_cb) { return BK_OK; } bk_err_t bk_flash_power_saving_enter(void) { // save flash ctrl setting to flash_ctrl_context; flash_set_line_mode(FLASH_LINE_MODE_TWO); return BK_OK; } bk_err_t bk_flash_power_saving_exit(void) { // restore flash ctrl setting from flash_ctrl_context; // the restore API must run in SRAM/ITCM. // don't access flash before restoring setting, especially for A/B image project. s_flash.flash_line_mode = 0; flash_set_line_mode(s_flash.flash_cfg->line_mode); return BK_OK; } __attribute__((section(".iram"))) bk_err_t bk_flash_enter_deep_sleep(void) { #if CONFIG_SOC_BK7236XX int ret = 0; uint8_t op_code = FLASH_CMD_ENTER_DEEP_PWR_DW; // flash need to change 2 line when do flash operate except read // need to recover 4 line, please do it manually //if (FLASH_LINE_MODE_FOUR == bk_flash_get_line_mode()) // bk_flash_set_line_mode(FLASH_LINE_MODE_TWO); ret = flash_bypass_op_write(&op_code, NULL, 0); if(ret == 0)// success { // delay T_dp: 3us //for(volatile int j=0; j<500; j++); return BK_OK; } #endif return BK_FAIL; } __attribute__((section(".iram"))) bk_err_t bk_flash_exit_deep_sleep(void) { #if CONFIG_SOC_BK7236XX int ret = 0; uint8_t op_code = FLASH_CMD_EXIT_DEEP_PWR_DW; // flash need to change 2 line when do flash operate except read // need to recover 4 line, please do it manually //if (FLASH_LINE_MODE_FOUR == bk_flash_get_line_mode()) // bk_flash_set_line_mode(FLASH_LINE_MODE_TWO); ret = flash_bypass_op_write(&op_code, NULL, 0); if(ret == 0)// success { // delay T_res1: 20us //for(volatile int j=0; j<500; j++); return BK_OK; } #endif return BK_FAIL; } #if CONFIG_SECURITY_OTA uint32_t flash_get_excute_enable() { return flash_hal_read_offset_enable(&s_flash.hal); } void bk_flash_enable_cpu_data_wr(void) { flash_hal_enable_cpu_data_wr(&s_flash.hal); } void bk_flash_disable_cpu_data_wr(void) { flash_hal_disable_cpu_data_wr(&s_flash.hal); } #endif /* flash dump APIs are called in context of interrupt disabled. */ bk_err_t bk_flash_dump_erase_sector(uint32_t address) { return flash_erase_no_lock(address, FLASH_OP_CMD_SE); } bk_err_t bk_flash_dump_write(uint32_t address, const uint8_t *user_buf, uint32_t size) { return flash_write_no_lock(address, user_buf, size); }