476 lines
12 KiB
C
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;
|
|
}
|
|
|