diff --git a/build/arm/linker/rtl872x/platform_ram_m23.ld b/build/arm/linker/rtl872x/platform_ram_m23.ld index 770d66cc02..69bf063669 100644 --- a/build/arm/linker/rtl872x/platform_ram_m23.ld +++ b/build/arm/linker/rtl872x/platform_ram_m23.ld @@ -24,7 +24,7 @@ x | KM0 part1 static RAM | | | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ | Heap | | KM0 part1 RAM code | | | -+-----------------------------+ 0x00086000 | | ++-----------------------------+ 0x00083400 | | | | | | | KM0 MBR static RAM | | | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ @@ -78,7 +78,7 @@ platform_km0_bootloader_stack_start = platform_km0_bootloader_stack_end - platfo /* Bootloader RAM, contains static data and code */ -platform_km0_mbr_ram_size = 16K; +platform_km0_mbr_ram_size = 5K; platform_km0_mbr_ram_start = platform_km0_ram_start; platform_km0_mbr_ram_end = platform_km0_mbr_ram_start + platform_km0_mbr_ram_size; diff --git a/hal/src/rtl872x/core_hal.c b/hal/src/rtl872x/core_hal.c index e3dbf4b42f..83eeb4c6be 100644 --- a/hal/src/rtl872x/core_hal.c +++ b/hal/src/rtl872x/core_hal.c @@ -264,39 +264,7 @@ void HAL_Core_Restore_Interrupt(IRQn_Type irqn) { #if HAL_PLATFORM_PROHIBIT_XIP static void prohibit_xip(void) { - const uint8_t regions = (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; - // Disable MPU - MPU->CTRL = 0; - // Clear all regions - for (uint8_t i = 0; i < regions; i++) { - MPU->RNR = i; - MPU->RASR = 0; - MPU->RBAR = 0; - } - - uint8_t st = 0; - sd_nvic_critical_region_enter(&st); - - // Forbid access to XIP - MPU->RNR = 0; - MPU->RBAR = EXTERNAL_FLASH_XIP_BASE; - // XN: 1, instruction fetches disabled - // AP: 0b000, all accesses generate a permission fault - // TEX: 0b000, S: 0, C: 1, B: 0, as suggested by core manual for flash memory - const uint32_t attr = 0x10050000; - MPU->RASR = attr | (1 << MPU_RASR_ENABLE_Pos) | ((31 - __CLZ(EXTERNAL_FLASH_XIP_LENGTH) - 1) << MPU_RASR_SIZE_Pos); - // Enable MPU - MPU->CTRL = 0x00000005; - - sd_nvic_critical_region_exit(st); - - // Use a DSB followed by an ISB instruction to ensure that the new MPU configuration is used by subsequent instructions. - __DSB(); - __ISB(); - - // Uncomment the code bellow will trigger hardfault - // uint8_t data = *((uint8_t*)(EXTERNAL_FLASH_XIP_BASE + EXTERNAL_FLASH_OTA_ADDRESS)); - // LOG(ERROR, "%d", data); + // FIXME } #endif // HAL_PLATFORM_PROHIBIT_XIP diff --git a/hal/src/rtl872x/exflash_hal.cpp b/hal/src/rtl872x/exflash_hal.cpp index a5f1506bd5..358dcb5b6b 100644 --- a/hal/src/rtl872x/exflash_hal.cpp +++ b/hal/src/rtl872x/exflash_hal.cpp @@ -35,6 +35,8 @@ extern "C" { #include "scope_guard.h" #include // for portBYTE_ALIGNMENT +#include + // TODO: move it to header file #define HAL_EXFLASH_OTP_MAGIC_NUMBER_ADDR 0x0 #define HAL_EXFLASH_OTP_MAGIC_NUMBER 0x9A7D5BC6 @@ -46,10 +48,13 @@ typedef enum { MXIC_FLASH_CMD_WRSCUR = 0x2F, MXIC_FLASH_CMD_ENSO = 0xB1, MXIC_FLASH_CMD_EXSO = 0xC1, + MXIC_FLASH_CMD_4PP = 0x38, GD_FLASH_CMD_ERS_SEC = 0x44, GD_FLASH_CMD_PGM_SEC = 0x42, GD_FLASH_CMD_RD_SEC = 0x48, + GD_FLASH_CMD_4PP = 0x32, + GD_FLASH_CMD_FPP = 0xf2, GENERIC_FLASH_CMD_RST = 0x99, GENERIC_FLASH_CMD_RSTEN = 0x66, @@ -60,6 +65,11 @@ typedef enum { GENERIC_FLASH_CMD_WREN = 0x06, GENERIC_FLASH_CMD_WRDI = 0x04, GENERIC_FLASH_CMD_RDSR = 0x05, + GENERIC_FLASH_CMD_WRSR = 0x01, + GENERIC_FLASH_CMD_SE = 0x20, + GENERIC_FLASH_CMD_BE32K = 0x52, + GENERIC_FLASH_CMD_BE64K = 0xd8, + GENERIC_FLASH_CMD_PP = 0x02 } hal_exflash_cmd_t; #define HAL_QSPI_FLASH_OTP_SECTOR_COUNT_GD25 3 @@ -124,6 +134,212 @@ class RsipIfRequired { int interruptState_ = 0; }; +#define RTK_SPIC_FIFO_SIZE 64 +#define RTK_SPIC_FIFO_HALF_SIZE (RTK_SPIC_FIFO_SIZE / 2) + +#define HAL_QSPI_FLASH_PAGE_SIZE ((size_t)256) + +#define RTK_SPIC_BIT_OFFSET_AUTO_LEN_DUM ((uint32_t)0) +#define RTK_SPIC_BIT_WIDTH_AUTO_LEN_DUM ((uint32_t)16) +#define RTK_SPIC_BIT_OFFSET_SR_TXE ((uint32_t)5) +#define RTK_SPIC_BIT_OFFSET_SR_BUSY ((uint32_t)0) + +#define RTK_SPIC_DATA_WIDTH_MODE_SINGLE (0) +#define RTK_SPIC_DATA_WIDTH_MODE_QUAD_I (0x00080000) +#define RTK_SPIC_DATA_WIDTH_MODE_QUAD_II (0x000a0000) +#define RTK_SPIC_DATA_WIDTH_MODE_DUAL_I (0x00040000) +#define RTK_SPIC_DATA_WIDTH_MODE_DUAL_II (0x00050000) + +#define RTK_SPIC_READ_TUNING_DUMMY_CYCLE 0x2 + +#define RTK_SPIC_BIT_MASK(offset) ((uint32_t)((offset) == 32) ? \ + 0x0 : (0x1 << (offset))) + +#define RTK_SPIC_BIT_MASK_WIDTH(offset, bit_num) ((uint32_t)((offset) == 32) ? \ + 0xFFFFFFFF : (((1 << (bit_num)) - 1) << (offset))) + +#define RTK_SPIC_BITS_SET_VAL(reg, offset, val, bit_num) \ + ((reg) = ((uint32_t)(reg) & (~RTK_SPIC_BIT_MASK_WIDTH(offset, bit_num))) | \ + ((val << (offset)) & RTK_SPIC_BIT_MASK_WIDTH(offset, bit_num))) + +#define RTK_SPIC_CMD_ADDR_FORMAT(cmd, addr) (((cmd) & 0x000000ff) | \ + ((addr & 0x000000ff) << 24) | \ + ((addr & 0x0000ff00) << 8) | \ + ((addr & 0x00ff0000) >> 8)) + +#define RTK_SPIC_BIT_GET_UNSHIFTED(reg, offset) \ + ((uint32_t)((reg) & RTK_SPIC_BIT_MASK(offset))) + +enum RtkSpicFlashDataWidth { + RTK_SPIC_DATA_BYTE = 0, + RTK_SPIC_DATA_HALF = 1, + RTK_SPIC_DATA_WORD = 2 +}; + +static void rtkSpiFlashSetDataReg(uint32_t index, uint32_t data, enum RtkSpicFlashDataWidth byteWidth) { + if (index > 31) { + return; + } else if (byteWidth == RTK_SPIC_DATA_BYTE) { + SPIC->dr[index].byte = (data & 0x000000ff); + } else if (byteWidth == RTK_SPIC_DATA_HALF) { + SPIC->dr[index].half = (data & 0x0000ffff); + } else if (byteWidth == RTK_SPIC_DATA_WORD) { + SPIC->dr[index].word = data; + } +} + +static void rtkSpiSetTxMode(uint32_t mode = RTK_SPIC_DATA_WIDTH_MODE_SINGLE) { + SPIC->ctrlr0 = SPIC->ctrlr0 & 0xfffffcff; + SPIC->ctrlr0 = (SPIC->ctrlr0 & 0xfff0ffff); + SPIC->ctrlr0 = (SPIC->ctrlr0) | (mode); +} + +static void rtkSpiFlashWaitBusy() { + while (1) { + if (RTK_SPIC_BIT_GET_UNSHIFTED(SPIC->sr, RTK_SPIC_BIT_OFFSET_SR_TXE)) { + break; + } + if ((!RTK_SPIC_BIT_GET_UNSHIFTED(SPIC->sr, RTK_SPIC_BIT_OFFSET_SR_BUSY))) { + break; + } + } +} + +static void rtkSpiSetRxMode() { + SPIC->ctrlr0 = (SPIC->ctrlr0 | 0x0300); + SPIC->ctrlr0 = (SPIC->ctrlr0 & 0xfff0ffff); +} + +static uint32_t rtkSpiFlashGetDataReg(uint32_t index, enum RtkSpicFlashDataWidth byteWidth) { + uint32_t data; + if (index > 31) { + return 0; + } else if (byteWidth == RTK_SPIC_DATA_BYTE) { + data = SPIC->dr[index].byte & 0x000000ff; + } else if (byteWidth == RTK_SPIC_DATA_HALF) { + data = SPIC->dr[index].half & 0x0000ffff; + } else if (byteWidth == RTK_SPIC_DATA_WORD) { + data = SPIC->dr[index].word; + } else { + return 0; + } + return data; +} + +// // FIXME: This should no longer be necessary as we are using FLASH_RxCmd(GENERIC_FLASH_CMD_RDSR, 1, &status)? +static uint8_t rtkSpiFlashReadSR() { + /* Disable SPI_FLASH */ + SPIC->ssienr = 0; + /* Set Ctrlr1; 1 byte data frames */ + SPIC->ctrlr1 = 1; + /* Set tuning dummy cycles */ + RTK_SPIC_BITS_SET_VAL(SPIC->auto_length, RTK_SPIC_BIT_OFFSET_AUTO_LEN_DUM, RTK_SPIC_READ_TUNING_DUMMY_CYCLE, RTK_SPIC_BIT_WIDTH_AUTO_LEN_DUM); + /* set ctrlr0: RX_mode */ + rtkSpiSetRxMode(); + /* set flash_cmd: write cmd to fifo */ + rtkSpiFlashSetDataReg(0, GENERIC_FLASH_CMD_RDSR, RTK_SPIC_DATA_BYTE); + /* Enable SPI_FLASH */ + SPIC->ssienr = 1; + rtkSpiFlashWaitBusy(); + return rtkSpiFlashGetDataReg(0, RTK_SPIC_DATA_BYTE); +} + +static void rtkSpiFlashEnableCsWriteErase() { + /* Enable SPI_FLASH */ + SPIC->ssienr = 1; + rtkSpiFlashWaitBusy(); + /* Check flash is in write progress or not */ + for (;;) { + uint8_t status = rtkSpiFlashReadSR(); + // FLASH_RxCmd(GENERIC_FLASH_CMD_RDSR, 1, &status); + if (!(status & 0x1)) { + break; + } + } +} + +static void rtkSpiFlashSendCmd(uint8_t cmd) { + /* Disble SPI_FLASH */ + SPIC->ssienr = 0; + /* set ctrlr0: TX mode */ + rtkSpiSetTxMode(); + /* set flash_cmd: wren to fifo */ + rtkSpiFlashSetDataReg(0, cmd, RTK_SPIC_DATA_BYTE); + rtkSpiFlashEnableCsWriteErase(); +} + +#if MODULE_FUNCTION != MOD_FUNC_BOOTLOADER + +static void rtkSpiFlashEnableCsRead(uint32_t len) { + /* set receive data length */ + if (len <= 0x00010000) { + SPIC->ctrlr1 = len; + } + /* Enable SPI_FLASH */ + SPIC->ssienr = 1; + rtkSpiFlashWaitBusy(); +} + +static void rtkSpiFlashRxCmdAddr(uint8_t cmd, uint32_t addr, uint32_t dummyCycle) { + /* Disable SPI_FLASH */ + SPIC->ssienr = 0; + if (dummyCycle != 0) { // spi_flash_set_dummy_cycle(dev, dummy); + uint32_t cycle = 0; + /* if using fast_read baud_rate */ + if (((SPIC->ctrlr0) & 0x00100000)) { + cycle = (SPIC->fbaudr); + } else { + cycle = (SPIC->baudr); + } + cycle = (cycle * dummyCycle * 2) + RTK_SPIC_READ_TUNING_DUMMY_CYCLE; + if (cycle <= 0x10000) { + RTK_SPIC_BITS_SET_VAL(SPIC->auto_length, RTK_SPIC_BIT_OFFSET_AUTO_LEN_DUM, cycle, RTK_SPIC_BIT_WIDTH_AUTO_LEN_DUM); + } + } else { + /* Set tuning dummy cycles */ + RTK_SPIC_BITS_SET_VAL(SPIC->auto_length, RTK_SPIC_BIT_OFFSET_AUTO_LEN_DUM, RTK_SPIC_READ_TUNING_DUMMY_CYCLE, RTK_SPIC_BIT_WIDTH_AUTO_LEN_DUM); + } + + /* set ctrlr0: RX mode, data_ch, addr_ch */ + rtkSpiSetRxMode(); + + /* set flash cmd + addr and write to fifo */ + SPIC->dr[0].word = RTK_SPIC_CMD_ADDR_FORMAT(cmd, addr); +} + +#endif // MODULE_FUNCTION != MOD_FUNC_BOOTLOADER + +static void rtkSpiFlashTxCmdAddr(uint8_t cmd, uint32_t addr, uint32_t mode = RTK_SPIC_DATA_WIDTH_MODE_SINGLE) { + /* Disable SPI_FLASH */ + SPIC->ssienr = 0; + /* set ctrlr0: TX mode, data_ch, addr_ch */ + rtkSpiSetTxMode(mode); + /* set flash cmd + addr and write to fifo */ + SPIC->dr[0].word = RTK_SPIC_CMD_ADDR_FORMAT(cmd, addr); +} + +class RtkSpicFlashConfigGuard { +public: + RtkSpicFlashConfigGuard() { + ctrl0_ = SPIC->ctrlr0; + autoLen_ = SPIC->auto_length; + addrLen_ = SPIC->addr_length; + /* setting auto mode CS_H_WR_LEN, address length(3 byte) */ + SPIC->auto_length = ((SPIC->auto_length & 0xfffcffff) | 0x00030000); + SPIC->addr_length = 3; + } + ~RtkSpicFlashConfigGuard() { + SPIC->ssienr = 0; + SPIC->ctrlr0 = ctrl0_; + SPIC->auto_length = autoLen_; + SPIC->addr_length = addrLen_; + } + +private: + uint32_t ctrl0_; + uint32_t autoLen_; + uint32_t addrLen_; +}; // Constructor, destructors and methods are executed from PSRAM. class ExFlashLock { @@ -176,6 +392,99 @@ class ExFlashLock { bool threading_; }; +static int writeInBestModeWithinPageBoundaries(uint32_t addr, uint8_t* buf, size_t size) { + uint32_t address = addr; + uint8_t cmd = GENERIC_FLASH_CMD_PP; + uint32_t mode = RTK_SPIC_DATA_WIDTH_MODE_SINGLE; + + if (flash_init_para.FLASH_cur_bitmode == SpicQuadBitMode) { + // Quad mode enabled + if (flash_init_para.FLASH_Id == FLASH_ID_GD) { + cmd = GD_FLASH_CMD_4PP; + mode = RTK_SPIC_DATA_WIDTH_MODE_QUAD_I; + } else { + cmd = MXIC_FLASH_CMD_4PP; + mode = RTK_SPIC_DATA_WIDTH_MODE_QUAD_II; + } + } else if (flash_init_para.FLASH_cur_bitmode == SpicDualBitMode) { + // Dual mode enabled + // FIXME: gd25q128ewig doesn't support this looks like? + // if (flash_init_para.FLASH_Id == FLASH_ID_GD) { + // cmd = GD_FLASH_CMD_FPP; + // mode = RTK_SPIC_DATA_WIDTH_MODE_DUAL_II; + // } + } + + size_t rem = addr % HAL_QSPI_FLASH_PAGE_SIZE; + if (rem == 0) { + // Can write the full page up to its size or less + size = std::min(HAL_QSPI_FLASH_PAGE_SIZE, size); + } else { + // Can write only up to page boundary otherwise we'll wrap around + size = std::min(HAL_QSPI_FLASH_PAGE_SIZE - rem, size); + } + + size_t written = size; + + while (size > 0) { + ExFlashLock lk(false); + size_t writeLen = 0; + { + rtkSpiFlashSendCmd(GENERIC_FLASH_CMD_WREN); + rtkSpiFlashTxCmdAddr(cmd, address, mode); + if (size > (RTK_SPIC_FIFO_HALF_SIZE - 4)) { + writeLen = RTK_SPIC_FIFO_HALF_SIZE - 4; + } else { + writeLen = size; + } + uint32_t data; + uint32_t cnt = writeLen / 4; + for (uint32_t i = 0; i < cnt; i++) { + memcpy(&data, buf, 4); + buf += 4; + rtkSpiFlashSetDataReg(0, data, RTK_SPIC_DATA_WORD); + } + cnt = writeLen % 4; + if (cnt > 0) { + if (cnt >= 2) { + memcpy(&data, buf, 2); + buf += 2; + rtkSpiFlashSetDataReg(0, data, RTK_SPIC_DATA_HALF); + cnt -= 2; + } + if (cnt > 0) { + memcpy(&data, buf, 1); + buf += 1; + rtkSpiFlashSetDataReg(0, data, RTK_SPIC_DATA_BYTE); + } + } + } + rtkSpiFlashEnableCsWriteErase(); + size -= writeLen; + address += writeLen; + } + + return written; +} + +static int writeInBestMode(uint32_t addr, uint8_t* buf, size_t size) { + uint32_t address = addr; + + RtkSpicFlashConfigGuard guard; + + while (size > 0) { + auto written = writeInBestModeWithinPageBoundaries(address, buf, size); + address += written; + buf += written; + size -= written; + } + + rtkSpiFlashSendCmd(GENERIC_FLASH_CMD_WRDI); + DCache_Invalidate(addr + SPI_FLASH_BASE, size); + + return SYSTEM_ERROR_NONE; +} + // We are safe to run the constructor/destructor, cos they are copied to PSRAM to run. class XipControl { public: @@ -235,21 +544,16 @@ signed char XipControl::mpuEntry_ = -1; static bool is_block_erased(uintptr_t addr, size_t size); +static int writeInBestMode(uint32_t addr, uint8_t* buf, size_t size); + __attribute__((section(".ram.text"), noinline)) static int perform_write(uintptr_t addr, const uint8_t* data, size_t size) { - // XXX: No way of knowing whether the write operation succeeded or not - for (size_t b = 0; b < size;) { - size_t rem = MIN(8, (size - b)); - // XXX: do not use 12 byte writes, sometimes we get deadlocked - // TxData256 doesn't seem to work - FLASH_TxData12B(addr + b, (uint8_t)rem, (uint8_t*)data + b); - b += rem; - } - - return SYSTEM_ERROR_NONE; + return writeInBestMode(addr, (uint8_t*)data, size); } int hal_exflash_init(void) { + // ExFlashLock lk; + // FLASH_ClockSwitch(BIT_SHIFT_FLASH_CLK_XTAL, _FALSE); return SYSTEM_ERROR_NONE; } @@ -291,36 +595,61 @@ static bool is_block_erased(uintptr_t addr, size_t size) { } __attribute__((section(".ram.text"), noinline)) -static int erase_common(uintptr_t start_addr, size_t num_blocks, int len) { - ExFlashLock lk; - - const size_t block_length = len == EraseSector ? 4096 : 64 * 1024; - - /* Round down to the nearest block */ - start_addr = ((start_addr / block_length) * block_length); - - for (size_t i = 0; i < num_blocks; i++) { - if (!is_block_erased(start_addr + i * block_length, block_length)) { - FLASH_Erase(len, start_addr + i * block_length); - } +static int erase_common(uintptr_t address, hal_exflash_cmd_t cmd) { + ExFlashLock lk(false); + size_t size = 0; + if (cmd == GENERIC_FLASH_CMD_SE) { + size = 4 * 1024; + } else if (cmd == GENERIC_FLASH_CMD_BE32K) { + size = 32 * 1024; + } else if (cmd == GENERIC_FLASH_CMD_BE64K) { + size = 64 * 1024; + } else { + return SYSTEM_ERROR_INVALID_ARGUMENT; } + address = ((address / (size)) * (size)); + if (is_block_erased(address, (size))) { + return size; + } + RtkSpicFlashConfigGuard guard; - // LOG_DEBUG(ERROR, "Erased %lu %lukB blocks starting from %" PRIxPTR, - // num_blocks, block_length / 1024, start_addr); - - dcacheCleanInvalidateAligned(SPI_FLASH_BASE + start_addr, block_length * num_blocks); - - return SYSTEM_ERROR_NONE; + rtkSpiFlashSendCmd(GENERIC_FLASH_CMD_WREN); + /* Disable SPI_FLASH */ + SPIC->ssienr = 0; + rtkSpiSetTxMode(); + /* set flash cmd + addr and write to fifo */ + SPIC->dr[0].word = RTK_SPIC_CMD_ADDR_FORMAT(cmd, address); + rtkSpiFlashEnableCsWriteErase(); + rtkSpiFlashSendCmd(GENERIC_FLASH_CMD_WRDI); + return size; } __attribute__((section(".ram.text"), noinline)) int hal_exflash_erase_sector(uintptr_t start_addr, size_t num_sectors) { - return erase_common(start_addr, num_sectors, EraseSector); + size_t sizeInBytes = num_sectors * 4096; + uintptr_t addr = start_addr; + while (sizeInBytes > 0) { + hal_exflash_cmd_t cmd = GENERIC_FLASH_CMD_SE; + if (addr % (64*1024) == 0 && sizeInBytes >= 64*1024) { + cmd = GENERIC_FLASH_CMD_BE64K; + } else if (addr % (32*1024) == 0 && sizeInBytes >= 32*1024) { + cmd = GENERIC_FLASH_CMD_BE32K; + } + size_t size = CHECK(erase_common(addr, cmd)); + addr += size; + sizeInBytes -= size; + } + dcacheCleanInvalidateAligned(SPI_FLASH_BASE + start_addr, num_sectors * 4096); + return 0; } __attribute__((section(".ram.text"), noinline)) int hal_exflash_erase_block(uintptr_t start_addr, size_t num_blocks) { - return erase_common(start_addr, num_blocks, EraseBlock); + for (size_t i = 0; i < num_blocks; i++) { + CHECK(erase_common(start_addr, GENERIC_FLASH_CMD_BE64K)); + } + dcacheCleanInvalidateAligned(SPI_FLASH_BASE + start_addr, num_blocks * 64 * 4096); + return 0; } __attribute__((section(".ram.text"), noinline)) @@ -373,195 +702,6 @@ static bool isSecureOtpMode(uint32_t normalContent) { #if MODULE_FUNCTION != MOD_FUNC_BOOTLOADER -// GD25 flash specific definitions - -#define RTK_SPIC_FIFO_SIZE 64 -#define RTK_SPIC_FIFO_HALF_SIZE (RTK_SPIC_FIFO_SIZE / 2) - -#define RTK_SPIC_BIT_OFFSET_AUTO_LEN_DUM ((uint32_t)0) -#define RTK_SPIC_BIT_WIDTH_AUTO_LEN_DUM ((uint32_t)16) -#define RTK_SPIC_BIT_OFFSET_SR_TXE ((uint32_t)5) -#define RTK_SPIC_BIT_OFFSET_SR_BUSY ((uint32_t)0) - -#define RTK_SPIC_READ_TUNING_DUMMY_CYCLE 0x2 - -#define RTK_SPIC_BIT_MASK(offset) ((uint32_t)((offset) == 32) ? \ - 0x0 : (0x1 << (offset))) - -#define RTK_SPIC_BIT_MASK_WIDTH(offset, bit_num) ((uint32_t)((offset) == 32) ? \ - 0xFFFFFFFF : (((1 << (bit_num)) - 1) << (offset))) - -#define RTK_SPIC_BITS_SET_VAL(reg, offset, val, bit_num) \ - ((reg) = ((uint32_t)(reg) & (~RTK_SPIC_BIT_MASK_WIDTH(offset, bit_num))) | \ - ((val << (offset)) & RTK_SPIC_BIT_MASK_WIDTH(offset, bit_num))) - -#define RTK_SPIC_CMD_ADDR_FORMAT(cmd, addr) (((cmd) & 0x000000ff) | \ - ((addr & 0x000000ff) << 24) | \ - ((addr & 0x0000ff00) << 8) | \ - ((addr & 0x00ff0000) >> 8)) - -#define RTK_SPIC_BIT_GET_UNSHIFTED(reg, offset) \ - ((uint32_t)((reg) & RTK_SPIC_BIT_MASK(offset))) - -enum RtkSpicFlashDataWidth { - RTK_SPIC_DATA_BYTE = 0, - RTK_SPIC_DATA_HALF = 1, - RTK_SPIC_DATA_WORD = 2 -}; - -static void rtkSpiFlashSetDataReg(uint32_t index, uint32_t data, enum RtkSpicFlashDataWidth byteWidth) { - if (index > 31) { - return; - } else if (byteWidth == RTK_SPIC_DATA_BYTE) { - SPIC->dr[index].byte = (data & 0x000000ff); - } else if (byteWidth == RTK_SPIC_DATA_HALF) { - SPIC->dr[index].half = (data & 0x0000ffff); - } else if (byteWidth == RTK_SPIC_DATA_WORD) { - SPIC->dr[index].word = data; - } -} - -static uint32_t rtkSpiFlashGetDataReg(uint32_t index, enum RtkSpicFlashDataWidth byteWidth) { - uint32_t data; - if (index > 31) { - return 0; - } else if (byteWidth == RTK_SPIC_DATA_BYTE) { - data = SPIC->dr[index].byte & 0x000000ff; - } else if (byteWidth == RTK_SPIC_DATA_HALF) { - data = SPIC->dr[index].half & 0x0000ffff; - } else if (byteWidth == RTK_SPIC_DATA_WORD) { - data = SPIC->dr[index].word; - } else { - return 0; - } - return data; -} - -static void rtkSpiSetRxMode() { - SPIC->ctrlr0 = (SPIC->ctrlr0 | 0x0300); - SPIC->ctrlr0 = (SPIC->ctrlr0 & 0xfff0ffff); -} - -static void rtkSpiSetTxMode() { - SPIC->ctrlr0 = SPIC->ctrlr0 & 0xfffffcff; - SPIC->ctrlr0 = (SPIC->ctrlr0 & 0xfff0ffff); -} - -static void rtkSpiFlashWaitBusy() { - while (1) { - if (RTK_SPIC_BIT_GET_UNSHIFTED(SPIC->sr, RTK_SPIC_BIT_OFFSET_SR_TXE)) { - break; - } - if ((!RTK_SPIC_BIT_GET_UNSHIFTED(SPIC->sr, RTK_SPIC_BIT_OFFSET_SR_BUSY))) { - break; - } - } -} - -static uint8_t gd25GetStatus() { - /* Disable SPI_FLASH */ - SPIC->ssienr = 0; - /* Set Ctrlr1; 1 byte data frames */ - SPIC->ctrlr1 = 1; - /* Set tuning dummy cycles */ - RTK_SPIC_BITS_SET_VAL(SPIC->auto_length, RTK_SPIC_BIT_OFFSET_AUTO_LEN_DUM, RTK_SPIC_READ_TUNING_DUMMY_CYCLE, RTK_SPIC_BIT_WIDTH_AUTO_LEN_DUM); - /* set ctrlr0: RX_mode */ - rtkSpiSetRxMode(); - /* set flash_cmd: write cmd to fifo */ - rtkSpiFlashSetDataReg(0, GENERIC_FLASH_CMD_RDSR, RTK_SPIC_DATA_BYTE); - /* Enable SPI_FLASH */ - SPIC->ssienr = 1; - rtkSpiFlashWaitBusy(); - return rtkSpiFlashGetDataReg(0, RTK_SPIC_DATA_BYTE); -} - -static void rtkSpiFlashEnableCsRead(uint32_t len) { - /* set receive data length */ - if (len <= 0x00010000) { - SPIC->ctrlr1 = len; - } - /* Enable SPI_FLASH */ - SPIC->ssienr = 1; - rtkSpiFlashWaitBusy(); -} - -static void rtkSpiFlashEnableCsWriteErase() { - /* Enable SPI_FLASH */ - SPIC->ssienr = 1; - rtkSpiFlashWaitBusy(); - /* Check flash is in write progress or not */ - while ((gd25GetStatus() & 0x1)) {} -} - -static void rtkSpiFlashSendCmd(uint8_t cmd) { - /* Disble SPI_FLASH */ - SPIC->ssienr = 0; - /* set ctrlr0: TX mode */ - rtkSpiSetTxMode(); - /* set flash_cmd: wren to fifo */ - rtkSpiFlashSetDataReg(0, cmd, RTK_SPIC_DATA_BYTE); - rtkSpiFlashEnableCsWriteErase(); -} - -static void rtkSpiFlashRxCmdAddr(uint8_t cmd, uint32_t addr, uint32_t dummyCycle) { - /* Disable SPI_FLASH */ - SPIC->ssienr = 0; - if (dummyCycle != 0) { // spi_flash_set_dummy_cycle(dev, dummy); - uint32_t cycle = 0; - /* if using fast_read baud_rate */ - if (((SPIC->ctrlr0) & 0x00100000)) { - cycle = (SPIC->fbaudr); - } else { - cycle = (SPIC->baudr); - } - cycle = (cycle * dummyCycle * 2) + RTK_SPIC_READ_TUNING_DUMMY_CYCLE; - if (cycle <= 0x10000) { - RTK_SPIC_BITS_SET_VAL(SPIC->auto_length, RTK_SPIC_BIT_OFFSET_AUTO_LEN_DUM, cycle, RTK_SPIC_BIT_WIDTH_AUTO_LEN_DUM); - } - } else { - /* Set tuning dummy cycles */ - RTK_SPIC_BITS_SET_VAL(SPIC->auto_length, RTK_SPIC_BIT_OFFSET_AUTO_LEN_DUM, RTK_SPIC_READ_TUNING_DUMMY_CYCLE, RTK_SPIC_BIT_WIDTH_AUTO_LEN_DUM); - } - - /* set ctrlr0: RX mode, data_ch, addr_ch */ - rtkSpiSetRxMode(); - - /* set flash cmd + addr and write to fifo */ - SPIC->dr[0].word = RTK_SPIC_CMD_ADDR_FORMAT(cmd, addr); -} - -static void rtkSpiFlashTxCmdAddr(uint8_t cmd, uint32_t addr) { - /* Disable SPI_FLASH */ - SPIC->ssienr = 0; - /* set ctrlr0: TX mode, data_ch, addr_ch */ - rtkSpiSetTxMode(); - /* set flash cmd + addr and write to fifo */ - SPIC->dr[0].word = RTK_SPIC_CMD_ADDR_FORMAT(cmd, addr); -} - -class RtkSpicFlashConfigGuard { -public: - RtkSpicFlashConfigGuard() { - ctrl0_ = SPIC->ctrlr0; - autoLen_ = SPIC->auto_length; - addrLen_ = SPIC->addr_length; - /* setting auto mode CS_H_WR_LEN, address length(3 byte) */ - SPIC->auto_length = ((SPIC->auto_length & 0xfffcffff) | 0x00030000); - SPIC->addr_length = 3; - } - ~RtkSpicFlashConfigGuard() { - SPIC->ssienr = 0; - SPIC->ctrlr0 = ctrl0_; - SPIC->auto_length = autoLen_; - SPIC->addr_length = addrLen_; - } - -private: - uint32_t ctrl0_; - uint32_t autoLen_; - uint32_t addrLen_; -}; - static int gd25ReadSecurityRegisters(uint8_t otpPageIdx, uint32_t addr, uint8_t* buf, size_t size) { CHECK_TRUE(otpPageIdx < HAL_QSPI_FLASH_OTP_SECTOR_COUNT_GD25, SYSTEM_ERROR_INVALID_ARGUMENT); CHECK_TRUE(addr + size <= HAL_QSPI_FLASH_OTP_SIZE_GD25, SYSTEM_ERROR_INVALID_ARGUMENT); @@ -652,6 +792,8 @@ static int gd25WriteSecurityRegisters(uint8_t otpPageIdx, uint32_t addr, uint8_t } static int gd25PerformSecurityRegistersOperation(Gd25SecurityRegistersOperation operation, uintptr_t addr, uint8_t* data_buf, size_t data_size) { + ExFlashLock lk(false); // Stop thread scheduler + // Determine which OTP Register to start operating from size_t otpPageIdx = addr / HAL_QSPI_FLASH_OTP_SECTOR_SIZE_GD25; size_t dataToProcessTotal = data_size; @@ -680,7 +822,7 @@ static int gd25PerformSecurityRegistersOperation(Gd25SecurityRegistersOperation } int hal_exflash_read_special(hal_exflash_special_sector_t sp, uintptr_t addr, uint8_t* data_buf, size_t data_size) { - ExFlashLock lk(false); // Stop thread scheduler + ExFlashLock lk; CHECK_TRUE(sp == HAL_EXFLASH_SPECIAL_SECTOR_OTP, SYSTEM_ERROR_INVALID_ARGUMENT); CHECK_TRUE(data_buf && data_size > 0, SYSTEM_ERROR_INVALID_ARGUMENT); @@ -714,7 +856,7 @@ int hal_exflash_read_special(hal_exflash_special_sector_t sp, uintptr_t addr, ui } int hal_exflash_write_special(hal_exflash_special_sector_t sp, uintptr_t addr, const uint8_t* data_buf, size_t data_size) { - ExFlashLock lk(false); // Stop thread scheduler + ExFlashLock lk; CHECK_TRUE(sp == HAL_EXFLASH_SPECIAL_SECTOR_OTP, SYSTEM_ERROR_INVALID_ARGUMENT); CHECK_TRUE(data_buf && data_size > 0, SYSTEM_ERROR_INVALID_ARGUMENT); diff --git a/hal/src/rtl872x/hal_platform_rtl8721x_config.h b/hal/src/rtl872x/hal_platform_rtl8721x_config.h index 3b2c329de2..49aa7ce76c 100644 --- a/hal/src/rtl872x/hal_platform_rtl8721x_config.h +++ b/hal/src/rtl872x/hal_platform_rtl8721x_config.h @@ -150,3 +150,5 @@ #ifndef HAL_PLATFORM_ETHERNET_FEATHERWING_SPI_CLOCK #define HAL_PLATFORM_ETHERNET_FEATHERWING_SPI_CLOCK (25000000) #endif + +#define HAL_PLATFORM_PROHIBIT_XIP (1) diff --git a/third_party/ambd_sdk/ambd_sdk b/third_party/ambd_sdk/ambd_sdk index ede1612108..a6b17b249f 160000 --- a/third_party/ambd_sdk/ambd_sdk +++ b/third_party/ambd_sdk/ambd_sdk @@ -1 +1 @@ -Subproject commit ede161210878fb0ee996f6edd0c4f81892109317 +Subproject commit a6b17b249f9134ae5fe001d884558c88bf78a872 diff --git a/user/tests/wiring/no_fixture_stress/exflash.cpp b/user/tests/wiring/no_fixture_stress/exflash.cpp index bbb7d992ee..dd1ed209bc 100644 --- a/user/tests/wiring/no_fixture_stress/exflash.cpp +++ b/user/tests/wiring/no_fixture_stress/exflash.cpp @@ -15,13 +15,16 @@ * License along with this library; if not, see . */ +#define PARTICLE_USE_UNSTABLE_API #include "application.h" #include "unit-test/unit-test.h" #include "scope_guard.h" +#include "storage_hal.h" + #if HAL_PLATFORM_FILESYSTEM && (HAL_PLATFORM_NRF52840 || HAL_PLATFORM_RTL872X) && !HAL_PLATFORM_PROHIBIT_XIP -void performXipRead() { +void performXipRead(std::atomic_bool& exit) { for (uint32_t* addr = (uint32_t*)EXTERNAL_FLASH_XIP_BASE; !exit && addr < (uint32_t*)(EXTERNAL_FLASH_XIP_BASE + EXTERNAL_FLASH_SIZE); addr++) { // We need to be doing something useful here, so that XIP accesses are not optimized out uint32_t result = HAL_Core_Compute_CRC32((const uint8_t*)addr, sizeof(*addr)); @@ -29,7 +32,7 @@ void performXipRead() { } } -__attribute__((section(".xip.text"), noinline)) void performXipReadFromXipCode() { +__attribute__((section(".xip.text"), noinline)) void performXipReadFromXipCode(std::atomic_bool& exit) { for (uint32_t* addr = (uint32_t*)EXTERNAL_FLASH_XIP_BASE; !exit && addr < (uint32_t*)(EXTERNAL_FLASH_XIP_BASE + EXTERNAL_FLASH_SIZE); addr++) { // We need to be doing something useful here, so that XIP accesses are not optimized out uint32_t result = HAL_Core_Compute_CRC32((const uint8_t*)addr, sizeof(*addr)); @@ -44,7 +47,7 @@ test(EXFLASH_00_ConcurrentXipAndWriteErasureUsageStress) { Thread* t = new Thread("test", [](void* param) -> os_thread_return_t { std::atomic_bool& exit = *static_cast(param); while (!exit) { - performXipRead(); + performXipRead(exit); } }, (void*)&exit); assertTrue(t); @@ -77,7 +80,7 @@ test(EXFLASH_01_ConcurrentXipCodeAndWriteErasureUsageStress) { Thread* t = new Thread("test", [](void* param) -> os_thread_return_t { std::atomic_bool& exit = *static_cast(param); while (!exit) { - performXipReadFromXipCode(); + performXipReadFromXipCode(exit); } }, (void*)&exit); assertTrue(t); @@ -104,3 +107,68 @@ test(EXFLASH_01_ConcurrentXipCodeAndWriteErasureUsageStress) { } #endif // HAL_PLATFORM_FILESYSTEM && (HAL_PLATFORM_NRF52840 || HAL_PLATFORM_RTL872X) && !HAL_PLATFORM_PROHIBIT_XIP + +void performNonXipRead(std::atomic_bool& exit) { + for (uint32_t* addr = (uint32_t*)EXTERNAL_FLASH_XIP_BASE; !exit && addr < (uint32_t*)(EXTERNAL_FLASH_XIP_BASE + EXTERNAL_FLASH_SIZE); addr++) { + // We need to be doing something useful here, so that XIP accesses are not optimized out + uint32_t dummy = 0; + hal_storage_read(HAL_STORAGE_ID_INTERNAL_FLASH, (uintptr_t)addr, (uint8_t*)&dummy, sizeof(dummy)); + uint32_t result = HAL_Core_Compute_CRC32((const uint8_t*)&dummy, sizeof(dummy)); + (void)HAL_Core_Compute_CRC32((const uint8_t*)&result, sizeof(result)); + } +} + +test(EXFLASH_02_ConcurrentNonXipReadAndWriteErasureUsageStress) { + std::atomic_bool exit; + exit = false; + + Thread* t = new Thread("test", [](void* param) -> os_thread_return_t { + std::atomic_bool& exit = *static_cast(param); + while (!exit) { + performNonXipRead(exit); + } + }, (void*)&exit); + assertTrue(t); + + SCOPE_GUARD({ + exit = true; + t->join(); + delete t; + }); + + // 30 seconds + constexpr system_tick_t duration = 30 * 1000; + + for (system_tick_t now = millis(), begin = now; now < begin + duration; now = millis()) { + uint32_t val = rand(); + uint32_t tmp; + EEPROM.get(0, tmp); + + val = val ^ tmp; + EEPROM.put(0, val); + EEPROM.get(0, tmp); + assertEqual(tmp, val); + } +} + +#if HAL_PLATFORM_RTL872X + +#include "hal_platform_rtl.h" +extern "C" { +#include "rtl8721d.h" +} + +test(EXFLASH_02_rtl872x_validate_mode) { + RRAM_TypeDef* RRAM = ((RRAM_TypeDef *) RRAM_BASE); +#if PLATFORM_ID == PLATFORM_P2 + // P2/Photon 2 in Dual IO mode + assertEqual((uint32_t)RRAM->FLASH_ReadMode, (uint32_t)ReadDualIOMode); +#else + // M SoM in Quad IO mode + assertEqual((uint32_t)RRAM->FLASH_ReadMode, (uint32_t)ReadQuadIOMode); +#endif // PLATFORM_ID == PLATFORM_P2 + // Highest clock speed (clkdiv=1) + assertEqual((uint32_t)SPIC->fbaudr, (uint32_t)1); + assertEqual((uint32_t)SPIC->baudr, (uint32_t)1); +} +#endif // HAL_PLATFORM_RTL872X