2025-10-10 16:07:00 +08:00

425 lines
12 KiB
C
Executable File

#include <common/bk_include.h>
#include "bk_arm_arch.h"
#include <common/sys_config.h>
#include "flash_bypass.h"
#include "sys_driver.h"
#include "gpio_driver.h"
#include <driver/spi.h>
#include "spi_hal.h"
#include "driver/flash.h"
#if CONFIG_SOC_BK7236XX
#define SPI_R_0X2(_id) (SPI_R_BASE(_id) + 2 * 0x04)
__attribute__((section(".iram"))) int flash_bypass_op_write(uint8_t *op_code, uint8_t *tx_buf, uint32_t tx_len)
{
uint32_t reg;
uint32_t reg_0x2, reg_ctrl, reg_dat;
uint32_t reg_stat, reg_cfg;
uint32_t int_status = 0;
int exceptional_flag = 0;
uint32_t reg_sys_clk_en_0xc, reg_sys_clk_sel_0xa;
int_status = rtos_disable_int();
/*step 1, save spi register configuration*/
reg_0x2 = REG_READ(SPI_R_0X2(0));
reg_ctrl = REG_READ(SPI_R_CTRL(0));
reg_stat = REG_READ(SPI_R_INT_STATUS(0));
reg_dat = REG_READ(SPI_R_DATA(0));
reg_cfg = REG_READ(SPI_R_CFG(0));
/*step 2, en software reset bit, bk7236/58 should enable this bit*/
reg = REG_READ(SPI_R_0X2(0));
reg |= (1 << 0);
REG_WRITE(SPI_R_0X2(0), reg);
/*step 3, config spi master*/
/* 3.1 clear spi fifo content*/
reg = REG_READ(SPI_R_INT_STATUS(0));
while (reg & SPI_STATUS_RXFIFO_RD_READY) {
REG_READ(SPI_R_DATA(0));
reg = REG_READ(SPI_R_INT_STATUS(0));
}
/* 3.2 disable spi block, and backup */
reg_sys_clk_en_0xc = reg = REG_READ(SYS_R_ADD_X(0xc));
reg &= ~(1 << 1);
REG_WRITE(SYS_R_ADD_X(0xc), reg);
/* 3.3 clear spi status*/
REG_WRITE(SPI_R_CTRL(0), 0);
reg = REG_READ(SPI_R_INT_STATUS(0));
REG_WRITE(SPI_R_INT_STATUS(0), reg);
REG_WRITE(SPI_R_CFG(0), 0);
/* 3.4 save the previous setting status*/
/* gpioi of SPI0 are set as high-impedance state or input state ,
for spi mux with them*/
//gpio_dev_unmap(SPI0_LL_CSN_PIN);
//gpio_dev_unmap(SPI0_LL_SCK_PIN);
//gpio_dev_unmap(SPI0_LL_MOSI_PIN);
//gpio_dev_unmap(SPI0_LL_MISO_PIN);
//gpio_dev_map(SPI0_LL_SCK_PIN, GPIO_DEV_SPI0_SCK);
//gpio_dev_map(SPI0_LL_CSN_PIN, GPIO_DEV_SPI0_CSN);
//gpio_dev_map(SPI0_LL_MOSI_PIN, GPIO_DEV_SPI0_MOSI);
//gpio_dev_map(SPI0_LL_MISO_PIN, GPIO_DEV_SPI0_MISO);
/* 3.5 set the spi master mode*/
// open clock, and backup
reg = REG_READ(SYS_R_ADD_X(0xc));
reg |= (1 << 1);
REG_WRITE(SYS_R_ADD_X(0xc), reg);
// select 26M
reg_sys_clk_sel_0xa = reg = REG_READ(SYS_R_ADD_X(0xa));
reg &= ~(1 << 4);
REG_WRITE(SYS_R_ADD_X(0xa), reg);
// set to spi config directly
reg = 0xC00100; // spien msten spi_clk=1---13M
REG_WRITE(SPI_R_CTRL(0), reg);
/*step 4, gpio(14/15/16/17) are set as high-impedance state or input state */
/*step 5, switch flash interface to spi
* Pay attention to prefetch instruction destination, the text can not
* fetch from flash space after this timepoint.
*/
//sys_drv_set_cpu_storage_connect_op_select_flash_sel(1);
reg = REG_READ(SYS_R_ADD_X(0x2));
reg |= (1 << 9);
REG_WRITE(SYS_R_ADD_X(0x2), reg);
if(op_code != NULL)
{
/*step 6, write enable for volatile status register: 50H*/
/* 6.1:take cs*/
reg = REG_READ(SPI_R_CFG(0));
reg &= ~(SPI_CFG_TRX_LEN_MASK << SPI_CFG_TX_TRAHS_LEN_POSI);
reg |= (1 << SPI_CFG_TX_TRAHS_LEN_POSI);
reg |= (SPI_CFG_TX_EN | SPI_CFG_TX_FIN_INT_EN);
REG_WRITE(SPI_R_CFG(0), reg);
/* 6.2:write tx fifo*/
reg = REG_READ(SPI_R_INT_STATUS(0));
if (reg & SPI_STATUS_TXFIFO_WR_READY)
REG_WRITE(SPI_R_DATA(0), *op_code);
else {
exceptional_flag = -1;
goto wr_exceptional;
}
/* 6.3:waiting for TXFIFO_EMPTY interrupt*/
while (1) {
reg = REG_READ(SPI_R_INT_STATUS(0));
if (reg & SPI_STATUS_TX_FINISH_INT)
break;
}
/* 6.4:release cs*/
reg = REG_READ(SPI_R_CFG(0));
reg &= ~(SPI_CFG_TRX_LEN_MASK << SPI_CFG_TX_TRAHS_LEN_POSI);
reg &= ~(SPI_CFG_TX_EN | SPI_CFG_TX_FIN_INT_EN);
REG_WRITE(SPI_R_CFG(0), reg);
// cler stat and fifo
reg = REG_READ(SPI_R_INT_STATUS(0));
while (reg & SPI_STATUS_RXFIFO_RD_READY) {
REG_READ(SPI_R_DATA(0));
reg = REG_READ(SPI_R_INT_STATUS(0));
}
reg = REG_READ(SPI_R_INT_STATUS(0));
REG_WRITE(SPI_R_INT_STATUS(0), reg);
}
if((tx_len == 0) || (tx_buf == NULL))
{
exceptional_flag = 0;
goto wr_exceptional;
}
/*step 7, for tx_buf */
/* 7.1:take cs*/
reg = REG_READ(SPI_R_CFG(0));
reg &= ~(SPI_CFG_TRX_LEN_MASK << SPI_CFG_TX_TRAHS_LEN_POSI);
reg &= ~(SPI_CFG_TRX_LEN_MASK << SPI_CFG_RX_TRAHS_LEN_POSI);
reg |= ((tx_len & SPI_CFG_TRX_LEN_MASK) << SPI_CFG_TX_TRAHS_LEN_POSI);
reg |= (SPI_CFG_TX_EN | SPI_CFG_TX_FIN_INT_EN);
REG_WRITE(SPI_R_CFG(0), reg);
/* 7.2:write tx fifo*/
// write tx first
for (int i = 0, wait = 0; i < tx_len; ) {
reg = REG_READ(SPI_R_INT_STATUS(0));
if ((reg & SPI_STATUS_TXFIFO_WR_READY) == 0) {
for(volatile int j=0; j<500; j++);
wait++;
if(wait > 100) {
exceptional_flag = -2;
goto wr_exceptional;
}
} else {
wait = 0;
REG_WRITE(SPI_R_DATA(0), tx_buf[i]);
i++;
}
}
/* 7.3:waiting for TXFIFO_EMPTY interrupt*/
while (1) {
reg = REG_READ(SPI_R_INT_STATUS(0));
if (reg & SPI_STATUS_TX_FINISH_INT)
break;
}
/* 7.4:release cs*/
reg = REG_READ(SPI_R_CFG(0));
reg &= ~(SPI_CFG_TRX_LEN_MASK << SPI_CFG_TX_TRAHS_LEN_POSI);
reg &= ~(SPI_CFG_TRX_LEN_MASK << SPI_CFG_RX_TRAHS_LEN_POSI);
reg &= (SPI_CFG_RX_EN | SPI_CFG_TX_EN | SPI_CFG_TX_FIN_INT_EN);
REG_WRITE(SPI_R_CFG(0), reg);
// cler stat and fifo
reg = REG_READ(SPI_R_INT_STATUS(0));
while (reg & SPI_STATUS_RXFIFO_RD_READY) {
REG_READ(SPI_R_DATA(0));
reg = REG_READ(SPI_R_INT_STATUS(0));
}
reg = REG_READ(SPI_R_INT_STATUS(0));
REG_WRITE(SPI_R_INT_STATUS(0), reg);
exceptional_flag = 0;
wr_exceptional:
/*step 8, switch flash interface to flash controller */
//sys_drv_set_cpu_storage_connect_op_select_flash_sel(0);
reg = REG_READ(SYS_R_ADD_X(0x2));
reg &= ~(1 << 9);
REG_WRITE(SYS_R_ADD_X(0x2), reg);
// recover icu and powerdown bits for spi
REG_WRITE(SYS_R_ADD_X(0xc), reg_sys_clk_en_0xc);
REG_WRITE(SYS_R_ADD_X(0xa), reg_sys_clk_sel_0xa);
/*step 9, gpio(14/15/16/17) second function*/
/*step 10, restore spi register configuration*/
REG_WRITE(SPI_R_CTRL(0), reg_ctrl);
REG_WRITE(SPI_R_INT_STATUS(0), reg_stat);
REG_WRITE(SPI_R_DATA(0), reg_dat);
REG_WRITE(SPI_R_CFG(0), reg_cfg);
REG_WRITE(SPI_R_0X2(0), reg_0x2);
/*step 11, enable interrupt*/
rtos_enable_int(int_status);
return exceptional_flag;
}
#else /*CONFIG_SOC_BK7236XX*/
void flash_bypass_init(void) {
char *text_ptr, temp_buf = 0;
uint32_t reg;
/*step 2, resident cache*/
REG_WRITE(SPI_R_CTRL(0), 0);
do {
text_ptr = (char *)flash_bypass_quad_enable;
for (uint32_t i = 0; i < CURRENT_ROUTINE_TEXT_SIZE; i ++)
temp_buf += text_ptr[i];
REG_WRITE(SPI_R_INT_STATUS(0), temp_buf);
} while (0);
/*step 3, config spi master*/
/* clear spi status*/
REG_WRITE(SPI_R_CTRL(0), 0);
reg = REG_READ(SPI_R_INT_STATUS(0));
REG_WRITE(SPI_R_INT_STATUS(0), reg);
REG_WRITE(SPI_R_CFG(0), 0);
spi_config_t config = {0};
config.role = SPI_ROLE_MASTER;
config.bit_width = SPI_BIT_WIDTH_8BITS;
config.polarity = 1;
config.phase = 1;
config.wire_mode = SPI_4WIRE_MODE;
config.baud_rate = 1000000;
config.bit_order = SPI_MSB_FIRST;
#if (CONFIG_SPI_BYTE_INTERVAL)
config.byte_interval = 1;
#endif
bk_spi_driver_init();
bk_spi_init(0, &config);
/*step 4, gpioi of SPI0 are set as high-impedance state or input state ,
for spi mux with them*/
gpio_dev_unmap(SPI0_LL_CSN_PIN);
gpio_dev_unmap(SPI0_LL_SCK_PIN);
gpio_dev_unmap(SPI0_LL_MOSI_PIN);
gpio_dev_unmap(SPI0_LL_MISO_PIN);
}
__attribute__((section(".itcm_sec_code"))) void flash_bypass_quad_enable(void)
{
uint32_t reg;
uint32_t reg_ctrl, reg_dat;
uint32_t reg_stat, reg_cfg;
uint32_t int_status = 0;
uint32_t spi_status = 0;
volatile uint32_t i, j, delay_count;
int_status = rtos_disable_int();
/*step 1, save spi register configuration*/
reg_ctrl = REG_READ(SPI_R_CTRL(0));
reg_stat = REG_READ(SPI_R_INT_STATUS(0));
reg_dat = REG_READ(SPI_R_DATA(0));
reg_cfg = REG_READ(SPI_R_CFG(0));
flash_bypass_init();
/*step 5, switch flash interface to spi
* Pay attention to prefetch instruction destination, the text can not
* fetch from flash space after this timepoint.
*/
sys_drv_set_cpu_storage_connect_op_select_flash_sel(1);
/*step 6, write enable for status register: 06H*/
reg = REG_READ(SPI_R_INT_STATUS(0));
REG_WRITE(SPI_R_INT_STATUS(0), reg);
REG_WRITE(SPI_R_CFG(0), SPI_CFG_TX_EN_ONE_BYTE);
REG_WRITE(SPI_R_DATA(0), FLASH_CMD_WR_EN_SR);
/*step 7, write cmd 31H, data 0x02*/
for(i = 0; i < 500; i++) {
spi_status = REG_READ(SPI_R_INT_STATUS(0));
if(0 != (spi_status & SPI_STATUS_TX_FINISH_INT)) {
break;
}
}
for(delay_count = 0; delay_count < 20000; delay_count ++)
{
for(j = 0; j < 8; j ++)
;
}
REG_WRITE(SPI_R_CFG(0), 0);
reg = REG_READ(SPI_R_INT_STATUS(0));
REG_WRITE(SPI_R_INT_STATUS(0), reg);
REG_WRITE(SPI_R_CFG(0), SPI_CFG_TX_EN_TWO_BYTE);
REG_WRITE(SPI_R_DATA(0), FLASH_CMD_WR_SR);
REG_WRITE(SPI_R_DATA(0), FLASH_GD25Q32C_SR_QUAD_EN);
for(i = 0; i < 500; i++) {
spi_status = REG_READ(SPI_R_INT_STATUS(0));
if(0 != (spi_status & SPI_STATUS_TX_FINISH_INT)) {
break;
}
}
for(delay_count = 0; delay_count < 20000; delay_count ++)
{
for(j = 0; j < 8; j ++)
;
}
REG_WRITE(SPI_R_CFG(0), 0);
reg = REG_READ(SPI_R_INT_STATUS(0));
REG_WRITE(SPI_R_INT_STATUS(0), reg);
/*step 8, switch flash interface to flash controller */
sys_drv_set_cpu_storage_connect_op_select_flash_sel(0);
/*step 9, restore spi register configuration*/
REG_WRITE(SPI_R_CTRL(0), reg_ctrl);
REG_WRITE(SPI_R_INT_STATUS(0), reg_stat);
REG_WRITE(SPI_R_DATA(0), reg_dat);
REG_WRITE(SPI_R_CFG(0), reg_cfg);
rtos_enable_int(int_status);
}
__attribute__((section(".itcm_sec_code"))) void flash_bypass_quad_test(uint32_t quad_enable, uint32_t delay_cycle1, uint32_t delay_cycle2)
{
uint32_t reg;
uint32_t reg_ctrl, reg_dat;
uint32_t reg_stat, reg_cfg;
uint32_t int_status = 0;
uint32_t spi_status = 0;
volatile uint32_t i, j, delay_count;
int_status = rtos_disable_int();
/*step 1, save spi register configuration*/
reg_ctrl = REG_READ(SPI_R_CTRL(0));
reg_stat = REG_READ(SPI_R_INT_STATUS(0));
reg_dat = REG_READ(SPI_R_DATA(0));
reg_cfg = REG_READ(SPI_R_CFG(0));
flash_bypass_init();
/*step 5, switch flash interface to spi
* Pay attention to prefetch instruction destination, the text can not
* fetch from flash space after this timepoint.
*/
sys_drv_set_cpu_storage_connect_op_select_flash_sel(1);
/*step 6, write enable for status register: 06H*/
reg = REG_READ(SPI_R_INT_STATUS(0));
REG_WRITE(SPI_R_INT_STATUS(0), reg);
REG_WRITE(SPI_R_CFG(0), SPI_CFG_TX_EN_ONE_BYTE);
REG_WRITE(SPI_R_DATA(0), FLASH_CMD_WR_EN_SR);
/*step 7, write cmd 31H, data 0x02*/
for(i = 0; i < delay_cycle1; i++) {
spi_status = REG_READ(SPI_R_INT_STATUS(0));
if(0 != (spi_status & SPI_STATUS_TX_FINISH_INT)) {
break;
}
}
for(delay_count = 0; delay_count < delay_cycle2; delay_count ++)
{
for(j = 0; j < 8; j ++)
;
}
REG_WRITE(SPI_R_CFG(0), 0);
reg = REG_READ(SPI_R_INT_STATUS(0));
REG_WRITE(SPI_R_INT_STATUS(0), reg);
REG_WRITE(SPI_R_CFG(0), SPI_CFG_TX_EN_TWO_BYTE);
REG_WRITE(SPI_R_DATA(0), FLASH_CMD_WR_SR);
if (quad_enable) {
REG_WRITE(SPI_R_DATA(0), FLASH_GD25Q32C_SR_QUAD_EN);
} else {
REG_WRITE(SPI_R_DATA(0), 0);
}
for(i = 0; i < delay_cycle1; i++) {
spi_status = REG_READ(SPI_R_INT_STATUS(0));
if(0 != (spi_status & SPI_STATUS_TX_FINISH_INT)) {
break;
}
}
for(delay_count = 0; delay_count < delay_cycle2; delay_count ++)
{
for(j = 0; j < 8; j ++)
;
}
REG_WRITE(SPI_R_CFG(0), 0);
reg = REG_READ(SPI_R_INT_STATUS(0));
REG_WRITE(SPI_R_INT_STATUS(0), reg);
/*step 8, switch flash interface to flash controller */
sys_drv_set_cpu_storage_connect_op_select_flash_sel(0);
/*step 9, restore spi register configuration*/
REG_WRITE(SPI_R_CTRL(0), reg_ctrl);
REG_WRITE(SPI_R_INT_STATUS(0), reg_stat);
REG_WRITE(SPI_R_DATA(0), reg_dat);
REG_WRITE(SPI_R_CFG(0), reg_cfg);
rtos_enable_int(int_status);
}
#endif