Files
kunlun/mfgtool/ram/src/erase_ext_flash.c
2024-09-28 14:24:04 +08:00

476 lines
12 KiB
C

/****************************************************************************
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
be copied by any method or incorporated into another program without
the express written consent of Aerospace C.Power. This Information or any portion
thereof remains the property of Aerospace C.Power. The Information contained herein
is believed to be accurate and Aerospace C.Power assumes no responsibility or
liability for its use in any way and conveys no license or title under
any patent or copyright and makes no representation or warranty that this
Information is free from patent or copyright infringement.
****************************************************************************/
#include "iot_config.h"
#include "iot_io.h"
#include "iot_clock.h"
#include "sfc.h"
#include "spi.h"
#include "gpio_mtx.h"
#include "apb.h"
#include "iot_errno_api.h"
#include "ram.h"
#include "iot_gpio.h"
#include "gpio_hw.h"
#include "ram_printf.h"
#include "gd25q32xx.h"
/* Flash status register bits */
#define SPI_FLASH_WIP 0x01
#define SPI_FLASH_WEL 0x02
/* wait cycles when set WEL or clear WIP */
#define SPI_FLASH_WAIT_TIMES 1000000
#define SPI_READ_DUMMY_PAT 0xFFFFFFFF
#define SPI_TXRX_DEFAULT_SIZE 16
#define SPI_FLASH_SECTOR_SIZE 0x00001000 /* 4KB */
#define SPI_FLASH_PAGE_SIZE 0x0000100 /* 256B */
#define SPI_FLASH_CYCLE_COUNT (10 * SPI_FLASH_SECTOR_SIZE / \
SPI_FLASH_PAGE_SIZE) /* 160 */
extern const spi_opr dw_ssi_ctrl;
extern iot_gpio_op_t hw_gpio_api_table;
extern int ram_error_no;
extern int ram_get_ext_spi_flash_gpio(int idx, iot_spi_gpio_sel_t **table);
extern const APB_MODULE spi_table[];
#define SPI_APB_DEV(dev) (spi_table[dev])
static iot_spi_gpio_sel_t *p_ext_spi_flash_gpio;
static uint8_t test_r_buff[SPI_FLASH_PAGE_SIZE];
static int ramFlashExtSpiReadData(int dev, char *buf, int rd_size)
{
int rx_byte=0, data;
char *pnt = buf;
if (0 == rd_size) {
return 0;
}
while ((rx_byte<rd_size) && (!dw_ssi_ctrl.rx_fifo_empty(dev))) {
data = dw_ssi_ctrl.get(dev);
rx_byte += sizeof(*pnt);
if (pnt) {
*(pnt++) = (char)(data&0xFF);
}
}
return rx_byte;
}
static int ramFlashExtSpiWriteData(int dev, char *buf, int wt_size)
{
int tx_byte =0, data =SPI_READ_DUMMY_PAT;
if (0 == wt_size) {
return 0;
}
char *pnt = buf;
while ((tx_byte<wt_size) && (!(volatile int)dw_ssi_ctrl.tx_fifo_full(dev))) {
if (pnt)
data = (int)(*(pnt++));
dw_ssi_ctrl.put(dev, data);
tx_byte += sizeof(*pnt);
}
return tx_byte;
}
static STATUS ramFlashExtSpiPollTransfer(int dev, xfer_buf *buf)
{
int xfr_size, tx_size, rx_size, try_cnt;
xfer_buf *p_buf = buf;
char *tx_buf, *rx_buf;
STATUS ret = OK;
hw_gpio_api_table.set_value(p_ext_spi_flash_gpio->cs, 0);
/* clear pending rx data */
while (!dw_ssi_ctrl.rx_fifo_empty(dev)) (void)dw_ssi_ctrl.get(dev);
try_cnt = 50000;
while (p_buf) {
tx_size= rx_size = p_buf->size;
tx_buf = p_buf->txbuf;
rx_buf = p_buf->rxbuf;
while (tx_size || rx_size) {
if (tx_size == rx_size) {
if (tx_size >= SPI_TXRX_DEFAULT_SIZE) {
xfr_size = ramFlashExtSpiWriteData(dev, tx_buf, SPI_TXRX_DEFAULT_SIZE);
} else {
xfr_size = ramFlashExtSpiWriteData(dev, tx_buf, tx_size);
}
tx_size -= xfr_size;
if (tx_buf) {
tx_buf += xfr_size;
}
}
if (tx_size != rx_size) {
if (rx_size >= SPI_TXRX_DEFAULT_SIZE) {
xfr_size = ramFlashExtSpiReadData(dev, rx_buf, SPI_TXRX_DEFAULT_SIZE);
} else {
xfr_size = ramFlashExtSpiReadData(dev, rx_buf, rx_size);
}
rx_size -= xfr_size;
if (rx_buf) {
rx_buf += xfr_size;
}
}
if (0 == xfr_size) {
if (--try_cnt == 0) {
ret = ERROR;
break;
}
} else {
try_cnt = 50000;
}
}
if (ERROR == ret) {
break;
}
p_buf ->xfer_size = p_buf->size;
p_buf = p_buf->p_nt;
}
/* wait for pending tx data. */
while (!dw_ssi_ctrl.tx_fifo_empty(dev));
hw_gpio_api_table.set_value(p_ext_spi_flash_gpio->cs, 1);
return ret;
}
static int ramFlashExtRawReadStatus(int dev)
{
char cmd_buf[4] = {0};
xfer_buf x_buf[2] = {0};
x_buf[0].p_nt = &x_buf[1];
x_buf[0].size = 1;
x_buf[0].txbuf = cmd_buf;
x_buf[1].p_nt = NULL;
x_buf[1].size = 1;
x_buf[1].rxbuf = cmd_buf;
cmd_buf[0] = READ_STS_REG1_CMD;
if (0 != ramFlashExtSpiPollTransfer(dev, x_buf)) {
cmd_buf[0] = 0xFF;
}
return ((uint32_t)cmd_buf[0]) & 0xFF;
}
static STATUS ramFlashExtRawWriteEnable(int dev)
{
char cmd_buf[4] = {0};
xfer_buf x_buf[1] = {0};
x_buf[0].size = 1;
x_buf[0].txbuf = cmd_buf;
cmd_buf[0] = WRITE_EN_CMD;
return ramFlashExtSpiPollTransfer(dev, x_buf);
}
static STATUS ramFlashExtRawWriteStart(int dev)
{
uint32_t try_cnt = SPI_FLASH_WAIT_TIMES, status;
/* 1ST : wait for WIP clear. */
do {
status = ramFlashExtRawReadStatus(dev);
if (!(SPI_FLASH_WIP & status)) {
break;
}
} while(--try_cnt);
if (0 == try_cnt) {
return ERROR;
}
try_cnt = SPI_FLASH_WAIT_TIMES;
/* 2ND : set WEL and wait success. */
do {
if (0 != ramFlashExtRawWriteEnable(dev)) {
return ERROR;
}
status = ramFlashExtRawReadStatus(dev);
if (SPI_FLASH_WEL & status) {
break;
}
} while(--try_cnt);
if (0 == try_cnt) {
return ERROR;
}
return OK;
}
static void ramFlashExtSpiGpioSel(iot_spi_gpio_sel_t *gpio)
{
gpio_sig_info_t info = {
4,
{
{IO_TYPE_OUT, 0, 0, 0xff, 20}, // CLK_out
{IO_TYPE_OUT, 0, 0, 0xff, 21}, // CS_out
{IO_TYPE_IN, 0, 0, 16, 0xff}, // MISO_in
{IO_TYPE_OUT, 0, 0, 0xff, 22} // MOSI_out
}
};
#if (TARGET_VERSION == TARGET_KUNLUN3)
info.CFG[0].outid = GPIO_MTX_SPI_M0_CLK_OUT;
info.CFG[1].outid = GPIO_MTX_SPI_M0_CS_OUT;
info.CFG[2].inid = GPIO_MTX_SPI_M0_SI_IN;
info.CFG[3].outid = GPIO_MTX_SPI_M0_SO_OUT;
#else
info.CFG[0].outid = SPI_M0_CLK_out;
info.CFG[1].outid = SPI_M0_CS_out;
info.CFG[2].inid = SPI_M0_SI_in;
info.CFG[3].outid = SPI_M0_SO_out;
#endif
info.CFG[0].func = gpio_pin_func_get(gpio->clk);
info.CFG[0].gpio = gpio->clk;
info.CFG[1].func = gpio_pin_func_get(gpio->cs);
info.CFG[1].gpio = gpio->cs;
info.CFG[2].func = gpio_pin_func_get(gpio->miso);
info.CFG[2].gpio = gpio->miso;
info.CFG[3].func = gpio_pin_func_get(gpio->mosi);
info.CFG[3].gpio = gpio->mosi;
gpio_module_pin_select(&info);
gpio_module_sig_select(&info, GPIO_MTX_MODE_MATRIX);
}
static STATUS ramFlashExtRegisterSpiDev(int dev)
{
spi_cfg spi_cfg;
/* disable all int */
(void)dw_ssi_ctrl.set_int_disable(0, SPI_INT_MASK);
(void)dw_ssi_ctrl.clear_int(0, SPI_INT_MASK);
spi_cfg.dev_type = SPI_MASTER;
spi_cfg.dfrm_sz = 8; /* 8bit */
spi_cfg.frm_fmt = FRM_STD;
spi_cfg.frq = 1 * 1000 * 1000; /* 1Mhz */
spi_cfg.trs_mode = TMOD_TRANCIEVER;
spi_cfg.rx_thd = 12;
spi_cfg.tx_thd = 5;
spi_cfg.cs_en = 0;
/* Enable before config */
apb_enable(SPI_APB_DEV(dev));
/* If NULL=tm, driver will use default config for timing */
if (OK == dw_ssi_ctrl.config(dev, &spi_cfg, NULL, NULL)) {
return OK;
} else {
return ERROR;
}
}
static STATUS ramFlashExtInitHardware(int dev)
{
apb_enable(APB_GPIO);
return ramFlashExtRegisterSpiDev(dev);
}
static STATUS ramFlashExtTryInitGpio(int idx)
{
if (0 == ram_get_ext_spi_flash_gpio(idx, &p_ext_spi_flash_gpio)) {
/* config GPIOs. */
ramFlashExtSpiGpioSel(p_ext_spi_flash_gpio);
/* gpio open. */
hw_gpio_api_table.set_gpio_mode(p_ext_spi_flash_gpio->cs, GPIO_OUTPUT);
gpio_pin_select(p_ext_spi_flash_gpio->cs,
gpio_pin_func_get(p_ext_spi_flash_gpio->cs));
gpio_mtx_sig_out_default(0xFF, p_ext_spi_flash_gpio->cs);
hw_gpio_api_table.set_value(p_ext_spi_flash_gpio->cs, 1);
return OK;
} else {
return ERROR;
}
}
static STATUS ramFlashExtReadMfid(int dev, uint8_t *p_buf, uint32_t size)
{
char cmd_buf[4] = {0};
xfer_buf x_buf[2] = {0};
x_buf[0].p_nt = &x_buf[1];
x_buf[0].size = 1;
x_buf[0].txbuf = cmd_buf;
x_buf[1].p_nt = NULL;
x_buf[1].size = size;
x_buf[1].rxbuf = (char *)p_buf;
cmd_buf[0] = READ_ID_CMD;
return ramFlashExtSpiPollTransfer(dev, x_buf);
}
static STATUS ramFlashExtRawRead(int dev, uint32_t offset, uint8_t *p_buf,
uint32_t size)
{
char cmd_buf[4] = {0};
xfer_buf x_buf[2] = {0};
uint32_t try_cnt;
try_cnt = SPI_FLASH_WAIT_TIMES;
x_buf[0].p_nt = &x_buf[1];
x_buf[0].size = 4;
x_buf[0].txbuf = cmd_buf;
x_buf[1].p_nt = NULL;
x_buf[1].size = size;
x_buf[1].rxbuf = (char *)p_buf;
cmd_buf[0] = READ_DATA_CMD;
cmd_buf[1] = (offset >> 16) & 0xFF;
cmd_buf[2] = (offset >> 8) & 0xFF;
cmd_buf[3] = (offset) & 0xFF;
/* wait for WIP clear. */
do {
if(!(SPI_FLASH_WIP & ramFlashExtRawReadStatus(dev))) {
break;
}
} while(--try_cnt);
/* read the flash chip. */
if (0 == try_cnt
|| ERR_OK != ramFlashExtSpiPollTransfer(dev, x_buf)) {
return ERR_FAIL;
}
return ERR_OK;
}
static STATUS ramFlashExtEraseChip(int dev)
{
char cmd_buf[4] = {0};
xfer_buf x_buf[1] = {0};
x_buf[0].size = 1;
x_buf[0].txbuf = cmd_buf;
cmd_buf[0] = CHIP_ERASE_CMD;
ramFlashExtRawWriteStart(dev);
if (ERR_OK != ramFlashExtSpiPollTransfer(dev, x_buf)) {
return ERR_FAIL;
}
return ERR_OK;
}
uint8_t ramFlashExtErase()
{
uint32_t offset = 0;
uint32_t *p_data = NULL;
int spi_flash_gpio_idx = 0;
const int spi_dev = DEVICE_SPI0_MASTER;
if (ERR_OK != ramFlashExtInitHardware(spi_dev)) {
goto err_nosupp;
}
while (1) {
uint8_t cha_buf[4] = {0};
if (ERR_OK != ramFlashExtTryInitGpio(spi_flash_gpio_idx)) {
goto err_nosupp;
}
if (ERR_OK == ramFlashExtReadMfid(spi_dev, cha_buf, 3)) {
uint8_t vendor_id = cha_buf[0];
if ((vendor_id == FLASH_VENDOR_ID_PUYA)
|| (vendor_id == FLASH_VENDOR_ID_GD)
|| (vendor_id == FLASH_VENDOR_ID_WINBOND)
|| (vendor_id == FLASH_VENDOR_ID_ZBIT)) {
break;
}
}
spi_flash_gpio_idx++;
}
if (ERR_OK != ramFlashExtEraseChip(spi_dev)) {
ram_error_no |= RAM_FLASH_EXT_ERASE_SECTOR_ERR;
goto err_out;
}
ramFlashExtRawWriteStart(spi_dev);
for (int i = 0; i < SPI_FLASH_CYCLE_COUNT; i++) {
if (ERR_OK != ramFlashExtRawRead(spi_dev, offset, test_r_buff,
SPI_FLASH_PAGE_SIZE)) {
ram_error_no |= RAM_FLASH_EXT_READ_SECTOR_ERR;
goto err_out;
}
p_data = (uint32_t*)test_r_buff;
for (int j = 0; j < SPI_FLASH_PAGE_SIZE / 4; j++) {
if (p_data[j] != 0xffffffff) {
ram_error_no |= RAM_FLASH_EXT_ERASE_SECTOR_ERR;
goto err_out;
}
}
offset += SPI_FLASH_PAGE_SIZE;
}
ram_printf("\r\nflash ext erase successfully!");
return ERR_OK;
err_nosupp:
ram_printf("\r\nflash ext not support!!!");
ram_error_no |= RAM_FLASH_EXT_CHECK_ERR;
return ERR_NOSUPP;
err_out:
ram_printf("\r\nflash ext erase failed!!!");
return ERR_FAIL;
}