Files
kunlun/driver/src/hw3/ndfc.c
2024-09-28 14:24:04 +08:00

1102 lines
27 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.
****************************************************************************/
/* os shim includes */
#include "os_types.h"
#include "iot_errno_api.h"
#include "ndfc.h"
#if 0
/* os shim includes */
#include "iot_config.h"
#include "hw_reg_api.h"
#include "chip_reg_base.h"
#include "ds35x1gaxxx.h"
#include "ap_clk_core_rf.h"
#include "dmc_reg_rf.h"
#include "ndfc_rf.h"
#include "os_mem_api.h"
#include "gpio_mtx.h"
int32_t iot_printf(const char *fmt, ...);
enum ndfc_signal_e
{
SIG_I_D0 = 62,
SIG_I_D1 = 63,
SIG_I_D2 = 64,
SIG_I_D3 = 65,
SIG_O_CLK = 96,
SIG_O_CS = 97,
SIG_O_D0 = 98,
SIG_O_D1 = 99,
SIG_O_D2 = 100,
SIG_O_D3 = 101,
SIG_NONE = 0xFF
};
enum ndfc_controller_mode_e
{
MODE_PROGRAM = 0,
MODE_ERASE = 1,
MODE_RANDRW = 2,
MODE_REGRW = 3,
MODE_FLASHREAD = 4,
MODE_PAGEREAD = 5,
MODE_PAGEWRITE = 6,
};
enum ndfc_spi_read_write_e
{
SPI_REG_R,
SPI_REG_W,
SPI_PROG_R,
SPI_PROG_W,
SPI_DATA_R,
SPI_DATA_W,
SPI_CACHE_R,
SPI_CACHE_W,
SPI_PROG_EXE,
};
typedef struct ndfc_flash_info_t
{
uint8_t mf_id;
uint8_t dev_id;
uint8_t data_xn;
uint8_t resv[1];
uint32_t page_num; /* Page number per block. */
uint32_t block_num; /* Total block number. */
uint32_t page_size; /* Bytes in signal page. */
}ndfc_flash_t;
typedef struct
{
uint8_t mode; /* Operation Mode */
uint8_t cmd; /* Specifies the Instruction to be sent */
uint8_t spi_rw; /* SPI write or read. enum ndfc_spi_read_write_e */
uint8_t dummy_len; /* Dummy bits len. */
uint32_t dlen_byte; /* spi trans data length, unit is byte */
uint32_t addr; /* Specifies the Address to be sent */
uint32_t alen_bits; /* length of address. */
uint32_t erase_wait_time;
uint32_t read_wait_time;
uint32_t prog_wait_time; /* program or erase wait time,
unit is clock cycle num */
uint32_t status; /* Status of flash abouot current command. */
uint32_t reg_rw; /* Data of register write to/read from on flash. */
uint8_t *dma_buf; /* Buffer for page read/write. */
} ndfc_op_t;
typedef struct ndfc_context_t
{
ndfc_flash_t flash;
ndfc_gpio_t gpio;
ndfc_op_t op;
uint8_t *dma_buf;
}ndfc_t;
ndfc_t g_ndfc_context;
#define NDFC_DEF_WAIT_CYCLE 0x30
#define NDFC_DEF_CMD_LEN 8
#define cpu_nop() __asm volatile ("nop\n")
static void ndfc_set_reg_field
(uint32_t mask, uint32_t offset, uint32_t addr, uint32_t value)
{
uint32_t tmp;
tmp = NDFC_RF_READ_REG(addr);
tmp &= ~mask;
tmp |= (((value) << offset) & mask);
NDFC_RF_WRITE_REG(addr, tmp);
return;
}
#define ndfc_set_register_field(FILD, addr, value) \
ndfc_set_reg_field(FILD##_MASK, FILD##_OFFSET, addr, (uint32_t)value)
#define ndfc_set_page_size(size) \
ndfc_set_register_field(CFG_NDFC_PAGE_SIZE, CFG_NDFC_CTRL0_ADDR, size)
#define ndfc_start() \
ndfc_set_register_field(SW_NDFC_ENA, CFG_NDFC_CMD0_ADDR, 0x1)
#define ndfc_busy() \
((0 != (NDFC_RF_READ_REG(CFG_NDFC_CMD0_ADDR) & SW_NDFC_ENA_MASK)) ? 1 : 0)
#define ndfc_set_mode(mode) \
ndfc_set_register_field(SW_NDFC_MODE, CFG_NDFC_CMD0_ADDR, mode)
#define ndfc_set_dma_buf(buf) \
ndfc_set_register_field(SW_DMA_START_ADDR, CFG_NDFC_CMD2_ADDR, buf)
#define ndfc_set_buf_len(len) \
ndfc_set_register_field(SW_NDFC_DLEN, CFG_NDFC_CMD0_ADDR, len)
#define ndfc_set_command(cmd) \
ndfc_set_register_field(SW_NDFC_CMD, CFG_NDFC_CMD1_ADDR, cmd)
#define ndfc_set_command_len(len) \
ndfc_set_register_field(CFG_CMD_LEN, CFG_NDFC_SWM_CFG1_ADDR, len)
#define ndfc_set_addr(addr) \
ndfc_set_register_field(SW_NDFC_ADDR, CFG_NDFC_CMD3_ADDR, addr)
#define ndfc_set_addr_bits(len) \
ndfc_set_register_field(CFG_ADDR_LEN, CFG_NDFC_SWM_CFG1_ADDR, len)
#define ndfc_set_dummy_bits(len) \
ndfc_set_register_field(CFG_DUMMY_LEN, CFG_NDFC_SWM_CFG1_ADDR, len)
#define ndfc_set_read_wait_cycle(cycle) \
ndfc_set_register_field(CFG_PAGE_RD_WAIT_TIME, CFG_NDFC_WAIT_TIME_ADDR, cycle)
#define ndfc_set_prog_wait_cycle(cycle) \
ndfc_set_register_field(CFG_PROG_WAIT_TIME, CFG_NDFC_CFG1_ADDR, cycle)
#define ndfc_set_erase_wait_cycle(cycle) \
ndfc_set_register_field(CFG_ERASE_WAIT_TIME, CFG_NDFC_CFG2_ADDR, cycle)
#define ndfc_set_reg_value(value) \
ndfc_set_register_field(SW_NDFC_WDATA, CFG_NDFC_WDATA_ADDR, value)
#define ndfc_get_reg_value() \
REG_FIELD_GET(SW_NDFC_RDATA, NDFC_RF_READ_REG(CFG_NDFC_RDATA_ADDR))
#define ndfc_set_cmd_page_read(cmd) \
ndfc_set_register_field(CFG_PAGE_RD_CMD, CFG_NDFC_CMD4_ADDR, cmd)
#define ndfc_set_cmd_program(cmd) \
ndfc_set_register_field(CFG_PROG_EXE_CMD, CFG_NDFC_CMD4_ADDR, cmd)
#define ndfc_set_cmd_oip(cmd) \
ndfc_set_register_field(CFG_OIP_CMD, CFG_NDFC_SWM_CFG2_ADDR, cmd)
#define ndfc_set_cmd_write_ena(cmd) \
ndfc_set_register_field(CFG_WR_EN_CMD, CFG_NDFC_SWM_CFG2_ADDR, cmd)
#define ndfc_set_cmd_write_dis(cmd) \
ndfc_set_register_field(CFG_WR_DIS_CMD, CFG_NDFC_SWM_CFG2_ADDR, cmd)
#define ndfc_flash_get_col_addr(offset) \
((offset) % (g_ndfc_context.flash.page_size))
#define ndfc_flash_get_page_addr(offset) \
((offset) / (g_ndfc_context.flash.page_size) \
% (g_ndfc_context.flash.page_num))
#define ndfc_flash_get_block_addr(offset) \
(((offset) \
/ (g_ndfc_context.flash.page_size * g_ndfc_context.flash.page_num)))
static ndfc_op_t *ndfc_alloc_op(void)
{
ndfc_op_t *p_op = &(g_ndfc_context.op);
os_mem_set(p_op, 0x0, sizeof(*p_op));
p_op->dma_buf = g_ndfc_context.dma_buf;
p_op->spi_rw = SPI_REG_W;
return p_op;
}
#define ndfc_free_op(op) /* Do nothing. */
static uint32_t ndfc_flash_get_status(uint32_t *p_status);
static void ndfc_set_data_mode(uint32_t mode)
{
uint32_t value, bits;
if(DATA_MODE_X4 == mode) {
bits = DATA_RD_DATA_QUAD_MODE_MASK;
} else if (DATA_MODE_X2 == mode) {
bits = DATA_RD_DATA_DUAL_MODE_MASK;
} else {
/* Default DATA_MODE_X1 */
bits = 0;
}
value = NDFC_RF_READ_REG(CFG_NDFC_DATA_RD_CFG0_ADDR);
value &= ~(DATA_RD_DATA_QUAD_MODE_MASK | DATA_RD_DATA_DUAL_MODE_MASK);
value |= bits;
NDFC_RF_WRITE_REG(CFG_NDFC_DATA_RD_CFG0_ADDR, value);
value = NDFC_RF_READ_REG(CFG_NDFC_PROG_LOAD_CFG0_ADDR);
value &= ~(DATA_RD_DATA_QUAD_MODE_MASK | DATA_RD_DATA_DUAL_MODE_MASK);
value |= bits;
NDFC_RF_WRITE_REG(CFG_NDFC_PROG_LOAD_CFG0_ADDR, value);
return;
}
static void ndfc_set_spi_wr_mode(uint32_t mode)
{
uint32_t addr = 0xFFFFFFFF, mask, value, tmp;
if(SPI_REG_R == mode) {
addr = CFG_NDFC_SWM_CFG0_ADDR;
mask = CFG_SPI_RD_MASK | CFG_SPI_WR_MASK;
value = CFG_SPI_RD_MASK;
} else if (SPI_REG_W == mode) {
addr = CFG_NDFC_SWM_CFG0_ADDR;
mask = CFG_SPI_RD_MASK | CFG_SPI_WR_MASK;
value = CFG_SPI_WR_MASK;
} else if (SPI_PROG_R == mode) {
addr = CFG_NDFC_PROG_LOAD_CFG0_ADDR;
mask = PROG_LOAD_SPI_WR_MASK | PROG_LOAD_SPI_RD_MASK;
value = PROG_LOAD_SPI_RD_MASK;
} else if (SPI_PROG_W == mode) {
addr = CFG_NDFC_PROG_LOAD_CFG0_ADDR;
mask = PROG_LOAD_SPI_WR_MASK | PROG_LOAD_SPI_RD_MASK;
value = PROG_LOAD_SPI_WR_MASK;
} else if (SPI_DATA_R == mode) {
addr = CFG_NDFC_DATA_RD_CFG0_ADDR;
mask = DATA_RD_SPI_WR_MASK | DATA_RD_SPI_RD_MASK;
value = DATA_RD_SPI_RD_MASK;
} else if (SPI_DATA_W == mode) {
addr = CFG_NDFC_DATA_RD_CFG0_ADDR;
mask = DATA_RD_SPI_WR_MASK | DATA_RD_SPI_RD_MASK;
value = DATA_RD_SPI_WR_MASK;
} else if (SPI_CACHE_R == mode) {
addr = CFG_NDFC_CACHE_CFG0_ADDR;
mask = CACHE_SPI_WR_MASK | CACHE_SPI_RD_MASK;
value = CACHE_SPI_RD_MASK;
} else if (SPI_CACHE_W == mode) {
addr = CFG_NDFC_CACHE_CFG0_ADDR;
mask = CACHE_SPI_WR_MASK | CACHE_SPI_RD_MASK;
value = CACHE_SPI_RD_MASK;
} else if (SPI_PROG_EXE == mode) {
addr = CFG_NDFC_PAGE_EXE_CFG0_ADDR;
mask = PROG_EXE_SPI_WR_MASK | PROG_EXE_SPI_RD_MASK;
value = PROG_EXE_SPI_WR_MASK;
}
/* else() do nothing. */
/* The default value of addr means no mode matched. */
if(0xFFFFFFFF != addr) {
tmp = NDFC_RF_READ_REG(addr);
tmp &= ~mask;
tmp |= value;
NDFC_RF_WRITE_REG(addr, tmp);
}
return;
}
static void ndfc_gpio_config(ndfc_gpio_t *p_gpio)
{
gpio_sig_info_t info;
info.sig_type = 6;
info.CFG[0].func = gpio_pin_func_get(p_gpio->clk);
info.CFG[0].gpio = p_gpio->clk;
info.CFG[0].type = IO_TYPE_OUT;
info.CFG[0].outid = SIG_O_CLK;
info.CFG[0].inid = SIG_NONE;
info.CFG[1].func = gpio_pin_func_get(p_gpio->cs);
info.CFG[1].gpio = p_gpio->cs;
info.CFG[1].type = IO_TYPE_OUT;
info.CFG[1].outid = SIG_O_CS;
info.CFG[1].inid = SIG_NONE;
info.CFG[2].func = gpio_pin_func_get(p_gpio->d0);
info.CFG[2].gpio = p_gpio->d0;
info.CFG[2].type = IO_TYPE_IO;
info.CFG[2].outid = SIG_O_D0;
info.CFG[2].inid = SIG_I_D0;
info.CFG[3].func = gpio_pin_func_get(p_gpio->d1);
info.CFG[3].gpio = p_gpio->d1;
info.CFG[3].type = IO_TYPE_IO;
info.CFG[3].outid = SIG_O_D1;
info.CFG[3].inid = SIG_I_D1;
info.CFG[4].func = gpio_pin_func_get(p_gpio->d2);
info.CFG[4].gpio = p_gpio->d2;
info.CFG[4].type = IO_TYPE_IO;
info.CFG[4].outid = SIG_O_D2;
info.CFG[4].inid = SIG_I_D2;
info.CFG[5].func = gpio_pin_func_get(p_gpio->d3);
info.CFG[5].gpio = p_gpio->d3;
info.CFG[5].type = IO_TYPE_IO;
info.CFG[5].outid = SIG_O_D3;
info.CFG[5].inid = SIG_I_D3;
gpio_module_pin_select(&info);
gpio_module_sig_select(&info, GPIO_MTX_MODE_MATRIX);
return;
}
static void ndfc_clk_freq_80m(void)
{
// to do: modify ndfc clk
return;
uint32_t data;
data = AP_CLK_CORE_RF_READ_REG(CFG_CLK_OD_SEL_ADDR);
REG_FIELD_SET(CLK_NAND_DIV, data, 4);
AP_CLK_CORE_RF_WRITE_REG(CFG_CLK_OD_SEL_ADDR, data);
}
void ndfc_set_dmc_pad(void)
{
uint32_t data;
data = DMC_RF_READ_REG(CFG_DMC_PAD_SEL1_ADDR);
REG_FIELD_SET(DUMMY1_PAD_SEL, data, 2);
REG_FIELD_SET(DUMMY0_PAD_SEL, data, 2);
DMC_RF_WRITE_REG(CFG_DMC_PAD_SEL1_ADDR, data);
return;
}
#define NDFC_CONTROLLER_WAIT_MAX 750000000
static uint32_t ndfc_skip_controller_busy(uint32_t wait)
{
uint32_t controller_wait = wait > 0 ? wait : NDFC_CONTROLLER_WAIT_MAX;
while(ndfc_busy() && ((--controller_wait) > 0)) cpu_nop();
return (controller_wait > 0) ? ERR_OK : ERR_FAIL;
}
#define NDFC_FLACH_WAIT_MAX 2000
static uint32_t ndfc_skip_flash_busy(void)
{
uint32_t flash_wait = NDFC_FLACH_WAIT_MAX, ret, status, busy = 1;;
ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
if(DATA_MODE_X4 == p_flash->data_xn) {
flash_wait <<= 3;
} else if (DATA_MODE_X2 == p_flash->data_xn) {
flash_wait <<= 2;
}
while(flash_wait > 0) {
ret = ndfc_flash_get_status(&status);
if(ERR_OK == ret) {
if(0 == (status & 0x1)) {
/* BUSY */
busy = 0;
break;
}
flash_wait -= 1;
} else {
flash_wait -= (flash_wait > 100) ? 100 : flash_wait;
}
}
if(status & 0x0C) {
/* PROG / ERASE failed. */
iot_printf("\nFLASH STATUS ERR#0x%02X!", status);
busy = 1;
} else if (busy) {
iot_printf("\nFLASH BUSY!");
}
return busy ? ERR_FAIL : ERR_OK;
}
static uint32_t ndfc_flash_operate(ndfc_op_t *p_op)
{
uint32_t tmp;
ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
if(0 == p_op->erase_wait_time) {
p_op->erase_wait_time = p_flash->page_size * p_flash->page_num * 8;
}
if(0 == p_op->prog_wait_time) {
p_op->prog_wait_time = ((p_op->dlen_byte * 8) < NDFC_DEF_WAIT_CYCLE)
? NDFC_DEF_WAIT_CYCLE : (p_op->dlen_byte * 8);
}
if(0 == p_op->read_wait_time) {
p_op->read_wait_time = ((p_op->dlen_byte * 8) < NDFC_DEF_WAIT_CYCLE)
? NDFC_DEF_WAIT_CYCLE : (p_op->dlen_byte * 8);
}
ndfc_set_spi_wr_mode(p_op->spi_rw);
ndfc_set_dma_buf(p_op->dma_buf);
ndfc_set_buf_len(p_op->dlen_byte);
ndfc_set_mode(p_op->mode);
ndfc_set_command_len(NDFC_DEF_CMD_LEN);
ndfc_set_addr(p_op->addr);
ndfc_set_addr_bits(p_op->alen_bits);
ndfc_set_dummy_bits(p_op->dummy_len);
ndfc_set_prog_wait_cycle(p_op->prog_wait_time);
ndfc_set_erase_wait_cycle(p_op->erase_wait_time);
ndfc_set_read_wait_cycle(p_op->read_wait_time);
ndfc_set_reg_value(p_op->reg_rw);
ndfc_set_command(p_op->cmd);
ndfc_start();
/* Wait ndfc finish operation. */
tmp = ndfc_skip_controller_busy(0);
p_op->reg_rw = ndfc_get_reg_value();
if(ERR_OK != tmp) {
iot_printf("\n!!! NDFC TIME OUT !!!");
}
return tmp;
}
uint32_t ndfc_flash_set_write_ability(uint32_t enable)
{
uint32_t ret;
ndfc_op_t *p_op = ndfc_alloc_op();
p_op->cmd = enable ? WRITE_EN_CMD : WRITE_DIS_CMD;
p_op->mode = MODE_REGRW;
p_op->spi_rw = SPI_REG_W;
ret = ndfc_flash_operate(p_op);
ndfc_free_op(p_op);
return ret;
}
static uint32_t ndfc_flash_get_feature(uint32_t ft_addr, uint32_t *p_feature)
{
uint32_t ret;
ndfc_op_t *p_op = ndfc_alloc_op();
p_op->cmd = GET_FEATURE_CMD;
p_op->spi_rw = SPI_REG_R;
p_op->dlen_byte = 1;
p_op->alen_bits = 8;
p_op->addr = (ft_addr << 16);
p_op->mode = MODE_REGRW;
ret = ndfc_flash_operate(p_op);
ndfc_free_op(p_op);
*p_feature = p_op->reg_rw;
return ret;
}
static uint32_t ndfc_flash_set_feature(uint32_t ft_addr, uint32_t ft_val)
{
uint32_t ret;
ndfc_op_t *p_op = ndfc_alloc_op();
p_op->cmd = SET_FEATURE_CMD;
p_op->spi_rw = SPI_REG_W;
p_op->dlen_byte = 1;
p_op->reg_rw = ft_val;
p_op->alen_bits = 8;
p_op->addr = (ft_addr << 16);
p_op->mode = MODE_REGRW;
ret = ndfc_flash_operate(p_op);
ndfc_free_op(p_op);
return ret;
}
static void ndfc_flash_reset(void)
{
ndfc_op_t *p_op = ndfc_alloc_op();
p_op->cmd = RESET_CMD;
p_op->spi_rw = SPI_REG_W;
p_op->mode = MODE_REGRW;
ndfc_flash_operate(p_op);
ndfc_free_op(p_op);
ndfc_skip_flash_busy();
return;
}
static void ndfc_flash_set_qe_mode(uint32_t enable)
{
uint32_t data;
ndfc_flash_get_feature(OTP_ADDR, &data);
if(enable) {
data |= 0x1;
} else {
data &= ~0x1;
}
data &= 0xFF;
ndfc_flash_set_feature(OTP_ADDR, data);
return;
}
static uint32_t ndfc_flash_get_status(uint32_t *p_status)
{
uint32_t ret;
ret = ndfc_flash_get_feature(STATUS_ADDR, p_status);
*p_status &= 0xFF;
return ret;
}
static uint32_t ndfc_flash_unlock_all(void)
{
return ndfc_flash_set_feature(BLOCK_LOCK_ADDR, 0x0);
}
static void ndfc_flash_page_read_to_cache(uint32_t offset)
{
ndfc_op_t *p_op;
uint32_t addr = 0;
p_op = ndfc_alloc_op();
addr = ndfc_flash_get_page_addr(offset) & 0x3F;
addr |= ((ndfc_flash_get_block_addr(offset) & 0x3FF) << 6);
p_op->cmd = PAGE_READ_CMD;
p_op->addr = addr;
p_op->dlen_byte = 0;
/* 24bits addr: 8bits dummy + 10bit block addr + 6bit page addr */
p_op->alen_bits = 24;
p_op->spi_rw = SPI_DATA_R;
p_op->mode = MODE_REGRW;
ndfc_flash_operate(p_op);
ndfc_free_op(p_op);
}
static void ndfc_flash_read_random_data(uint32_t offset, uint32_t force_xn)
{
uint32_t cmd_xn, qe_ena, xn;
ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
ndfc_op_t *p_op;
uint32_t addr = 0;
if(DATA_MODE_INVALID != force_xn) {
xn = force_xn;
} else {
xn = p_flash->data_xn;
}
if(DATA_MODE_X4 == xn) {
qe_ena = 1;
cmd_xn = READ_FROM_CACHE_4_CMD;
} else if (DATA_MODE_X2 == xn) {
qe_ena = 0;
cmd_xn = READ_FROM_CACHE_2_CMD;
} else {
qe_ena = 0;
xn = DATA_MODE_X1;
cmd_xn = READ_FROM_CACHE_CMD;
}
ndfc_flash_set_qe_mode(qe_ena);
ndfc_set_data_mode(xn);
p_op = ndfc_alloc_op();
/* reg addr: 10bits block addr + 6bits page addr + 12bits column addr */
addr = ndfc_flash_get_col_addr(offset);
addr |= (ndfc_flash_get_page_addr(offset) << 12);
addr |= (ndfc_flash_get_block_addr(offset) << 18);
p_op->cmd = cmd_xn;
p_op->addr = addr;
p_op->dlen_byte = p_flash->page_size;
/* 32bits addr: 4bits dummy + 12bits column addr + 16bits dummy */
p_op->alen_bits = 32;
p_op->spi_rw = SPI_DATA_R;
p_op->mode = MODE_RANDRW;
os_mem_set(p_op->dma_buf, 0x0, p_op->dlen_byte);
ndfc_flash_operate(p_op);
ndfc_free_op(p_op);
}
static void ndfc_flash_prog_load(uint32_t offset, uint32_t force_xn)
{
uint32_t cmd_xn, qe_ena, xn;
ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
ndfc_op_t *p_op;
uint32_t addr = 0;
if(DATA_MODE_INVALID != force_xn) {
xn = force_xn;
} else {
xn = p_flash->data_xn;
}
if(DATA_MODE_X4 == xn) {
qe_ena = 1;
cmd_xn = PROGRAM_LOAD_4_CMD;
} else {
xn = DATA_MODE_X1;
qe_ena = 0;
cmd_xn = PROGRAM_LOAD_CMD;
}
ndfc_set_data_mode(xn);
ndfc_flash_set_qe_mode(qe_ena);
p_op = ndfc_alloc_op();
/* reg addr: 10bits block addr + 6bits page addr + 12bits column addr */
addr = ndfc_flash_get_col_addr(offset);
addr |= (ndfc_flash_get_page_addr(offset) << 12);
addr |= (ndfc_flash_get_block_addr(offset) << 18);
p_op->cmd = cmd_xn;
p_op->addr = addr;
p_op->dlen_byte = p_flash->page_size;
/* 16bits addr: 3bits dummy + 1bit plane + 12bits address */
p_op->alen_bits = 16;
p_op->spi_rw = SPI_PROG_W;
p_op->mode = MODE_PROGRAM;
ndfc_flash_operate(p_op);
ndfc_free_op(p_op);
}
static void ndfc_flash_prog_exe(uint32_t offset)
{
ndfc_op_t *p_op;
uint32_t addr = 0;
p_op = ndfc_alloc_op();
/* reg addr: 10bits block addr + 6bits page addr + 12bits column addr */
addr = ndfc_flash_get_col_addr(offset);
addr |= (ndfc_flash_get_page_addr(offset) << 12);
addr |= (ndfc_flash_get_block_addr(offset) << 18);
p_op->cmd = PROGRAM_EXECUTE_CMD;
p_op->addr = addr;
p_op->dlen_byte = 0;
/* 16bits addr: 8bits dummy + 10bits block address + 6bits page address */
p_op->alen_bits = 24;
p_op->spi_rw = SPI_PROG_EXE;
p_op->mode = MODE_PAGEWRITE;
ndfc_flash_operate(p_op);
ndfc_free_op(p_op);
}
static void ndfc_flash_read_page(uint32_t offset, uint32_t force_xn)
{
// page read to cache
ndfc_flash_page_read_to_cache(offset);
// get feature command to read the status
ndfc_skip_flash_busy();
// random data read from (0 - page_size), here read whole page
ndfc_flash_read_random_data(offset, force_xn);
return;
}
static void ndfc_flash_write_page(uint32_t offset, uint32_t force_xn)
{
// write enable
ndfc_flash_set_write_ability(1);
// program load
ndfc_flash_prog_load(offset, force_xn);
// program execute
ndfc_flash_prog_exe(offset);
// get feature command to read the status
ndfc_skip_flash_busy();
return;
}
static void ndfc_flash_erase_block(uint32_t offset)
{
//uint32_t block;
uint32_t addr = 0;
ndfc_op_t *p_op = ndfc_alloc_op();
//ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
addr = (ndfc_flash_get_block_addr(offset) << 18);
p_op->cmd = BLOCK_ERASE_CMD;
p_op->addr = addr;
p_op->alen_bits = 24; /* 8BITS dummy + 16BITS address. */
p_op->mode = MODE_ERASE;
ndfc_flash_operate(p_op);
ndfc_skip_flash_busy();
ndfc_free_op(p_op);
return;
}
static uint32_t ndfc_flash_get_id(void)
{
uint32_t id;
ndfc_op_t *p_op = ndfc_alloc_op();
/* Get Flash ID. */
p_op->cmd = READ_ID_CMD;
p_op->spi_rw = SPI_REG_R;
p_op->dlen_byte = 2;
p_op->dummy_len = 8;
p_op->mode = MODE_REGRW;
ndfc_flash_operate(p_op);
id = p_op->reg_rw;
ndfc_free_op(p_op);
return id;
}
uint32_t iot_ndfc_flash_get_param_page(void *p_data, uint32_t lenth)
{
uint32_t r_len;
ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
ndfc_flash_set_feature(OTP_ADDR, 0x40);
ndfc_flash_read_page(PRAMTR_PAGE_ADDR * p_flash->page_size, DATA_MODE_X1);
r_len = g_ndfc_context.flash.page_size > lenth ? lenth
: g_ndfc_context.flash.page_size;
if((NULL != p_data) && (r_len > 0)) {
os_mem_cpy(p_data, g_ndfc_context.dma_buf, lenth);
}
ndfc_flash_set_feature(OTP_ADDR, 0x10);
return 0;
}
uint32_t iot_ndfc_flash_get_id(void)
{
uint32_t id;
ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
id = (p_flash->mf_id << 8) | p_flash->dev_id;
return id;
}
uint32_t iot_ndfc_flash_get_flash_size(void)
{
uint32_t size;
ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
size = p_flash->page_size * p_flash->page_num * p_flash->block_num;
return size;
}
uint32_t iot_ndfc_flash_get_page_size(void)
{
ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
return p_flash->page_size;
}
/* Page number per block. */
uint32_t iot_ndfc_flash_get_page_num(void)
{
ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
return p_flash->page_num;
}
uint32_t iot_ndfc_flash_get_block_size(void)
{
ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
return (p_flash->page_size * p_flash->page_num);
}
uint32_t iot_ndfc_flash_get_block_num(void)
{
ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
return p_flash->block_num;
}
uint32_t iot_ndfc_flash_read(uint8_t *p_buf, uint32_t offset, uint32_t size)
{
uint32_t cur_len, tot_len;
ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
uint8_t *p_src = g_ndfc_context.dma_buf;
tot_len = 0;
while(size > 0) {
ndfc_flash_read_page(offset, DATA_MODE_INVALID);
cur_len = p_flash->page_size - (offset % p_flash->page_size);
cur_len = (cur_len > size) ? size : cur_len;
os_mem_cpy(p_buf+tot_len, p_src+(offset%p_flash->page_size), cur_len);
tot_len += cur_len;
offset += cur_len;
size -= cur_len;
}
return ERR_OK;
}
uint32_t iot_ndfc_flash_write(uint8_t *p_buf, uint32_t offset, uint32_t size)
{
uint32_t cur_len, tot_len;
ndfc_flash_t *p_flash = &(g_ndfc_context.flash);
uint8_t *p_dst = g_ndfc_context.dma_buf;
if(NULL == p_buf) {
return ERR_FAIL;
}
if(0 == size) {
return ERR_OK;
}
tot_len = 0;
if(offset % p_flash->page_size) {
//page = ndfc_flash_get_page_addr(offset);
ndfc_flash_read_page(offset, DATA_MODE_INVALID);
cur_len = p_flash->page_size - (offset % p_flash->page_size);
cur_len = (cur_len > size) ? size : cur_len;
os_mem_cpy(p_dst + (offset % p_flash->page_size), p_buf, cur_len);
//ndfc_flash_set_write_ability(1);
ndfc_flash_write_page(offset, DATA_MODE_INVALID);
tot_len += cur_len;
offset += cur_len;
size -= cur_len;
} else {
//ndfc_flash_set_write_ability(1);
}
while(size > p_flash->page_size) {
cur_len = p_flash->page_size;
os_mem_cpy(p_dst, p_buf + tot_len, cur_len);
ndfc_flash_write_page(offset, DATA_MODE_INVALID);
tot_len += cur_len;
offset += cur_len;
size -= cur_len;
}
if(size > 0) {
ndfc_flash_read_page(offset, DATA_MODE_INVALID);
cur_len = size;
os_mem_cpy(p_dst, p_buf + tot_len, cur_len);
//ndfc_flash_set_write_ability(1);
ndfc_flash_write_page(offset, DATA_MODE_INVALID);
tot_len += cur_len;
offset += cur_len;
size -= cur_len;
}
//ndfc_flash_set_write_ability(0);
return ERR_OK;
}
uint32_t iot_ndfc_flash_erase_block(uint32_t offset)
{
ndfc_flash_erase_block(offset);
return ERR_OK;
}
uint32_t iot_ndfc_get_int_status(void)
{
uint32_t status;
#ifdef CFG_NDFC_INTERRUPT_ADDR
status = NDFC_RF_READ_REG(CFG_NDFC_INTERRUPT_ADDR);
#else
status = NDFC_RF_READ_REG(0x120);
#endif
return status;
}
uint32_t iot_ndfc_init(ndfc_cfg_t *p_cfg)
{
uint32_t data;
os_mem_cpy(&(g_ndfc_context.gpio), &(p_cfg->gpio),
sizeof(g_ndfc_context.gpio));
ndfc_gpio_config(&(p_cfg->gpio));
ndfc_clk_freq_80m();
ndfc_set_cmd_oip(GET_FEATURE_CMD);
//ndfc_set_dmc_pad();
/* TODO read from flash. */
//g_ndfc_context.flash.page_size = DATA_FIELD_LEN + SPARE_FIELD_LEN;
g_ndfc_context.flash.page_size = DATA_FIELD_LEN;
g_ndfc_context.flash.page_num = PAGE_PER_BLOCK;
g_ndfc_context.flash.block_num = BLOCK_PER_CHIP;
g_ndfc_context.flash.data_xn = p_cfg->data_mode;
g_ndfc_context.dma_buf =
(uint8_t *)os_mem_malloc(0, g_ndfc_context.flash.page_size);
if(NULL == g_ndfc_context.dma_buf) {
return ERR_FAIL;
}
ndfc_set_page_size(g_ndfc_context.flash.page_size);
ndfc_flash_reset();
ndfc_flash_unlock_all();
data = ndfc_flash_get_id();
g_ndfc_context.flash.dev_id = (data & 0xFF00) >> 8;
g_ndfc_context.flash.mf_id = data & 0xFF;
/* Set data array ready. */
ndfc_flash_set_feature(OTP_ADDR, 0x10);
return ERR_OK;
}
#else
uint32_t iot_ndfc_init(ndfc_cfg_t *p_cfg)
{
return ERR_FAIL;
}
uint32_t iot_ndfc_get_int_status(void)
{
return ERR_FAIL;
}
uint32_t iot_ndfc_flash_erase_block(uint32_t offset)
{
return ERR_FAIL;
}
uint32_t iot_ndfc_flash_write(uint8_t *p_buf, uint32_t offset, uint32_t size)
{
return ERR_FAIL;
}
uint32_t iot_ndfc_flash_read(uint8_t *p_buf, uint32_t offset, uint32_t size)
{
return ERR_FAIL;
}
uint32_t iot_ndfc_flash_get_id(void)
{
return ERR_FAIL;
}
uint32_t iot_ndfc_flash_get_flash_size(void)
{
return ERR_FAIL;
}
uint32_t iot_ndfc_flash_get_page_size(void)
{
return ERR_FAIL;
}
uint32_t iot_ndfc_flash_get_page_num(void)
{
return ERR_FAIL;
}
uint32_t iot_ndfc_flash_get_block_size(void)
{
return ERR_FAIL;
}
uint32_t iot_ndfc_flash_get_block_num(void)
{
return ERR_FAIL;
}
uint32_t iot_ndfc_flash_get_param_page(void *p_data, uint32_t lenth)
{
return ERR_FAIL;
}
#endif