684 lines
18 KiB
C
684 lines
18 KiB
C
#include "nandflash.h"
|
||
#include "timer.h"
|
||
#include "app_config.h"
|
||
#include "asm/clock.h"
|
||
|
||
#if TCFG_NANDFLASH_DEV_ENABLE
|
||
|
||
#undef LOG_TAG_CONST
|
||
#define LOG_TAG "[FLASH]"
|
||
#define LOG_ERROR_ENABLE
|
||
#define LOG_INFO_ENABLE
|
||
#include "debug.h"
|
||
|
||
#define NAND_FLASH_TIMEOUT 500
|
||
#define NAND_PAGE_SIZE 2048
|
||
#define MAX_NANDFLASH_PART_NUM 4
|
||
#define NAND_BLOCK_SIZE 0x20000
|
||
|
||
struct nandflash_partition {
|
||
const char *name;
|
||
u32 start_addr;
|
||
u32 size;
|
||
struct device device;
|
||
};
|
||
|
||
static struct nandflash_partition nor_part[MAX_NANDFLASH_PART_NUM];
|
||
|
||
struct nandflash_info {
|
||
u32 flash_id;
|
||
int spi_num;
|
||
int spi_err;
|
||
u8 spi_cs_io;
|
||
u8 spi_r_width;
|
||
u8 part_num;
|
||
u8 open_cnt;
|
||
struct nandflash_partition *const part_list;
|
||
OS_MUTEX mutex;
|
||
u32 max_end_addr;
|
||
};
|
||
|
||
static struct nandflash_info _nandflash = {
|
||
.spi_num = (int) - 1,
|
||
.part_list = nor_part,
|
||
};
|
||
|
||
int nand_flash_read(u32 addr, u8 *buf, u32 len);
|
||
int nand_flash_erase(u32 addr);
|
||
|
||
|
||
#define spi_cs_init() \
|
||
do { \
|
||
gpio_set_die(_nandflash.spi_cs_io, 1); \
|
||
gpio_set_direction(_nandflash.spi_cs_io, 0); \
|
||
gpio_write(_nandflash.spi_cs_io, 1); \
|
||
} while (0)
|
||
|
||
#define spi_cs_uninit() \
|
||
do { \
|
||
gpio_set_die(_nandflash.spi_cs_io, 0); \
|
||
gpio_set_direction(_nandflash.spi_cs_io, 1); \
|
||
gpio_set_pull_up(_nandflash.spi_cs_io, 0); \
|
||
gpio_set_pull_down(_nandflash.spi_cs_io, 0); \
|
||
} while (0)
|
||
#define spi_cs_h() gpio_write(_nandflash.spi_cs_io, 1)
|
||
#define spi_cs_l() gpio_write(_nandflash.spi_cs_io, 0)
|
||
#define spi_read_byte() spi_recv_byte(_nandflash.spi_num, &_nandflash.spi_err)
|
||
#define spi_write_byte(x) spi_send_byte(_nandflash.spi_num, x)
|
||
#define spi_dma_read(x, y) spi_dma_recv(_nandflash.spi_num, x, y)
|
||
#define spi_dma_write(x, y) spi_dma_send(_nandflash.spi_num, x, y)
|
||
#define spi_set_width(x) spi_set_bit_mode(_nandflash.spi_num, x)
|
||
|
||
static struct nandflash_partition *nandflash_find_part(const char *name)
|
||
{
|
||
struct nandflash_partition *part = NULL;
|
||
u32 idx;
|
||
for (idx = 0; idx < MAX_NANDFLASH_PART_NUM; idx++) {
|
||
part = &_nandflash.part_list[idx];
|
||
if (part->name == NULL) {
|
||
continue;
|
||
}
|
||
if (!strcmp(part->name, name)) {
|
||
return part;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
static struct nandflash_partition *nandflash_new_part(const char *name, u32 addr, u32 size)
|
||
{
|
||
struct nandflash_partition *part;
|
||
u32 idx;
|
||
for (idx = 0; idx < MAX_NANDFLASH_PART_NUM; idx++) {
|
||
part = &_nandflash.part_list[idx];
|
||
if (part->name == NULL) {
|
||
break;
|
||
}
|
||
}
|
||
if (part->name != NULL) {
|
||
log_error("create nandflash part fail\n");
|
||
return NULL;
|
||
}
|
||
memset(part, 0, sizeof(*part));
|
||
part->name = name;
|
||
part->start_addr = addr;
|
||
part->size = size;
|
||
if (part->start_addr + part->size > _nandflash.max_end_addr) {
|
||
_nandflash.max_end_addr = part->start_addr + part->size;
|
||
}
|
||
_nandflash.part_num++;
|
||
return part;
|
||
}
|
||
|
||
static void nandflash_delete_part(const char *name)
|
||
{
|
||
struct nandflash_partition *part;
|
||
u32 idx;
|
||
for (idx = 0; idx < MAX_NANDFLASH_PART_NUM; idx++) {
|
||
part = &_nandflash.part_list[idx];
|
||
if (part->name == NULL) {
|
||
continue;
|
||
}
|
||
if (!strcmp(part->name, name)) {
|
||
part->name = NULL;
|
||
_nandflash.part_num--;
|
||
}
|
||
}
|
||
}
|
||
|
||
static int nandflash_verify_part(struct nandflash_partition *p)
|
||
{
|
||
struct nandflash_partition *part = NULL;
|
||
u32 idx;
|
||
for (idx = 0; idx < MAX_NANDFLASH_PART_NUM; idx++) {
|
||
part = &_nandflash.part_list[idx];
|
||
if (part->name == NULL) {
|
||
continue;
|
||
}
|
||
if ((p->start_addr >= part->start_addr) && (p->start_addr < part->start_addr + part->size)) {
|
||
if (strcmp(p->name, part->name) != 0) {
|
||
return -1;
|
||
}
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
u16 nand_flash_read_id()
|
||
{
|
||
u16 id;
|
||
spi_cs_l();//SPI_CS(0);
|
||
spi_write_byte(0xff); //命令头
|
||
spi_cs_h();//SPI_CS(1);
|
||
os_time_dly(1);
|
||
spi_cs_l();//SPI_CS(0)
|
||
spi_write_byte(GD_READ_ID);
|
||
spi_write_byte(0x0);
|
||
id = spi_read_byte();
|
||
id <<= 8;
|
||
id |= spi_read_byte();
|
||
spi_cs_h();//SPI_CS(1);yy
|
||
return id;
|
||
}
|
||
|
||
static void nand_write_enable()
|
||
{
|
||
spi_cs_l();//SPI_CS(0);
|
||
spi_write_byte(GD_WRITE_ENABLE);
|
||
spi_cs_h();//SPI_CS(1);
|
||
}
|
||
|
||
static void nand_write_disable()
|
||
{
|
||
spi_cs_l();//SPI_CS(0);
|
||
spi_write_byte(GD_WRITE_DISABLE);
|
||
spi_cs_h();//SPI_CS(1);
|
||
}
|
||
|
||
static void nand_set_features(u8 cmd, u8 dat)
|
||
{
|
||
nand_write_enable();
|
||
spi_cs_l();//SPI_CS(0);
|
||
spi_write_byte(GD_SET_FEATURES); //命令头
|
||
spi_write_byte(cmd); //发送protection寄存器地址
|
||
spi_write_byte(dat); //需要设置的数据
|
||
spi_cs_h();;//SPI_CS(1);
|
||
nand_write_disable();
|
||
}
|
||
|
||
static u8 nand_get_features(u8 cmd)
|
||
{
|
||
spi_cs_l();
|
||
spi_write_byte(GD_GET_FEATURES); //命令头
|
||
spi_write_byte(cmd); //发送protection寄存器地址
|
||
cmd = spi_read_byte();
|
||
spi_cs_h();
|
||
return cmd;
|
||
}
|
||
|
||
static u8 nand_flash_wait_ok(u32 timeout)
|
||
{
|
||
u8 sta;
|
||
do {
|
||
sta = nand_get_features(GD_GET_STATUS);
|
||
if ((sta & NAND_STATUS_OIP) == 0) {
|
||
break;
|
||
}
|
||
#if 0
|
||
if (sta & NAND_STATUS_OIP) { //ing
|
||
continue;
|
||
}
|
||
if (sta & NAND_STATUS_E_FAIL) { //erase fail
|
||
break;
|
||
}
|
||
if ((sta & NAND_STATUS_ECCS) == 0x20) { //ecc error
|
||
break;
|
||
}
|
||
#endif
|
||
} while (timeout--);
|
||
if (timeout == 0) {
|
||
puts("nand_flash_wait_ok timeout!\r\n");
|
||
sta = -1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
void nand_flash_reset(void)
|
||
{
|
||
spi_cs_l();
|
||
spi_write_byte(0xff); //命令头
|
||
spi_cs_h();
|
||
}
|
||
|
||
static u16 block_page_get(u32 addr, u32 *cache_addr)
|
||
{
|
||
u32 page = 0;
|
||
u32 block = 0, bp_mix = 0;
|
||
|
||
//<地址超1页范围
|
||
if (addr >= NAND_PAGE_SIZE) {
|
||
if (addr >= NAND_BLOCK_SIZE) {
|
||
while (addr >= NAND_BLOCK_SIZE) {
|
||
block++;
|
||
addr -= NAND_BLOCK_SIZE;
|
||
}
|
||
goto _page_count;
|
||
} else {
|
||
goto _page_count;
|
||
}
|
||
}
|
||
//<地址不超1页范围
|
||
else {
|
||
goto _end_count;
|
||
}
|
||
|
||
_page_count:
|
||
while (addr >= NAND_PAGE_SIZE) {
|
||
page++;
|
||
addr -= NAND_PAGE_SIZE;
|
||
}
|
||
|
||
_end_count:
|
||
*cache_addr = addr;
|
||
bp_mix = (block << 6) | page; //16位构成里高8位为block号码,低8位里高两位依然为block,低6位为page号码
|
||
//printf_u16(g_real_page);
|
||
//printf_u16(bp_mix);
|
||
//printf_u16(block);
|
||
//printf_u16(page);
|
||
return bp_mix;
|
||
}
|
||
|
||
#define block_change(x) (x)
|
||
|
||
int nand_flash_erase(u32 address)
|
||
{
|
||
u32 bp_mix = 0;
|
||
u32 cache_addr;
|
||
// puts("erase\n");
|
||
bp_mix = block_page_get(address, &cache_addr);
|
||
nand_write_enable();
|
||
spi_cs_l();//SPI_CS(0);
|
||
spi_write_byte(GD_BLOCK_ERASE);
|
||
spi_write_byte(0xff); //8位dummy bits(值任意)
|
||
spi_write_byte(bp_mix >> 8);
|
||
spi_write_byte(bp_mix);
|
||
spi_cs_h();//SPI_CS(1);
|
||
nand_write_disable();
|
||
nand_flash_wait_ok(NAND_FLASH_TIMEOUT);
|
||
return nand_get_features(GD_GET_STATUS);
|
||
}
|
||
|
||
static void nand_flash_erase_all()
|
||
{
|
||
nand_set_features(0xA0, 0x00);
|
||
for (int i = 0; i <= 1024; i++) {
|
||
nand_flash_erase(128000 * i);
|
||
}
|
||
r_printf("nandflash erase all!!!");
|
||
}
|
||
|
||
static void nand_page_read_to_cache(u32 block_page_addr) //PageRead
|
||
{
|
||
spi_cs_l();//SPI_CS(0);
|
||
spi_write_byte(GD_PAGE_READ_CACHE); //PageRead to cache
|
||
spi_write_byte(0xff); //send the Page/Block Add
|
||
spi_write_byte((u8)((block_page_addr) >> 8));
|
||
spi_write_byte((u8)block_page_addr);
|
||
spi_cs_h();//SPI_CS(1);
|
||
nand_flash_wait_ok(NAND_FLASH_TIMEOUT);
|
||
}
|
||
|
||
static void nand_read_from_cache(u8 *buf, u32 cache_addr, u32 len) //ReadCache
|
||
{
|
||
/* cache_addr |= 0x4000; */
|
||
spi_cs_l();//SPI_CS(0);
|
||
spi_write_byte(GD_READ_FROM_CACHE); //PageRead to cache
|
||
spi_write_byte((u8)((cache_addr) >> 8));
|
||
spi_write_byte((u8)cache_addr);
|
||
spi_write_byte(0xFF); //send 1byte dummy clk
|
||
spi_dma_read(buf, len);
|
||
spi_cs_h();//SPI_CS(1);
|
||
}
|
||
|
||
#if 1
|
||
static void nand_program_load(u8 *buf, u32 cache_addr, u32 len)
|
||
{
|
||
spi_cs_l();//SPI_CS(0);
|
||
spi_write_byte(GD_PROGRAM_LOAD); //PageLoad to cache ,change the data
|
||
spi_write_byte((u8)((cache_addr) >> 8));
|
||
spi_write_byte((u8)cache_addr);
|
||
spi_dma_write(buf, len); //将数据放到总线上
|
||
spi_cs_h();//SPI_CS(1);
|
||
}
|
||
|
||
static int nand_program_excute(u32 block_page_addr)
|
||
{
|
||
int reg;
|
||
nand_write_enable();
|
||
spi_cs_l();//SPI_CS(0);
|
||
spi_write_byte(GD_PROGRAM_EXECUTE);
|
||
spi_write_byte(0xff); //send the Page/Block Add
|
||
spi_write_byte((u8)((block_page_addr) >> 8));
|
||
spi_write_byte((u8)block_page_addr);
|
||
spi_cs_h();//SPI_CS(1);
|
||
nand_write_disable();
|
||
reg = nand_flash_wait_ok(NAND_FLASH_TIMEOUT);
|
||
return reg;
|
||
}
|
||
|
||
|
||
static int nand_write(u32 addr, u16 len, u8 *buf)
|
||
{
|
||
int reg;
|
||
u32 bp_mix = 0;
|
||
u32 cache_addr;
|
||
|
||
bp_mix = block_page_get(addr, &cache_addr);
|
||
bp_mix = block_change(bp_mix);
|
||
//printf_u16(cache_addr);
|
||
nand_program_load(buf, cache_addr, len);
|
||
reg = nand_program_excute(bp_mix);
|
||
return reg;
|
||
}/**/
|
||
|
||
|
||
static void nand_program_load_random_data(u8 *buf, u16 cache_addr, u16 len)
|
||
{
|
||
spi_cs_l();//SPI_CS(0);
|
||
spi_write_byte(GD_PROGRAM_LOAD_RANDOM_DATA);
|
||
spi_write_byte((u8)((cache_addr) >> 8));
|
||
spi_write_byte((u8)cache_addr);
|
||
spi_dma_write(buf, len); //将数据放到总线上
|
||
spi_cs_h();//SPI_CS(1);
|
||
nand_flash_wait_ok(NAND_FLASH_TIMEOUT);
|
||
}
|
||
|
||
int nand_internal_data_move(u32 addr, u16 len, u8 *buf)
|
||
{
|
||
u32 bp_mix = 0;
|
||
u32 cache_addr;
|
||
|
||
bp_mix = block_page_get(addr, &cache_addr);
|
||
bp_mix = block_change(bp_mix);
|
||
|
||
//<1、PAGE READ to cache
|
||
nand_page_read_to_cache(bp_mix);
|
||
//<2、PROGRAM LOAD RANDOM DATA
|
||
nand_program_load_random_data(buf, cache_addr, len);
|
||
//<3、WRITE ENABLE
|
||
//<4、PROGRAM EXECUTE
|
||
nand_program_excute(bp_mix);
|
||
//<5、GET FEATURE
|
||
return nand_get_features(GD_GET_STATUS);
|
||
}
|
||
|
||
int nand_flash_write(u32 offset, u8 *buf, u16 len)
|
||
{
|
||
/* printf("%s() %x l: %x @:%x \n",__func__,buf,len,offset); */
|
||
int reg;
|
||
int _len = len;
|
||
u8 *_buf = (u8 *)buf;
|
||
os_mutex_pend(&_nandflash.mutex, 0);
|
||
u32 first_page_len = NAND_PAGE_SIZE - (offset % NAND_PAGE_SIZE);
|
||
/* printf("first_page_len %x %x \n", first_page_len, offset % NAND_PAGE_SIZE); */
|
||
first_page_len = _len > first_page_len ? first_page_len : _len;
|
||
reg = nand_write(offset, first_page_len, _buf);
|
||
if (reg) {
|
||
goto __exit;
|
||
}
|
||
_len -= first_page_len;
|
||
_buf += first_page_len;
|
||
offset += first_page_len;
|
||
while (_len) {
|
||
u32 cnt = _len > NAND_PAGE_SIZE ? NAND_PAGE_SIZE : _len;
|
||
reg = nand_write(offset, cnt, _buf);
|
||
if (reg) {
|
||
goto __exit;
|
||
}
|
||
_len -= cnt;
|
||
offset += cnt;
|
||
_buf += cnt;
|
||
}
|
||
__exit:
|
||
os_mutex_post(&_nandflash.mutex);
|
||
return 0;
|
||
}
|
||
|
||
#endif
|
||
|
||
static void nand_read(u32 addr, u32 len, u8 *buf)
|
||
{
|
||
u32 bp_mix = 0;
|
||
u32 cache_addr;
|
||
bp_mix = block_page_get(addr, &cache_addr);
|
||
bp_mix = block_change(bp_mix);
|
||
nand_page_read_to_cache(bp_mix);
|
||
nand_read_from_cache(buf, cache_addr, len);
|
||
}
|
||
|
||
|
||
int nand_flash_read(u32 offset, u8 *buf, u32 len)
|
||
{
|
||
/* printf("%s() %x l: %x @:%x \n",__func__,buf,len,offset); */
|
||
int reg = 0;
|
||
int _len = len;
|
||
u8 *_buf = (u8 *)buf;
|
||
os_mutex_pend(&_nandflash.mutex, 0);
|
||
u32 first_page_len = NAND_PAGE_SIZE - (offset % NAND_PAGE_SIZE);
|
||
/* printf("first_page_len %x %x \n", first_page_len, offset % NAND_PAGE_SIZE); */
|
||
first_page_len = _len > first_page_len ? first_page_len : _len;
|
||
nand_read(offset, first_page_len, _buf);
|
||
_len -= first_page_len;
|
||
_buf += first_page_len;
|
||
offset += first_page_len;
|
||
while (_len) {
|
||
u32 cnt = _len > NAND_PAGE_SIZE ? NAND_PAGE_SIZE : _len;
|
||
nand_read(offset, cnt, _buf);
|
||
_len -= cnt;
|
||
offset += cnt;
|
||
_buf += cnt;
|
||
}
|
||
os_mutex_post(&_nandflash.mutex);
|
||
return reg;
|
||
}
|
||
|
||
|
||
int _nandflash_init(const char *name, struct nandflash_dev_platform_data *pdata)
|
||
{
|
||
log_info("nandflash_init ! %x %x", pdata->spi_cs_port, pdata->spi_read_width);
|
||
if (_nandflash.spi_num == (int) - 1) {
|
||
_nandflash.spi_num = pdata->spi_hw_num;
|
||
_nandflash.spi_cs_io = pdata->spi_cs_port;
|
||
_nandflash.spi_r_width = pdata->spi_read_width;
|
||
_nandflash.flash_id = 0;
|
||
os_mutex_create(&_nandflash.mutex);
|
||
_nandflash.max_end_addr = 0;
|
||
_nandflash.part_num = 0;
|
||
}
|
||
ASSERT(_nandflash.spi_num == pdata->spi_hw_num);
|
||
ASSERT(_nandflash.spi_cs_io == pdata->spi_cs_port);
|
||
ASSERT(_nandflash.spi_r_width == pdata->spi_read_width);
|
||
struct nandflash_partition *part;
|
||
part = nandflash_find_part(name);
|
||
if (!part) {
|
||
part = nandflash_new_part(name, pdata->start_addr, pdata->size);
|
||
ASSERT(part, "not enough nandflash partition memory in array\n");
|
||
ASSERT(nandflash_verify_part(part) == 0, "nandflash partition %s overlaps\n", name);
|
||
log_info("nandflash new partition %s\n", part->name);
|
||
} else {
|
||
ASSERT(0, "nandflash partition name already exists\n");
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static void clock_critical_enter()
|
||
{
|
||
|
||
}
|
||
static void clock_critical_exit()
|
||
{
|
||
if (!(_nandflash.flash_id == 0 || _nandflash.flash_id == 0xffff)) {
|
||
spi_set_baud(_nandflash.spi_num, spi_get_baud(_nandflash.spi_num));
|
||
}
|
||
}
|
||
CLOCK_CRITICAL_HANDLE_REG(spi_nandflash, clock_critical_enter, clock_critical_exit);
|
||
|
||
int _nandflash_open(void *arg)
|
||
{
|
||
int reg = 0;
|
||
os_mutex_pend(&_nandflash.mutex, 0);
|
||
log_info("nandflash open\n");
|
||
if (!_nandflash.open_cnt) {
|
||
spi_cs_init();
|
||
spi_open(_nandflash.spi_num);
|
||
_nandflash.flash_id = nand_flash_read_id();
|
||
log_info("nandflash_read_id: 0x%x\n", _nandflash.flash_id);
|
||
if ((_nandflash.flash_id == 0) || (_nandflash.flash_id == 0xffff)) {
|
||
log_error("read nandflash id error !\n");
|
||
reg = -ENODEV;
|
||
goto __exit;
|
||
}
|
||
log_info("nandflash open success !\n");
|
||
}
|
||
if (_nandflash.flash_id == 0 || _nandflash.flash_id == 0xffff) {
|
||
log_error("re-open nandflash id error !\n");
|
||
reg = -EFAULT;
|
||
goto __exit;
|
||
}
|
||
_nandflash.open_cnt++;
|
||
nand_flash_erase_all();
|
||
__exit:
|
||
os_mutex_post(&_nandflash.mutex);
|
||
return reg;
|
||
}
|
||
|
||
int _nandflash_close(void)
|
||
{
|
||
os_mutex_pend(&_nandflash.mutex, 0);
|
||
log_info("nandflash close\n");
|
||
if (_nandflash.open_cnt) {
|
||
_nandflash.open_cnt--;
|
||
}
|
||
if (!_nandflash.open_cnt) {
|
||
spi_close(_nandflash.spi_num);
|
||
spi_cs_uninit();
|
||
|
||
log_info("nandflash close done\n");
|
||
}
|
||
os_mutex_post(&_nandflash.mutex);
|
||
return 0;
|
||
}
|
||
|
||
|
||
int _nandflash_ioctl(u32 cmd, u32 arg, u32 unit, void *_part)
|
||
{
|
||
int reg = 0;
|
||
struct nandflash_partition *part = _part;
|
||
os_mutex_pend(&_nandflash.mutex, 0);
|
||
switch (cmd) {
|
||
case IOCTL_GET_STATUS:
|
||
*(u32 *)arg = 1;
|
||
break;
|
||
case IOCTL_GET_ID:
|
||
*((u32 *)arg) = _nandflash.flash_id;
|
||
break;
|
||
case IOCTL_GET_BLOCK_SIZE:
|
||
*(u32 *)arg = 512;
|
||
break;
|
||
case IOCTL_ERASE_BLOCK:
|
||
reg = nand_flash_erase(arg);
|
||
break;
|
||
case IOCTL_GET_CAPACITY:
|
||
*(u32 *)arg = 128 * 1024 / unit;
|
||
break;
|
||
case IOCTL_FLUSH:
|
||
break;
|
||
case IOCTL_CMD_RESUME:
|
||
break;
|
||
case IOCTL_CMD_SUSPEND:
|
||
break;
|
||
default:
|
||
reg = -EINVAL;
|
||
break;
|
||
}
|
||
__exit:
|
||
os_mutex_post(&_nandflash.mutex);
|
||
return reg;
|
||
}
|
||
|
||
|
||
/*************************************************************************************
|
||
* 挂钩 device_api
|
||
************************************************************************************/
|
||
|
||
static int nandflash_dev_init(const struct dev_node *node, void *arg)
|
||
{
|
||
struct nandflash_dev_platform_data *pdata = arg;
|
||
return _nandflash_init(node->name, pdata);
|
||
}
|
||
|
||
static int nandflash_dev_open(const char *name, struct device **device, void *arg)
|
||
{
|
||
struct nandflash_partition *part;
|
||
part = nandflash_find_part(name);
|
||
if (!part) {
|
||
log_error("no nandflash partition is found\n");
|
||
return -ENODEV;
|
||
}
|
||
*device = &part->device;
|
||
(*device)->private_data = part;
|
||
if (atomic_read(&part->device.ref)) {
|
||
return 0;
|
||
}
|
||
return _nandflash_open(arg);
|
||
}
|
||
static int nandflash_dev_close(struct device *device)
|
||
{
|
||
return _nandflash_close();
|
||
}
|
||
static int nandflash_dev_read(struct device *device, void *buf, u32 len, u32 offset)
|
||
{
|
||
int reg;
|
||
offset = offset * 512;
|
||
len = len * 512;
|
||
/* r_printf("flash read sector = %d, num = %d\n", offset, len); */
|
||
struct nandflash_partition *part;
|
||
part = (struct nandflash_partition *)device->private_data;
|
||
if (!part) {
|
||
log_error("nandflash partition invalid\n");
|
||
return -EFAULT;
|
||
}
|
||
offset += part->start_addr;
|
||
reg = nand_flash_read(offset, buf, len);
|
||
if (reg) {
|
||
r_printf(">>>[r error]:\n");
|
||
len = 0;
|
||
}
|
||
len = len / 512;
|
||
return len;
|
||
}
|
||
static int nandflash_dev_write(struct device *device, void *buf, u32 len, u32 offset)
|
||
{
|
||
/* r_printf("flash write sector = %d, num = %d\n", offset, len); */
|
||
int reg = 0;
|
||
offset = offset * 512;
|
||
len = len * 512;
|
||
struct nandflash_partition *part = device->private_data;
|
||
if (!part) {
|
||
log_error("nandflash partition invalid\n");
|
||
return -EFAULT;
|
||
}
|
||
offset += part->start_addr;
|
||
reg = nand_flash_write(offset, buf, len);
|
||
if (reg) {
|
||
r_printf(">>>[w error]:\n");
|
||
len = 0;
|
||
}
|
||
len = len / 512;
|
||
return len;
|
||
}
|
||
static bool nandflash_dev_online(const struct dev_node *node)
|
||
{
|
||
return 1;
|
||
}
|
||
static int nandflash_dev_ioctl(struct device *device, u32 cmd, u32 arg)
|
||
{
|
||
struct nandflash_partition *part = device->private_data;
|
||
if (!part) {
|
||
log_error("nandflash partition invalid\n");
|
||
return -EFAULT;
|
||
}
|
||
return _nandflash_ioctl(cmd, arg, 512, part);
|
||
}
|
||
const struct device_operations nandflash_dev_ops = {
|
||
.init = nandflash_dev_init,
|
||
.online = nandflash_dev_online,
|
||
.open = nandflash_dev_open,
|
||
.read = nandflash_dev_read,
|
||
.write = nandflash_dev_write,
|
||
.ioctl = nandflash_dev_ioctl,
|
||
.close = nandflash_dev_close,
|
||
};
|
||
#endif
|