#endif
#if defined(CONFIG_CMD_NAND)
-#if !defined(CFG_NAND_LEGACY)
+#if !defined(CONFIG_NAND_LEGACY)
#include <nand.h>
#include <s3c2410.h>
+ #include <asm/io.h>
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)
- static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd)
+ #define S3C2410_ADDR_NALE 4
+ #define S3C2410_ADDR_NCLE 8
+
+ static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *chip = mtd->priv;
- DEBUGN("hwcontrol(): 0x%02x: ", cmd);
-
- switch (cmd) {
- case NAND_CTL_SETNCE:
- NFCONF &= ~S3C2410_NFCONF_nFCE;
- DEBUGN("NFCONF=0x%08x\n", NFCONF);
- break;
- case NAND_CTL_CLRNCE:
- NFCONF |= S3C2410_NFCONF_nFCE;
- DEBUGN("NFCONF=0x%08x\n", NFCONF);
- break;
- case NAND_CTL_SETALE:
- chip->IO_ADDR_W = NF_BASE + 0x8;
- DEBUGN("SETALE\n");
- break;
- case NAND_CTL_SETCLE:
- chip->IO_ADDR_W = NF_BASE + 0x4;
- DEBUGN("SETCLE\n");
- break;
- default:
- chip->IO_ADDR_W = NF_BASE + 0xc;
- break;
+ DEBUGN("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ ulong IO_ADDR_W = NF_BASE;
+
+ if (!(ctrl & NAND_CLE))
+ IO_ADDR_W |= S3C2410_ADDR_NCLE;
+ if (!(ctrl & NAND_ALE))
+ IO_ADDR_W |= S3C2410_ADDR_NALE;
+
+ chip->IO_ADDR_W = (void *)IO_ADDR_W;
+
+ if (ctrl & NAND_NCE)
+ NFCONF &= ~S3C2410_NFCONF_nFCE;
+ else
+ NFCONF |= S3C2410_NFCONF_nFCE;
}
- return;
+
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, chip->IO_ADDR_W);
}
static int s3c2410_dev_ready(struct mtd_info *mtd)
#ifdef CONFIG_S3C2410_NAND_HWECC
void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
- DEBUGN("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd ,mode);
+ DEBUGN("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);
NFCONF |= S3C2410_NFCONF_INITECC;
}
NFCONF = cfg;
/* initialize nand_chip data structure */
- nand->IO_ADDR_R = nand->IO_ADDR_W = 0x4e00000c;
+ nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e00000c;
/* read_buf and write_buf are default */
/* read_byte and write_byte are default */
/* hwcontrol always must be implemented */
- nand->hwcontrol = s3c2410_hwcontrol;
+ nand->cmd_ctrl = s3c2410_hwcontrol;
nand->dev_ready = s3c2410_dev_ready;
#ifdef CONFIG_S3C2410_NAND_HWECC
- nand->enable_hwecc = s3c2410_nand_enable_hwecc;
- nand->calculate_ecc = s3c2410_nand_calculate_ecc;
- nand->correct_data = s3c2410_nand_correct_data;
- nand->eccmode = NAND_ECC_HW3_512;
+ nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
+ nand->ecc.calculate = s3c2410_nand_calculate_ecc;
+ nand->ecc.correct = s3c2410_nand_correct_data;
+ nand->ecc.mode = NAND_ECC_HW3_512;
#else
- nand->eccmode = NAND_ECC_SOFT;
+ nand->ecc.mode = NAND_ECC_SOFT;
#endif
#ifdef CONFIG_S3C2410_NAND_BBT
*/
#include <common.h>
-
-#ifdef CONFIG_CMD_ONENAND
-
#include <linux/mtd/compat.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/onenand.h>
if (ONENAND_CURRENT_BUFFERRAM(this)) {
if (area == ONENAND_DATARAM)
- return mtd->oobblock;
+ return mtd->writesize;
if (area == ONENAND_SPARERAM)
return mtd->oobsize;
}
return 0;
}
+ /**
+ * onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information
+ * @param mtd MTD data structure
+ * @param addr start address to invalidate
+ * @param len length to invalidate
+ *
+ * Invalidate BufferRAM information
+ */
+ static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr,
+ unsigned int len)
+ {
+ struct onenand_chip *this = mtd->priv;
+ int i;
+ loff_t end_addr = addr + len;
+
+ /* Invalidate BufferRAM */
+ for (i = 0; i < MAX_BUFFERRAM; i++) {
+ loff_t buf_addr = this->bufferram[i].block << this->erase_shift;
+
+ if (buf_addr >= addr && buf_addr < end_addr)
+ this->bufferram[i].valid = 0;
+ }
+ }
+
/**
* onenand_get_device - [GENERIC] Get chip for selected access
* @param mtd MTD device structure
onenand_get_device(mtd, FL_READING);
while (read < len) {
- thislen = min_t(int, mtd->oobblock, len - read);
+ thislen = min_t(int, mtd->writesize, len - read);
- column = from & (mtd->oobblock - 1);
- if (column + thislen > mtd->oobblock)
- thislen = mtd->oobblock - column;
+ column = from & (mtd->writesize - 1);
+ if (column + thislen > mtd->writesize)
+ thislen = mtd->writesize - column;
if (!onenand_check_bufferram(mtd, from)) {
this->command(mtd, ONENAND_CMD_READ, from,
- mtd->oobblock);
+ mtd->writesize);
ret = this->wait(mtd, FL_READING);
/* First copy data and check return value for ECC handling */
onenand_update_bufferram(mtd, from, 1);
/* Read more? */
if (read < len) {
/* Page size */
- from += mtd->oobblock;
+ from += mtd->writesize;
column = 0;
}
}
void __iomem *dataram0, *dataram1;
int ret = 0;
- this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock);
+ this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize);
ret = this->wait(mtd, FL_READING);
if (ret)
/* Check, if the two dataram areas are same */
dataram0 = this->base + ONENAND_DATARAM;
- dataram1 = dataram0 + mtd->oobblock;
+ dataram1 = dataram0 + mtd->writesize;
- if (memcmp(dataram0, dataram1, mtd->oobblock))
+ if (memcmp(dataram0, dataram1, mtd->writesize))
return -EBADMSG;
return 0;
#define onenand_verify_page(...) (0)
#endif
- #define NOTALIGNED(x) ((x & (mtd->oobblock - 1)) != 0)
+ #define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0)
/**
* onenand_write_ecc - [MTD Interface] OneNAND write with ECC
/* Loop until all data write */
while (written < len) {
- int thislen = min_t(int, mtd->oobblock, len - written);
+ int thislen = min_t(int, mtd->writesize, len - written);
- this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock);
+ this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize);
this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen);
this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0,
mtd->oobsize);
- this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock);
+ this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
onenand_update_bufferram(mtd, to, 1);
return 0;
}
+ /**
+ * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
+ * @param mtd MTD device structure
+ * @param ofs offset from device start
+ * @param allowbbt 1, if its allowed to access the bbt area
+ *
+ * Check, if the block is bad, Either by reading the bad block table or
+ * calling of the scan function.
+ */
+ static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
+ {
+ struct onenand_chip *this = mtd->priv;
+ struct bbm_info *bbm = this->bbm;
+
+ /* Return info from the table */
+ return bbm->isbad_bbt(mtd, ofs, allowbbt);
+ }
+
+
/**
* onenand_erase - [MTD Interface] erase block(s)
* @param mtd MTD device structure
this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
+ onenand_invalidate_bufferram(mtd, addr, block_size);
+
ret = this->wait(mtd, FL_ERASING);
/* Check, if it is write protected */
if (ret) {
* onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
* @param mtd MTD device structure
* @param ofs offset relative to mtd start
+ *
+ * Check whether the block is bad
*/
int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
{
- /*
- * TODO
- * 1. Bad block table (BBT)
- * -> using NAND BBT to support JFFS2
- * 2. Bad block management (BBM)
- * -> bad block replace scheme
- *
- * Currently we do nothing
- */
- return 0;
+ int ret;
+
+ /* Check for invalid offset */
+ if (ofs > mtd->size)
+ return -EINVAL;
+
+ onenand_get_device(mtd, FL_READING);
+ ret = onenand_block_isbad_nolock(mtd,ofs, 0);
+ onenand_release_device(mtd);
+ return ret;
}
/**
* onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
* @param mtd MTD device structure
* @param ofs offset relative to mtd start
+ *
+ * Mark the block as bad
*/
int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
- /* see above */
- return 0;
+ struct onenand_chip *this = mtd->priv;
+ int ret;
+
+ ret = onenand_block_isbad(mtd, ofs);
+ if (ret) {
+ /* If it was bad already, return success and do nothing */
+ if (ret > 0)
+ return 0;
+ return ret;
+ }
+
+ ret = this->block_markbad(mtd, ofs);
+ return ret;
}
/**
/* Reset OneNAND to read default register values */
this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
- {
- int i;
- for (i = 0; i < 10000; i++) ;
- }
+ /* Wait reset */
+ this->wait(mtd, FL_RESETING);
/* Read manufacturer and device IDs from Register */
maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
/* OneNAND page size & block size */
/* The data buffer size is equal to page size */
- mtd->oobblock =
+ mtd->writesize =
this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
- mtd->oobsize = mtd->oobblock >> 5;
+ mtd->oobsize = mtd->writesize >> 5;
/* Pagers per block is always 64 in OneNAND */
- mtd->erasesize = mtd->oobblock << 6;
+ mtd->erasesize = mtd->writesize << 6;
this->erase_shift = ffs(mtd->erasesize) - 1;
- this->page_shift = ffs(mtd->oobblock) - 1;
+ this->page_shift = ffs(mtd->writesize) - 1;
this->ppb_shift = (this->erase_shift - this->page_shift);
- this->page_mask = (mtd->erasesize / mtd->oobblock) - 1;
+ this->page_mask = (mtd->erasesize / mtd->writesize) - 1;
/* REVIST: Multichip handling */
this->options |= ONENAND_CONT_LOCK;
}
+ mtd->flags = MTD_CAP_NANDFLASH;
mtd->erase = onenand_erase;
mtd->read = onenand_read;
mtd->write = onenand_write;
- mtd->read_ecc = onenand_read_ecc;
- mtd->write_ecc = onenand_write_ecc;
mtd->read_oob = onenand_read_oob;
mtd->write_oob = onenand_write_oob;
mtd->sync = onenand_sync;
void onenand_release(struct mtd_info *mtd)
{
}
-
-#endif /* CONFIG_CMD_ONENAND */