blob: 080e2c0ef78b629fa5915b9d3f28e797ae2a622d [file] [log] [blame]
#define UBOOT_CODE
#ifdef UBOOT_CODE
#include <config.h>
#include <common.h>
#include <malloc.h>
#include <nand.h>
#include <spi.h>
#include <spi_flash.h>
#include <nand_spi.h>
#include "../../../../drivers/mtd/spi/spi_flash_internal.h" /*TODO:change it to related path*/
#ifdef MV_NAND_SPI
#undef NAND_SPI_DEBUG
#ifdef NAND_SPI_DEBUG
#define DB(x) x
#else
#define DB(x)
#endif /* NAND_SPI_DEBUG */
#define debug_spi printf
static int nand_spi_enable(struct nand_spi *nspi);
static void nand_spi_select_chip(struct mtd_info *mtd, int chip);
static void nand_spi_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr);
static void nand_spi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len);
static void nand_spi_cmd_write(struct nand_spi *nspi);
static void nand_spi_cmd_read(struct nand_spi *nspi);
static void nand_spi_cmd_read_oob(struct nand_spi *nspi);
static void nand_spi_cmd_erase(struct nand_spi *nspi);
static void nand_spi_cmd_status(struct nand_spi *nspi);
static void nand_spi_cmd_seqin(struct nand_spi *nspi);
static void nand_spi_cmd_read_id(struct nand_spi *nspi);
static int nand_spi_waitfunc(struct mtd_info *mtd, struct nand_chip *nspi);
static void nand_spi_ecc_hwctl(struct mtd_info *mtd, int mode);
static int nand_spi_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code);
static int nand_spi_ecc_correct(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc);
static uint8_t nand_spi_read_byte(struct mtd_info *mtd);
static u16 nand_spi_read_word(struct mtd_info *mtd);
static void nand_spi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len);
static uint8_t bbt_pattern = { 0xff };
static struct nand_bbt_descr nand_spi_bbt = {
.options = 0,
.offs = 0,
.len = 1,
.pattern = &bbt_pattern,
};
static struct nand_ecclayout nand_spi_ecc = {
.eccbytes = 16,
.eccpos = {
12, 13, 14, 15,
28, 29, 30, 31,
44, 45, 46, 47,
60, 61, 62, 63},
.oobfree = { {1, 3}, {4, 8}, {16, 4}, {20, 8}, {32, 4}, {36, 8}, {48, 4}, {52, 8} }
};
int board_nand_spi_init(struct nand_chip *nand)
{
struct nand_spi *nspi;
nspi = malloc(sizeof(struct nand_spi));
nand->priv = nspi;
nand->num_devs = 1;
nand->waitfunc = nand_spi_waitfunc;
nand->dev_ready = 0;
nand->options = NAND_USE_FLASH_BBT;
nand->cmdfunc = nand_spi_cmdfunc;
nand->select_chip = nand_spi_select_chip;
nand->read_byte = nand_spi_read_byte;
nand->read_word = nand_spi_read_word;
nand->read_buf = nand_spi_read_buf;
nand->write_buf = nand_spi_write_buf;
nand->verify_buf = 0;
nand->block_markbad = 0;
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.hwctl = nand_spi_ecc_hwctl;
nand->ecc.calculate = nand_spi_ecc_calculate;
nand->ecc.correct = nand_spi_ecc_correct;
/* Hardware generates ECC per 512 Bytes, 4 Bytes per step */
nand->ecc.size = 512;
nand->ecc.bytes = 4;
nand->ecc.layout = &nand_spi_ecc;
nand->bbt_td = 0;
nand->bbt_md = 0;
nand->badblock_pattern = &nand_spi_bbt;
nspi->page_size = NAND_SPI_PAGE_SIZE;
nspi->page_per_sector = 64;
nspi->sector_size = nspi->page_size * nspi->page_per_sector;
nspi->data_buf = malloc(nspi->page_size + NAND_SPI_OOB_SIZE);
nspi->data_pos = 0;
nspi->ecc_status = 0;
nspi->spi = spi_setup_slave(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, CONFIG_ENV_SPI_MAX_HZ, SPI_MODE_3);
nand_spi_enable(nspi);
return 0;
}
static u16 nand_spi_read_word(struct mtd_info *mtd)
{
u16 val;
struct nand_spi *nspi = (struct nand_spi *)((struct nand_chip *)mtd->priv)->priv;
val = *((u16 *)(nspi->data_buf + nspi->data_pos));
nspi->data_pos += sizeof(u16);
return val;
}
static uint8_t nand_spi_read_byte(struct mtd_info *mtd)
{
char val;
struct nand_spi *nspi = (struct nand_spi *)((struct nand_chip *)mtd->priv)->priv;
val = *(nspi->data_buf + nspi->data_pos);
nspi->data_pos++;
return val;
}
static void nand_spi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
struct nand_spi *nspi = (struct nand_spi *)((struct nand_chip *)mtd->priv)->priv;
memcpy(buf, nspi->data_buf + nspi->data_pos, len);
nspi->data_pos += len;
}
static void nand_spi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
struct nand_spi *nspi = (struct nand_spi *)((struct nand_chip *)mtd->priv)->priv;
memcpy(nspi->data_buf + nspi->data_pos, buf, len);
nspi->data_pos += len;
}
static int nand_spi_wait_ready(struct nand_spi *nspi, unsigned long timeout)
{
u8 cmd[2], buf[3];
unsigned long timebase;
timebase = get_timer(0);
DB(debug_spi("nand-spi:status register: (cmd 0x%x, %x)",
CMD_RDSR, 0xC0));
cmd[0] = CMD_RDSR;
cmd[1] = 0xC0; /* Protection status */
do {
spi_flash_cmd_read(nspi->spi, cmd, 2, buf, 1);
DB(debug_spi(" = 0x%x", buf[0]));
if ((buf[0] & SR_OIP_BIT) == 0)
break;
} while (get_timer(timebase) < timeout);
if ((buf[0] & SR_OIP_BIT) == 0) {
DB(debug_spi(" (device ready)\n"));
return 0;
}
/* Timed out */
DB(debug_spi(" timed out\n"));
return -1;
}
static void nand_spi_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr)
{
struct nand_spi *nspi = (struct nand_spi *)((struct nand_chip *)mtd->priv)->priv;
DB(debug_spi("nand-spi:command=0x%x(%d) column=%d page_addr=%d\n",
command, command, column, page_addr));
switch (command) {
case NAND_CMD_SEQIN:
nspi->column = column;
nspi->page_addr = page_addr;
nand_spi_cmd_seqin(nspi);
break;
case NAND_CMD_READOOB:
nspi->column = column;
nspi->page_addr = page_addr;
nand_spi_cmd_read_oob(nspi);
break;
case NAND_CMD_STATUS:
nand_spi_cmd_status(nspi);
break;
case NAND_CMD_READ0:
nspi->column = column;
nspi->page_addr = page_addr;
nand_spi_cmd_read(nspi);
break;
case NAND_CMD_RESET:
break;
case NAND_CMD_ERASE1:
nspi->column = column;
nspi->page_addr = page_addr;
nand_spi_cmd_erase(nspi);
break;
case NAND_CMD_READID:
nand_spi_cmd_read_id(nspi);
break;
case NAND_CMD_PAGEPROG:
nand_spi_cmd_write(nspi);
break;
}
}
static void nand_spi_ecc_hwctl(struct mtd_info *mtd, int mode)
{
}
static int nand_spi_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code)
{
return 0;
}
static int nand_spi_waitfunc(struct mtd_info *mtd, struct nand_chip *nspi)
{
return 0;
}
static void nand_spi_select_chip(struct mtd_info *mtd, int chip)
{
int ret;
struct nand_spi *nspi = (struct nand_spi *)((struct nand_chip *)mtd->priv)->priv;
ret = spi_flash_cmd(nspi->spi, CMD_WREN, NULL, 0);
if (ret < 0) {
debug_spi("nand-spi: error while enabling write operation\n");
}
}
static int nand_spi_ecc_correct(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc)
{
/*
* ecc_status:
* 00b = No bit errors detected during last read opeartion
* 01b = bit error was detected and corrected, error bit number = 1~7
* 10b = bit error was detected and bot corrected
* 11b = bit error was detected and corrected, error bit number = 8
*/
struct nand_spi *nspi = (struct nand_spi *)((struct nand_chip *)mtd->priv)->priv;
if(nspi->ecc_status == ECC_ERR_NOT_CORRECTED)
return -1;
return (nspi->ecc_status >> 1);
}
static int nand_spi_enable(struct nand_spi *nspi)
{
int ret;
u8 cmd[3];
/* Write Enable */
ret = spi_flash_cmd(nspi->spi, CMD_WREN, NULL, 0);
if(ret < 0) {
debug_spi("nand-spi: error while enabling write operation\n");
return ret;
}
/* Set Features : Status register */
cmd[0] = CMD_WRSR;
cmd[1] = 0xA0;
cmd[2] = 0x0;
ret = spi_flash_cmd_write(nspi->spi, cmd, 3, NULL, 0);
if(ret < 0) {
debug_spi("nand-spi:write status register failed\n");
return ret;
}
/* Enable ECC */
/* Set Features : Status register */
cmd[0] = CMD_WRSR;
cmd[1] = 0xB0;
cmd[2] = ECC_EN_BIT;
ret = spi_flash_cmd_write(nspi->spi, cmd, 3, NULL, 0);
if (ret < 0) {
debug_spi("nand-spi:write status register failed\n");
return ret;
}
return 0;
}
static void nand_spi_cmd_seqin(struct nand_spi *nspi)
{
nspi->data_pos = 0;
}
static void nand_spi_cmd_read_id(struct nand_spi *nspi)
{
int ret;
u8 idcode[8];
nspi->data_pos = 0;
memset(idcode, 0, sizeof(idcode));
ret = spi_flash_cmd(nspi->spi, CMD_READ_ID, idcode, sizeof(idcode));
if(ret) {
goto err_read_id;
}
memcpy(nspi->data_buf, idcode, sizeof(idcode));
return;
err_read_id:
spi_free_slave(nspi->spi);
}
static void nand_spi_cmd_status(struct nand_spi *nspi)
{
u8 cmd[3], buf[1];
/* Get Features : protection register */
cmd[0] = CMD_RDSR;
cmd[1] = 0xA0; /* Protection status */
spi_flash_cmd_read(nspi->spi, cmd, 2, buf, 1);
DB(debug_spi("nand-spi:get features:protection register (command 0x%x, " \
"%x), value=0x%x\n", CMD_RDSR, 0xA0, buf[0]));
/* Get Features : feature register */
cmd[0] = CMD_RDSR;
cmd[1] = 0xB0; /* Protection status */
spi_flash_cmd_read(nspi->spi, cmd, 2, buf, 3);
DB(debug_spi("feature register (command 0x%x, %x), value=0x%x\n", \
CMD_RDSR, 0xB0, buf[0]));
/* Get Features : status register */
cmd[0] = CMD_RDSR;
cmd[1] = 0xC0; /* Protection status */
spi_flash_cmd_read(nspi->spi, cmd, 2, buf, 3);
DB(debug_spi("status register (command 0x%x, %x), value=0x%x\n", \
CMD_RDSR, 0xC0, buf[0]));
/* The nand stack check if the device is in write protected state by test Bit-7 (0x80) */
/* while NAND-SPI use Bit-1 (0x02) to indicates write protected state */
if(buf[0] & WP_BIT) {
buf[0] |= 0x80;
}
memcpy(nspi->data_buf, buf, sizeof(buf));
nspi->data_pos = 0;
}
static void nand_spi_cmd_write(struct nand_spi *nspi)
{
unsigned long page_num, sector_num;
u8 cmd[4];
int ret = 0, len;
len = nspi->data_pos;
/* Enable ECC */
/* Set Features : Status register */
cmd[0] = CMD_WRSR;
cmd[1] = 0xB0;
cmd[2] = ECC_EN_BIT;
cmd[2] = 0x10;
ret = spi_flash_cmd_write(nspi->spi, cmd, 3, NULL, 0);
if (ret < 0) {
debug_spi("nand-spi:write status register failed\n");
return;
}
page_num = nspi->page_addr;
sector_num = page_num >> 6;
/* PROGRAM LOAD: Write page to Cache */
cmd[0] = CMD_PP_TO_CACHE;
cmd[1] = 0;
cmd[2] = 0;
ret = spi_flash_cmd_write(nspi->spi, cmd, 3, nspi->data_buf, len);
/* Write Enable */
ret = spi_flash_cmd(nspi->spi, CMD_WREN, NULL, 0);
if(ret < 0) {
debug_spi("nand-spi:enabling write failed\n");
return;
}
/* Read status - wait for device to finish transaction */
ret = nand_spi_wait_ready(nspi, SPI_FLASH_PROG_TIMEOUT);
if (ret < 0) {
debug_spi("nand-spi:page programming timed out\n");
}
/* Program Execute: Write page from Cache to flash */
/* command requires a 24-bit address consisting of: */
/* - 8 dummy bits */
/* - 10 bits of sector number */
/* - 6 bit of page number */
cmd[0] = CMD_PROGRAM_EXECUTE;
cmd[1] = 0; /* Dummy */
cmd[2] = sector_num >> 2; /* 8 bits sector number (8 MSB bits) */
cmd[3] = page_num & 0x3f; /* 6 LSB bits of cmd[0] = page address */
cmd[3] |= (sector_num & 0x3) << 6; /* 2 LSB bits of cmd[0]= 1st 2 bits of sector address */
ret = spi_flash_cmd_write(nspi->spi, cmd, 4, NULL, 0);
if (ret < 0) {
debug_spi("nand-spi:program execute to flash failed\n");
return;
}
/* Read status - wait for device to finish transaction */
ret = nand_spi_wait_ready(nspi, SPI_FLASH_PROG_TIMEOUT);
if (ret < 0) {
debug_spi("nand-spi:page programming timed out\n");
return;
}
DB(debug_spi("nand-spi:Successfully programmed %u bytes\n", len));
}
static void nand_spi_cmd_read(struct nand_spi *nspi)
{
char buf[3];
unsigned long page_num, sector_num;
u8 cmd[5];
int ret = -1, len;
len = NAND_SPI_PAGE_SIZE + NAND_SPI_OOB_SIZE;
page_num = nspi->page_addr;
/*64 pages per sector*/
sector_num = (page_num >> 6);
/* Read page from Flash to Cache: */
/* command requires a 24-bit address consisting of */
/* - 8 dummy bits */
/* - 10 bits of sector number */
/* - 6 bit of page number */
cmd[0] = CMD_READ_TO_CACHE;
cmd[1] = 0;
cmd[2] = sector_num >> 2;
cmd[3] = page_num & 0x3f; /* 6 LSB bits */
cmd[3] |= (sector_num & 0x3) << 6; /* 2 MSB bits */
ret = spi_flash_cmd_write(nspi->spi, cmd, 4, NULL, 0);
if (ret < 0) {
debug_spi("nand-spi:read to cache failed\n");
return;
}
/* Read status - wait for device to finish transaction */
ret = nand_spi_wait_ready(nspi, SPI_FLASH_PROG_TIMEOUT);
if (ret < 0) {
debug_spi("nand-spi:page programming timed out\n");
return;
}
/* Read first page from Cache */
cmd[0] = CMD_READ_FROM_CACHE;
cmd[1] = 0x0;
cmd[2] = 0x0;
cmd[3] = 0x0;
ret = spi_flash_cmd_read(nspi->spi, cmd, 4, nspi->data_buf, len);
if (ret < 0) {
debug_spi("nand-spi:read from cache failed\n");
return;
}
nspi->data_pos = 0;
/* Get Features : Status register */
cmd[0] = CMD_RDSR;
cmd[1] = 0xC0; /* status */
spi_flash_cmd_read(nspi->spi, cmd, 2, buf, 3);
nspi->ecc_status = (buf[0] & 0x30) >> 4;
DB(debug_spi("nand-spi:read sector=%lu page=%lu. ecc reg=0x%x\n",
sector_num, page_num, nspi->ecc_status));
}
static void nand_spi_cmd_read_oob(struct nand_spi *nspi)
{
char buf[3];
unsigned long page_num, sector_num;
u8 cmd[5];
int ret = -1, len;
len = NAND_SPI_OOB_SIZE;
page_num = nspi->page_addr;
/*64 pages per sector*/
sector_num = (page_num >> 6);
DB(debug_spi("nand-spi:read_oob operation. sector=%lu, page=%lu\n",
sector_num, page_num));
/* Read page from Flash to Cache:
* command requires a 24-bit address consisting of
* - 8 dummy bits
* - 10 bits of sector number
* - 6 bit of page number */
cmd[0] = CMD_READ_TO_CACHE;
cmd[1] = 0;
cmd[2] = sector_num >> 2;
cmd[3] = page_num & 0x3f; /* 6 LSB bits */
cmd[3] |= (sector_num & 0x3) << 6; /* 2 MSB bits */
ret = spi_flash_cmd_write(nspi->spi, cmd, 4, NULL, 0);
if (ret < 0) {
debug_spi("nand-spi:read to cache failed\n");
return;
}
/* Read status - wait for device to finish transaction */
ret = nand_spi_wait_ready(nspi, SPI_FLASH_PROG_TIMEOUT);
if (ret < 0) {
DB(debug_spi("nand-spi:page programming timed out\n"));
return;
}
/* Read oob data from Cache */
cmd[0] = CMD_READ_FROM_CACHE;
cmd[1] = 0x80; /*64-len for oob area */
cmd[1] |= 0x08; /*offset(2-bits MSB) 2048 for OOB data (0x800)*/
cmd[2] = 0x0; /*offset(4-bits-LSB) 2048 for OOB data (0x800)*/
cmd[3] = 0x0;
ret = spi_flash_cmd_read(nspi->spi, cmd, 4, nspi->data_buf, len);
if (ret < 0) {
debug_spi("nand-spi:read_oob from cache failed\n");
return;
}
nspi->data_pos = 0;
/* Get Features : Status register */
cmd[0] = CMD_RDSR;
cmd[1] = 0xC0; /* status */
spi_flash_cmd_read(nspi->spi, cmd, 2, buf, 3);
nspi->ecc_status = ((buf[0] & 0x30) >> 4);
DB(debug_spi("nand-spi:read_oob sector=%lu page=%lu. ecc reg=0x%x\n",
sector_num, page_num, nspi->ecc_status));
}
static void nand_spi_cmd_erase(struct nand_spi *nspi)
{
unsigned long sector_num;
int ret = 0;
u8 cmd[4];
/*page_addr indicates the number of the first page in erased block*/
sector_num = nspi->page_addr >> 6;
cmd[0] = CMD_SECTOR_ERASE;
cmd[1] = 0x00; /* Dummy */
/* command requires a 24-bit address consisting of:
* - 8 dummy bits
* - 10 bits of sector number
* - 6 bit of page number */
cmd[2] = sector_num >> 2; /* 6 MSB bits */
cmd[3] = (sector_num & 0x3) << 6; /* 2 LSB bits */
DB(debug_spi("nand-spi:erase. sector_num=%lu\n", sector_num));
ret = spi_flash_cmd(nspi->spi, CMD_WREN, NULL, 0);
if (ret < 0) {
debug_spi("nand-spi:erase. enable write failed\n");
/*break'*/
return;
}
/* Read status - wait for device to finish transaction */
ret = nand_spi_wait_ready(nspi, SPI_FLASH_PROG_TIMEOUT);
if (ret < 0) {
debug_spi("nand-spi:sector programming timed out\n");
return;
}
ret = spi_flash_cmd_write(nspi->spi, cmd, 4, NULL, 0);
if (ret < 0) {
DB(debug_spi("nand-spi:sector erase failed. sector=0x%lx\n",
sector_num));
return;
}
/* Read status - wait for device to finish transaction */
ret = nand_spi_wait_ready(nspi, SPI_FLASH_PAGE_ERASE_TIMEOUT);
if (ret < 0) {
debug_spi("nand-spi:sector erase timed out. sector=0x%lx\n", sector_num);
return;
}
DB(debug_spi("nand-spi:erased sector=0x%lx\n", sector_num));
}
#endif /*MV_NAND_SPI*/
#endif