/*************************************************************************** * * Copyright 2015-2019 BES. * All rights reserved. All unpublished rights reserved. * * No part of this work may be used or reproduced in any form or by any * means, or stored in a database or retrieval system, without prior written * permission of BES. * * Use of this work is governed by a license granted by BES. * This work contains confidential and proprietary information of * BES. which is protected by copyright, trade secret, * trademark and other intellectual property rights. * ****************************************************************************/ #include "plat_types.h" #include "plat_addr_map.h" #include "cmsis.h" #include "hal_cache.h" #include "hal_location.h" #if (CHIP_CACHE_VER < 2) #include "hal_norflash.h" #endif #include "hal_timer.h" #define HAL_CACHE_YES 1 #define HAL_CACHE_NO 0 /* cache controller */ #if 0 #elif defined(CHIP_BEST1000) #define CACHE_SIZE 0x1000 #define CACHE_LINE_SIZE 0x10 #elif defined(CHIP_BEST2000) || defined(CHIP_BEST3001) #define CACHE_SIZE 0x2000 #define CACHE_LINE_SIZE 0x10 #elif defined(CHIP_BEST2001) #define CACHE_SIZE 0x4000 #define CACHE_LINE_SIZE 0x20 #else #define CACHE_SIZE 0x2000 #define CACHE_LINE_SIZE 0x20 #endif #define CACHE_ASSOCIATIVITY_WAY_NUM 4 /* reg value */ #define CACHE_ENABLE_REG_OFFSET 0x00 #define CACHE_INI_CMD_REG_OFFSET 0x04 #define WRITEBUFFER_ENABLE_REG_OFFSET 0x08 #define WRITEBUFFER_FLUSH_REG_OFFSET 0x0C #define LOCK_UNCACHEABLE_REG_OFFSET 0x10 #define INVALIDATE_ADDRESS_REG_OFFSET 0x14 #define INVALIDATE_SET_CMD_REG_OFFSET 0x18 // Since best2300 #define MONITOR_ENABLE_REG_OFFSET 0x1C #define MONITOR_CNT_READ_HIT0_REG_OFFSET 0x20 #define MONITOR_CNT_READ_HIT1_REG_OFFSET 0x24 #define MONITOR_CNT_READ_MISS0_REG_OFFSET 0x28 #define MONITOR_CNT_READ_MISS1_REG_OFFSET 0x2C // Since best2300p #define STATUS_REG_OFFSET 0x30 // Since best2300p #define SYNC_CMD_REG_OFFSET 0x34 #define CACHE_EN (1 << 0) // Since best2300 #define WRAP_EN (1 << 1) #define WRITEBUFFER_EN (1 << 0) // Since best2300 #define WRITE_BACK_EN (1 << 1) #define LOCK_UNCACHEABLE (1 << 0) // Since best2300 #define MONITOR_EN (1 << 0) #define CNT_READ_HIT_31_0_SHIFT (0) #define CNT_READ_HIT_31_0_MASK (0xFFFFFFFF << CNT_READ_HIT_31_0_SHIFT) #define CNT_READ_HIT_31_0(n) BITFIELD_VAL(CNT_READ_HIT_31_0, n) #define CNT_READ_HIT_39_32_SHIFT (0) #define CNT_READ_HIT_39_32_MASK (0xFF << CNT_READ_HIT_39_32_SHIFT) #define CNT_READ_HIT_39_32(n) BITFIELD_VAL(CNT_READ_HIT_39_32, n) // Since best2300p #define STATUS_FETCHING (1 << 0) /* read write */ #define cacheip_write32(v,b,a) \ (*((volatile uint32_t *)(b+a)) = v) #define cacheip_read32(b,a) \ (*((volatile uint32_t *)(b+a))) __STATIC_FORCEINLINE void cacheip_enable_cache(uint32_t reg_base, uint32_t v) { uint32_t val; if (v) { val = CACHE_EN; } else { val = 0; } cacheip_write32(val, reg_base, CACHE_ENABLE_REG_OFFSET); } __STATIC_FORCEINLINE void cacheip_enable_wrap(uint32_t reg_base, uint32_t v) { uint32_t val; val = cacheip_read32(reg_base, CACHE_ENABLE_REG_OFFSET); if (v) { val |= WRAP_EN; } else { val &= ~WRAP_EN; } cacheip_write32(val, reg_base, CACHE_ENABLE_REG_OFFSET); } __STATIC_FORCEINLINE POSSIBLY_UNUSED int cacheip_wrap_enabled(uint32_t reg_base) { uint32_t val; val = cacheip_read32(reg_base, CACHE_ENABLE_REG_OFFSET); return !!(val & WRAP_EN); } __STATIC_FORCEINLINE void cacheip_init_cache(uint32_t reg_base) { cacheip_write32(1, reg_base, CACHE_INI_CMD_REG_OFFSET); } __STATIC_FORCEINLINE void cacheip_enable_writebuffer(uint32_t reg_base, uint32_t v) { // PSRAM controller V2 has an embedded write buffer and the cache write buffer can be ignored #if defined(CHIP_HAS_PSRAM) && defined(PSRAM_ENABLE) && defined(CHIP_PSRAM_CTRL_VER) && (CHIP_PSRAM_CTRL_VER == 1) uint32_t val; val = cacheip_read32(reg_base, WRITEBUFFER_ENABLE_REG_OFFSET); if (v) { val |= WRITEBUFFER_EN; } else { val &= ~WRITEBUFFER_EN; } cacheip_write32(val, reg_base, WRITEBUFFER_ENABLE_REG_OFFSET); #endif } __STATIC_FORCEINLINE void cacheip_enable_writeback(uint32_t reg_base, uint32_t v) { // Cache implements write back feature since PSRAM controller V2 #if !defined(CHIP_BEST2001) #if (defined(CHIP_HAS_PSRAM) && defined(PSRAM_ENABLE) && defined(CHIP_PSRAM_CTRL_VER) && (CHIP_PSRAM_CTRL_VER >= 2)) || (defined(CHIP_HAS_PSRAMUHS) && defined(PSRAMUHS_ENABLE)) uint32_t val; val = cacheip_read32(reg_base, WRITEBUFFER_ENABLE_REG_OFFSET); if (v) { val |= WRITE_BACK_EN; } else { val &= ~WRITE_BACK_EN; } cacheip_write32(val, reg_base, WRITEBUFFER_ENABLE_REG_OFFSET); #endif #endif } __STATIC_FORCEINLINE void cacheip_flush_writebuffer(uint32_t reg_base) { cacheip_write32(1, reg_base, WRITEBUFFER_FLUSH_REG_OFFSET); } __STATIC_FORCEINLINE void cacheip_set_invalidate_address(uint32_t reg_base, uint32_t v) { cacheip_write32(v, reg_base, INVALIDATE_ADDRESS_REG_OFFSET); } __STATIC_FORCEINLINE void cacheip_trigger_invalidate(uint32_t reg_base) { cacheip_write32(1, reg_base, INVALIDATE_SET_CMD_REG_OFFSET); } __STATIC_FORCEINLINE void cacheip_trigger_sync(uint32_t reg_base) { cacheip_write32(1, reg_base, SYNC_CMD_REG_OFFSET); } /* cache controller end */ /* hal api */ __STATIC_FORCEINLINE uint32_t _cache_get_reg_base(enum HAL_CACHE_ID_T id) { uint32_t base; if (id == HAL_CACHE_ID_I_CACHE) { base = ICACHE_CTRL_BASE; } else if (id == HAL_CACHE_ID_D_CACHE) { #ifdef DCACHE_CTRL_BASE base = DCACHE_CTRL_BASE; #else base = 0; #endif } else { base = 0; } return base; } uint8_t BOOT_TEXT_FLASH_LOC hal_cache_enable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cache_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_init_cache(reg_base); cacheip_enable_cache(reg_base, HAL_CACHE_YES); return 0; } uint8_t SRAM_TEXT_LOC hal_cache_disable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cache_get_reg_base(id); if (reg_base == 0) { return 0; } #if !(defined(ROM_BUILD) || defined(PROGRAMMER)) #if (CHIP_CACHE_VER >= 2) uint32_t val; do { val = cacheip_read32(reg_base, STATUS_REG_OFFSET); } while (val & STATUS_FETCHING); #else uint32_t time; time = hal_sys_timer_get(); while (hal_norflash_busy() && (hal_sys_timer_get() - time) < MS_TO_TICKS(2)); // Delay for at least 8 cycles till the cache becomes idle for (int delay = 0; delay < 8; delay++) { asm volatile("nop"); } #endif #endif cacheip_enable_cache(reg_base, HAL_CACHE_NO); return 0; } uint8_t BOOT_TEXT_FLASH_LOC hal_cache_writebuffer_enable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cache_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_enable_writebuffer(reg_base, HAL_CACHE_YES); return 0; } uint8_t hal_cache_writebuffer_disable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cache_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_enable_writebuffer(reg_base, HAL_CACHE_NO); return 0; } uint8_t hal_cache_writebuffer_flush(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cache_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_flush_writebuffer(reg_base); return 0; } uint8_t BOOT_TEXT_FLASH_LOC hal_cache_writeback_enable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cache_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_enable_writeback(reg_base, HAL_CACHE_YES); return 0; } uint8_t hal_cache_writeback_disable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cache_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_enable_writeback(reg_base, HAL_CACHE_NO); return 0; } // Wrap is enabled during flash init uint8_t BOOT_TEXT_SRAM_LOC hal_cache_wrap_enable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cache_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_enable_wrap(reg_base, HAL_CACHE_YES); return 0; } uint8_t hal_cache_wrap_disable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cache_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_enable_wrap(reg_base, HAL_CACHE_NO); return 0; } // Flash timing calibration might need to invalidate cache uint8_t BOOT_TEXT_SRAM_LOC hal_cache_invalidate(enum HAL_CACHE_ID_T id, uint32_t start_address, uint32_t len) { uint32_t reg_base; uint32_t end_address; uint32_t lock; #ifndef DCACHE_CTRL_BASE if (id == HAL_CACHE_ID_D_CACHE) { id = HAL_CACHE_ID_I_CACHE; } #endif reg_base = _cache_get_reg_base(id); if (reg_base == 0) { return 0; } lock = int_lock_global(); #if defined(CHIP_BEST2300) || defined(CHIP_BEST1400) uint32_t time; time = hal_sys_timer_get(); while (hal_norflash_busy() && (hal_sys_timer_get() - time) < MS_TO_TICKS(2)); // Delay for at least 8 cycles till the cache becomes idle for (int delay = 0; delay < 8; delay++) { asm volatile("nop"); } #endif if (len >= CACHE_SIZE / 2) { cacheip_init_cache(reg_base); cacheip_init_cache(reg_base); } else { end_address = start_address + len; start_address &= (~(CACHE_LINE_SIZE-1)); while (start_address < end_address) { cacheip_set_invalidate_address(reg_base, start_address); cacheip_trigger_invalidate(reg_base); cacheip_trigger_invalidate(reg_base); start_address += CACHE_LINE_SIZE; } } int_unlock_global(lock); return 0; } uint8_t hal_cache_invalidate_all(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cache_get_reg_base(id); if (reg_base == 0) { return 0; } //warning BEST1501 may change this reg offset to 0x38 cacheip_write32(1, reg_base, CACHE_INI_CMD_REG_OFFSET); cacheip_write32(1, reg_base, CACHE_INI_CMD_REG_OFFSET); return 0; } uint8_t hal_cache_sync(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cache_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_trigger_sync(reg_base); return 0; } #ifdef CHIP_HAS_CP __STATIC_FORCEINLINE uint32_t _cachecp_get_reg_base(enum HAL_CACHE_ID_T id) { uint32_t base; if (id == HAL_CACHE_ID_I_CACHE) { base = ICACHECP_CTRL_BASE; } else if (id == HAL_CACHE_ID_D_CACHE) { #ifdef DCACHECP_CTRL_BASE base = DCACHECP_CTRL_BASE; #else base = 0; #endif } else { base = 0; } return base; } uint8_t hal_cachecp_enable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; uint32_t main_cache_reg_base; enum HAL_CMU_MOD_ID_T mod; reg_base = _cachecp_get_reg_base(id); if (reg_base == 0) { return 0; } if (id == HAL_CACHE_ID_D_CACHE) { mod = HAL_CMU_H_DCACHECP; } else { mod = HAL_CMU_H_ICACHECP; } hal_cmu_clock_enable(mod); hal_cmu_reset_clear(mod); cacheip_init_cache(reg_base); cacheip_enable_cache(reg_base, HAL_CACHE_YES); // Init wrap option main_cache_reg_base = _cache_get_reg_base(id); if (main_cache_reg_base == 0) { return 0; } cacheip_enable_wrap(reg_base, cacheip_wrap_enabled(main_cache_reg_base)); return 0; } uint8_t CP_TEXT_SRAM_LOC hal_cachecp_disable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; enum HAL_CMU_MOD_ID_T mod; reg_base = _cachecp_get_reg_base(id); if (reg_base == 0) { return 0; } #if !(defined(ROM_BUILD) || defined(PROGRAMMER)) uint32_t val; do { val = cacheip_read32(reg_base, STATUS_REG_OFFSET); } while (val & STATUS_FETCHING); #endif cacheip_enable_cache(reg_base, HAL_CACHE_NO); if (id == HAL_CACHE_ID_D_CACHE) { mod = HAL_CMU_H_DCACHECP; } else { mod = HAL_CMU_H_ICACHECP; } hal_cmu_reset_set(mod); hal_cmu_clock_disable(mod); return 0; } uint8_t hal_cachecp_writebuffer_enable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cachecp_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_enable_writebuffer(reg_base, HAL_CACHE_YES); return 0; } uint8_t hal_cachecp_writebuffer_disable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cachecp_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_enable_writebuffer(reg_base, HAL_CACHE_NO); return 0; } uint8_t hal_cachecp_writebuffer_flush(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cachecp_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_flush_writebuffer(reg_base); return 0; } uint8_t hal_cachecp_writeback_enable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cachecp_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_enable_writeback(reg_base, HAL_CACHE_YES); return 0; } uint8_t hal_cachecp_writeback_disable(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cachecp_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_enable_writeback(reg_base, HAL_CACHE_NO); return 0; } uint8_t CP_TEXT_SRAM_LOC hal_cachecp_invalidate(enum HAL_CACHE_ID_T id, uint32_t start_address, uint32_t len) { uint32_t reg_base; uint32_t end_address; #ifndef DCACHECP_CTRL_BASE if (id == HAL_CACHE_ID_D_CACHE) { id = HAL_CACHE_ID_I_CACHE; } #endif reg_base = _cachecp_get_reg_base(id); if (reg_base == 0) { return 0; } if (len >= CACHE_SIZE / 2) { cacheip_init_cache(reg_base); cacheip_init_cache(reg_base); } else { end_address = start_address + len; start_address &= (~(CACHE_LINE_SIZE-1)); while (start_address < end_address) { cacheip_set_invalidate_address(reg_base, start_address); cacheip_trigger_invalidate(reg_base); cacheip_trigger_invalidate(reg_base); start_address += CACHE_LINE_SIZE; } } return 0; } uint8_t hal_cachecp_sync(enum HAL_CACHE_ID_T id) { uint32_t reg_base = 0; reg_base = _cachecp_get_reg_base(id); if (reg_base == 0) { return 0; } cacheip_trigger_sync(reg_base); return 0; } #endif