Update MTD to that of Linux 2.6.22.1

A lot changed in the Linux MTD code, since it was last ported from
Linux to U-Boot. This patch takes U-Boot NAND support to the level
of Linux 2.6.22.1 and will enable support for very large NAND devices
(4KB pages) and ease the compatibility between U-Boot and Linux
filesystems.

This patch is tested on two custom boards with PPC and ARM
processors running YAFFS in U-Boot and Linux using gcc-4.1.2
cross compilers.

MAKEALL ppc/arm has some issues:
 * DOC/OneNand/nand_spl is not building (I have not tried porting
   these parts, and since I do not have any HW and I am not familiar
   with this code/HW I think its best left to someone else.)

Except for the issues mentioned above, I have ported all drivers
necessary to run MAKEALL ppc/arm without errors and warnings. Many
drivers were trivial to port, but some were not so trivial. The
following drivers must be examined carefully and maybe rewritten to
some degree:
 cpu/ppc4xx/ndfc.c
 cpu/arm926ejs/davinci/nand.c
 board/delta/nand.c
 board/zylonite/nand.c

Signed-off-by: William Juul <william.juul@tandberg.com>
Signed-off-by: Stig Olsen <stig.olsen@tandberg.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
This commit is contained in:
William Juul 2007-10-31 13:53:06 +01:00 committed by Scott Wood
parent cd82919e6c
commit cfa460adfd
37 changed files with 4829 additions and 3436 deletions

View file

@ -37,34 +37,29 @@
/*
* hardware specific access to control-lines
*/
static void bfin_hwcontrol(struct mtd_info *mtd, int cmd)
static void bfin_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
register struct nand_chip *this = mtd->priv;
u32 IO_ADDR_W = (u32) this->IO_ADDR_W;
switch (cmd) {
case NAND_CTL_SETCLE:
this->IO_ADDR_W = CFG_NAND_BASE + BFIN_NAND_CLE;
break;
case NAND_CTL_CLRCLE:
this->IO_ADDR_W = CFG_NAND_BASE;
break;
case NAND_CTL_SETALE:
this->IO_ADDR_W = CFG_NAND_BASE + BFIN_NAND_ALE;
break;
case NAND_CTL_CLRALE:
this->IO_ADDR_W = CFG_NAND_BASE;
break;
case NAND_CTL_SETNCE:
case NAND_CTL_CLRNCE:
break;
if (ctrl & NAND_CTRL_CHANGE) {
if( ctrl & NAND_CLE )
IO_ADDR_W = CFG_NAND_BASE + BFIN_NAND_CLE;
else
IO_ADDR_W = CFG_NAND_BASE;
if( ctrl & NAND_ALE )
IO_ADDR_W = CFG_NAND_BASE + BFIN_NAND_ALE;
else
IO_ADDR_W = CFG_NAND_BASE;
this->IO_ADDR_W = (void __iomem *) IO_ADDR_W;
}
this->IO_ADDR_R = this->IO_ADDR_W;
/* Drain the writebuffer */
SSYNC();
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
int bfin_device_ready(struct mtd_info *mtd)
@ -79,11 +74,11 @@ int bfin_device_ready(struct mtd_info *mtd)
* argument are board-specific (per include/linux/mtd/nand.h):
* - IO_ADDR_R?: address to read the 8 I/O lines of the flash device
* - IO_ADDR_W?: address to write the 8 I/O lines of the flash device
* - hwcontrol: hardwarespecific function for accesing control-lines
* - cmd_ctrl: hardwarespecific function for accesing control-lines
* - dev_ready: hardwarespecific function for accesing device ready/busy line
* - enable_hwecc?: function to enable (reset) hardware ecc generator. Must
* only be provided if a hardware ECC is available
* - eccmode: mode of ecc, see defines
* - ecc.mode: mode of ecc, see defines
* - chip_delay: chip dependent delay for transfering data from array to
* read regs (tR)
* - options: various chip options. They can partly be set to inform
@ -98,8 +93,8 @@ void board_nand_init(struct nand_chip *nand)
*PORT(CONFIG_NAND_GPIO_PORT, IO_DIR) &= ~BFIN_NAND_READY;
*PORT(CONFIG_NAND_GPIO_PORT, IO_INEN) |= BFIN_NAND_READY;
nand->hwcontrol = bfin_hwcontrol;
nand->eccmode = NAND_ECC_SOFT;
nand->cmd_ctrl = bfin_hwcontrol;
nand->ecc.mode = NAND_ECC_SOFT;
nand->dev_ready = bfin_device_ready;
nand->chip_delay = 30;
}

View file

@ -21,7 +21,7 @@
*/
#include <common.h>
#include <asm/io.h>
#if defined(CONFIG_CMD_NAND)
@ -31,31 +31,28 @@
* hardware specific access to control-lines
* function borrowed from Linux 2.6 (drivers/mtd/nand/ppchameleonevb.c)
*/
static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd)
static void ppchameleonevb_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *this = mtdinfo->priv;
struct nand_chip *this = mtd->priv;
ulong base = (ulong) this->IO_ADDR_W;
switch(cmd) {
case NAND_CTL_SETCLE:
if (ctrl & NAND_CTRL_CHANGE) {
if ( ctrl & NAND_CLE )
MACRO_NAND_CTL_SETCLE((unsigned long)base);
break;
case NAND_CTL_CLRCLE:
else
MACRO_NAND_CTL_CLRCLE((unsigned long)base);
break;
case NAND_CTL_SETALE:
MACRO_NAND_CTL_SETALE((unsigned long)base);
break;
case NAND_CTL_CLRALE:
if ( ctrl & NAND_ALE )
MACRO_NAND_CTL_CLRCLE((unsigned long)base);
else
MACRO_NAND_CTL_CLRALE((unsigned long)base);
break;
case NAND_CTL_SETNCE:
if ( ctrl & NAND_NCE )
MACRO_NAND_ENABLE_CE((unsigned long)base);
break;
case NAND_CTL_CLRNCE:
else
MACRO_NAND_DISABLE_CE((unsigned long)base);
break;
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
@ -92,11 +89,11 @@ static int ppchameleonevb_device_ready(struct mtd_info *mtdinfo)
* argument are board-specific (per include/linux/mtd/nand.h):
* - IO_ADDR_R?: address to read the 8 I/O lines of the flash device
* - IO_ADDR_W?: address to write the 8 I/O lines of the flash device
* - hwcontrol: hardwarespecific function for accesing control-lines
* - cmd_ctrl: hardwarespecific function for accesing control-lines
* - dev_ready: hardwarespecific function for accesing device ready/busy line
* - enable_hwecc?: function to enable (reset) hardware ecc generator. Must
* only be provided if a hardware ECC is available
* - eccmode: mode of ecc, see defines
* - ecc.mode: mode of ecc, see defines
* - chip_delay: chip dependent delay for transfering data from array to
* read regs (tR)
* - options: various chip options. They can partly be set to inform
@ -108,9 +105,9 @@ static int ppchameleonevb_device_ready(struct mtd_info *mtdinfo)
int board_nand_init(struct nand_chip *nand)
{
nand->hwcontrol = ppchameleonevb_hwcontrol;
nand->cmd_ctrl = ppchameleonevb_hwcontrol;
nand->dev_ready = ppchameleonevb_device_ready;
nand->eccmode = NAND_ECC_SOFT;
nand->ecc.mode = NAND_ECC_SOFT;
nand->chip_delay = NAND_BIG_DELAY_US;
nand->options = NAND_SAMSUNG_LP_OPTIONS;
return 0;

View file

@ -69,7 +69,7 @@ static struct nand_oobinfo delta_oob = {
/*
* not required for Monahans DFC
*/
static void dfc_hwcontrol(struct mtd_info *mtdinfo, int cmd)
static void dfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
return;
}
@ -110,30 +110,6 @@ static void dfc_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
}
/*
* These functions are quite problematic for the DFC. Luckily they are
* not used in the current nand code, except for nand_command, which
* we've defined our own anyway. The problem is, that we always need
* to write 4 bytes to the DFC Data Buffer, but in these functions we
* don't know if to buffer the bytes/half words until we've gathered 4
* bytes or if to send them straight away.
*
* Solution: Don't use these with Mona's DFC and complain loudly.
*/
static void dfc_write_word(struct mtd_info *mtd, u16 word)
{
printf("dfc_write_word: WARNING, this function does not work with the Monahans DFC!\n");
}
static void dfc_write_byte(struct mtd_info *mtd, u_char byte)
{
printf("dfc_write_byte: WARNING, this function does not work with the Monahans DFC!\n");
}
/* The original:
* static void dfc_read_buf(struct mtd_info *mtd, const u_char *buf, int len)
*
* Shouldn't this be "u_char * const buf" ?
*/
static void dfc_read_buf(struct mtd_info *mtd, u_char* const buf, int len)
{
int i=0, j;
@ -168,7 +144,7 @@ static void dfc_read_buf(struct mtd_info *mtd, u_char* const buf, int len)
*/
static u16 dfc_read_word(struct mtd_info *mtd)
{
printf("dfc_write_byte: UNIMPLEMENTED.\n");
printf("dfc_read_word: UNIMPLEMENTED.\n");
return 0;
}
@ -289,9 +265,10 @@ static void dfc_new_cmd(void)
/* this function is called after Programm and Erase Operations to
* check for success or failure */
static int dfc_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
static int dfc_wait(struct mtd_info *mtd, struct nand_chip *this)
{
unsigned long ndsr=0, event=0;
int state = this->state;
if(state == FL_WRITING) {
event = NDSR_CS0_CMDD | NDSR_CS0_BBD;
@ -439,7 +416,7 @@ static void dfc_gpio_init(void)
* - dev_ready: hardwarespecific function for accesing device ready/busy line
* - enable_hwecc?: function to enable (reset) hardware ecc generator. Must
* only be provided if a hardware ECC is available
* - eccmode: mode of ecc, see defines
* - ecc.mode: mode of ecc, see defines
* - chip_delay: chip dependent delay for transfering data from array to
* read regs (tR)
* - options: various chip options. They can partly be set to inform
@ -561,20 +538,18 @@ int board_nand_init(struct nand_chip *nand)
/* wait(10); */
nand->hwcontrol = dfc_hwcontrol;
nand->cmd_ctrl = dfc_hwcontrol;
/* nand->dev_ready = dfc_device_ready; */
nand->eccmode = NAND_ECC_SOFT;
nand->ecc.mode = NAND_ECC_SOFT;
nand->options = NAND_BUSWIDTH_16;
nand->waitfunc = dfc_wait;
nand->read_byte = dfc_read_byte;
nand->write_byte = dfc_write_byte;
nand->read_word = dfc_read_word;
nand->write_word = dfc_write_word;
nand->read_buf = dfc_read_buf;
nand->write_buf = dfc_write_buf;
nand->cmdfunc = dfc_cmdfunc;
nand->autooob = &delta_oob;
// nand->autooob = &delta_oob;
nand->badblock_pattern = &delta_bbt_descr;
return 0;
}

View file

@ -30,28 +30,26 @@
/*
* hardware specific access to control-lines
*/
static void esd405ep_nand_hwcontrol(struct mtd_info *mtdinfo, int cmd)
static void esd405ep_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
switch(cmd) {
case NAND_CTL_SETCLE:
struct nand_chip *this = mtd->priv;
if (ctrl & NAND_CTRL_CHANGE) {
if ( ctrl & NAND_CLE )
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) | CFG_NAND_CLE);
break;
case NAND_CTL_CLRCLE:
else
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) & ~CFG_NAND_CLE);
break;
case NAND_CTL_SETALE:
if ( ctrl & NAND_ALE )
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) | CFG_NAND_ALE);
break;
case NAND_CTL_CLRALE:
else
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) & ~CFG_NAND_ALE);
break;
case NAND_CTL_SETNCE:
if ( ctrl & NAND_NCE )
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) & ~CFG_NAND_CE);
break;
case NAND_CTL_CLRNCE:
else
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) | CFG_NAND_CE);
break;
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
@ -77,9 +75,9 @@ int board_nand_init(struct nand_chip *nand)
/*
* Initialize nand_chip structure
*/
nand->hwcontrol = esd405ep_nand_hwcontrol;
nand->cmd_ctrl = esd405ep_nand_hwcontrol;
nand->dev_ready = esd405ep_nand_device_ready;
nand->eccmode = NAND_ECC_SOFT;
nand->ecc.mode = NAND_ECC_SOFT;
nand->chip_delay = NAND_BIG_DELAY_US;
nand->options = NAND_SAMSUNG_LP_OPTIONS;
return 0;

View file

@ -40,36 +40,26 @@ DECLARE_GLOBAL_DATA_PTR;
#define SET_ALE 0x08
#define CLR_ALE ~SET_ALE
static void nand_hwcontrol(struct mtd_info *mtdinfo, int cmd)
static void nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *this = mtdinfo->priv;
volatile fbcs_t *fbcs = (fbcs_t *) MMAP_FBCS;
/* volatile fbcs_t *fbcs = (fbcs_t *) MMAP_FBCS; TODO: handle wp */
u32 nand_baseaddr = (u32) this->IO_ADDR_W;
switch (cmd) {
case NAND_CTL_SETNCE:
case NAND_CTL_CLRNCE:
break;
case NAND_CTL_SETCLE:
if (ctrl & NAND_CTRL_CHANGE) {
if ( ctrl & NAND_CLE )
nand_baseaddr |= SET_CLE;
break;
case NAND_CTL_CLRCLE:
else
nand_baseaddr &= CLR_CLE;
break;
case NAND_CTL_SETALE:
if ( ctrl & NAND_ALE )
nand_baseaddr |= SET_ALE;
break;
case NAND_CTL_CLRALE:
nand_baseaddr |= CLR_ALE;
break;
case NAND_CTL_SETWP:
fbcs->csmr2 |= FBCS_CSMR_WP;
break;
case NAND_CTL_CLRWP:
fbcs->csmr2 &= ~FBCS_CSMR_WP;
break;
else
nand_baseaddr &= CLR_ALE;
}
this->IO_ADDR_W = (void __iomem *)(nand_baseaddr);
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
static void nand_write_byte(struct mtd_info *mtdinfo, u_char byte)
@ -103,8 +93,8 @@ int board_nand_init(struct nand_chip *nand)
gpio->podr_timer = 0;
nand->chip_delay = 50;
nand->eccmode = NAND_ECC_SOFT;
nand->hwcontrol = nand_hwcontrol;
nand->ecc.mode = NAND_ECC_SOFT;
nand->cmd_ctrl = nand_hwcontrol;
nand->read_byte = nand_read_byte;
nand->write_byte = nand_write_byte;
nand->dev_ready = nand_dev_ready;

View file

@ -22,7 +22,7 @@
*/
#include <common.h>
#include <asm/io.h>
#if defined(CONFIG_CMD_NAND)
@ -32,57 +32,49 @@
/*
* hardware specific access to control-lines
*/
static void nc650_hwcontrol(struct mtd_info *mtd, int cmd)
static void nc650_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *this = mtd->priv;
switch(cmd) {
case NAND_CTL_SETCLE:
if (ctrl & NAND_CTRL_CHANGE) {
if ( ctrl & NAND_CLE )
this->IO_ADDR_W += 2;
break;
case NAND_CTL_CLRCLE:
else
this->IO_ADDR_W -= 2;
break;
case NAND_CTL_SETALE:
if ( ctrl & NAND_ALE )
this->IO_ADDR_W += 1;
break;
case NAND_CTL_CLRALE:
else
this->IO_ADDR_W -= 1;
break;
case NAND_CTL_SETNCE:
case NAND_CTL_CLRNCE:
/* nop */
break;
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
#elif defined(CONFIG_IDS852_REV2)
/*
* hardware specific access to control-lines
*/
static void nc650_hwcontrol(struct mtd_info *mtd, int cmd)
static void nc650_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *this = mtd->priv;
switch(cmd) {
case NAND_CTL_SETCLE:
*(((volatile __u8 *) this->IO_ADDR_W) + 0xa) = 0;
break;
case NAND_CTL_CLRCLE:
*(((volatile __u8 *) this->IO_ADDR_W) + 0x8) = 0;
break;
case NAND_CTL_SETALE:
*(((volatile __u8 *) this->IO_ADDR_W) + 0x9) = 0;
break;
case NAND_CTL_CLRALE:
*(((volatile __u8 *) this->IO_ADDR_W) + 0x8) = 0;
break;
case NAND_CTL_SETNCE:
*(((volatile __u8 *) this->IO_ADDR_W) + 0x8) = 0;
break;
case NAND_CTL_CLRNCE:
*(((volatile __u8 *) this->IO_ADDR_W) + 0xc) = 0;
break;
if (ctrl & NAND_CTRL_CHANGE) {
if ( ctrl & NAND_CLE )
writeb(0, (volatile __u8 *) this->IO_ADDR_W + 0xa);
else
writeb(0, (volatile __u8 *) this->IO_ADDR_W) + 0x8);
if ( ctrl & NAND_ALE )
writeb(0, (volatile __u8 *) this->IO_ADDR_W) + 0x9);
else
writeb(0, (volatile __u8 *) this->IO_ADDR_W) + 0x8);
if ( ctrl & NAND_NCE )
writeb(0, (volatile __u8 *) this->IO_ADDR_W) + 0x8);
else
writeb(0, (volatile __u8 *) this->IO_ADDR_W) + 0xc);
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
#else
#error Unknown IDS852 module revision
@ -93,11 +85,11 @@ static void nc650_hwcontrol(struct mtd_info *mtd, int cmd)
* argument are board-specific (per include/linux/mtd/nand.h):
* - IO_ADDR_R?: address to read the 8 I/O lines of the flash device
* - IO_ADDR_W?: address to write the 8 I/O lines of the flash device
* - hwcontrol: hardwarespecific function for accesing control-lines
* - cmd_ctrl: hardwarespecific function for accesing control-lines
* - dev_ready: hardwarespecific function for accesing device ready/busy line
* - enable_hwecc?: function to enable (reset) hardware ecc generator. Must
* only be provided if a hardware ECC is available
* - eccmode: mode of ecc, see defines
* - eccm.ode: mode of ecc, see defines
* - chip_delay: chip dependent delay for transfering data from array to
* read regs (tR)
* - options: various chip options. They can partly be set to inform
@ -109,8 +101,8 @@ static void nc650_hwcontrol(struct mtd_info *mtd, int cmd)
int board_nand_init(struct nand_chip *nand)
{
nand->hwcontrol = nc650_hwcontrol;
nand->eccmode = NAND_ECC_SOFT;
nand->cmd_ctrl = nc650_hwcontrol;
nand->ecc.mode = NAND_ECC_SOFT;
nand->chip_delay = 12;
/* nand->options = NAND_SAMSUNG_LP_OPTIONS;*/
return 0;

View file

@ -21,6 +21,7 @@
*/
#include <common.h>
#include <asm/io.h>
#if defined(CONFIG_CMD_NAND)
@ -32,24 +33,29 @@
#define MASK_CLE 0x02
#define MASK_ALE 0x04
static void netstar_nand_hwcontrol(struct mtd_info *mtd, int cmd)
static void netstar_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *this = mtd->priv;
ulong IO_ADDR_W = (ulong) this->IO_ADDR_W;
IO_ADDR_W &= ~(MASK_ALE|MASK_CLE);
switch (cmd) {
case NAND_CTL_SETCLE: IO_ADDR_W |= MASK_CLE; break;
case NAND_CTL_SETALE: IO_ADDR_W |= MASK_ALE; break;
if (ctrl & NAND_CTRL_CHANGE) {
if ( ctrl & NAND_CLE )
IO_ADDR_W |= MASK_CLE;
if ( ctrl & NAND_ALE )
IO_ADDR_W |= MASK_ALE;
}
this->IO_ADDR_W = (void *) IO_ADDR_W;
this->IO_ADDR_W = (void __iomem *) IO_ADDR_W;
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
int board_nand_init(struct nand_chip *nand)
{
nand->options = NAND_SAMSUNG_LP_OPTIONS;
nand->eccmode = NAND_ECC_SOFT;
nand->hwcontrol = netstar_nand_hwcontrol;
nand->ecc.mode = NAND_ECC_SOFT;
nand->cmd_ctrl = netstar_nand_hwcontrol;
nand->chip_delay = 400;
return 0;
}

View file

@ -56,43 +56,24 @@ static struct alpr_ndfc_regs *alpr_ndfc = NULL;
*
* There are 2 NAND devices on the board, a Hynix HY27US08561A (1 GByte).
*/
static void alpr_nand_hwcontrol(struct mtd_info *mtd, int cmd)
static void alpr_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
switch (cmd) {
case NAND_CTL_SETCLE:
struct nand_chip *this = mtd->priv;
if (ctrl & NAND_CTRL_CHANGE) {
if ( ctrl & NAND_CLE )
hwctl |= 0x1;
break;
case NAND_CTL_CLRCLE:
else
hwctl &= ~0x1;
break;
case NAND_CTL_SETALE:
if ( ctrl & NAND_ALE )
hwctl |= 0x2;
break;
case NAND_CTL_CLRALE:
else
hwctl &= ~0x2;
break;
case NAND_CTL_SETNCE:
break;
case NAND_CTL_CLRNCE:
if ( (ctrl & NAND_NCE) != NAND_NCE)
writeb(0x00, &(alpr_ndfc->term));
break;
}
}
static void alpr_nand_write_byte(struct mtd_info *mtd, u_char byte)
{
struct nand_chip *nand = mtd->priv;
if (hwctl & 0x1)
/*
* IO_ADDR_W used as CMD[i] reg to support multiple NAND
* chips.
*/
writeb(byte, nand->IO_ADDR_W);
else if (hwctl & 0x2) {
writeb(byte, &(alpr_ndfc->addr_wait));
} else
writeb(byte, &(alpr_ndfc->data));
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
static u_char alpr_nand_read_byte(struct mtd_info *mtd)
@ -158,12 +139,10 @@ int board_nand_init(struct nand_chip *nand)
{
alpr_ndfc = (struct alpr_ndfc_regs *)CFG_NAND_BASE;
nand->eccmode = NAND_ECC_SOFT;
nand->ecc.mode = NAND_ECC_SOFT;
/* Reference hardware control function */
nand->hwcontrol = alpr_nand_hwcontrol;
/* Set command delay time */
nand->write_byte = alpr_nand_write_byte;
nand->cmd_ctrl = alpr_nand_hwcontrol;
nand->read_byte = alpr_nand_read_byte;
nand->write_buf = alpr_nand_write_buf;
nand->read_buf = alpr_nand_read_buf;

View file

@ -52,40 +52,26 @@ static struct pdnb3_ndfc_regs *pdnb3_ndfc;
*
* There is one NAND devices on the board, a Hynix HY27US08561A (32 MByte).
*/
static void pdnb3_nand_hwcontrol(struct mtd_info *mtd, int cmd)
static void pdnb3_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
switch (cmd) {
case NAND_CTL_SETCLE:
struct nand_chip *this = mtd->priv;
if (ctrl & NAND_CTRL_CHANGE) {
if ( ctrl & NAND_CLE )
hwctl |= 0x1;
break;
case NAND_CTL_CLRCLE:
hwctl &= ~0x1;
break;
case NAND_CTL_SETALE:
hwctl |= 0x2;
break;
case NAND_CTL_CLRALE:
hwctl &= ~0x2;
break;
case NAND_CTL_SETNCE:
break;
case NAND_CTL_CLRNCE:
writeb(0x00, &(pdnb3_ndfc->term));
break;
}
}
static void pdnb3_nand_write_byte(struct mtd_info *mtd, u_char byte)
{
if (hwctl & 0x1)
writeb(byte, &(pdnb3_ndfc->cmd));
else if (hwctl & 0x2)
writeb(byte, &(pdnb3_ndfc->addr));
else
writeb(byte, &(pdnb3_ndfc->data));
hwctl &= ~0x1;
if ( ctrl & NAND_ALE )
hwctl |= 0x2;
else
hwctl &= ~0x2;
if ( (ctrl & NAND_NCE) != NAND_NCE)
writeb(0x00, &(pdnb3_ndfc->term));
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
static u_char pdnb3_nand_read_byte(struct mtd_info *mtd)
{
@ -152,16 +138,13 @@ int board_nand_init(struct nand_chip *nand)
{
pdnb3_ndfc = (struct pdnb3_ndfc_regs *)CFG_NAND_BASE;
nand->eccmode = NAND_ECC_SOFT;
nand->ecc.mode = NAND_ECC_SOFT;
/* Set address of NAND IO lines (Using Linear Data Access Region) */
nand->IO_ADDR_R = (void __iomem *) ((ulong) pdnb3_ndfc + 0x4);
nand->IO_ADDR_W = (void __iomem *) ((ulong) pdnb3_ndfc + 0x4);
/* Reference hardware control function */
nand->hwcontrol = pdnb3_nand_hwcontrol;
/* Set command delay time */
nand->hwcontrol = pdnb3_nand_hwcontrol;
nand->write_byte = pdnb3_nand_write_byte;
nand->cmd_ctrl = pdnb3_nand_hwcontrol;
nand->read_byte = pdnb3_nand_read_byte;
nand->write_buf = pdnb3_nand_write_buf;
nand->read_buf = pdnb3_nand_read_buf;

View file

@ -39,30 +39,26 @@
static void *sc3_io_base;
static void *sc3_control_base = (void *)0xEF600700;
static void sc3_nand_hwcontrol(struct mtd_info *mtd, int cmd)
static void sc3_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
switch (cmd) {
case NAND_CTL_SETCLE:
struct nand_chip *this = mtd->priv;
if (ctrl & NAND_CTRL_CHANGE) {
if ( ctrl & NAND_CLE )
set_bit (SC3_NAND_CLE, sc3_control_base);
break;
case NAND_CTL_CLRCLE:
else
clear_bit (SC3_NAND_CLE, sc3_control_base);
break;
case NAND_CTL_SETALE:
if ( ctrl & NAND_ALE )
set_bit (SC3_NAND_ALE, sc3_control_base);
break;
case NAND_CTL_CLRALE:
else
clear_bit (SC3_NAND_ALE, sc3_control_base);
break;
case NAND_CTL_SETNCE:
if ( ctrl & NAND_NCE )
set_bit (SC3_NAND_CE, sc3_control_base);
break;
case NAND_CTL_CLRNCE:
else
clear_bit (SC3_NAND_CE, sc3_control_base);
break;
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
static int sc3_nand_dev_ready(struct mtd_info *mtd)
@ -79,14 +75,14 @@ static void sc3_select_chip(struct mtd_info *mtd, int chip)
int board_nand_init(struct nand_chip *nand)
{
nand->eccmode = NAND_ECC_SOFT;
nand->ecc.mode = NAND_ECC_SOFT;
sc3_io_base = (void *) CFG_NAND_BASE;
/* Set address of NAND IO lines (Using Linear Data Access Region) */
nand->IO_ADDR_R = (void __iomem *) sc3_io_base;
nand->IO_ADDR_W = (void __iomem *) sc3_io_base;
/* Reference hardware control function */
nand->hwcontrol = sc3_nand_hwcontrol;
nand->cmd_ctrl = sc3_nand_hwcontrol;
nand->dev_ready = sc3_nand_dev_ready;
nand->select_chip = sc3_select_chip;
return 0;

View file

@ -1068,24 +1068,22 @@ int update_flash_size (int flash_size)
static u8 hwctl = 0;
static void upmnand_hwcontrol(struct mtd_info *mtdinfo, int cmd)
static void upmnand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
switch (cmd) {
case NAND_CTL_SETCLE:
struct nand_chip *this = mtd->priv;
if (ctrl & NAND_CTRL_CHANGE) {
if ( ctrl & NAND_CLE )
hwctl |= 0x1;
break;
case NAND_CTL_CLRCLE:
else
hwctl &= ~0x1;
break;
case NAND_CTL_SETALE:
if ( ctrl & NAND_ALE )
hwctl |= 0x2;
break;
case NAND_CTL_CLRALE:
else
hwctl &= ~0x2;
break;
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
static void upmnand_write_byte(struct mtd_info *mtdinfo, u_char byte)
@ -1188,9 +1186,9 @@ int board_nand_init(struct nand_chip *nand)
memctl->memc_br3 = CFG_NAND_BR;
memctl->memc_mbmr = (MxMR_OP_NORM);
nand->eccmode = NAND_ECC_SOFT;
nand->ecc.mode = NAND_ECC_SOFT;
nand->hwcontrol = upmnand_hwcontrol;
nand->cmd_ctrl = upmnand_hwcontrol;
nand->read_byte = upmnand_read_byte;
nand->write_byte = upmnand_write_byte;
nand->dev_ready = tqm8272_dev_ready;

View file

@ -69,7 +69,7 @@ static struct nand_oobinfo delta_oob = {
/*
* not required for Monahans DFC
*/
static void dfc_hwcontrol(struct mtd_info *mtdinfo, int cmd)
static void dfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
return;
}
@ -110,25 +110,6 @@ static void dfc_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
}
/*
* These functions are quite problematic for the DFC. Luckily they are
* not used in the current nand code, except for nand_command, which
* we've defined our own anyway. The problem is, that we always need
* to write 4 bytes to the DFC Data Buffer, but in these functions we
* don't know if to buffer the bytes/half words until we've gathered 4
* bytes or if to send them straight away.
*
* Solution: Don't use these with Mona's DFC and complain loudly.
*/
static void dfc_write_word(struct mtd_info *mtd, u16 word)
{
printf("dfc_write_word: WARNING, this function does not work with the Monahans DFC!\n");
}
static void dfc_write_byte(struct mtd_info *mtd, u_char byte)
{
printf("dfc_write_byte: WARNING, this function does not work with the Monahans DFC!\n");
}
/* The original:
* static void dfc_read_buf(struct mtd_info *mtd, const u_char *buf, int len)
*
@ -168,7 +149,7 @@ static void dfc_read_buf(struct mtd_info *mtd, u_char* const buf, int len)
*/
static u16 dfc_read_word(struct mtd_info *mtd)
{
printf("dfc_write_byte: UNIMPLEMENTED.\n");
printf("dfc_read_word: UNIMPLEMENTED.\n");
return 0;
}
@ -289,9 +270,10 @@ static void dfc_new_cmd(void)
/* this function is called after Programm and Erase Operations to
* check for success or failure */
static int dfc_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
static int dfc_wait(struct mtd_info *mtd, struct nand_chip *this)
{
unsigned long ndsr=0, event=0;
int state = this->state;
if(state == FL_WRITING) {
event = NDSR_CS0_CMDD | NDSR_CS0_BBD;
@ -435,11 +417,11 @@ static void dfc_gpio_init(void)
* argument are board-specific (per include/linux/mtd/nand_new.h):
* - IO_ADDR_R?: address to read the 8 I/O lines of the flash device
* - IO_ADDR_W?: address to write the 8 I/O lines of the flash device
* - hwcontrol: hardwarespecific function for accesing control-lines
* - cmd_ctrl: hardwarespecific function for accesing control-lines
* - dev_ready: hardwarespecific function for accesing device ready/busy line
* - enable_hwecc?: function to enable (reset) hardware ecc generator. Must
* only be provided if a hardware ECC is available
* - eccmode: mode of ecc, see defines
* - ecc.mode: mode of ecc, see defines
* - chip_delay: chip dependent delay for transfering data from array to
* read regs (tR)
* - options: various chip options. They can partly be set to inform
@ -560,21 +542,18 @@ int board_nand_init(struct nand_chip *nand)
/* wait 10 us due to cmd buffer clear reset */
/* wait(10); */
nand->hwcontrol = dfc_hwcontrol;
nand->cmd_ctrl = dfc_hwcontrol;
/* nand->dev_ready = dfc_device_ready; */
nand->eccmode = NAND_ECC_SOFT;
nand->ecc.mode = NAND_ECC_SOFT;
nand->options = NAND_BUSWIDTH_16;
nand->waitfunc = dfc_wait;
nand->read_byte = dfc_read_byte;
nand->write_byte = dfc_write_byte;
nand->read_word = dfc_read_word;
nand->write_word = dfc_write_word;
nand->read_buf = dfc_read_buf;
nand->write_buf = dfc_write_buf;
nand->cmdfunc = dfc_cmdfunc;
nand->autooob = &delta_oob;
// nand->autooob = &delta_oob;
nand->badblock_pattern = &delta_bbt_descr;
return 0;
}

View file

@ -14,6 +14,7 @@
#include <linux/mtd/nftl.h>
#include <linux/mtd/doc2000.h>
#if 0
#ifdef CFG_DOC_SUPPORT_2000
#define DoC_is_2000(doc) (doc->ChipID == DOC_ChipID_Doc2k)
#else
@ -1629,3 +1630,6 @@ void doc_probe(unsigned long physadr)
puts ("No DiskOnChip found\n");
}
}
#else
void doc_probe(unsigned long physadr) {}
#endif

View file

@ -18,6 +18,7 @@
*
*/
#include <common.h>
#include <linux/mtd/mtd.h>
#if defined(CONFIG_CMD_NAND)
@ -47,20 +48,26 @@ static int nand_dump(nand_info_t *nand, ulong off)
int i;
u_char *buf, *p;
buf = malloc(nand->oobblock + nand->oobsize);
buf = malloc(nand->writesize + nand->oobsize);
if (!buf) {
puts("No memory for page buffer\n");
return 1;
}
off &= ~(nand->oobblock - 1);
i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize);
off &= ~(nand->writesize - 1);
#if 0
i = nand_read_raw(nand, buf, off, nand->writesize, nand->oobsize);
#else
size_t dummy;
loff_t addr = (loff_t) off;
i = nand->read(nand, addr, nand->writesize, &dummy, buf);
#endif
if (i < 0) {
printf("Error (%d) reading page %08lx\n", i, off);
free(buf);
return 1;
}
printf("Page %08lx dump:\n", off);
i = nand->oobblock >> 4; p = buf;
i = nand->writesize >> 4; p = buf;
while (i--) {
printf("\t%02x %02x %02x %02x %02x %02x %02x %02x"
" %02x %02x %02x %02x %02x %02x %02x %02x\n",
@ -155,7 +162,7 @@ out:
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
int i, dev, ret;
int i, dev, ret = 0;
ulong addr, off;
size_t size;
char *cmd, *s;
@ -250,7 +257,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) {
nand_erase_options_t opts;
/* "clean" at index 2 means request to write cleanmarker */
int clean = argc > 2 && !strcmp("clean", argv[2]);
int clean = !strcmp("clean", argv[2]);
int o = clean ? 3 : 2;
int scrub = !strcmp(cmd, "scrub");
@ -260,6 +267,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
return 1;
memset(&opts, 0, sizeof(opts));
opts.offset = off;
opts.length = size;
opts.jffs2 = clean;
@ -332,28 +340,29 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
opts.length = size;
opts.offset = off;
opts.quiet = quiet;
ret = nand_read_opts(nand, &opts);
// ret = nand_read_opts(nand, &opts);
} else {
/* write */
nand_write_options_t opts;
mtd_oob_ops_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr;
opts.length = size;
opts.offset = off;
/* opts.forcejffs2 = 1; */
opts.pad = 1;
opts.blockalign = 1;
opts.quiet = quiet;
ret = nand_write_opts(nand, &opts);
opts.datbuf = (u_char*) addr;
opts.len = size;
opts.ooblen = 64;
opts.mode = MTD_OOB_AUTO;
ret = nand_write_opts(nand, off, &opts);
}
} else if (s != NULL && !strcmp(s, ".oob")) {
/* read out-of-band data */
/* out-of-band data */
mtd_oob_ops_t ops = {
.oobbuf = (u8 *)addr,
.ooblen = size,
.mode = MTD_OOB_RAW
};
if (read)
ret = nand->read_oob(nand, off, size, &size,
(u_char *) addr);
ret = nand->read_oob(nand, off, &ops);
else
ret = nand->write_oob(nand, off, size, &size,
(u_char *) addr);
ret = nand->write_oob(nand, off, &ops);
} else {
if (read)
ret = nand_read(nand, off, &size, (u_char *)addr);
@ -397,9 +406,9 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
}
if (status) {
ulong block_start = 0;
// ulong block_start = 0;
ulong off;
int last_status = -1;
// int last_status = -1;
struct nand_chip *nand_chip = nand->priv;
/* check the WP bit */
@ -408,33 +417,33 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
(nand_chip->read_byte(nand) & 0x80 ?
"NOT " : "" ) );
for (off = 0; off < nand->size; off += nand->oobblock) {
int s = nand_get_lock_status(nand, off);
/* print message only if status has changed
* or at end of chip
*/
if (off == nand->size - nand->oobblock
|| (s != last_status && off != 0)) {
printf("%08lx - %08lx: %8lu pages %s%s%s\n",
block_start,
off-1,
(off-block_start)/nand->oobblock,
((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""),
((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""),
((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : ""));
}
last_status = s;
for (off = 0; off < nand->size; off += nand->writesize) {
// int s = nand_get_lock_status(nand, off);
//
// /* print message only if status has changed
// * or at end of chip
// */
// if (off == nand->size - nand->writesize
// || (s != last_status && off != 0)) {
//
// printf("%08lx - %08lx: %8d pages %s%s%s\n",
// block_start,
// off-1,
// (off-block_start)/nand->writesize,
// ((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""),
// ((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""),
// ((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : ""));
// }
//
// last_status = s;
}
} else {
if (!nand_lock(nand, tight)) {
puts("NAND flash successfully locked\n");
} else {
puts("Error locking NAND flash\n");
return 1;
}
// if (!nand_lock(nand, tight)) {
// puts("NAND flash successfully locked\n");
// } else {
// puts("Error locking NAND flash\n");
// return 1;
// }
}
return 0;
}
@ -443,13 +452,13 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)
return 1;
if (!nand_unlock(nand, off, size)) {
puts("NAND flash successfully unlocked\n");
} else {
puts("Error unlocking NAND flash, "
"write and erase will probably fail\n");
return 1;
}
// if (!nand_unlock(nand, off, size)) {
// puts("NAND flash successfully unlocked\n");
// } else {
// puts("Error unlocking NAND flash, "
// "write and erase will probably fail\n");
// return 1;
// }
return 0;
}
@ -463,16 +472,18 @@ U_BOOT_CMD(nand, 5, 1, do_nand,
"info - show available NAND devices\n"
"nand device [dev] - show or set current device\n"
"nand read[.jffs2] - addr off|partition size\n"
"nand write[.jffs2] - addr off|partition size - read/write `size' bytes starting\n"
" at offset `off' to/from memory address `addr'\n"
"nand erase [clean] [off size] - erase `size' bytes from\n"
" offset `off' (entire device if not specified)\n"
"nand write[.jffs2] - addr off|partition size\n"
" read/write 'size' bytes starting at offset 'off'\n"
" to/from memory address 'addr'\n"
"nand erase [clean] [off size] - erase 'size' bytes from\n"
" offset 'off' (entire device if not specified)\n"
"nand bad - show bad blocks\n"
"nand dump[.oob] off - dump page\n"
"nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
"nand markbad off - mark bad block at offset (UNSAFE)\n"
"nand biterr off - make a bit error at offset (UNSAFE)\n"
"nand lock [tight] [status] - bring nand to lock state or display locked pages\n"
"nand lock [tight] [status]\n"
" bring nand to lock state or display locked pages\n"
"nand unlock [offset] [size] - unlock section\n");
static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
@ -494,19 +505,8 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset);
cnt = nand->oobblock;
if (jffs2) {
nand_read_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr;
opts.length = cnt;
opts.offset = offset;
opts.quiet = 1;
r = nand_read_opts(nand, &opts);
} else {
cnt = nand->writesize;
r = nand_read(nand, offset, &cnt, (u_char *) addr);
}
if (r) {
puts("** Read error\n");
show_boot_progress (-56);
@ -537,18 +537,7 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
return 1;
}
if (jffs2) {
nand_read_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr;
opts.length = cnt;
opts.offset = offset;
opts.quiet = 1;
r = nand_read_opts(nand, &opts);
} else {
r = nand_read(nand, offset, &cnt, (u_char *) addr);
}
if (r) {
puts("** Read error\n");
show_boot_progress (-58);

View file

@ -42,6 +42,7 @@
*/
#include <common.h>
#include <asm/io.h>
#ifdef CFG_USE_NAND
#if !defined(CFG_NAND_LEGACY)
@ -52,23 +53,23 @@
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd)
static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *this = mtd->priv;
u_int32_t IO_ADDR_W = (u_int32_t)this->IO_ADDR_W;
IO_ADDR_W &= ~(MASK_ALE|MASK_CLE);
switch (cmd) {
case NAND_CTL_SETCLE:
if (ctrl & NAND_CTRL_CHANGE) {
if ( ctrl & NAND_CLE )
IO_ADDR_W |= MASK_CLE;
break;
case NAND_CTL_SETALE:
if ( ctrl & NAND_ALE )
IO_ADDR_W |= MASK_ALE;
break;
this->IO_ADDR_W = (void __iomem *) IO_ADDR_W;
}
this->IO_ADDR_W = (void *)IO_ADDR_W;
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
/* Set WP on deselect, write enable on select */
@ -145,7 +146,7 @@ static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
int region, n;
struct nand_chip *this = mtd->priv;
n = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1;
n = (this->ecc.size/512);
region = 1;
while (n--) {
@ -281,7 +282,7 @@ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char *
int block_count = 0, i, rc;
this = mtd->priv;
block_count = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1;
block_count = (this->ecc.size/512);
for (i = 0; i < block_count; i++) {
if (memcmp(read_ecc, calc_ecc, 3) != 0) {
rc = nand_davinci_compare_ecc(read_ecc, calc_ecc, dat);
@ -306,7 +307,7 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd)
return(emif_addr->NANDFSR & 0x1);
}
static int nand_davinci_waitfunc(struct mtd_info *mtd, struct nand_chip *this, int state)
static int nand_davinci_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
{
while(!nand_davinci_dev_ready(mtd)) {;}
*NAND_CE0CLE = NAND_STATUS;
@ -362,22 +363,26 @@ int board_nand_init(struct nand_chip *nand)
#endif
#ifdef CFG_NAND_HW_ECC
#ifdef CFG_NAND_LARGEPAGE
nand->eccmode = NAND_ECC_HW12_2048;
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.size = 2048;
nand->ecc.bytes = 12;
#elif defined(CFG_NAND_SMALLPAGE)
nand->eccmode = NAND_ECC_HW3_512;
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.size = 512;
nand->ecc.bytes = 3;
#else
#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!"
#endif
nand->autooob = &davinci_nand_oobinfo;
nand->calculate_ecc = nand_davinci_calculate_ecc;
nand->correct_data = nand_davinci_correct_data;
nand->enable_hwecc = nand_davinci_enable_hwecc;
// nand->autooob = &davinci_nand_oobinfo;
nand->ecc.calculate = nand_davinci_calculate_ecc;
nand->ecc.correct = nand_davinci_correct_data;
nand->ecc.hwctl = nand_davinci_enable_hwecc;
#else
nand->eccmode = NAND_ECC_SOFT;
nand->ecc.mode = NAND_ECC_SOFT;
#endif
/* Set address of hardware control function */
nand->hwcontrol = nand_davinci_hwcontrol;
nand->cmd_ctrl = nand_davinci_hwcontrol;
nand->dev_ready = nand_davinci_dev_ready;
nand->waitfunc = nand_davinci_waitfunc;

View file

@ -46,38 +46,22 @@
static u8 hwctl = 0;
static void ndfc_hwcontrol(struct mtd_info *mtdinfo, int cmd)
static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
switch (cmd) {
case NAND_CTL_SETCLE:
struct nand_chip *this = mtd->priv;
if (ctrl & NAND_CTRL_CHANGE) {
if ( ctrl & NAND_CLE )
hwctl |= 0x1;
break;
case NAND_CTL_CLRCLE:
hwctl &= ~0x1;
break;
case NAND_CTL_SETALE:
hwctl |= 0x2;
break;
case NAND_CTL_CLRALE:
hwctl &= ~0x2;
break;
}
}
static void ndfc_write_byte(struct mtd_info *mtdinfo, u_char byte)
{
struct nand_chip *this = mtdinfo->priv;
ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
if (hwctl & 0x1)
out_8((u8 *)(base + NDFC_CMD), byte);
else if (hwctl & 0x2)
out_8((u8 *)(base + NDFC_ALE), byte);
else
out_8((u8 *)(base + NDFC_DATA), byte);
hwctl &= ~0x1;
if ( ctrl & NAND_ALE )
hwctl |= 0x2;
else
hwctl &= ~0x2;
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
static u_char ndfc_read_byte(struct mtd_info *mtdinfo)
@ -194,16 +178,17 @@ int board_nand_init(struct nand_chip *nand)
int cs = (ulong)nand->IO_ADDR_W & 0x00000003;
ulong base = (ulong)nand->IO_ADDR_W & 0xfffffffc;
nand->hwcontrol = ndfc_hwcontrol;
nand->cmd_ctrl = ndfc_hwcontrol;
nand->read_byte = ndfc_read_byte;
nand->read_buf = ndfc_read_buf;
nand->write_byte = ndfc_write_byte;
nand->dev_ready = ndfc_dev_ready;
nand->eccmode = NAND_ECC_HW3_256;
nand->enable_hwecc = ndfc_enable_hwecc;
nand->calculate_ecc = ndfc_calculate_ecc;
nand->correct_data = nand_correct_data;
nand->ecc.correct = nand_correct_data;
nand->ecc.hwctl = ndfc_enable_hwecc;
nand->ecc.calculate = ndfc_calculate_ecc;
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.size = 256;
nand->ecc.bytes = 3;
#ifndef CONFIG_NAND_SPL
nand->write_buf = ndfc_write_buf;

View file

@ -16,7 +16,7 @@
*
* Interface to generic NAND code for M-Systems DiskOnChip devices
*
* $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $
* $Id: diskonchip.c,v 1.55 2005/11/07 11:14:30 gleixner Exp $
*/
#include <common.h>
@ -39,13 +39,13 @@
#include <linux/mtd/inftl.h>
/* Where to look for the devices? */
#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS
#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0
#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
#endif
static unsigned long __initdata doc_locations[] = {
#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH
#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
@ -65,7 +65,7 @@ static unsigned long __initdata doc_locations[] = {
0xff000000,
#elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
0xff000000,
##else
#else
#warning Unknown architecture for DiskOnChip. No default probe locations defined
#endif
0xffffffff };
@ -85,14 +85,10 @@ struct doc_priv {
struct mtd_info *nextdoc;
};
/* Max number of eraseblocks to scan (from start of device) for the (I)NFTL
MediaHeader. The spec says to just keep going, I think, but that's just
silly. */
#define MAX_MEDIAHEADER_SCAN 8
/* This is the syndrome computed by the HW ecc generator upon reading an empty
page, one with all 0xff for data and stored ecc code. */
static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a };
/* This is the ecc value computed by the HW ecc generator upon writing an empty
page, one with all 0xff for data. */
static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
@ -103,7 +99,8 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd);
static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int bitmask);
static void doc200x_select_chip(struct mtd_info *mtd, int chip);
static int debug = 0;
@ -115,23 +112,23 @@ module_param(try_dword, int, 0);
static int no_ecc_failures = 0;
module_param(no_ecc_failures, int, 0);
#ifdef CONFIG_MTD_PARTITIONS
static int no_autopart = 0;
module_param(no_autopart, int, 0);
#endif
#ifdef MTD_NAND_DISKONCHIP_BBTWRITE
static int show_firmware_partition = 0;
module_param(show_firmware_partition, int, 0);
#ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE
static int inftl_bbt_write = 1;
#else
static int inftl_bbt_write = 0;
#endif
module_param(inftl_bbt_write, int, 0);
static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS;
static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
module_param(doc_config_location, ulong, 0);
MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
/* Sector size for HW ECC */
#define SECTOR_SIZE 512
/* The sector bytes are packed into NB_DATA 10 bit words */
@ -213,8 +210,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
can be modified since pos is even */
index = (pos >> 3) ^ 1;
bitpos = pos & 7;
if ((index >= 0 && index < SECTOR_SIZE) ||
index == (SECTOR_SIZE + 1)) {
if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
val = (uint8_t) (errval[i] >> (2 + bitpos));
parity ^= val;
if (index < SECTOR_SIZE)
@ -224,8 +220,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
bitpos = (bitpos + 10) & 7;
if (bitpos == 0)
bitpos = 8;
if ((index >= 0 && index < SECTOR_SIZE) ||
index == (SECTOR_SIZE + 1)) {
if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
val = (uint8_t) (errval[i] << (8 - bitpos));
parity ^= val;
if (index < SECTOR_SIZE)
@ -261,7 +256,8 @@ static int _DoC_WaitReady(struct doc_priv *doc)
void __iomem *docptr = doc->virtadr;
unsigned long timeo = jiffies + (HZ * 10);
if(debug) printk("_DoC_WaitReady...\n");
if (debug)
printk("_DoC_WaitReady...\n");
/* Out-of-line routine to wait for chip response */
if (DoC_is_MillenniumPlus(doc)) {
while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
@ -306,7 +302,8 @@ static inline int DoC_WaitReady(struct doc_priv *doc)
DoC_Delay(doc, 2);
}
if(debug) printk("DoC_WaitReady OK\n");
if (debug)
printk("DoC_WaitReady OK\n");
return ret;
}
@ -316,7 +313,8 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
if(debug)printk("write_byte %02x\n", datum);
if (debug)
printk("write_byte %02x\n", datum);
WriteDOC(datum, docptr, CDSNSlowIO);
WriteDOC(datum, docptr, 2k_CDSN_IO);
}
@ -331,35 +329,37 @@ static u_char doc2000_read_byte(struct mtd_info *mtd)
ReadDOC(docptr, CDSNSlowIO);
DoC_Delay(doc, 2);
ret = ReadDOC(docptr, 2k_CDSN_IO);
if (debug) printk("read_byte returns %02x\n", ret);
if (debug)
printk("read_byte returns %02x\n", ret);
return ret;
}
static void doc2000_writebuf(struct mtd_info *mtd,
const u_char *buf, int len)
static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
if (debug)printk("writebuf of %d bytes: ", len);
if (debug)
printk("writebuf of %d bytes: ", len);
for (i = 0; i < len; i++) {
WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i);
if (debug && i < 16)
printk("%02x ", buf[i]);
}
if (debug) printk("\n");
if (debug)
printk("\n");
}
static void doc2000_readbuf(struct mtd_info *mtd,
u_char *buf, int len)
static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
if (debug)printk("readbuf of %d bytes: ", len);
if (debug)
printk("readbuf of %d bytes: ", len);
for (i = 0; i < len; i++) {
buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
@ -374,7 +374,8 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd,
void __iomem *docptr = doc->virtadr;
int i;
if (debug) printk("readbuf_dword of %d bytes: ", len);
if (debug)
printk("readbuf_dword of %d bytes: ", len);
if (unlikely((((unsigned long)buf) | len) & 3)) {
for (i = 0; i < len; i++) {
@ -387,8 +388,7 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd,
}
}
static int doc2000_verifybuf(struct mtd_info *mtd,
const u_char *buf, int len)
static int doc2000_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
@ -408,12 +408,15 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
uint16_t ret;
doc200x_select_chip(mtd, nr);
doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
this->write_byte(mtd, NAND_CMD_READID);
doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE);
doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
this->write_byte(mtd, 0);
doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
doc200x_hwcontrol(mtd, NAND_CMD_READID,
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/* We cant' use dev_ready here, but at least we wait for the
* command to complete
*/
udelay(50);
ret = this->read_byte(mtd) << 8;
ret |= this->read_byte(mtd);
@ -426,12 +429,13 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
} ident;
void __iomem *docptr = doc->virtadr;
doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
doc2000_write_byte(mtd, NAND_CMD_READID);
doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE);
doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
doc2000_write_byte(mtd, 0);
doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
doc200x_hwcontrol(mtd, NAND_CMD_READID,
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
doc200x_hwcontrol(mtd, NAND_CMD_NONE,
NAND_NCE | NAND_CTRL_CHANGE);
udelay(50);
ident.dword = readl(docptr + DoC_2k_CDSN_IO);
if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
@ -465,7 +469,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd)
printk(KERN_DEBUG "Detected %d chips per floor.\n", i);
}
static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
{
struct doc_priv *doc = this->priv;
@ -496,16 +500,15 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)
struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
/*ReadDOC(docptr, CDSNSlowIO); */
//ReadDOC(docptr, CDSNSlowIO);
/* 11.4.5 -- delay twice to allow extended length cycle */
DoC_Delay(doc, 2);
ReadDOC(docptr, ReadPipeInit);
/*return ReadDOC(docptr, Mil_CDSN_IO); */
//return ReadDOC(docptr, Mil_CDSN_IO);
return ReadDOC(docptr, LastDataRead);
}
static void doc2001_writebuf(struct mtd_info *mtd,
const u_char *buf, int len)
static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
@ -518,8 +521,7 @@ static void doc2001_writebuf(struct mtd_info *mtd,
WriteDOC(0x00, docptr, WritePipeTerm);
}
static void doc2001_readbuf(struct mtd_info *mtd,
u_char *buf, int len)
static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
@ -536,8 +538,7 @@ static void doc2001_readbuf(struct mtd_info *mtd,
buf[i] = ReadDOC(docptr, LastDataRead);
}
static int doc2001_verifybuf(struct mtd_info *mtd,
const u_char *buf, int len)
static int doc2001_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
@ -567,36 +568,38 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd)
ReadDOC(docptr, Mplus_ReadPipeInit);
ReadDOC(docptr, Mplus_ReadPipeInit);
ret = ReadDOC(docptr, Mplus_LastDataRead);
if (debug) printk("read_byte returns %02x\n", ret);
if (debug)
printk("read_byte returns %02x\n", ret);
return ret;
}
static void doc2001plus_writebuf(struct mtd_info *mtd,
const u_char *buf, int len)
static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
if (debug)printk("writebuf of %d bytes: ", len);
if (debug)
printk("writebuf of %d bytes: ", len);
for (i = 0; i < len; i++) {
WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
if (debug && i < 16)
printk("%02x ", buf[i]);
}
if (debug) printk("\n");
if (debug)
printk("\n");
}
static void doc2001plus_readbuf(struct mtd_info *mtd,
u_char *buf, int len)
static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
if (debug)printk("readbuf of %d bytes: ", len);
if (debug)
printk("readbuf of %d bytes: ", len);
/* Start read pipeline */
ReadDOC(docptr, Mplus_ReadPipeInit);
@ -615,18 +618,19 @@ static void doc2001plus_readbuf(struct mtd_info *mtd,
buf[len - 1] = ReadDOC(docptr, Mplus_LastDataRead);
if (debug && i < 16)
printk("%02x ", buf[len - 1]);
if (debug) printk("\n");
if (debug)
printk("\n");
}
static int doc2001plus_verifybuf(struct mtd_info *mtd,
const u_char *buf, int len)
static int doc2001plus_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
if (debug)printk("verifybuf of %d bytes: ", len);
if (debug)
printk("verifybuf of %d bytes: ", len);
/* Start read pipeline */
ReadDOC(docptr, Mplus_ReadPipeInit);
@ -652,7 +656,8 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
void __iomem *docptr = doc->virtadr;
int floor = 0;
if(debug)printk("select chip (%d)\n", chip);
if (debug)
printk("select chip (%d)\n", chip);
if (chip == -1) {
/* Disable flash internally */
@ -678,7 +683,8 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
void __iomem *docptr = doc->virtadr;
int floor = 0;
if(debug)printk("select chip (%d)\n", chip);
if (debug)
printk("select chip (%d)\n", chip);
if (chip == -1)
return;
@ -687,54 +693,42 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
chip -= (floor * doc->chips_per_floor);
/* 11.4.4 -- deassert CE before changing chip */
doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE);
doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
WriteDOC(floor, docptr, FloorSelect);
WriteDOC(chip, docptr, CDSNDeviceSelect);
doc200x_hwcontrol(mtd, NAND_CTL_SETNCE);
doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
doc->curchip = chip;
doc->curfloor = floor;
}
static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd)
#define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE)
static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
switch(cmd) {
case NAND_CTL_SETNCE:
doc->CDSNControl |= CDSN_CTRL_CE;
break;
case NAND_CTL_CLRNCE:
doc->CDSNControl &= ~CDSN_CTRL_CE;
break;
case NAND_CTL_SETCLE:
doc->CDSNControl |= CDSN_CTRL_CLE;
break;
case NAND_CTL_CLRCLE:
doc->CDSNControl &= ~CDSN_CTRL_CLE;
break;
case NAND_CTL_SETALE:
doc->CDSNControl |= CDSN_CTRL_ALE;
break;
case NAND_CTL_CLRALE:
doc->CDSNControl &= ~CDSN_CTRL_ALE;
break;
case NAND_CTL_SETWP:
doc->CDSNControl |= CDSN_CTRL_WP;
break;
case NAND_CTL_CLRWP:
doc->CDSNControl &= ~CDSN_CTRL_WP;
break;
}
if (debug)printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
if (ctrl & NAND_CTRL_CHANGE) {
doc->CDSNControl &= ~CDSN_CTRL_MSK;
doc->CDSNControl |= ctrl & CDSN_CTRL_MSK;
if (debug)
printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
WriteDOC(doc->CDSNControl, docptr, CDSNControl);
/* 11.4.3 -- 4 NOPs after CSDNControl write */
DoC_Delay(doc, 4);
}
if (cmd != NAND_CMD_NONE) {
if (DoC_is_2000(doc))
doc2000_write_byte(mtd, cmd);
else
doc2001_write_byte(mtd, cmd);
}
}
static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
{
@ -757,9 +751,9 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col
if (command == NAND_CMD_SEQIN) {
int readcmd;
if (column >= mtd->oobblock) {
if (column >= mtd->writesize) {
/* OOB area */
column -= mtd->oobblock;
column -= mtd->writesize;
readcmd = NAND_CMD_READOOB;
} else if (column < 256) {
/* First 256 bytes --> READ0 */
@ -794,7 +788,8 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col
WriteDOC(0, docptr, Mplus_WritePipeTerm);
WriteDOC(0, docptr, Mplus_WritePipeTerm);
/* deassert ALE */
if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || command == NAND_CMD_READOOB || command == NAND_CMD_READID)
if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 ||
command == NAND_CMD_READOOB || command == NAND_CMD_READID)
WriteDOC(0, docptr, Mplus_FlashControl);
}
@ -854,7 +849,8 @@ static int doc200x_dev_ready(struct mtd_info *mtd)
printk("not ready\n");
return 0;
}
if (debug)printk("was ready\n");
if (debug)
printk("was ready\n");
return 1;
} else {
/* 11.4.2 -- must NOP four times before checking FR/B# */
@ -866,7 +862,8 @@ static int doc200x_dev_ready(struct mtd_info *mtd)
}
/* 11.4.2 -- Must NOP twice if it's ready */
DoC_Delay(doc, 2);
if (debug)printk("was ready\n");
if (debug)
printk("was ready\n");
return 1;
}
}
@ -917,8 +914,7 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
}
/* This code is only called on write */
static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
unsigned char *ecc_code)
static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
@ -962,7 +958,8 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
often. It could be optimized away by examining the data in
the writebuf routine, and remembering the result. */
for (i = 0; i < 512; i++) {
if (dat[i] == 0xff) continue;
if (dat[i] == 0xff)
continue;
emptymatch = 0;
break;
}
@ -970,17 +967,20 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
/* If emptymatch still =1, we do have an all-0xff data buffer.
Return all-0xff ecc value instead of the computed one, so
it'll look just like a freshly-erased page. */
if (emptymatch) memset(ecc_code, 0xff, 6);
if (emptymatch)
memset(ecc_code, 0xff, 6);
#endif
return 0;
}
static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *isnull)
{
int i, ret = 0;
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
uint8_t calc_ecc[6];
volatile u_char dummy;
int emptymatch = 1;
@ -1013,7 +1013,8 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
all-0xff data and stored ecc block. Check the stored ecc. */
if (emptymatch) {
for (i = 0; i < 6; i++) {
if (read_ecc[i] == 0xff) continue;
if (read_ecc[i] == 0xff)
continue;
emptymatch = 0;
break;
}
@ -1024,7 +1025,8 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
often. It could be optimized away by examining the data in
the readbuf routine, and remembering the result. */
for (i = 0; i < 512; i++) {
if (dat[i] == 0xff) continue;
if (dat[i] == 0xff)
continue;
emptymatch = 0;
break;
}
@ -1033,7 +1035,8 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
erased block, in which case the ECC will not come out right.
We'll suppress the error and tell the caller everything's
OK. Because it is. */
if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc);
if (!emptymatch)
ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);
if (ret > 0)
printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
}
@ -1048,13 +1051,22 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
return ret;
}
/*u_char mydatabuf[528]; */
//u_char mydatabuf[528];
static struct nand_oobinfo doc200x_oobinfo = {
.useecc = MTD_NANDECC_AUTOPLACE,
/* The strange out-of-order .oobfree list below is a (possibly unneeded)
* attempt to retain compatibility. It used to read:
* .oobfree = { {8, 8} }
* Since that leaves two bytes unusable, it was changed. But the following
* scheme might affect existing jffs2 installs by moving the cleanmarker:
* .oobfree = { {6, 10} }
* jffs2 seems to handle the above gracefully, but the current scheme seems
* safer. The only problem with it is that any code that parses oobfree must
* be able to handle out-of-order segments.
*/
static struct nand_ecclayout doc200x_oobinfo = {
.eccbytes = 6,
.eccpos = {0, 1, 2, 3, 4, 5},
.oobfree = { {8, 8} }
.oobfree = {{8, 8}, {6, 2}}
};
/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
@ -1063,28 +1075,28 @@ static struct nand_oobinfo doc200x_oobinfo = {
either "ANAND" or "BNAND". If findmirror=1, also look for the mirror media
header. The page #s of the found media headers are placed in mh0_page and
mh1_page in the DOC private structure. */
static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
const char *id, int findmirror)
static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift);
unsigned offs;
int ret;
size_t retlen;
end = min(end, mtd->size); /* paranoia */
for (offs = 0; offs < end; offs += mtd->erasesize) {
ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
if (retlen != mtd->oobblock) continue;
for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf);
if (retlen != mtd->writesize)
continue;
if (ret) {
printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n",
offs);
printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", offs);
}
if (memcmp(buf, id, 6)) continue;
if (memcmp(buf, id, 6))
continue;
printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
if (doc->mh0_page == -1) {
doc->mh0_page = offs >> this->page_shift;
if (!findmirror) return 1;
if (!findmirror)
return 1;
continue;
}
doc->mh1_page = offs >> this->page_shift;
@ -1097,8 +1109,8 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
/* Only one mediaheader was found. We want buf to contain a
mediaheader on return, so we'll have to re-read the one we found. */
offs = doc->mh0_page << this->page_shift;
ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
if (retlen != mtd->oobblock) {
ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf);
if (retlen != mtd->writesize) {
/* Insanity. Give up. */
printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
return 0;
@ -1106,8 +1118,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
return 1;
}
static inline int __init nftl_partscan(struct mtd_info *mtd,
struct mtd_partition *parts)
static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
@ -1115,19 +1126,23 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
u_char *buf;
struct NFTLMediaHeader *mh;
const unsigned psize = 1 << this->page_shift;
int numparts = 0;
unsigned blocks, maxblocks;
int offs, numheaders;
buf = kmalloc(mtd->oobblock, GFP_KERNEL);
buf = kmalloc(mtd->writesize, GFP_KERNEL);
if (!buf) {
printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
return 0;
}
if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out;
if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1)))
goto out;
mh = (struct NFTLMediaHeader *)buf;
/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */
/* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */
mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits);
mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN);
mh->FormattedSize = le32_to_cpu(mh->FormattedSize);
printk(KERN_INFO " DataOrgID = %s\n"
" NumEraseUnits = %d\n"
" FirstPhysicalEUN = %d\n"
@ -1136,7 +1151,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
mh->DataOrgID, mh->NumEraseUnits,
mh->FirstPhysicalEUN, mh->FormattedSize,
mh->UnitSizeFactor);
/*#endif */
blocks = mtd->size >> this->phys_erase_shift;
maxblocks = min(32768U, mtd->erasesize - psize);
@ -1179,31 +1193,35 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
offs <<= this->page_shift;
offs += mtd->erasesize;
/*parts[0].name = " DiskOnChip Boot / Media Header partition"; */
/*parts[0].offset = 0; */
/*parts[0].size = offs; */
parts[0].name = " DiskOnChip BDTL partition";
parts[0].offset = offs;
parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
offs += parts[0].size;
if (offs < mtd->size) {
parts[1].name = " DiskOnChip Remainder partition";
parts[1].offset = offs;
parts[1].size = mtd->size - offs;
ret = 2;
goto out;
if (show_firmware_partition == 1) {
parts[0].name = " DiskOnChip Firmware / Media Header partition";
parts[0].offset = 0;
parts[0].size = offs;
numparts = 1;
}
ret = 1;
parts[numparts].name = " DiskOnChip BDTL partition";
parts[numparts].offset = offs;
parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
offs += parts[numparts].size;
numparts++;
if (offs < mtd->size) {
parts[numparts].name = " DiskOnChip Remainder partition";
parts[numparts].offset = offs;
parts[numparts].size = mtd->size - offs;
numparts++;
}
ret = numparts;
out:
kfree(buf);
return ret;
}
/* This is a stripped-down copy of the code in inftlmount.c */
static inline int __init inftl_partscan(struct mtd_info *mtd,
struct mtd_partition *parts)
static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
@ -1220,13 +1238,14 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
if (inftl_bbt_write)
end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
buf = kmalloc(mtd->oobblock, GFP_KERNEL);
buf = kmalloc(mtd->writesize, GFP_KERNEL);
if (!buf) {
printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
return 0;
}
if (!find_media_headers(mtd, buf, "BNAND", 0)) goto out;
if (!find_media_headers(mtd, buf, "BNAND", 0))
goto out;
doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
mh = (struct INFTLMediaHeader *)buf;
@ -1237,8 +1256,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */
/* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */
printk(KERN_INFO " bootRecordID = %s\n"
" NoOfBootImageBlocks = %d\n"
" NoOfBinaryPartitions = %d\n"
@ -1256,7 +1273,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
((unsigned char *) &mh->OsakVersion)[2] & 0xf,
((unsigned char *) &mh->OsakVersion)[3] & 0xf,
mh->PercentUsed);
/*#endif */
vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
@ -1282,8 +1298,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
ip->spareUnits = le32_to_cpu(ip->spareUnits);
ip->Reserved0 = le32_to_cpu(ip->Reserved0);
/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */
/* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */
printk(KERN_INFO " PARTITION[%d] ->\n"
" virtualUnits = %d\n"
" firstUnit = %d\n"
@ -1293,16 +1307,14 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
i, ip->virtualUnits, ip->firstUnit,
ip->lastUnit, ip->flags,
ip->spareUnits);
/*#endif */
/*
if ((i == 0) && (ip->firstUnit > 0)) {
if ((show_firmware_partition == 1) &&
(i == 0) && (ip->firstUnit > 0)) {
parts[0].name = " DiskOnChip IPL / Media Header partition";
parts[0].offset = 0;
parts[0].size = mtd->erasesize * ip->firstUnit;
numparts = 1;
}
*/
if (ip->flags & INFTL_BINARY)
parts[numparts].name = " DiskOnChip BDK partition";
@ -1311,8 +1323,10 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
parts[numparts].offset = ip->firstUnit << vshift;
parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;
numparts++;
if (ip->lastUnit > lastvunit) lastvunit = ip->lastUnit;
if (ip->flags & INFTL_LAST) break;
if (ip->lastUnit > lastvunit)
lastvunit = ip->lastUnit;
if (ip->flags & INFTL_LAST)
break;
}
lastvunit++;
if ((lastvunit << vshift) < end) {
@ -1338,7 +1352,8 @@ static int __init nftl_scan_bbt(struct mtd_info *mtd)
/* On NFTL, we have to find the media headers before we can read the
BBTs, since they're stored in the media header eraseblocks. */
numparts = nftl_partscan(mtd, parts);
if (!numparts) return -EIO;
if (!numparts)
return -EIO;
this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
NAND_BBT_VERSION;
@ -1385,8 +1400,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
this->bbt_td->pages[0] = 2;
this->bbt_md = NULL;
} else {
this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT |
NAND_BBT_VERSION;
this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
if (inftl_bbt_write)
this->bbt_td->options |= NAND_BBT_WRITE;
this->bbt_td->offs = 8;
@ -1396,8 +1410,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
this->bbt_td->reserved_block_code = 0x01;
this->bbt_td->pattern = "MSYS_BBT";
this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT |
NAND_BBT_VERSION;
this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
if (inftl_bbt_write)
this->bbt_md->options |= NAND_BBT_WRITE;
this->bbt_md->offs = 8;
@ -1417,7 +1430,8 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
/* At least for now, require the INFTL Media Header. We could probably
do without it for non-INFTL use, since all it gives us is
autopartitioning, but I want to give it more thought. */
if (!numparts) return -EIO;
if (!numparts)
return -EIO;
add_mtd_device(mtd);
#ifdef CONFIG_MTD_PARTITIONS
if (!no_autopart)
@ -1431,7 +1445,6 @@ static inline int __init doc2000_init(struct mtd_info *mtd)
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
this->write_byte = doc2000_write_byte;
this->read_byte = doc2000_read_byte;
this->write_buf = doc2000_writebuf;
this->read_buf = doc2000_readbuf;
@ -1449,7 +1462,6 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
this->write_byte = doc2001_write_byte;
this->read_byte = doc2001_read_byte;
this->write_buf = doc2001_writebuf;
this->read_buf = doc2001_readbuf;
@ -1481,16 +1493,15 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
this->write_byte = NULL;
this->read_byte = doc2001plus_read_byte;
this->write_buf = doc2001plus_writebuf;
this->read_buf = doc2001plus_readbuf;
this->verify_buf = doc2001plus_verifybuf;
this->scan_bbt = inftl_scan_bbt;
this->hwcontrol = NULL;
this->cmd_ctrl = NULL;
this->select_chip = doc2001plus_select_chip;
this->cmdfunc = doc2001plus_command;
this->enable_hwecc = doc2001plus_enable_hwecc;
this->ecc.hwctl = doc2001plus_enable_hwecc;
doc->chips_per_floor = 1;
mtd->name = "DiskOnChip Millennium Plus";
@ -1498,7 +1509,7 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
return 1;
}
static inline int __init doc_probe(unsigned long physadr)
static int __init doc_probe(unsigned long physadr)
{
unsigned char ChipID;
struct mtd_info *mtd;
@ -1527,16 +1538,12 @@ static inline int __init doc_probe(unsigned long physadr)
save_control = ReadDOC(virtadr, DOCControl);
/* Reset the DiskOnChip ASIC */
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
virtadr, DOCControl);
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
virtadr, DOCControl);
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
/* Enable the DiskOnChip ASIC */
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
virtadr, DOCControl);
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
virtadr, DOCControl);
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
ChipID = ReadDOC(virtadr, ChipID);
@ -1556,15 +1563,13 @@ static inline int __init doc_probe(unsigned long physadr)
ReadDOC(virtadr, Mplus_Power);
/* Reset the Millennium Plus ASIC */
tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
DOC_MODE_BDECT;
tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
WriteDOC(tmp, virtadr, Mplus_DOCControl);
WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
mdelay(1);
/* Enable the Millennium Plus ASIC */
tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
DOC_MODE_BDECT;
tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
WriteDOC(tmp, virtadr, Mplus_DOCControl);
WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
mdelay(1);
@ -1618,11 +1623,11 @@ static inline int __init doc_probe(unsigned long physadr)
if (ChipID == DOC_ChipID_DocMilPlus16) {
WriteDOC(~newval, virtadr, Mplus_AliasResolution);
oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
WriteDOC(newval, virtadr, Mplus_AliasResolution); /* restore it */
WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it
} else {
WriteDOC(~newval, virtadr, AliasResolution);
oldval = ReadDOC(doc->virtadr, AliasResolution);
WriteDOC(newval, virtadr, AliasResolution); /* restore it */
WriteDOC(newval, virtadr, AliasResolution); // restore it
}
newval = ~newval;
if (oldval == newval) {
@ -1634,16 +1639,13 @@ static inline int __init doc_probe(unsigned long physadr)
printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);
len = sizeof(struct mtd_info) +
sizeof(struct nand_chip) +
sizeof(struct doc_priv) +
(2 * sizeof(struct nand_bbt_descr));
mtd = kmalloc(len, GFP_KERNEL);
sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr));
mtd = kzalloc(len, GFP_KERNEL);
if (!mtd) {
printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);
ret = -ENOMEM;
goto fail;
}
memset(mtd, 0, len);
nand = (struct nand_chip *) (mtd + 1);
doc = (struct doc_priv *) (nand + 1);
@ -1655,17 +1657,19 @@ static inline int __init doc_probe(unsigned long physadr)
nand->priv = doc;
nand->select_chip = doc200x_select_chip;
nand->hwcontrol = doc200x_hwcontrol;
nand->cmd_ctrl = doc200x_hwcontrol;
nand->dev_ready = doc200x_dev_ready;
nand->waitfunc = doc200x_wait;
nand->block_bad = doc200x_block_bad;
nand->enable_hwecc = doc200x_enable_hwecc;
nand->calculate_ecc = doc200x_calculate_ecc;
nand->correct_data = doc200x_correct_data;
nand->ecc.hwctl = doc200x_enable_hwecc;
nand->ecc.calculate = doc200x_calculate_ecc;
nand->ecc.correct = doc200x_correct_data;
nand->autooob = &doc200x_oobinfo;
nand->eccmode = NAND_ECC_HW6_512;
nand->options = NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME;
nand->ecc.layout = &doc200x_oobinfo;
nand->ecc.mode = NAND_ECC_HW_SYNDROME;
nand->ecc.size = 512;
nand->ecc.bytes = 6;
nand->options = NAND_USE_FLASH_BBT;
doc->physadr = physadr;
doc->virtadr = virtadr;

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,7 @@
*
* Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
*
* $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $
* $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -48,7 +48,7 @@
*
* Following assumptions are made:
* - bbts start at a page boundary, if autolocated on a block boundary
* - the space neccecary for a bbt in FLASH does not exceed a block boundary
* - the space necessary for a bbt in FLASH does not exceed a block boundary
*
*/
@ -63,6 +63,19 @@
#include <asm/errno.h>
/* XXX U-BOOT XXX */
#if 0
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/compatmac.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#endif
/**
* check_pattern - [GENERIC] check if a pattern is in the buffer
* @buf: the buffer to search
@ -78,7 +91,7 @@
*/
static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
{
int i, end;
int i, end = 0;
uint8_t *p = buf;
end = paglen + td->offs;
@ -96,9 +109,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
return -1;
}
if (td->options & NAND_BBT_SCANEMPTY) {
p += td->len;
end += td->len;
if (td->options & NAND_BBT_SCANEMPTY) {
for (i = end; i < len; i++) {
if (*p++ != 0xff)
return -1;
@ -107,6 +120,29 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
return 0;
}
/**
* check_short_pattern - [GENERIC] check if a pattern is in the buffer
* @buf: the buffer to search
* @td: search pattern descriptor
*
* Check for a pattern at the given place. Used to search bad block
* tables and good / bad block identifiers. Same as check_pattern, but
* no optional empty check
*
*/
static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
{
int i;
uint8_t *p = buf;
/* Compare the pattern */
for (i = 0; i < td->len; i++) {
if (p[td->offs + i] != td->pattern[i])
return -1;
}
return 0;
}
/**
* read_bbt - [GENERIC] Read the bad block table starting from page
* @mtd: MTD device structure
@ -134,7 +170,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
while (totlen) {
len = min(totlen, (size_t) (1 << this->bbt_erase_shift));
res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob);
res = mtd->read(mtd, from, len, &retlen, buf);
if (res < 0) {
if (retlen != len) {
printk(KERN_INFO "nand_bbt: Error reading bad block table\n");
@ -150,11 +186,11 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
uint8_t tmp = (dat >> j) & msk;
if (tmp == msk)
continue;
if (reserved_block_code &&
(tmp == reserved_block_code)) {
if (reserved_block_code && (tmp == reserved_block_code)) {
printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n",
((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
mtd->ecc_stats.bbtblocks++;
continue;
}
/* Leave it for now, if its matured we can move this
@ -166,6 +202,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
else
this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
mtd->ecc_stats.badblocks++;
}
}
totlen -= len;
@ -209,6 +246,42 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
return 0;
}
/*
* Scan read raw data from flash
*/
static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
size_t len)
{
struct mtd_oob_ops ops;
ops.mode = MTD_OOB_RAW;
ops.ooboffs = 0;
ops.ooblen = mtd->oobsize;
ops.oobbuf = buf;
ops.datbuf = buf;
ops.len = len;
return mtd->read_oob(mtd, offs, &ops);
}
/*
* Scan write data with oob to flash
*/
static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
uint8_t *buf, uint8_t *oob)
{
struct mtd_oob_ops ops;
ops.mode = MTD_OOB_PLACE;
ops.ooboffs = 0;
ops.ooblen = mtd->oobsize;
ops.datbuf = buf;
ops.oobbuf = oob;
ops.len = len;
return mtd->write_oob(mtd, offs, &ops);
}
/**
* read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
* @mtd: MTD device structure
@ -220,27 +293,83 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
* We assume that the bbt bits are in consecutive order.
*
*/
static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td,
struct nand_bbt_descr *md)
static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr *td, struct nand_bbt_descr *md)
{
struct nand_chip *this = mtd->priv;
/* Read the primary version, if available */
if (td->options & NAND_BBT_VERSION) {
nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
td->version[0] = buf[mtd->oobblock + td->veroffs];
printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]);
scan_read_raw(mtd, buf, td->pages[0] << this->page_shift,
mtd->writesize);
td->version[0] = buf[mtd->writesize + td->veroffs];
printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
td->pages[0], td->version[0]);
}
/* Read the mirror version, if available */
if (md && (md->options & NAND_BBT_VERSION)) {
nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
md->version[0] = buf[mtd->oobblock + md->veroffs];
printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]);
scan_read_raw(mtd, buf, md->pages[0] << this->page_shift,
mtd->writesize);
md->version[0] = buf[mtd->writesize + md->veroffs];
printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
md->pages[0], md->version[0]);
}
return 1;
}
/*
* Scan a given block full
*/
static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
loff_t offs, uint8_t *buf, size_t readlen,
int scanlen, int len)
{
int ret, j;
ret = scan_read_raw(mtd, buf, offs, readlen);
if (ret)
return ret;
for (j = 0; j < len; j++, buf += scanlen) {
if (check_pattern(buf, scanlen, mtd->writesize, bd))
return 1;
}
return 0;
}
/*
* Scan a given block partially
*/
static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
loff_t offs, uint8_t *buf, int len)
{
struct mtd_oob_ops ops;
int j, ret;
ops.ooblen = mtd->oobsize;
ops.oobbuf = buf;
ops.ooboffs = 0;
ops.datbuf = NULL;
ops.mode = MTD_OOB_PLACE;
for (j = 0; j < len; j++) {
/*
* Read the full oob until read_oob is fixed to
* handle single byte reads for 16 bit
* buswidth
*/
ret = mtd->read_oob(mtd, offs, &ops);
if (ret)
return ret;
if (check_short_pattern(buf, bd))
return 1;
offs += mtd->writesize;
}
return 0;
}
/**
* create_bbt - [GENERIC] Create a bad block table by scanning the device
@ -253,13 +382,16 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de
* Create a bad block table by scanning the device
* for the given good/bad block identify pattern
*/
static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr *bd, int chip)
{
struct nand_chip *this = mtd->priv;
int i, j, numblocks, len, scanlen;
int i, numblocks, len, scanlen;
int startblock;
loff_t from;
size_t readlen, ooblen;
size_t readlen;
printk(KERN_INFO "Scanning device for bad blocks\n");
if (bd->options & NAND_BBT_SCANALLPAGES)
len = 1 << (this->bbt_erase_shift - this->page_shift);
@ -269,13 +401,20 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
else
len = 1;
}
scanlen = mtd->oobblock + mtd->oobsize;
readlen = len * mtd->oobblock;
ooblen = len * mtd->oobsize;
if (!(bd->options & NAND_BBT_SCANEMPTY)) {
/* We need only read few bytes from the OOB area */
scanlen = 0;
readlen = bd->len;
} else {
/* Full page content should be read */
scanlen = mtd->writesize + mtd->oobsize;
readlen = len * mtd->writesize;
}
if (chip == -1) {
/* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
* makes shifting and masking less painful */
/* Note that numblocks is 2 * (real numblocks) here, see i+=2
* below as it makes shifting and masking less painful */
numblocks = mtd->size >> (this->bbt_erase_shift - 1);
startblock = 0;
from = 0;
@ -283,7 +422,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
if (chip >= this->numchips) {
printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",
chip + 1, this->numchips);
return;
return -EINVAL;
}
numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
startblock = chip * numblocks;
@ -292,16 +431,28 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
}
for (i = startblock; i < numblocks;) {
nand_read_raw (mtd, buf, from, readlen, ooblen);
for (j = 0; j < len; j++) {
if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
int ret;
if (bd->options & NAND_BBT_SCANALLPAGES)
ret = scan_block_full(mtd, bd, from, buf, readlen,
scanlen, len);
else
ret = scan_block_fast(mtd, bd, from, buf, len);
if (ret < 0)
return ret;
if (ret) {
this->bbt[i >> 3] |= 0x03 << (i & 0x6);
break;
}
printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
i >> 1, (unsigned int)from);
mtd->ecc_stats.badblocks++;
}
i += 2;
from += (1 << this->bbt_erase_shift);
}
return 0;
}
/**
@ -316,7 +467,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
* block.
* If the option NAND_BBT_PERCHIP is given, each chip is searched
* for a bbt, which contains the bad block information of this chip.
* This is neccecary to provide support for certain DOC devices.
* This is necessary to provide support for certain DOC devices.
*
* The bbt ident pattern resides in the oob area of the first page
* in a block.
@ -326,8 +477,9 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
struct nand_chip *this = mtd->priv;
int i, chips;
int bits, startblock, block, dir;
int scanlen = mtd->oobblock + mtd->oobsize;
int scanlen = mtd->writesize + mtd->oobsize;
int bbtblocks;
int blocktopage = this->bbt_erase_shift - this->page_shift;
/* Search direction top -> down ? */
if (td->options & NAND_BBT_LASTBLOCK) {
@ -357,13 +509,16 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
td->pages[i] = -1;
/* Scan the maximum number of blocks */
for (block = 0; block < td->maxblocks; block++) {
int actblock = startblock + dir * block;
loff_t offs = actblock << this->bbt_erase_shift;
/* Read first page */
nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize);
if (!check_pattern(buf, scanlen, mtd->oobblock, td)) {
td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift);
scan_read_raw(mtd, buf, offs, mtd->writesize);
if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
td->pages[i] = actblock << blocktopage;
if (td->options & NAND_BBT_VERSION) {
td->version[i] = buf[mtd->oobblock + td->veroffs];
td->version[i] = buf[mtd->writesize + td->veroffs];
}
break;
}
@ -375,7 +530,8 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
if (td->pages[i] == -1)
printk(KERN_WARNING "Bad block table not found for chip %d\n", i);
else
printk (KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]);
printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i],
td->version[i]);
}
return 0;
}
@ -389,8 +545,7 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
*
* Search and read the bad block table(s)
*/
static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr *td, struct nand_bbt_descr *md)
static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)
{
/* Search the primary table */
search_bbt(mtd, buf, td);
@ -403,7 +558,6 @@ static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf,
return 1;
}
/**
* write_bbt - [GENERIC] (Re)write the bad block table
*
@ -417,18 +571,24 @@ static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf,
*
*/
static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel)
struct nand_bbt_descr *td, struct nand_bbt_descr *md,
int chipsel)
{
struct nand_chip *this = mtd->priv;
struct nand_oobinfo oobinfo;
struct erase_info einfo;
int i, j, res, chip = 0;
int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
int nrchips, bbtoffs, pageoffs;
int nrchips, bbtoffs, pageoffs, ooboffs;
uint8_t msk[4];
uint8_t rcode = td->reserved_block_code;
size_t retlen, len = 0;
loff_t to;
struct mtd_oob_ops ops;
ops.ooblen = mtd->oobsize;
ops.ooboffs = 0;
ops.datbuf = NULL;
ops.mode = MTD_OOB_PLACE;
if (!rcode)
rcode = 0xff;
@ -472,12 +632,14 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
for (i = 0; i < td->maxblocks; i++) {
int block = startblock + dir * i;
/* Check, if the block is bad */
switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) {
switch ((this->bbt[block >> 2] >>
(2 * (block & 0x03))) & 0x03) {
case 0x01:
case 0x03:
continue;
}
page = block << (this->bbt_erase_shift - this->page_shift);
page = block <<
(this->bbt_erase_shift - this->page_shift);
/* Check, if the block is used by the mirror table */
if (!md || md->pages[chip] != page)
goto write;
@ -488,11 +650,20 @@ write:
/* Set up shift count and masks for the flash table */
bits = td->options & NAND_BBT_NRBITS_MSK;
msk[2] = ~rcode;
switch (bits) {
case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x01; break;
case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x03; break;
case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; msk[2] = ~rcode; msk[3] = 0x0f; break;
case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break;
case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;
msk[3] = 0x01;
break;
case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;
msk[3] = 0x03;
break;
case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;
msk[3] = 0x0f;
break;
case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;
msk[3] = 0xff;
break;
default: return -EINVAL;
}
@ -500,48 +671,55 @@ write:
to = ((loff_t) page) << this->page_shift;
memcpy (&oobinfo, this->autooob, sizeof(oobinfo));
oobinfo.useecc = MTD_NANDECC_PLACEONLY;
/* Must we save the block contents ? */
if (td->options & NAND_BBT_SAVECONTENT) {
/* Make it block aligned */
to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));
len = 1 << this->bbt_erase_shift;
res = mtd->read_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
res = mtd->read(mtd, to, len, &retlen, buf);
if (res < 0) {
if (retlen != len) {
printk (KERN_INFO "nand_bbt: Error reading block for writing the bad block table\n");
printk(KERN_INFO "nand_bbt: Error "
"reading block for writing "
"the bad block table\n");
return res;
}
printk (KERN_WARNING "nand_bbt: ECC error while reading block for writing bad block table\n");
printk(KERN_WARNING "nand_bbt: ECC error "
"while reading block for writing "
"bad block table\n");
}
/* Read oob data */
ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
ops.oobbuf = &buf[len];
res = mtd->read_oob(mtd, to + mtd->writesize, &ops);
if (res < 0 || ops.oobretlen != ops.ooblen)
goto outerr;
/* Calc the byte offset in the buffer */
pageoffs = page - (int)(to >> this->page_shift);
offs = pageoffs << this->page_shift;
/* Preset the bbt area with 0xff */
memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));
/* Preset the bbt's oob area with 0xff */
memset (&buf[len + pageoffs * mtd->oobsize], 0xff,
((len >> this->page_shift) - pageoffs) * mtd->oobsize);
if (td->options & NAND_BBT_VERSION) {
buf[len + (pageoffs * mtd->oobsize) + td->veroffs] = td->version[chip];
}
ooboffs = len + (pageoffs * mtd->oobsize);
} else {
/* Calc length */
len = (size_t) (numblocks >> sft);
/* Make it page aligned ! */
len = (len + (mtd->oobblock-1)) & ~(mtd->oobblock-1);
len = (len + (mtd->writesize - 1)) &
~(mtd->writesize - 1);
/* Preset the buffer with 0xff */
memset (buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize);
memset(buf, 0xff, len +
(len >> this->page_shift)* mtd->oobsize);
offs = 0;
ooboffs = len;
/* Pattern is located in oob area of first page */
memcpy (&buf[len + td->offs], td->pattern, td->len);
if (td->options & NAND_BBT_VERSION) {
buf[len + td->veroffs] = td->version[chip];
}
memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);
}
if (td->options & NAND_BBT_VERSION)
buf[ooboffs + td->veroffs] = td->version[chip];
/* walk through the memory table */
for (i = 0; i < numblocks;) {
uint8_t dat;
@ -549,7 +727,8 @@ write:
for (j = 0; j < 4; j++, i++) {
int sftcnt = (i << (3 - sft)) & sftmsk;
/* Do not store the reserved bbt blocks ! */
buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt);
buf[offs + (i >> sft)] &=
~(msk[dat & 0x03] << sftcnt);
dat >>= 2;
}
}
@ -559,23 +738,25 @@ write:
einfo.addr = (unsigned long)to;
einfo.len = 1 << this->bbt_erase_shift;
res = nand_erase_nand(mtd, &einfo, 1);
if (res < 0) {
printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res);
return res;
}
if (res < 0)
goto outerr;
res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
if (res < 0) {
printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res);
return res;
}
printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n",
(unsigned int) to, td->version[chip]);
res = scan_write_bbt(mtd, to, len, buf, &buf[len]);
if (res < 0)
goto outerr;
printk(KERN_DEBUG "Bad block table written to 0x%08x, version "
"0x%02X\n", (unsigned int)to, td->version[chip]);
/* Mark it as used */
td->pages[chip] = page;
}
return 0;
outerr:
printk(KERN_WARNING
"nand_bbt: Error while writing bad block table %d\n", res);
return res;
}
/**
@ -586,26 +767,24 @@ write:
* The function creates a memory based bbt by scanning the device
* for manufacturer / software marked good / bad blocks
*/
static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
struct nand_chip *this = mtd->priv;
/* Ensure that we only scan for the pattern and nothing else */
bd->options = 0;
create_bbt (mtd, this->data_buf, bd, -1);
return 0;
bd->options &= ~NAND_BBT_SCANEMPTY;
return create_bbt(mtd, this->buffers->databuf, bd, -1);
}
/**
* check_create - [GENERIC] create and write bbt(s) if neccecary
* check_create - [GENERIC] create and write bbt(s) if necessary
* @mtd: MTD device structure
* @buf: temporary buffer
* @bd: descriptor for the good/bad block search pattern
*
* The function checks the results of the previous call to read_bbt
* and creates / updates the bbt(s) if neccecary
* Creation is neccecary if no bbt was found for the chip/device
* Update is neccecary if one of the tables is missing or the
* and creates / updates the bbt(s) if necessary
* Creation is necessary if no bbt was found for the chip/device
* Update is necessary if one of the tables is missing or the
* version nr. of one table is less than the other
*/
static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
@ -739,7 +918,8 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
for (i = 0; i < chips; i++) {
if ((td->options & NAND_BBT_ABSPAGE) ||
!(td->options & NAND_BBT_WRITE)) {
if (td->pages[i] == -1) continue;
if (td->pages[i] == -1)
continue;
block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
block <<= 1;
oldval = this->bbt[(block >> 3)];
@ -759,7 +939,8 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
oldval = this->bbt[(block >> 3)];
newval = oldval | (0x2 << (block & 0x06));
this->bbt[(block >> 3)] = newval;
if (oldval != newval) update = 1;
if (oldval != newval)
update = 1;
block += 2;
}
/* If we want reserved blocks to be recorded to flash, and some
@ -793,25 +974,29 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
struct nand_bbt_descr *md = this->bbt_md;
len = mtd->size >> (this->bbt_erase_shift + 2);
/* Allocate memory (2bit per block) */
this->bbt = kmalloc (len, GFP_KERNEL);
/* Allocate memory (2bit per block) and clear the memory bad block table */
this->bbt = kzalloc(len, GFP_KERNEL);
if (!this->bbt) {
printk(KERN_ERR "nand_scan_bbt: Out of memory\n");
return -ENOMEM;
}
/* Clear the memory bad block table */
memset (this->bbt, 0x00, len);
/* If no primary table decriptor is given, scan the device
* to build a memory based bad block table
*/
if (!td)
return nand_memory_bbt(mtd, bd);
if (!td) {
if ((res = nand_memory_bbt(mtd, bd))) {
printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n");
kfree(this->bbt);
this->bbt = NULL;
}
return res;
}
/* Allocate a temporary buffer for one eraseblock incl. oob */
len = (1 << this->bbt_erase_shift);
len += (len >> this->page_shift) * mtd->oobsize;
buf = kmalloc (len, GFP_KERNEL);
buf = vmalloc(len);
if (!buf) {
printk(KERN_ERR "nand_bbt: Out of memory\n");
kfree(this->bbt);
@ -835,11 +1020,10 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
if (md)
mark_bbt_region(mtd, md);
kfree (buf);
vfree(buf);
return res;
}
/**
* nand_update_bbt - [NAND Interface] update bad block table(s)
* @mtd: MTD device structure
@ -901,14 +1085,11 @@ out:
}
/* Define some generic bad / good block scan pattern which are used
* while scanning a device for factory marked good / bad blocks
*
* The memory based patterns just
*/
* while scanning a device for factory marked good / bad blocks. */
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
static struct nand_bbt_descr smallpage_memorybased = {
.options = 0,
.options = NAND_BBT_SCAN2NDPAGE,
.offs = 5,
.len = 1,
.pattern = scan_ff_pattern
@ -922,14 +1103,14 @@ static struct nand_bbt_descr largepage_memorybased = {
};
static struct nand_bbt_descr smallpage_flashbased = {
.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
.options = NAND_BBT_SCAN2NDPAGE,
.offs = 5,
.len = 1,
.pattern = scan_ff_pattern
};
static struct nand_bbt_descr largepage_flashbased = {
.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
.options = NAND_BBT_SCAN2NDPAGE,
.offs = 0,
.len = 2,
.pattern = scan_ff_pattern
@ -998,7 +1179,6 @@ int nand_default_bbt (struct mtd_info *mtd)
return nand_scan_bbt(mtd, &agand_flashbased);
}
/* Is a flash based bad block table requested ? */
if (this->options & NAND_USE_FLASH_BBT) {
/* Use the default pattern descriptors */
@ -1007,14 +1187,13 @@ int nand_default_bbt (struct mtd_info *mtd)
this->bbt_md = &bbt_mirror_descr;
}
if (!this->badblock_pattern) {
this->badblock_pattern = (mtd->oobblock > 512) ?
&largepage_flashbased : &smallpage_flashbased;
this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased;
}
} else {
this->bbt_td = NULL;
this->bbt_md = NULL;
if (!this->badblock_pattern) {
this->badblock_pattern = (mtd->oobblock > 512) ?
this->badblock_pattern = (mtd->writesize > 512) ?
&largepage_memorybased : &smallpage_memorybased;
}
}
@ -1042,11 +1221,20 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
"(block %d) 0x%02x\n", (unsigned int)offs, res, block >> 1);
switch ((int)res) {
case 0x00: return 0;
case 0x01: return 1;
case 0x02: return allowbbt ? 0 : 1;
case 0x00:
return 0;
case 0x01:
return 1;
case 0x02:
return allowbbt ? 0 : 1;
}
return 1;
}
/* XXX U-BOOT XXX */
#if 0
EXPORT_SYMBOL(nand_scan_bbt);
EXPORT_SYMBOL(nand_default_bbt);
#endif
#endif

View file

@ -7,7 +7,9 @@
* Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
* Toshiba America Electronics Components, Inc.
*
* $Id: nand_ecc.c,v 1.14 2004/06/16 15:34:37 gleixner Exp $
* Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de>
*
* $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@ -39,6 +41,14 @@
#if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
/* XXX U-BOOT XXX */
#if 0
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mtd/nand_ecc.h>
#endif
#include<linux/mtd/mtd.h>
/*
@ -128,6 +138,10 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
return 0;
}
/* XXX U-BOOT XXX */
#if 0
EXPORT_SYMBOL(nand_calculate_ecc);
#endif
#endif /* CONFIG_NAND_SPL */
static inline int countbits(uint32_t byte)
@ -197,4 +211,9 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat,
return -1;
}
/* XXX U-BOOT XXX */
#if 0
EXPORT_SYMBOL(nand_correct_data);
#endif
#endif

View file

@ -3,7 +3,7 @@
*
* Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
*
* $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $
* $Id: nand_ids.c,v 1.16 2005/11/07 11:14:31 gleixner Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -16,7 +16,6 @@
#if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
#include <linux/mtd/nand.h>
/*
* Chip ID list
*
@ -29,6 +28,8 @@
* 512 512 Byte page size
*/
struct nand_flash_dev nand_flash_ids[] = {
#ifdef CONFIG_MTD_NAND_MUSEUM_IDS
{"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
{"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},
{"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0},
@ -44,6 +45,7 @@ struct nand_flash_dev nand_flash_ids[] = {
{"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},
{"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
{"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
#endif
{"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
{"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
@ -61,52 +63,72 @@ struct nand_flash_dev nand_flash_ids[] = {
{"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
{"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0},
{"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0},
{"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0},
{"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
{"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
{"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
{"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
{"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
/* These are the new chips with large page size. The pagesize
* and the erasesize is determined from the extended id bytes
/*
* These are the new chips with large page size. The pagesize and the
* erasesize is determined from the extended id bytes
*/
#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR)
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
/*512 Megabit */
{"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS},
{"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS},
{"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16},
{"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16},
/* 1 Gigabit */
{"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS},
{"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS},
{"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16},
{"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16},
/* 2 Gigabit */
{"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS},
{"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS},
{"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, LP_OPTIONS16},
{"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, LP_OPTIONS16},
/* 4 Gigabit */
{"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, LP_OPTIONS},
{"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, LP_OPTIONS},
{"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16},
{"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16},
/* 8 Gigabit */
{"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16},
{"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16},
/* 16 Gigabit */
{"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, LP_OPTIONS},
{"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS},
{"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16},
{"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},
/* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout !
* The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes
* 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7
* Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go
* There are more speed improvements for reads and writes possible, but not implemented now
/*
* Renesas AND 1 Gigabit. Those chips do not support extended id and
* have a strange page/block layout ! The chosen minimum erasesize is
* 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page
* planes 1 block = 2 pages, but due to plane arrangement the blocks
* 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would
* increase the eraseblock size so we chose a combined one which can be
* erased in one go There are more speed improvements for reads and
* writes possible, but not implemented now
*/
{"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY},
{"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000,
NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY |
BBT_AUTO_REFRESH
},
{NULL,}
};
@ -121,6 +143,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_NATIONAL, "National"},
{NAND_MFR_RENESAS, "Renesas"},
{NAND_MFR_STMICRO, "ST Micro"},
{NAND_MFR_HYNIX, "Hynix"},
{NAND_MFR_MICRON, "Micron"},
{0x0, "Unknown"}
};

View file

@ -39,6 +39,9 @@
#include <malloc.h>
#include <div64.h>
#include <asm/errno.h>
#include <linux/mtd/mtd.h>
#include <nand.h>
#include <jffs2/jffs2.h>
@ -69,71 +72,33 @@ static int nand_block_bad_scrub(struct mtd_info *mtd, loff_t ofs, int getchip)
int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
{
struct jffs2_unknown_node cleanmarker;
int clmpos = 0;
int clmlen = 8;
erase_info_t erase;
ulong erase_length;
int isNAND;
int bbtest = 1;
int result;
int percent_complete = -1;
int (*nand_block_bad_old)(struct mtd_info *, loff_t, int) = NULL;
const char *mtd_device = meminfo->name;
struct mtd_oob_ops oob_opts;
struct nand_chip *chip = meminfo->priv;
uint8_t buf[64];
memset(buf, 0, sizeof(buf));
memset(&erase, 0, sizeof(erase));
memset(&oob_opts, 0, sizeof(oob_opts));
erase.mtd = meminfo;
erase.len = meminfo->erasesize;
erase.addr = opts->offset;
erase_length = opts->length;
isNAND = meminfo->type == MTD_NANDFLASH ? 1 : 0;
if (opts->jffs2) {
cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
if (isNAND) {
struct nand_oobinfo *oobinfo = &meminfo->oobinfo;
/* check for autoplacement */
if (oobinfo->useecc == MTD_NANDECC_AUTOPLACE) {
/* get the position of the free bytes */
if (!oobinfo->oobfree[0][1]) {
printf(" Eeep. Autoplacement selected "
"and no empty space in oob\n");
return -1;
}
clmpos = oobinfo->oobfree[0][0];
clmlen = oobinfo->oobfree[0][1];
if (clmlen > 8)
clmlen = 8;
} else {
/* legacy mode */
switch (meminfo->oobsize) {
case 8:
clmpos = 6;
clmlen = 2;
break;
case 16:
clmpos = 8;
clmlen = 8;
break;
case 64:
clmpos = 16;
clmlen = 8;
break;
}
}
cleanmarker.totlen = cpu_to_je32(8);
} else {
cleanmarker.totlen =
cpu_to_je32(sizeof(struct jffs2_unknown_node));
}
cleanmarker.hdr_crc = cpu_to_je32(
crc32_no_comp(0, (unsigned char *) &cleanmarker,
sizeof(struct jffs2_unknown_node) - 4));
}
/* scrub option allows to erase badblock. To prevent internal
* check from erase() method, set block check method to dummy
@ -194,25 +159,21 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
/* format for JFFS2 ? */
if (opts->jffs2) {
/* write cleanmarker */
if (isNAND) {
size_t written;
chip->ops.len = chip->ops.ooblen = 64;
chip->ops.datbuf = NULL;
chip->ops.oobbuf = buf;
chip->ops.ooboffs = chip->badblockpos & ~0x01;
result = meminfo->write_oob(meminfo,
erase.addr + clmpos,
clmlen,
&written,
(unsigned char *)
&cleanmarker);
erase.addr + meminfo->oobsize,
&chip->ops);
if (result != 0) {
printf("\n%s: MTD writeoob failure: %d\n",
mtd_device, result);
continue;
}
} else {
printf("\n%s: this erase routine only supports"
" NAND devices!\n",
mtd_device);
}
else
printf("%s: MTD writeoob at 0x%08x\n",mtd_device, erase.addr + meminfo->oobsize );
}
if (!opts->quiet) {
@ -253,6 +214,9 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
return 0;
}
/* XXX U-BOOT XXX */
#if 0
#define MAX_PAGE_SIZE 2048
#define MAX_OOB_SIZE 64
@ -263,26 +227,189 @@ static unsigned char data_buf[MAX_PAGE_SIZE];
static unsigned char oob_buf[MAX_OOB_SIZE];
/* OOB layouts to pass into the kernel as default */
static struct nand_oobinfo none_oobinfo = {
static struct nand_ecclayout none_ecclayout = {
.useecc = MTD_NANDECC_OFF,
};
static struct nand_oobinfo jffs2_oobinfo = {
static struct nand_ecclayout jffs2_ecclayout = {
.useecc = MTD_NANDECC_PLACE,
.eccbytes = 6,
.eccpos = { 0, 1, 2, 3, 6, 7 }
};
static struct nand_oobinfo yaffs_oobinfo = {
static struct nand_ecclayout yaffs_ecclayout = {
.useecc = MTD_NANDECC_PLACE,
.eccbytes = 6,
.eccpos = { 8, 9, 10, 13, 14, 15}
};
static struct nand_oobinfo autoplace_oobinfo = {
static struct nand_ecclayout autoplace_ecclayout = {
.useecc = MTD_NANDECC_AUTOPLACE
};
#endif
/**
* nand_fill_oob - [Internal] Transfer client buffer to oob
* @chip: nand chip structure
* @oob: oob data buffer
* @ops: oob ops structure
*
* Copied from nand_base.c
*/
static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
struct mtd_oob_ops *ops)
{
size_t len = ops->ooblen;
switch(ops->mode) {
case MTD_OOB_PLACE:
case MTD_OOB_RAW:
memcpy(chip->oob_poi + ops->ooboffs, oob, len);
return oob + len;
case MTD_OOB_AUTO: {
struct nand_oobfree *free = chip->ecc.layout->oobfree;
uint32_t boffs = 0, woffs = ops->ooboffs;
size_t bytes = 0;
for(; free->length && len; free++, len -= bytes) {
/* Write request not from offset 0 ? */
if (unlikely(woffs)) {
if (woffs >= free->length) {
woffs -= free->length;
continue;
}
boffs = free->offset + woffs;
bytes = min_t(size_t, len,
(free->length - woffs));
woffs = 0;
} else {
bytes = min_t(size_t, len, free->length);
boffs = free->offset;
}
memcpy(chip->oob_poi + boffs, oob, bytes);
oob += bytes;
}
return oob;
}
default:
BUG();
}
return NULL;
}
#define NOTALIGNED(x) (x & (chip->subpagesize - 1)) != 0
/* copied from nand_base.c: nand_do_write_ops()
* Only very small changes
*/
int nand_write_opts(nand_info_t *mtd, loff_t to, mtd_oob_ops_t *ops)
{
int chipnr, realpage, page, blockmask, column;
struct nand_chip *chip = mtd->priv;
uint32_t writelen = ops->len;
uint8_t *oob = ops->oobbuf;
uint8_t *buf = ops->datbuf;
int ret, subpage;
ops->retlen = 0;
if (!writelen)
return 0;
printk("nand_write_opts: to: 0x%08x, ops->len: 0x%08x\n", to, ops->len);
/* reject writes, which are not page aligned */
if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
printk(KERN_NOTICE "nand_write: "
"Attempt to write not page aligned data\n");
return -EINVAL;
}
column = to & (mtd->writesize - 1);
subpage = column || (writelen & (mtd->writesize - 1));
if (subpage && oob) {
printk(KERN_NOTICE "nand_write: "
"Attempt to write oob to subpage\n");
return -EINVAL;
}
chipnr = (int)(to >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
/* XXX U-BOOT XXX */
#if 0
/* Check, if it is write protected */
if (nand_check_wp(mtd))
return -EIO;
#endif
realpage = (int)(to >> chip->page_shift);
page = realpage & chip->pagemask;
blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
/* Invalidate the page cache, when we write to the cached page */
if (to <= (chip->pagebuf << chip->page_shift) &&
(chip->pagebuf << chip->page_shift) < (to + ops->len))
chip->pagebuf = -1;
/* If we're not given explicit OOB data, let it be 0xFF */
if (likely(!oob)) {
printf("!oob, writing %d bytes with 0xff to chip->oob_poi (0x%08x)\n", mtd->oobsize, chip->oob_poi);
memset(chip->oob_poi, 0xff, mtd->oobsize);
}
while(1) {
int bytes = mtd->writesize;
int cached = writelen > bytes && page != blockmask;
uint8_t *wbuf = buf;
/* Partial page write ? */
if (unlikely(column || writelen < (mtd->writesize - 1))) {
cached = 0;
bytes = min_t(int, bytes - column, (int) writelen);
chip->pagebuf = -1;
memset(chip->buffers->databuf, 0xff, mtd->writesize);
memcpy(&chip->buffers->databuf[column], buf, bytes);
wbuf = chip->buffers->databuf;
}
if (unlikely(oob))
oob = nand_fill_oob(chip, oob, ops);
ret = chip->write_page(mtd, chip, wbuf, page, cached,
(ops->mode == MTD_OOB_RAW));
if (ret)
break;
writelen -= bytes;
if (!writelen)
break;
column = 0;
buf += bytes;
realpage++;
page = realpage & chip->pagemask;
/* Check, if we cross a chip boundary */
if (!page) {
chipnr++;
chip->select_chip(mtd, -1);
chip->select_chip(mtd, chipnr);
}
}
ops->retlen = ops->len - writelen;
if (unlikely(oob))
ops->oobretlen = ops->ooblen;
return ret;
}
/* XXX U-BOOT XXX */
#if 0
/**
* nand_write_opts: - write image to NAND flash with support for various options
*
@ -301,9 +428,9 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
int blockstart = -1;
loff_t offs;
int readlen;
int oobinfochanged = 0;
int ecclayoutchanged = 0;
int percent_complete = -1;
struct nand_oobinfo old_oobinfo;
struct nand_ecclayout old_ecclayout;
ulong mtdoffset = opts->offset;
ulong erasesize_blockalign;
u_char *buffer = opts->buffer;
@ -324,35 +451,35 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
}
/* make sure device page sizes are valid */
if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512)
&& !(meminfo->oobsize == 8 && meminfo->oobblock == 256)
&& !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) {
if (!(meminfo->oobsize == 16 && meminfo->writesize == 512)
&& !(meminfo->oobsize == 8 && meminfo->writesize == 256)
&& !(meminfo->oobsize == 64 && meminfo->writesize == 2048)) {
printf("Unknown flash (not normal NAND)\n");
return -1;
}
/* read the current oob info */
memcpy(&old_oobinfo, &meminfo->oobinfo, sizeof(old_oobinfo));
memcpy(&old_ecclayout, &meminfo->ecclayout, sizeof(old_ecclayout));
/* write without ecc? */
if (opts->noecc) {
memcpy(&meminfo->oobinfo, &none_oobinfo,
sizeof(meminfo->oobinfo));
oobinfochanged = 1;
memcpy(&meminfo->ecclayout, &none_ecclayout,
sizeof(meminfo->ecclayout));
ecclayoutchanged = 1;
}
/* autoplace ECC? */
if (opts->autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
if (opts->autoplace && (old_ecclayout.useecc != MTD_NANDECC_AUTOPLACE)) {
memcpy(&meminfo->oobinfo, &autoplace_oobinfo,
sizeof(meminfo->oobinfo));
oobinfochanged = 1;
memcpy(&meminfo->ecclayout, &autoplace_ecclayout,
sizeof(meminfo->ecclayout));
ecclayoutchanged = 1;
}
/* force OOB layout for jffs2 or yaffs? */
if (opts->forcejffs2 || opts->forceyaffs) {
struct nand_oobinfo *oobsel =
opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
struct nand_ecclayout *oobsel =
opts->forcejffs2 ? &jffs2_ecclayout : &yaffs_ecclayout;
if (meminfo->oobsize == 8) {
if (opts->forceyaffs) {
@ -361,15 +488,15 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
goto restoreoob;
}
/* Adjust number of ecc bytes */
jffs2_oobinfo.eccbytes = 3;
jffs2_ecclayout.eccbytes = 3;
}
memcpy(&meminfo->oobinfo, oobsel, sizeof(meminfo->oobinfo));
memcpy(&meminfo->ecclayout, oobsel, sizeof(meminfo->ecclayout));
}
/* get image length */
imglen = opts->length;
pagelen = meminfo->oobblock
pagelen = meminfo->writesize
+ ((opts->writeoob != 0) ? meminfo->oobsize : 0);
/* check, if file is pagealigned */
@ -379,11 +506,11 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
}
/* check, if length fits into device */
if (((imglen / pagelen) * meminfo->oobblock)
if (((imglen / pagelen) * meminfo->writesize)
> (meminfo->size - opts->offset)) {
printf("Image %d bytes, NAND page %d bytes, "
"OOB area %u bytes, device size %u bytes\n",
imglen, pagelen, meminfo->oobblock, meminfo->size);
imglen, pagelen, meminfo->writesize, meminfo->size);
printf("Input block does not fit into device\n");
goto restoreoob;
}
@ -437,11 +564,11 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
} while (offs < blockstart + erasesize_blockalign);
}
readlen = meminfo->oobblock;
readlen = meminfo->writesize;
if (opts->pad && (imglen < readlen)) {
readlen = imglen;
memset(data_buf + readlen, 0xff,
meminfo->oobblock - readlen);
meminfo->writesize - readlen);
}
/* read page data from input memory buffer */
@ -474,7 +601,7 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
/* write out the page data */
result = meminfo->write(meminfo,
mtdoffset,
meminfo->oobblock,
meminfo->writesize,
&written,
(unsigned char *) &data_buf);
@ -505,16 +632,16 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
}
}
mtdoffset += meminfo->oobblock;
mtdoffset += meminfo->writesize;
}
if (!opts->quiet)
printf("\n");
restoreoob:
if (oobinfochanged) {
memcpy(&meminfo->oobinfo, &old_oobinfo,
sizeof(meminfo->oobinfo));
if (ecclayoutchanged) {
memcpy(&meminfo->ecclayout, &old_ecclayout,
sizeof(meminfo->ecclayout));
}
if (imglen > 0) {
@ -548,22 +675,22 @@ int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)
int result;
/* make sure device page sizes are valid */
if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512)
&& !(meminfo->oobsize == 8 && meminfo->oobblock == 256)
&& !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) {
if (!(meminfo->oobsize == 16 && meminfo->writesize == 512)
&& !(meminfo->oobsize == 8 && meminfo->writesize == 256)
&& !(meminfo->oobsize == 64 && meminfo->writesize == 2048)) {
printf("Unknown flash (not normal NAND)\n");
return -1;
}
pagelen = meminfo->oobblock
pagelen = meminfo->writesize
+ ((opts->readoob != 0) ? meminfo->oobsize : 0);
/* check, if length is not larger than device */
if (((imglen / pagelen) * meminfo->oobblock)
if (((imglen / pagelen) * meminfo->writesize)
> (meminfo->size - opts->offset)) {
printf("Image %d bytes, NAND page %d bytes, "
"OOB area %u bytes, device size %u bytes\n",
imglen, pagelen, meminfo->oobblock, meminfo->size);
imglen, pagelen, meminfo->writesize, meminfo->size);
printf("Input block is larger than device\n");
return -1;
}
@ -621,7 +748,7 @@ int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)
/* read page data to memory buffer */
result = meminfo->read(meminfo,
mtdoffset,
meminfo->oobblock,
meminfo->writesize,
&readlen,
(unsigned char *) &data_buf);
@ -685,7 +812,7 @@ int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)
}
}
mtdoffset += meminfo->oobblock;
mtdoffset += meminfo->writesize;
}
if (!opts->quiet)
@ -699,7 +826,10 @@ int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)
/* return happy */
return 0;
}
#endif
/* XXX U-BOOT XXX */
#if 0
/******************************************************************************
* Support for locking / unlocking operations of some NAND devices
*****************************************************************************/
@ -784,7 +914,7 @@ int nand_get_lock_status(nand_info_t *meminfo, ulong offset)
this->select_chip(meminfo, chipnr);
if ((offset & (meminfo->oobblock - 1)) != 0) {
if ((offset & (meminfo->writesize - 1)) != 0) {
printf ("nand_get_lock_status: "
"Start address must be beginning of "
"nand page!\n");
@ -813,7 +943,7 @@ int nand_get_lock_status(nand_info_t *meminfo, ulong offset)
* @param meminfo nand mtd instance
* @param start start byte address
* @param length number of bytes to unlock (must be a multiple of
* page size nand->oobblock)
* page size nand->writesize)
*
* @return 0 on success, -1 in case of error
*/
@ -839,14 +969,14 @@ int nand_unlock(nand_info_t *meminfo, ulong start, ulong length)
goto out;
}
if ((start & (meminfo->oobblock - 1)) != 0) {
if ((start & (meminfo->writesize - 1)) != 0) {
printf ("nand_unlock: Start address must be beginning of "
"nand page!\n");
ret = -1;
goto out;
}
if (length == 0 || (length & (meminfo->oobblock - 1)) != 0) {
if (length == 0 || (length & (meminfo->writesize - 1)) != 0) {
printf ("nand_unlock: Length must be a multiple of nand page "
"size!\n");
ret = -1;
@ -875,5 +1005,6 @@ int nand_unlock(nand_info_t *meminfo, ulong start, ulong length)
this->select_chip(meminfo, -1);
return ret;
}
#endif
#endif

View file

@ -119,11 +119,13 @@ typedef volatile unsigned char vu_char;
#define debugX(level,fmt,args...)
#endif /* DEBUG */
#ifndef BUG
#define BUG() do { \
printf("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \
panic("BUG!"); \
} while (0)
#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
#endif /* BUG */
typedef void (interrupt_handler_t)(void *);

45
include/linux/err.h Normal file
View file

@ -0,0 +1,45 @@
#ifndef _LINUX_ERR_H
#define _LINUX_ERR_H
/* XXX U-BOOT XXX */
#if 0
#include <linux/compiler.h>
#else
#include <linux/mtd/compat.h>
#endif
#include <asm/errno.h>
/*
* Kernel pointers have redundant information, so we can use a
* scheme where we can return either an error code or a dentry
* pointer with the same return value.
*
* This should be a per-architecture thing, to allow different
* error and pointer decisions.
*/
#define MAX_ERRNO 4095
#ifndef __ASSEMBLY__
#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
static inline void *ERR_PTR(long error)
{
return (void *) error;
}
static inline long PTR_ERR(const void *ptr)
{
return (long) ptr;
}
static inline long IS_ERR(const void *ptr)
{
return IS_ERR_VALUE((unsigned long)ptr);
}
#endif
#endif /* _LINUX_ERR_H */

View file

@ -0,0 +1,81 @@
/*
* $Id: blktrans.h,v 1.6 2005/11/07 11:14:54 gleixner Exp $
*
* (C) 2003 David Woodhouse <dwmw2@infradead.org>
*
* Interface to Linux block layer for MTD 'translation layers'.
*
*/
#ifndef __MTD_TRANS_H__
#define __MTD_TRANS_H__
/* XXX U-BOOT XXX */
#if 0
#include <linux/mutex.h>
#else
#include <linux/list.h>
#endif
struct hd_geometry;
struct mtd_info;
struct mtd_blktrans_ops;
struct file;
struct inode;
struct mtd_blktrans_dev {
struct mtd_blktrans_ops *tr;
struct list_head list;
struct mtd_info *mtd;
/* XXX U-BOOT XXX */
#if 0
struct mutex lock;
#endif
int devnum;
unsigned long size;
int readonly;
void *blkcore_priv; /* gendisk in 2.5, devfs_handle in 2.4 */
};
struct blkcore_priv; /* Differs for 2.4 and 2.5 kernels; private */
struct mtd_blktrans_ops {
char *name;
int major;
int part_bits;
int blksize;
int blkshift;
/* Access functions */
int (*readsect)(struct mtd_blktrans_dev *dev,
unsigned long block, char *buffer);
int (*writesect)(struct mtd_blktrans_dev *dev,
unsigned long block, char *buffer);
/* Block layer ioctls */
int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo);
int (*flush)(struct mtd_blktrans_dev *dev);
/* Called with mtd_table_mutex held; no race with add/remove */
int (*open)(struct mtd_blktrans_dev *dev);
int (*release)(struct mtd_blktrans_dev *dev);
/* Called on {de,}registration and on subsequent addition/removal
of devices, with mtd_table_mutex held. */
void (*add_mtd)(struct mtd_blktrans_ops *tr, struct mtd_info *mtd);
void (*remove_dev)(struct mtd_blktrans_dev *dev);
struct list_head devs;
struct list_head list;
struct module *owner;
struct mtd_blkcore_priv *blkcore_priv;
};
extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr);
extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr);
extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
#endif /* __MTD_TRANS_H__ */

View file

@ -18,7 +18,12 @@
#define KERN_DEBUG
#define kmalloc(size, flags) malloc(size)
#define kzalloc(size, flags) calloc(size, 1)
#define vmalloc(size) malloc(size)
#define kfree(ptr) free(ptr)
#define vfree(ptr) free(ptr)
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
/*
* ..and if you can't take the strict

View file

@ -1,15 +1,23 @@
/* Linux driver for Disk-On-Chip 2000 */
/* (c) 1999 Machine Vision Holdings, Inc. */
/* Author: David Woodhouse <dwmw2@mvhi.com> */
/* $Id: doc2000.h,v 1.15 2001/09/19 00:22:15 dwmw2 Exp $ */
/*
* Linux driver for Disk-On-Chip devices
*
* Copyright (C) 1999 Machine Vision Holdings, Inc.
* Copyright (C) 2001-2003 David Woodhouse <dwmw2@infradead.org>
* Copyright (C) 2002-2003 Greg Ungerer <gerg@snapgear.com>
* Copyright (C) 2002-2003 SnapGear Inc
*
* $Id: doc2000.h,v 1.25 2005/11/07 11:14:54 gleixner Exp $
*
* Released under GPL
*/
#ifndef __MTD_DOC2000_H__
#define __MTD_DOC2000_H__
struct DiskOnChip;
#include <linux/mtd/nftl.h>
#include <linux/mtd/mtd.h>
#if 0
#include <linux/mutex.h>
#endif
#define DoC_Sig1 0
#define DoC_Sig2 1
@ -40,10 +48,58 @@ struct DiskOnChip;
#define DoC_Mil_CDSN_IO 0x0800
#define DoC_2k_CDSN_IO 0x1800
#define ReadDOC_(adr, reg) ((volatile unsigned char)(*(volatile __u8 *)(((unsigned long)adr)+((reg)))))
#define WriteDOC_(d, adr, reg) do{ *(volatile __u8 *)(((unsigned long)adr)+((reg))) = (__u8)d; eieio();} while(0)
#define DoC_Mplus_NOP 0x1002
#define DoC_Mplus_AliasResolution 0x1004
#define DoC_Mplus_DOCControl 0x1006
#define DoC_Mplus_AccessStatus 0x1008
#define DoC_Mplus_DeviceSelect 0x1008
#define DoC_Mplus_Configuration 0x100a
#define DoC_Mplus_OutputControl 0x100c
#define DoC_Mplus_FlashControl 0x1020
#define DoC_Mplus_FlashSelect 0x1022
#define DoC_Mplus_FlashCmd 0x1024
#define DoC_Mplus_FlashAddress 0x1026
#define DoC_Mplus_FlashData0 0x1028
#define DoC_Mplus_FlashData1 0x1029
#define DoC_Mplus_ReadPipeInit 0x102a
#define DoC_Mplus_LastDataRead 0x102c
#define DoC_Mplus_LastDataRead1 0x102d
#define DoC_Mplus_WritePipeTerm 0x102e
#define DoC_Mplus_ECCSyndrome0 0x1040
#define DoC_Mplus_ECCSyndrome1 0x1041
#define DoC_Mplus_ECCSyndrome2 0x1042
#define DoC_Mplus_ECCSyndrome3 0x1043
#define DoC_Mplus_ECCSyndrome4 0x1044
#define DoC_Mplus_ECCSyndrome5 0x1045
#define DoC_Mplus_ECCConf 0x1046
#define DoC_Mplus_Toggle 0x1046
#define DoC_Mplus_DownloadStatus 0x1074
#define DoC_Mplus_CtrlConfirm 0x1076
#define DoC_Mplus_Power 0x1fff
/* How to access the device?
* On ARM, it'll be mmap'd directly with 32-bit wide accesses.
* On PPC, it's mmap'd and 16-bit wide.
* Others use readb/writeb
*/
#if defined(__arm__)
#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2))))
#define WriteDOC_(d, adr, reg) do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
#define DOC_IOREMAP_LEN 0x8000
#elif defined(__ppc__)
#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1))))
#define WriteDOC_(d, adr, reg) do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
#define DOC_IOREMAP_LEN 0x4000
#else
#define ReadDOC_(adr, reg) readb((void __iomem *)(adr) + (reg))
#define WriteDOC_(d, adr, reg) writeb(d, (void __iomem *)(adr) + (reg))
#define DOC_IOREMAP_LEN 0x2000
#endif
#if defined(__i386__) || defined(__x86_64__)
#define USE_MEMCPY
#endif
/* These are provided to directly use the DoC_xxx defines */
#define ReadDOC(adr, reg) ReadDOC_(adr,DoC_##reg)
@ -54,14 +110,21 @@ struct DiskOnChip;
#define DOC_MODE_RESERVED1 2
#define DOC_MODE_RESERVED2 3
#define DOC_MODE_MDWREN 4
#define DOC_MODE_CLR_ERR 0x80
#define DOC_MODE_RST_LAT 0x10
#define DOC_MODE_BDECT 0x08
#define DOC_MODE_MDWREN 0x04
#define DOC_ChipID_UNKNOWN 0x00
#define DOC_ChipID_Doc2k 0x20
#define DOC_ChipID_Doc2kTSOP 0x21 /* internal number for MTD */
#define DOC_ChipID_DocMil 0x30
#define DOC_ChipID_DocMilPlus32 0x40
#define DOC_ChipID_DocMilPlus16 0x41
#define CDSN_CTRL_FR_B 0x80
#define CDSN_CTRL_FR_B0 0x40
#define CDSN_CTRL_FR_B1 0x80
#define CDSN_CTRL_ECC_IO 0x20
#define CDSN_CTRL_FLASH_IO 0x10
#define CDSN_CTRL_WP 0x08
@ -77,20 +140,14 @@ struct DiskOnChip;
#define DOC_ECC_RESV 0x02
#define DOC_ECC_IGNORE 0x01
#define DOC_FLASH_CE 0x80
#define DOC_FLASH_WP 0x40
#define DOC_FLASH_BANK 0x02
/* We have to also set the reserved bit 1 for enable */
#define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV)
#define DOC_ECC_DIS (DOC_ECC_RESV)
#define MAX_FLOORS 4
#define MAX_CHIPS 4
#define MAX_FLOORS_MIL 4
#define MAX_CHIPS_MIL 1
#define ADDR_COLUMN 1
#define ADDR_PAGE 2
#define ADDR_COLUMN_PAGE 3
struct Nand {
char floor, chip;
unsigned long curadr;
@ -98,20 +155,32 @@ struct Nand {
/* Also some erase/write/pipeline info when we get that far */
};
#define MAX_FLOORS 4
#define MAX_CHIPS 4
#define MAX_FLOORS_MIL 1
#define MAX_CHIPS_MIL 1
#define MAX_FLOORS_MPLUS 2
#define MAX_CHIPS_MPLUS 1
#define ADDR_COLUMN 1
#define ADDR_PAGE 2
#define ADDR_COLUMN_PAGE 3
struct DiskOnChip {
unsigned long physadr;
unsigned long virtadr;
void __iomem *virtadr;
unsigned long totlen;
char* name;
char ChipID; /* Type of DiskOnChip */
unsigned char ChipID; /* Type of DiskOnChip */
int ioreg;
char* chips_name;
unsigned long mfr; /* Flash IDs - only one type of flash per device */
unsigned long id;
int chipshift;
char page256;
char pageadrlen;
char interleave; /* Internal interleaving - Millennium Plus style */
unsigned long erasesize;
int curfloor;
@ -119,98 +188,22 @@ struct DiskOnChip {
int numchips;
struct Nand *chips;
int nftl_found;
struct NFTLrecord nftl;
struct mtd_info *nextdoc;
/* XXX U-BOOT XXX */
#if 0
struct mutex lock;
#endif
};
#define SECTORSIZE 512
/* Return codes from doc_write(), doc_read(), and doc_erase().
*/
#define DOC_OK 0
#define DOC_EIO 1
#define DOC_EINVAL 2
#define DOC_EECC 3
#define DOC_ETIMEOUT 4
/*
* Function Prototypes
*/
int doc_decode_ecc(unsigned char sector[512], unsigned char ecc1[6]);
int doc_rw(struct DiskOnChip* this, int cmd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
int doc_read_ecc(struct DiskOnChip* this, loff_t from, size_t len,
size_t *retlen, u_char *buf, u_char *eccbuf);
int doc_write_ecc(struct DiskOnChip* this, loff_t to, size_t len,
size_t *retlen, const u_char *buf, u_char *eccbuf);
int doc_read_oob(struct DiskOnChip* this, loff_t ofs, size_t len,
size_t *retlen, u_char *buf);
int doc_write_oob(struct DiskOnChip* this, loff_t ofs, size_t len,
size_t *retlen, const u_char *buf);
int doc_erase (struct DiskOnChip* this, loff_t ofs, size_t len);
void doc_probe(unsigned long physadr);
void doc_print(struct DiskOnChip*);
/*
* Standard NAND flash commands
*/
#define NAND_CMD_READ0 0
#define NAND_CMD_READ1 1
#define NAND_CMD_PAGEPROG 0x10
#define NAND_CMD_READOOB 0x50
#define NAND_CMD_ERASE1 0x60
#define NAND_CMD_STATUS 0x70
#define NAND_CMD_SEQIN 0x80
#define NAND_CMD_READID 0x90
#define NAND_CMD_ERASE2 0xd0
#define NAND_CMD_RESET 0xff
/* XXX U-BOOT XXX */
#if 1
/*
* NAND Flash Manufacturer ID Codes
*/
#define NAND_MFR_TOSHIBA 0x98
#define NAND_MFR_SAMSUNG 0xec
/*
* NAND Flash Device ID Structure
*
* Structure overview:
*
* name - Complete name of device
*
* manufacture_id - manufacturer ID code of device.
*
* model_id - model ID code of device.
*
* chipshift - total number of address bits for the device which
* is used to calculate address offsets and the total
* number of bytes the device is capable of.
*
* page256 - denotes if flash device has 256 byte pages or not.
*
* pageadrlen - number of bytes minus one needed to hold the
* complete address into the flash array. Keep in
* mind that when a read or write is done to a
* specific address, the address is input serially
* 8 bits at a time. This structure member is used
* by the read/write routines as a loop index for
* shifting the address out 8 bits at a time.
*
* erasesize - size of an erase block in the flash device.
*/
struct nand_flash_dev {
char * name;
int manufacture_id;
int model_id;
int chipshift;
char page256;
char pageadrlen;
unsigned long erasesize;
int bus16;
};
#endif
#endif /* __MTD_DOC2000_H__ */

View file

@ -0,0 +1,91 @@
/*
* $Id: inftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
*
* Parts of INFTL headers shared with userspace
*
*/
#ifndef __MTD_INFTL_USER_H__
#define __MTD_INFTL_USER_H__
#define OSAK_VERSION 0x5120
#define PERCENTUSED 98
#define SECTORSIZE 512
/* Block Control Information */
struct inftl_bci {
uint8_t ECCsig[6];
uint8_t Status;
uint8_t Status1;
} __attribute__((packed));
struct inftl_unithead1 {
uint16_t virtualUnitNo;
uint16_t prevUnitNo;
uint8_t ANAC;
uint8_t NACs;
uint8_t parityPerField;
uint8_t discarded;
} __attribute__((packed));
struct inftl_unithead2 {
uint8_t parityPerField;
uint8_t ANAC;
uint16_t prevUnitNo;
uint16_t virtualUnitNo;
uint8_t NACs;
uint8_t discarded;
} __attribute__((packed));
struct inftl_unittail {
uint8_t Reserved[4];
uint16_t EraseMark;
uint16_t EraseMark1;
} __attribute__((packed));
union inftl_uci {
struct inftl_unithead1 a;
struct inftl_unithead2 b;
struct inftl_unittail c;
};
struct inftl_oob {
struct inftl_bci b;
union inftl_uci u;
};
/* INFTL Media Header */
struct INFTLPartition {
__u32 virtualUnits;
__u32 firstUnit;
__u32 lastUnit;
__u32 flags;
__u32 spareUnits;
__u32 Reserved0;
__u32 Reserved1;
} __attribute__((packed));
struct INFTLMediaHeader {
char bootRecordID[8];
__u32 NoOfBootImageBlocks;
__u32 NoOfBinaryPartitions;
__u32 NoOfBDTLPartitions;
__u32 BlockMultiplierBits;
__u32 FormatFlags;
__u32 OsakVersion;
__u32 PercentUsed;
struct INFTLPartition Partitions[4];
} __attribute__((packed));
/* Partition flag types */
#define INFTL_BINARY 0x20000000
#define INFTL_BDTL 0x40000000
#define INFTL_LAST 0x80000000
#endif /* __MTD_INFTL_USER_H__ */

View file

@ -0,0 +1,35 @@
/*
* $Id: jffs2-user.h,v 1.1 2004/05/05 11:57:54 dwmw2 Exp $
*
* JFFS2 definitions for use in user space only
*/
#ifndef __JFFS2_USER_H__
#define __JFFS2_USER_H__
/* This file is blessed for inclusion by userspace */
#include <linux/jffs2.h>
#include <endian.h>
#include <byteswap.h>
#undef cpu_to_je16
#undef cpu_to_je32
#undef cpu_to_jemode
#undef je16_to_cpu
#undef je32_to_cpu
#undef jemode_to_cpu
extern int target_endian;
#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); })
#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); })
#define cpu_to_je16(x) ((jint16_t){t16(x)})
#define cpu_to_je32(x) ((jint32_t){t32(x)})
#define cpu_to_jemode(x) ((jmode_t){t32(x)})
#define je16_to_cpu(x) (t16((x).v16))
#define je32_to_cpu(x) (t32((x).v32))
#define jemode_to_cpu(x) (t32((x).m))
#endif /* __JFFS2_USER_H__ */

View file

@ -1,5 +1,5 @@
/*
* $Id: mtd-abi.h,v 1.7 2004/11/23 15:37:32 gleixner Exp $
* $Id: mtd-abi.h,v 1.13 2005/11/07 11:14:56 gleixner Exp $
*
* Portions of MTD ABI definition which are shared by kernel and user space
*/
@ -7,6 +7,10 @@
#ifndef __MTD_ABI_H__
#define __MTD_ABI_H__
#if 1
#include <linux/mtd/compat.h>
#endif
struct erase_info_user {
uint32_t start;
uint32_t length;
@ -15,7 +19,7 @@ struct erase_info_user {
struct mtd_oob_buf {
uint32_t start;
uint32_t length;
unsigned char *ptr;
unsigned char __user *ptr;
};
#define MTD_ABSENT 0
@ -23,47 +27,41 @@ struct mtd_oob_buf {
#define MTD_ROM 2
#define MTD_NORFLASH 3
#define MTD_NANDFLASH 4
#define MTD_PEROM 5
#define MTD_OTHER 14
#define MTD_UNKNOWN 15
#define MTD_DATAFLASH 6
#define MTD_UBIVOLUME 7
#define MTD_CLEAR_BITS 1 /* Bits can be cleared (flash) */
#define MTD_SET_BITS 2 /* Bits can be set */
#define MTD_ERASEABLE 4 /* Has an erase function */
#define MTD_WRITEB_WRITEABLE 8 /* Direct IO is possible */
#define MTD_VOLATILE 16 /* Set for RAMs */
#define MTD_XIP 32 /* eXecute-In-Place possible */
#define MTD_OOB 64 /* Out-of-band data (NAND flash) */
#define MTD_ECC 128 /* Device capable of automatic ECC */
#define MTD_NO_VIRTBLOCKS 256 /* Virtual blocks not allowed */
#define MTD_WRITEABLE 0x400 /* Device is writeable */
#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */
#define MTD_NO_ERASE 0x1000 /* No erase necessary */
#define MTD_STUPID_LOCK 0x2000 /* Always locked after reset */
/* Some common devices / combinations of capabilities */
// Some common devices / combinations of capabilities
#define MTD_CAP_ROM 0
#define MTD_CAP_RAM (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEB_WRITEABLE)
#define MTD_CAP_NORFLASH (MTD_CLEAR_BITS|MTD_ERASEABLE)
#define MTD_CAP_NANDFLASH (MTD_CLEAR_BITS|MTD_ERASEABLE|MTD_OOB)
#define MTD_WRITEABLE (MTD_CLEAR_BITS|MTD_SET_BITS)
/* Types of automatic ECC/Checksum available */
#define MTD_ECC_NONE 0 /* No automatic ECC available */
#define MTD_ECC_RS_DiskOnChip 1 /* Automatic ECC on DiskOnChip */
#define MTD_ECC_SW 2 /* SW ECC for Toshiba & Samsung devices */
#define MTD_CAP_RAM (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
#define MTD_CAP_NORFLASH (MTD_WRITEABLE | MTD_BIT_WRITEABLE)
#define MTD_CAP_NANDFLASH (MTD_WRITEABLE)
/* ECC byte placement */
#define MTD_NANDECC_OFF 0 /* Switch off ECC (Not recommended) */
#define MTD_NANDECC_PLACE 1 /* Use the given placement in the structure (YAFFS1 legacy mode) */
#define MTD_NANDECC_AUTOPLACE 2 /* Use the default placement scheme */
#define MTD_NANDECC_PLACEONLY 3 /* Use the given placement in the structure (Do not store ecc result on read) */
#define MTD_NANDECC_AUTOPL_USR 4 /* Use the given autoplacement scheme rather than using the default */
#define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended)
#define MTD_NANDECC_PLACE 1 // Use the given placement in the structure (YAFFS1 legacy mode)
#define MTD_NANDECC_AUTOPLACE 2 // Use the default placement scheme
#define MTD_NANDECC_PLACEONLY 3 // Use the given placement in the structure (Do not store ecc result on read)
#define MTD_NANDECC_AUTOPL_USR 4 // Use the given autoplacement scheme rather than using the default
/* OTP mode selection */
#define MTD_OTP_OFF 0
#define MTD_OTP_FACTORY 1
#define MTD_OTP_USER 2
struct mtd_info_user {
uint8_t type;
uint32_t flags;
uint32_t size; /* Total size of the MTD */
uint32_t size; // Total size of the MTD
uint32_t erasesize;
uint32_t oobblock; /* Size of OOB blocks (e.g. 512) */
uint32_t oobsize; /* Amount of OOB data per block (e.g. 16) */
uint32_t writesize;
uint32_t oobsize; // Amount of OOB data per block (e.g. 16)
/* The below two fields are obsolete and broken, do not use them
* (TODO: remove at some point) */
uint32_t ecctype;
uint32_t eccsize;
};
@ -76,6 +74,12 @@ struct region_info_user {
uint32_t regionindex;
};
struct otp_info {
uint32_t start;
uint32_t length;
uint32_t locked;
};
#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
#define MEMERASE _IOW('M', 2, struct erase_info_user)
#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
@ -88,7 +92,18 @@ struct region_info_user {
#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo)
#define MEMGETBADBLOCK _IOW('M', 11, loff_t)
#define MEMSETBADBLOCK _IOW('M', 12, loff_t)
#define OTPSELECT _IOR('M', 13, int)
#define OTPGETREGIONCOUNT _IOW('M', 14, int)
#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
#define OTPLOCK _IOR('M', 16, struct otp_info)
#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout)
#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
#define MTDFILEMODE _IO('M', 19)
/*
* Obsolete legacy interface. Keep it in order not to break userspace
* interfaces
*/
struct nand_oobinfo {
uint32_t useecc;
uint32_t eccbytes;
@ -96,4 +111,46 @@ struct nand_oobinfo {
uint32_t eccpos[48];
};
struct nand_oobfree {
uint32_t offset;
uint32_t length;
};
#define MTD_MAX_OOBFREE_ENTRIES 8
/*
* ECC layout control structure. Exported to userspace for
* diagnosis and to allow creation of raw images
*/
struct nand_ecclayout {
uint32_t eccbytes;
uint32_t eccpos[64];
uint32_t oobavail;
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
};
/**
* struct mtd_ecc_stats - error correction stats
*
* @corrected: number of corrected bits
* @failed: number of uncorrectable errors
* @badblocks: number of bad blocks in this partition
* @bbtblocks: number of blocks reserved for bad block tables
*/
struct mtd_ecc_stats {
uint32_t corrected;
uint32_t failed;
uint32_t badblocks;
uint32_t bbtblocks;
};
/*
* Read/write file modes for access to MTD
*/
enum mtd_file_modes {
MTD_MODE_NORMAL = MTD_OTP_OFF,
MTD_MODE_OTP_FACTORY = MTD_OTP_FACTORY,
MTD_MODE_OTP_USER = MTD_OTP_USER,
MTD_MODE_RAW,
};
#endif /* __MTD_ABI_H__ */

View file

@ -1,5 +1,5 @@
/*
* $Id: mtd.h,v 1.56 2004/08/09 18:46:04 dmarlin Exp $
* $Id: mtd.h,v 1.61 2005/11/07 11:14:54 gleixner Exp $
*
* Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
*
@ -8,10 +8,13 @@
#ifndef __MTD_MTD_H__
#define __MTD_MTD_H__
#include <linux/types.h>
#include <linux/mtd/mtd-abi.h>
#define MAX_MTD_DEVICES 16
#define MTD_CHAR_MAJOR 90
#define MTD_BLOCK_MAJOR 31
#define MAX_MTD_DEVICES 32
#define MTD_ERASE_PENDING 0x01
#define MTD_ERASING 0x02
@ -41,32 +44,83 @@ struct mtd_erase_region_info {
u_int32_t offset; /* At which this region starts, from the beginning of the MTD */
u_int32_t erasesize; /* For this region */
u_int32_t numblocks; /* Number of blocks of erasesize in this region */
unsigned long *lockmap; /* If keeping bitmap of locks */
};
/*
* oob operation modes
*
* MTD_OOB_PLACE: oob data are placed at the given offset
* MTD_OOB_AUTO: oob data are automatically placed at the free areas
* which are defined by the ecclayout
* MTD_OOB_RAW: mode to read raw data+oob in one chunk. The oob data
* is inserted into the data. Thats a raw image of the
* flash contents.
*/
typedef enum {
MTD_OOB_PLACE,
MTD_OOB_AUTO,
MTD_OOB_RAW,
} mtd_oob_mode_t;
/**
* struct mtd_oob_ops - oob operation operands
* @mode: operation mode
*
* @len: number of data bytes to write/read
*
* @retlen: number of data bytes written/read
*
* @ooblen: number of oob bytes to write/read
* @oobretlen: number of oob bytes written/read
* @ooboffs: offset of oob data in the oob area (only relevant when
* mode = MTD_OOB_PLACE)
* @datbuf: data buffer - if NULL only oob data are read/written
* @oobbuf: oob data buffer
*
* Note, it is allowed to read more then one OOB area at one go, but not write.
* The interface assumes that the OOB write requests program only one page's
* OOB area.
*/
struct mtd_oob_ops {
mtd_oob_mode_t mode;
size_t len;
size_t retlen;
size_t ooblen;
size_t oobretlen;
uint32_t ooboffs;
uint8_t *datbuf;
uint8_t *oobbuf;
};
struct mtd_info {
u_char type;
u_int32_t flags;
u_int32_t size; /* Total size of the MTD */
u_int32_t size; // Total size of the MTD
/* "Major" erase size for the device. Naïve users may take this
/* "Major" erase size for the device. Naïve users may take this
* to be the only erase size available, or may use the more detailed
* information below if they desire
*/
u_int32_t erasesize;
/* Minimal writable flash unit size. In case of NOR flash it is 1 (even
* though individual bits can be cleared), in case of NAND flash it is
* one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
* it is of ECC block size, etc. It is illegal to have writesize = 0.
* Any driver registering a struct mtd_info must ensure a writesize of
* 1 or larger.
*/
u_int32_t writesize;
u_int32_t oobblock; /* Size of OOB blocks (e.g. 512) */
u_int32_t oobsize; /* Amount of OOB data per block (e.g. 16) */
u_int32_t oobavail; /* Number of bytes in OOB area available for fs */
u_int32_t ecctype;
u_int32_t eccsize;
u_int32_t oobsize; // Amount of OOB data per block (e.g. 16)
u_int32_t oobavail; // Available OOB bytes per block
/* Kernel-only stuff starts here. */
// Kernel-only stuff starts here.
char *name;
int index;
/* oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) */
struct nand_oobinfo oobinfo;
/* ecc layout structure pointer - read only ! */
struct nand_ecclayout *ecclayout;
/* Data for variable erase regions. If numeraseregions is zero,
* it means that the whole device has erasesize as given above.
@ -74,9 +128,6 @@ struct mtd_info {
int numeraseregions;
struct mtd_erase_region_info *eraseregions;
/* This really shouldn't be here. It can go away in 2.5 */
u_int32_t bank_size;
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
/* This stuff for eXecute-In-Place */
@ -89,39 +140,35 @@ struct mtd_info {
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
int (*read_oob) (struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops);
int (*write_oob) (struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops);
/*
* Methods to access the protection register area, present in some
* flash devices. The user data is one time programmable but the
* factory data is read only.
*/
int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
/* This function is not yet implemented */
int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
/* XXX U-BOOT XXX */
#if 0
/* kvec-based read/write methods. We need these especially for NAND flash,
with its limited number of write cycles per erase.
/* kvec-based read/write methods.
NB: The 'count' parameter is the number of _vectors_, each of
which contains an (ofs, len) tuple.
*/
int (*readv) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen);
int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from,
size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to,
size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
#endif
/* Sync */
void (*sync) (struct mtd_info *mtd);
#if 0
/* Chip-supported device locking */
int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len);
int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len);
@ -129,15 +176,32 @@ struct mtd_info {
/* Power Management functions */
int (*suspend) (struct mtd_info *mtd);
void (*resume) (struct mtd_info *mtd);
#endif
/* Bad block management functions */
int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
/* XXX U-BOOT XXX */
#if 0
struct notifier_block reboot_notifier; /* default mode before reboot */
#endif
/* ECC status information */
struct mtd_ecc_stats ecc_stats;
/* Subpage shift (NAND) */
int subpage_sft;
void *priv;
struct module *owner;
int usecount;
/* If the driver is something smart, like UBI, it may need to maintain
* its own reference counting. The below functions are only for driver.
* The driver may register its callbacks. These callbacks are not
* supposed to be called by MTD users */
int (*get_device) (struct mtd_info *mtd);
void (*put_device) (struct mtd_info *mtd);
};
@ -147,9 +211,11 @@ extern int add_mtd_device(struct mtd_info *mtd);
extern int del_mtd_device (struct mtd_info *mtd);
extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num);
extern struct mtd_info *get_mtd_device_nm(const char *name);
extern void put_mtd_device(struct mtd_info *mtd);
/* XXX U-BOOT XXX */
#if 0
struct mtd_notifier {
void (*add)(struct mtd_info *mtd);
@ -157,7 +223,6 @@ struct mtd_notifier {
struct list_head list;
};
extern void register_mtd_user (struct mtd_notifier *new);
extern int unregister_mtd_user (struct mtd_notifier *old);
@ -168,20 +233,6 @@ int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
unsigned long count, loff_t from, size_t *retlen);
#endif
#define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args)
#define MTD_POINT(mtd, a,b,c,d) (*(mtd->point))(mtd, a,b,c, (u_char **)(d))
#define MTD_UNPOINT(mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg)
#define MTD_READ(mtd, args...) (*(mtd->read))(mtd, args)
#define MTD_WRITE(mtd, args...) (*(mtd->write))(mtd, args)
#define MTD_READV(mtd, args...) (*(mtd->readv))(mtd, args)
#define MTD_WRITEV(mtd, args...) (*(mtd->writev))(mtd, args)
#define MTD_READECC(mtd, args...) (*(mtd->read_ecc))(mtd, args)
#define MTD_WRITEECC(mtd, args...) (*(mtd->write_ecc))(mtd, args)
#define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args)
#define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args)
#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0)
#ifdef CONFIG_MTD_PARTITIONS
void mtd_erase_callback(struct erase_info *instr);
#else
@ -208,7 +259,6 @@ static inline void mtd_erase_callback(struct erase_info *instr)
} while(0)
#else /* CONFIG_MTD_DEBUG */
#define MTDDEBUG(n, args...) do { } while(0)
#endif /* CONFIG_MTD_DEBUG */
#endif /* __MTD_MTD_H__ */

View file

@ -5,7 +5,7 @@
* Steven J. Hill <sjhill@realitydiluted.com>
* Thomas Gleixner <tglx@linutronix.de>
*
* $Id: nand.h,v 1.68 2004/11/12 10:40:37 gleixner Exp $
* $Id: nand.h,v 1.74 2005/09/15 13:58:50 vwool Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -15,101 +15,110 @@
* Contains standard defines and IDs for NAND flash devices
*
* Changelog:
* 01-31-2000 DMW Created
* 09-18-2000 SJH Moved structure out of the Disk-On-Chip drivers
* so it can be used by other NAND flash device
* drivers. I also changed the copyright since none
* of the original contents of this file are specific
* to DoC devices. David can whack me with a baseball
* bat later if I did something naughty.
* 10-11-2000 SJH Added private NAND flash structure for driver
* 10-24-2000 SJH Added prototype for 'nand_scan' function
* 10-29-2001 TG changed nand_chip structure to support
* hardwarespecific function for accessing control lines
* 02-21-2002 TG added support for different read/write adress and
* ready/busy line access function
* 02-26-2002 TG added chip_delay to nand_chip structure to optimize
* command delay times for different chips
* 04-28-2002 TG OOB config defines moved from nand.c to avoid duplicate
* defines in jffs2/wbuf.c
* 08-07-2002 TG forced bad block location to byte 5 of OOB, even if
* CONFIG_MTD_NAND_ECC_JFFS2 is not set
* 08-10-2002 TG extensions to nand_chip structure to support HW-ECC
*
* 08-29-2002 tglx nand_chip structure: data_poi for selecting
* internal / fs-driver buffer
* support for 6byte/512byte hardware ECC
* read_ecc, write_ecc extended for different oob-layout
* oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB,
* NAND_YAFFS_OOB
* 11-25-2002 tglx Added Manufacturer code FUJITSU, NATIONAL
* Split manufacturer and device ID structures
*
* 02-08-2004 tglx added option field to nand structure for chip anomalities
* 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id
* update of nand_chip structure description
* See git changelog.
*/
#ifndef __LINUX_MTD_NAND_H
#define __LINUX_MTD_NAND_H
#include <linux/mtd/compat.h>
/* XXX U-BOOT XXX */
#if 0
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/mtd/mtd.h>
#endif
#include "config.h"
#include "linux/mtd/compat.h"
#include "linux/mtd/mtd.h"
struct mtd_info;
/* Scan and identify a NAND device */
extern int nand_scan (struct mtd_info *mtd, int max_chips);
/* Separate phases of nand_scan(), allowing board driver to intervene
* and override command or ECC setup according to flash type */
extern int nand_scan_ident(struct mtd_info *mtd, int max_chips);
extern int nand_scan_tail(struct mtd_info *mtd);
/* Free resources held by the NAND device */
extern void nand_release (struct mtd_info *mtd);
/* Read raw data from the device without ECC */
extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen);
/* Internal helper for board drivers which need to override command function */
extern void nand_wait_ready(struct mtd_info *mtd);
/* The maximum number of NAND chips in an array */
#ifndef NAND_MAX_CHIPS
#define NAND_MAX_CHIPS 8
#endif
/* This constant declares the max. oobsize / page, which
* is supported now. If you add a chip with bigger oobsize/page
* adjust this accordingly.
*/
#define NAND_MAX_OOBSIZE 64
#define NAND_MAX_OOBSIZE 128
#define NAND_MAX_PAGESIZE 4096
/*
* Constants for hardware specific CLE/ALE/NCE function
*
* These are bits which can be or'ed to set/clear multiple
* bits in one go.
*/
/* Select the chip by setting nCE to low */
#define NAND_CTL_SETNCE 1
/* Deselect the chip by setting nCE to high */
#define NAND_CTL_CLRNCE 2
#define NAND_NCE 0x01
/* Select the command latch by setting CLE to high */
#define NAND_CTL_SETCLE 3
/* Deselect the command latch by setting CLE to low */
#define NAND_CTL_CLRCLE 4
#define NAND_CLE 0x02
/* Select the address latch by setting ALE to high */
#define NAND_CTL_SETALE 5
/* Deselect the address latch by setting ALE to low */
#define NAND_CTL_CLRALE 6
/* Set write protection by setting WP to high. Not used! */
#define NAND_CTL_SETWP 7
/* Clear write protection by setting WP to low. Not used! */
#define NAND_CTL_CLRWP 8
#define NAND_ALE 0x04
#define NAND_CTRL_CLE (NAND_NCE | NAND_CLE)
#define NAND_CTRL_ALE (NAND_NCE | NAND_ALE)
#define NAND_CTRL_CHANGE 0x80
/*
* Standard NAND flash commands
*/
#define NAND_CMD_READ0 0
#define NAND_CMD_READ1 1
#define NAND_CMD_RNDOUT 5
#define NAND_CMD_PAGEPROG 0x10
#define NAND_CMD_READOOB 0x50
#define NAND_CMD_ERASE1 0x60
#define NAND_CMD_STATUS 0x70
#define NAND_CMD_STATUS_MULTI 0x71
#define NAND_CMD_SEQIN 0x80
#define NAND_CMD_RNDIN 0x85
#define NAND_CMD_READID 0x90
#define NAND_CMD_ERASE2 0xd0
#define NAND_CMD_RESET 0xff
/* Extended commands for large page devices */
#define NAND_CMD_READSTART 0x30
#define NAND_CMD_RNDOUTSTART 0xE0
#define NAND_CMD_CACHEDPROG 0x15
/* Extended commands for AG-AND device */
/*
* Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
* there is no way to distinguish that from NAND_CMD_READ0
* until the remaining sequence of commands has been completed
* so add a high order bit and mask it off in the command.
*/
#define NAND_CMD_DEPLETE1 0x100
#define NAND_CMD_DEPLETE2 0x38
#define NAND_CMD_STATUS_MULTI 0x71
#define NAND_CMD_STATUS_ERROR 0x72
/* multi-bank error status (banks 0-3) */
#define NAND_CMD_STATUS_ERROR0 0x73
#define NAND_CMD_STATUS_ERROR1 0x74
#define NAND_CMD_STATUS_ERROR2 0x75
#define NAND_CMD_STATUS_ERROR3 0x76
#define NAND_CMD_STATUS_RESET 0x7f
#define NAND_CMD_STATUS_CLEAR 0xff
#define NAND_CMD_NONE -1
/* Status bits */
#define NAND_STATUS_FAIL 0x01
#define NAND_STATUS_FAIL_N1 0x02
@ -120,21 +129,12 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
/*
* Constants for ECC_MODES
*/
/* No ECC. Usage is not recommended ! */
#define NAND_ECC_NONE 0
/* Software ECC 3 byte ECC per 256 Byte data */
#define NAND_ECC_SOFT 1
/* Hardware ECC 3 byte ECC per 256 Byte data */
#define NAND_ECC_HW3_256 2
/* Hardware ECC 3 byte ECC per 512 Byte data */
#define NAND_ECC_HW3_512 3
/* Hardware ECC 6 byte ECC per 512 Byte data */
#define NAND_ECC_HW6_512 4
/* Hardware ECC 8 byte ECC per 512 Byte data */
#define NAND_ECC_HW8_512 6
/* Hardware ECC 12 byte ECC per 2048 Byte data */
#define NAND_ECC_HW12_2048 7
typedef enum {
NAND_ECC_NONE,
NAND_ECC_SOFT,
NAND_ECC_HW,
NAND_ECC_HW_SYNDROME,
} nand_ecc_modes_t;
/*
* Constants for Hardware ECC
@ -146,6 +146,10 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
/* Enable Hardware ECC before syndrom is read back from flash */
#define NAND_ECC_READSYN 2
/* Bit mask for flags passed to do_nand_read_ecc */
#define NAND_GET_DEVICE 0x80
/* Option constants for bizarre disfunctionality and real
* features
*/
@ -165,6 +169,17 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
/* Chip has a array of 4 pages which can be read without
* additional ready /busy waits */
#define NAND_4PAGE_ARRAY 0x00000040
/* Chip requires that BBT is periodically rewritten to prevent
* bits from adjacent blocks from 'leaking' in altering data.
* This happens with the Renesas AG-AND chips, possibly others. */
#define BBT_AUTO_REFRESH 0x00000080
/* Chip does not require ready check on read. True
* for all large page devices, as they do not support
* autoincrement.*/
#define NAND_NO_READRDY 0x00000100
/* Chip does not allow subpage writes */
#define NAND_NO_SUBPAGE_WRITE 0x00000200
/* Options valid for Samsung large page devices */
#define NAND_SAMSUNG_LP_OPTIONS \
@ -183,18 +198,18 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
/* Use a flash based bad block table. This option is passed to the
* default bad block table function. */
#define NAND_USE_FLASH_BBT 0x00010000
/* The hw ecc generator provides a syndrome instead a ecc value on read
* This can only work if we have the ecc bytes directly behind the
* data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */
#define NAND_HWECC_SYNDROME 0x00020000
/* This option skips the bbt scan during initialization. */
#define NAND_SKIP_BBTSCAN 0x00020000
/* This option is defined if the board driver allocates its own buffers
(e.g. because it needs them DMA-coherent */
#define NAND_OWN_BUFFERS 0x00040000
/* Options set by nand scan */
/* Nand scan has allocated oob_buf */
#define NAND_OOBBUF_ALLOC 0x40000000
/* Nand scan has allocated data_buf */
#define NAND_DATABUF_ALLOC 0x80000000
/* Nand scan has allocated controller struct */
#define NAND_CONTROLLER_ALLOC 0x80000000
/* Cell info constants */
#define NAND_CI_CHIPNR_MSK 0x03
#define NAND_CI_CELLTYPE_MSK 0x0C
/*
* nand_state_t - chip states
@ -207,135 +222,216 @@ typedef enum {
FL_ERASING,
FL_SYNCING,
FL_CACHEDPRG,
FL_PM_SUSPENDED,
} nand_state_t;
/* Keep gcc happy */
struct nand_chip;
#if 0
/**
* struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices
* struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
* @lock: protection lock
* @active: the mtd device which holds the controller currently
* @wq: wait queue to sleep on if a NAND operation is in progress
* used instead of the per chip wait queue when a hw controller is available
*/
struct nand_hw_control {
#if 0
spinlock_t lock;
wait_queue_head_t wq;
#endif
struct nand_chip *active;
};
#endif
/**
* struct nand_ecc_ctrl - Control structure for ecc
* @mode: ecc mode
* @steps: number of ecc steps per page
* @size: data bytes per ecc step
* @bytes: ecc bytes per step
* @total: total number of ecc bytes per page
* @prepad: padding information for syndrome based ecc generators
* @postpad: padding information for syndrome based ecc generators
* @layout: ECC layout control struct pointer
* @hwctl: function to control hardware ecc generator. Must only
* be provided if an hardware ECC is available
* @calculate: function for ecc calculation or readback from ecc hardware
* @correct: function for ecc correction, matching to ecc generator (sw/hw)
* @read_page_raw: function to read a raw page without ECC
* @write_page_raw: function to write a raw page without ECC
* @read_page: function to read a page according to the ecc generator requirements
* @write_page: function to write a page according to the ecc generator requirements
* @read_oob: function to read chip OOB data
* @write_oob: function to write chip OOB data
*/
struct nand_ecc_ctrl {
nand_ecc_modes_t mode;
int steps;
int size;
int bytes;
int total;
int prepad;
int postpad;
struct nand_ecclayout *layout;
void (*hwctl)(struct mtd_info *mtd, int mode);
int (*calculate)(struct mtd_info *mtd,
const uint8_t *dat,
uint8_t *ecc_code);
int (*correct)(struct mtd_info *mtd, uint8_t *dat,
uint8_t *read_ecc,
uint8_t *calc_ecc);
int (*read_page_raw)(struct mtd_info *mtd,
struct nand_chip *chip,
uint8_t *buf);
void (*write_page_raw)(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf);
int (*read_page)(struct mtd_info *mtd,
struct nand_chip *chip,
uint8_t *buf);
void (*write_page)(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf);
int (*read_oob)(struct mtd_info *mtd,
struct nand_chip *chip,
int page,
int sndcmd);
int (*write_oob)(struct mtd_info *mtd,
struct nand_chip *chip,
int page);
};
/**
* struct nand_buffers - buffer structure for read/write
* @ecccalc: buffer for calculated ecc
* @ecccode: buffer for ecc read from flash
* @databuf: buffer for data - dynamically sized
*
* Do not change the order of buffers. databuf and oobrbuf must be in
* consecutive order.
*/
struct nand_buffers {
uint8_t ecccalc[NAND_MAX_OOBSIZE];
uint8_t ecccode[NAND_MAX_OOBSIZE];
uint8_t databuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE];
};
/**
* struct nand_chip - NAND Private Flash Chip Data
* @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device
* @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device
* @read_byte: [REPLACEABLE] read one byte from the chip
* @write_byte: [REPLACEABLE] write one byte to the chip
* @read_word: [REPLACEABLE] read one word from the chip
* @write_word: [REPLACEABLE] write one word to the chip
* @write_buf: [REPLACEABLE] write data from the buffer to the chip
* @read_buf: [REPLACEABLE] read data from the chip into the buffer
* @verify_buf: [REPLACEABLE] verify buffer contents against the chip data
* @select_chip: [REPLACEABLE] select chip nr
* @block_bad: [REPLACEABLE] check, if the block is bad
* @block_markbad: [REPLACEABLE] mark the block bad
* @hwcontrol: [BOARDSPECIFIC] hardwarespecific function for accesing control-lines
* @cmd_ctrl: [BOARDSPECIFIC] hardwarespecific funtion for controlling
* ALE/CLE/nCE. Also used to write command and address
* @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line
* If set to NULL no access to ready/busy is available and the ready/busy information
* is read from the chip status register
* @cmdfunc: [REPLACEABLE] hardwarespecific function for writing commands to the chip
* @waitfunc: [REPLACEABLE] hardwarespecific function for wait on ready
* @calculate_ecc: [REPLACEABLE] function for ecc calculation or readback from ecc hardware
* @correct_data: [REPLACEABLE] function for ecc correction, matching to ecc generator (sw/hw)
* @enable_hwecc: [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only
* be provided if a hardware ECC is available
* @ecc: [BOARDSPECIFIC] ecc control ctructure
* @buffers: buffer structure for read/write
* @hwcontrol: platform-specific hardware control structure
* @ops: oob operation operands
* @erase_cmd: [INTERN] erase command write function, selectable due to AND support
* @scan_bbt: [REPLACEABLE] function to scan bad block table
* @eccmode: [BOARDSPECIFIC] mode of ecc, see defines
* @eccsize: [INTERN] databytes used per ecc-calculation
* @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step
* @eccsteps: [INTERN] number of ecc calculation steps per page
* @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
* @chip_lock: [INTERN] spinlock used to protect access to this structure and the chip
* @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress
* @state: [INTERN] the current state of the NAND device
* @oob_poi: poison value buffer
* @page_shift: [INTERN] number of address bits in a page (column address bits)
* @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock
* @bbt_erase_shift: [INTERN] number of address bits in a bbt entry
* @chip_shift: [INTERN] number of address bits in one chip
* @data_buf: [INTERN] internal buffer for one page + oob
* @oob_buf: [INTERN] oob buffer for one eraseblock
* @datbuf: [INTERN] internal buffer for one page + oob
* @oobbuf: [INTERN] oob buffer for one eraseblock
* @oobdirty: [INTERN] indicates that oob_buf must be reinitialized
* @data_poi: [INTERN] pointer to a data buffer
* @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about
* special functionality. See the defines for further explanation
* @badblockpos: [INTERN] position of the bad block marker in the oob area
* @cellinfo: [INTERN] MLC/multichip data from chip ident
* @numchips: [INTERN] number of physical chips
* @chipsize: [INTERN] the size of one chip for multichip arrays
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
* @pagebuf: [INTERN] holds the pagenumber which is currently in data_buf
* @autooob: [REPLACEABLE] the default (auto)placement scheme
* @subpagesize: [INTERN] holds the subpagesize
* @ecclayout: [REPLACEABLE] the default ecc placement scheme
* @bbt: [INTERN] bad block table pointer
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup
* @bbt_md: [REPLACEABLE] bad block table mirror descriptor
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan
* @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices
* @controller: [REPLACEABLE] a pointer to a hardware controller structure
* which is shared among multiple independend devices
* @priv: [OPTIONAL] pointer to private chip date
* @errstat: [OPTIONAL] hardware specific function to perform additional error status checks
* (determine if errors are correctable)
* @write_page: [REPLACEABLE] High-level page write function
*/
struct nand_chip {
void __iomem *IO_ADDR_R;
void __iomem *IO_ADDR_W;
u_char (*read_byte)(struct mtd_info *mtd);
void (*write_byte)(struct mtd_info *mtd, u_char byte);
uint8_t (*read_byte)(struct mtd_info *mtd);
u16 (*read_word)(struct mtd_info *mtd);
void (*write_word)(struct mtd_info *mtd, u16 word);
void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);
void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);
int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len);
void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
void (*select_chip)(struct mtd_info *mtd, int chip);
int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
void (*hwcontrol)(struct mtd_info *mtd, int cmd);
void (*cmd_ctrl)(struct mtd_info *mtd, int dat,
unsigned int ctrl);
int (*dev_ready)(struct mtd_info *mtd);
void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
void (*enable_hwecc)(struct mtd_info *mtd, int mode);
int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
void (*erase_cmd)(struct mtd_info *mtd, int page);
int (*scan_bbt)(struct mtd_info *mtd);
int eccmode;
int eccsize;
int eccbytes;
int eccsteps;
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int page, int cached, int raw);
int chip_delay;
#if 0
spinlock_t chip_lock;
wait_queue_head_t wq;
nand_state_t state;
#endif
unsigned int options;
int page_shift;
int phys_erase_shift;
int bbt_erase_shift;
int chip_shift;
u_char *data_buf;
u_char *oob_buf;
int oobdirty;
u_char *data_poi;
unsigned int options;
int badblockpos;
int numchips;
unsigned long chipsize;
int pagemask;
int pagebuf;
struct nand_oobinfo *autooob;
int subpagesize;
uint8_t cellinfo;
int badblockpos;
nand_state_t state;
uint8_t *oob_poi;
struct nand_hw_control *controller;
struct nand_ecclayout *ecclayout;
struct nand_ecc_ctrl ecc;
struct nand_buffers *buffers;
struct nand_hw_control hwcontrol;
struct mtd_oob_ops ops;
uint8_t *bbt;
struct nand_bbt_descr *bbt_td;
struct nand_bbt_descr *bbt_md;
struct nand_bbt_descr *badblock_pattern;
struct nand_hw_control *controller;
void *priv;
};
@ -348,11 +444,11 @@ struct nand_chip {
#define NAND_MFR_NATIONAL 0x8f
#define NAND_MFR_RENESAS 0x07
#define NAND_MFR_STMICRO 0x20
#define NAND_MFR_HYNIX 0xad
#define NAND_MFR_MICRON 0x2c
/**
* struct nand_flash_dev - NAND Flash Device ID Structure
*
* @name: Identify the device type
* @id: device ID code
* @pagesize: Pagesize in bytes. Either 256 or 512 or 0
@ -462,7 +558,10 @@ extern int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd);
extern int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
extern int nand_default_bbt(struct mtd_info *mtd);
extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt);
extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
int allowbbt);
extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, uint8_t * buf);
/*
* Constants for oob configuration
@ -470,4 +569,67 @@ extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int
#define NAND_SMALL_BADBLOCK_POS 5
#define NAND_LARGE_BADBLOCK_POS 0
/**
* struct platform_nand_chip - chip level device structure
* @nr_chips: max. number of chips to scan for
* @chip_offset: chip number offset
* @nr_partitions: number of partitions pointed to by partitions (or zero)
* @partitions: mtd partition list
* @chip_delay: R/B delay value in us
* @options: Option flags, e.g. 16bit buswidth
* @ecclayout: ecc layout info structure
* @part_probe_types: NULL-terminated array of probe types
* @priv: hardware controller specific settings
*/
struct platform_nand_chip {
int nr_chips;
int chip_offset;
int nr_partitions;
struct mtd_partition *partitions;
struct nand_ecclayout *ecclayout;
int chip_delay;
unsigned int options;
const char **part_probe_types;
void *priv;
};
/**
* struct platform_nand_ctrl - controller level device structure
* @hwcontrol: platform specific hardware control structure
* @dev_ready: platform specific function to read ready/busy pin
* @select_chip: platform specific chip select function
* @cmd_ctrl: platform specific function for controlling
* ALE/CLE/nCE. Also used to write command and address
* @priv: private data to transport driver specific settings
*
* All fields are optional and depend on the hardware driver requirements
*/
struct platform_nand_ctrl {
void (*hwcontrol)(struct mtd_info *mtd, int cmd);
int (*dev_ready)(struct mtd_info *mtd);
void (*select_chip)(struct mtd_info *mtd, int chip);
void (*cmd_ctrl)(struct mtd_info *mtd, int dat,
unsigned int ctrl);
void *priv;
};
/**
* struct platform_nand_data - container structure for platform-specific data
* @chip: chip level chip structure
* @ctrl: controller level device structure
*/
struct platform_nand_data {
struct platform_nand_chip chip;
struct platform_nand_ctrl ctrl;
};
/* Some helpers to access the data structures */
static inline
struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
return chip->priv;
}
#endif /* __LINUX_MTD_NAND_H */

View file

@ -0,0 +1,76 @@
/*
* $Id: nftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
*
* Parts of NFTL headers shared with userspace
*
*/
#ifndef __MTD_NFTL_USER_H__
#define __MTD_NFTL_USER_H__
/* Block Control Information */
struct nftl_bci {
unsigned char ECCSig[6];
uint8_t Status;
uint8_t Status1;
}__attribute__((packed));
/* Unit Control Information */
struct nftl_uci0 {
uint16_t VirtUnitNum;
uint16_t ReplUnitNum;
uint16_t SpareVirtUnitNum;
uint16_t SpareReplUnitNum;
} __attribute__((packed));
struct nftl_uci1 {
uint32_t WearInfo;
uint16_t EraseMark;
uint16_t EraseMark1;
} __attribute__((packed));
struct nftl_uci2 {
uint16_t FoldMark;
uint16_t FoldMark1;
uint32_t unused;
} __attribute__((packed));
union nftl_uci {
struct nftl_uci0 a;
struct nftl_uci1 b;
struct nftl_uci2 c;
};
struct nftl_oob {
struct nftl_bci b;
union nftl_uci u;
};
/* NFTL Media Header */
struct NFTLMediaHeader {
char DataOrgID[6];
uint16_t NumEraseUnits;
uint16_t FirstPhysicalEUN;
uint32_t FormattedSize;
unsigned char UnitSizeFactor;
} __attribute__((packed));
#define MAX_ERASE_ZONES (8192 - 512)
#define ERASE_MARK 0x3c69
#define SECTOR_FREE 0xff
#define SECTOR_USED 0x55
#define SECTOR_IGNORE 0x11
#define SECTOR_DELETED 0x00
#define FOLD_MARK_IN_PROGRESS 0x5555
#define ZONE_GOOD 0xff
#define ZONE_BAD_ORIGINAL 0
#define ZONE_BAD_MARKED 7
#endif /* __MTD_NFTL_USER_H__ */

View file

@ -1,75 +1,16 @@
/* Defines for NAND Flash Translation Layer */
/* (c) 1999 Machine Vision Holdings, Inc. */
/* Author: David Woodhouse <dwmw2@mvhi.com> */
/* $Id: nftl.h,v 1.10 2000/12/29 00:25:38 dwmw2 Exp $ */
/*
* $Id: nftl.h,v 1.16 2004/06/30 14:49:00 dbrown Exp $
*
* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
*/
#ifndef __MTD_NFTL_H__
#define __MTD_NFTL_H__
/* Block Control Information */
#include <linux/mtd/mtd.h>
#include <linux/mtd/blktrans.h>
struct nftl_bci {
unsigned char ECCSig[6];
__u8 Status;
__u8 Status1;
}__attribute__((packed));
/* Unit Control Information */
struct nftl_uci0 {
__u16 VirtUnitNum;
__u16 ReplUnitNum;
__u16 SpareVirtUnitNum;
__u16 SpareReplUnitNum;
} __attribute__((packed));
struct nftl_uci1 {
__u32 WearInfo;
__u16 EraseMark;
__u16 EraseMark1;
} __attribute__((packed));
struct nftl_uci2 {
__u16 FoldMark;
__u16 FoldMark1;
__u32 unused;
} __attribute__((packed));
union nftl_uci {
struct nftl_uci0 a;
struct nftl_uci1 b;
struct nftl_uci2 c;
};
struct nftl_oob {
struct nftl_bci b;
union nftl_uci u;
};
/* NFTL Media Header */
struct NFTLMediaHeader {
char DataOrgID[6];
__u16 NumEraseUnits;
__u16 FirstPhysicalEUN;
__u32 FormattedSize;
unsigned char UnitSizeFactor;
} __attribute__((packed));
#define MAX_ERASE_ZONES (8192 - 512)
#define ERASE_MARK 0x3c69
#define SECTOR_FREE 0xff
#define SECTOR_USED 0x55
#define SECTOR_IGNORE 0x11
#define SECTOR_DELETED 0x00
#define FOLD_MARK_IN_PROGRESS 0x5555
#define ZONE_GOOD 0xff
#define ZONE_BAD_ORIGINAL 0
#define ZONE_BAD_MARKED 7
#include <linux/mtd/nftl-user.h>
/* these info are used in ReplUnitTable */
#define BLOCK_NIL 0xffff /* last block of a chain */
@ -78,7 +19,7 @@ struct NFTLMediaHeader {
#define BLOCK_RESERVED 0xfffc /* bios block or bad block */
struct NFTLrecord {
struct DiskOnChip *mtd;
struct mtd_blktrans_dev mbd;
__u16 MediaUnit, SpareMediaUnit;
__u32 EraseSize;
struct NFTLMediaHeader MediaHdr;
@ -90,16 +31,24 @@ struct NFTLrecord {
__u16 lastEUN; /* should be suppressed */
__u16 numfreeEUNs;
__u16 LastFreeEUN; /* To speed up finding a free EUN */
__u32 nr_sects;
int head,sect,cyl;
__u16 *EUNtable; /* [numvunits]: First EUN for each virtual unit */
__u16 *ReplUnitTable; /* [numEUNs]: ReplUnitNumber for each */
unsigned int nb_blocks; /* number of physical blocks */
unsigned int nb_boot_blocks; /* number of blocks used by the bios */
struct erase_info instr;
struct nand_ecclayout oobinfo;
};
int NFTL_mount(struct NFTLrecord *s);
int NFTL_formatblock(struct NFTLrecord *s, int block);
#ifndef NFTL_MAJOR
#define NFTL_MAJOR 93
#endif
#define MAX_NFTLS 16
#define MAX_SECTORS_PER_UNIT 32
#define MAX_SECTORS_PER_UNIT 64
#define NFTL_PARTN_BITS 4
#endif /* __MTD_NFTL_H__ */

View file

@ -0,0 +1,360 @@
/*
* Copyright (c) International Business Machines Corp., 2006
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Authors: Artem Bityutskiy (Битюцкий Артём)
* Thomas Gleixner
* Frank Haverkamp
* Oliver Lohmann
* Andreas Arnez
*/
/*
* This file defines the layout of UBI headers and all the other UBI on-flash
* data structures. May be included by user-space.
*/
#ifndef __UBI_HEADER_H__
#define __UBI_HEADER_H__
#include <asm/byteorder.h>
/* The version of UBI images supported by this implementation */
#define UBI_VERSION 1
/* The highest erase counter value supported by this implementation */
#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF
/* The initial CRC32 value used when calculating CRC checksums */
#define UBI_CRC32_INIT 0xFFFFFFFFU
/* Erase counter header magic number (ASCII "UBI#") */
#define UBI_EC_HDR_MAGIC 0x55424923
/* Volume identifier header magic number (ASCII "UBI!") */
#define UBI_VID_HDR_MAGIC 0x55424921
/*
* Volume type constants used in the volume identifier header.
*
* @UBI_VID_DYNAMIC: dynamic volume
* @UBI_VID_STATIC: static volume
*/
enum {
UBI_VID_DYNAMIC = 1,
UBI_VID_STATIC = 2
};
/*
* Compatibility constants used by internal volumes.
*
* @UBI_COMPAT_DELETE: delete this internal volume before anything is written
* to the flash
* @UBI_COMPAT_RO: attach this device in read-only mode
* @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its
* physical eraseblocks, don't allow the wear-leveling unit to move them
* @UBI_COMPAT_REJECT: reject this UBI image
*/
enum {
UBI_COMPAT_DELETE = 1,
UBI_COMPAT_RO = 2,
UBI_COMPAT_PRESERVE = 4,
UBI_COMPAT_REJECT = 5
};
/*
* ubi16_t/ubi32_t/ubi64_t - 16, 32, and 64-bit integers used in UBI on-flash
* data structures.
*/
typedef struct {
uint16_t int16;
} __attribute__ ((packed)) ubi16_t;
typedef struct {
uint32_t int32;
} __attribute__ ((packed)) ubi32_t;
typedef struct {
uint64_t int64;
} __attribute__ ((packed)) ubi64_t;
/*
* In this implementation of UBI uses the big-endian format for on-flash
* integers. The below are the corresponding conversion macros.
*/
#define cpu_to_ubi16(x) ((ubi16_t){__cpu_to_be16(x)})
#define ubi16_to_cpu(x) ((uint16_t)__be16_to_cpu((x).int16))
#define cpu_to_ubi32(x) ((ubi32_t){__cpu_to_be32(x)})
#define ubi32_to_cpu(x) ((uint32_t)__be32_to_cpu((x).int32))
#define cpu_to_ubi64(x) ((ubi64_t){__cpu_to_be64(x)})
#define ubi64_to_cpu(x) ((uint64_t)__be64_to_cpu((x).int64))
/* Sizes of UBI headers */
#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr)
#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
/* Sizes of UBI headers without the ending CRC */
#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(ubi32_t))
#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(ubi32_t))
/**
* struct ubi_ec_hdr - UBI erase counter header.
* @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
* @version: version of UBI implementation which is supposed to accept this
* UBI image
* @padding1: reserved for future, zeroes
* @ec: the erase counter
* @vid_hdr_offset: where the VID header starts
* @data_offset: where the user data start
* @padding2: reserved for future, zeroes
* @hdr_crc: erase counter header CRC checksum
*
* The erase counter header takes 64 bytes and has a plenty of unused space for
* future usage. The unused fields are zeroed. The @version field is used to
* indicate the version of UBI implementation which is supposed to be able to
* work with this UBI image. If @version is greater then the current UBI
* version, the image is rejected. This may be useful in future if something
* is changed radically. This field is duplicated in the volume identifier
* header.
*
* The @vid_hdr_offset and @data_offset fields contain the offset of the the
* volume identifier header and user data, relative to the beginning of the
* physical eraseblock. These values have to be the same for all physical
* eraseblocks.
*/
struct ubi_ec_hdr {
ubi32_t magic;
uint8_t version;
uint8_t padding1[3];
ubi64_t ec; /* Warning: the current limit is 31-bit anyway! */
ubi32_t vid_hdr_offset;
ubi32_t data_offset;
uint8_t padding2[36];
ubi32_t hdr_crc;
} __attribute__ ((packed));
/**
* struct ubi_vid_hdr - on-flash UBI volume identifier header.
* @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC)
* @version: UBI implementation version which is supposed to accept this UBI
* image (%UBI_VERSION)
* @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
* @copy_flag: if this logical eraseblock was copied from another physical
* eraseblock (for wear-leveling reasons)
* @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
* %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
* @vol_id: ID of this volume
* @lnum: logical eraseblock number
* @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be
* removed, kept only for not breaking older UBI users)
* @data_size: how many bytes of data this logical eraseblock contains
* @used_ebs: total number of used logical eraseblocks in this volume
* @data_pad: how many bytes at the end of this physical eraseblock are not
* used
* @data_crc: CRC checksum of the data stored in this logical eraseblock
* @padding1: reserved for future, zeroes
* @sqnum: sequence number
* @padding2: reserved for future, zeroes
* @hdr_crc: volume identifier header CRC checksum
*
* The @sqnum is the value of the global sequence counter at the time when this
* VID header was created. The global sequence counter is incremented each time
* UBI writes a new VID header to the flash, i.e. when it maps a logical
* eraseblock to a new physical eraseblock. The global sequence counter is an
* unsigned 64-bit integer and we assume it never overflows. The @sqnum
* (sequence number) is used to distinguish between older and newer versions of
* logical eraseblocks.
*
* There are 2 situations when there may be more then one physical eraseblock
* corresponding to the same logical eraseblock, i.e., having the same @vol_id
* and @lnum values in the volume identifier header. Suppose we have a logical
* eraseblock L and it is mapped to the physical eraseblock P.
*
* 1. Because UBI may erase physical eraseblocks asynchronously, the following
* situation is possible: L is asynchronously erased, so P is scheduled for
* erasure, then L is written to,i.e. mapped to another physical eraseblock P1,
* so P1 is written to, then an unclean reboot happens. Result - there are 2
* physical eraseblocks P and P1 corresponding to the same logical eraseblock
* L. But P1 has greater sequence number, so UBI picks P1 when it attaches the
* flash.
*
* 2. From time to time UBI moves logical eraseblocks to other physical
* eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P
* to P1, and an unclean reboot happens before P is physically erased, there
* are two physical eraseblocks P and P1 corresponding to L and UBI has to
* select one of them when the flash is attached. The @sqnum field says which
* PEB is the original (obviously P will have lower @sqnum) and the copy. But
* it is not enough to select the physical eraseblock with the higher sequence
* number, because the unclean reboot could have happen in the middle of the
* copying process, so the data in P is corrupted. It is also not enough to
* just select the physical eraseblock with lower sequence number, because the
* data there may be old (consider a case if more data was added to P1 after
* the copying). Moreover, the unclean reboot may happen when the erasure of P
* was just started, so it result in unstable P, which is "mostly" OK, but
* still has unstable bits.
*
* UBI uses the @copy_flag field to indicate that this logical eraseblock is a
* copy. UBI also calculates data CRC when the data is moved and stores it at
* the @data_crc field of the copy (P1). So when UBI needs to pick one physical
* eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is
* examined. If it is cleared, the situation* is simple and the newer one is
* picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC
* checksum is correct, this physical eraseblock is selected (P1). Otherwise
* the older one (P) is selected.
*
* Note, there is an obsolete @leb_ver field which was used instead of @sqnum
* in the past. But it is not used anymore and we keep it in order to be able
* to deal with old UBI images. It will be removed at some point.
*
* There are 2 sorts of volumes in UBI: user volumes and internal volumes.
* Internal volumes are not seen from outside and are used for various internal
* UBI purposes. In this implementation there is only one internal volume - the
* layout volume. Internal volumes are the main mechanism of UBI extensions.
* For example, in future one may introduce a journal internal volume. Internal
* volumes have their own reserved range of IDs.
*
* The @compat field is only used for internal volumes and contains the "degree
* of their compatibility". It is always zero for user volumes. This field
* provides a mechanism to introduce UBI extensions and to be still compatible
* with older UBI binaries. For example, if someone introduced a journal in
* future, he would probably use %UBI_COMPAT_DELETE compatibility for the
* journal volume. And in this case, older UBI binaries, which know nothing
* about the journal volume, would just delete this volume and work perfectly
* fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image
* - it just ignores the Ext3fs journal.
*
* The @data_crc field contains the CRC checksum of the contents of the logical
* eraseblock if this is a static volume. In case of dynamic volumes, it does
* not contain the CRC checksum as a rule. The only exception is when the
* data of the physical eraseblock was moved by the wear-leveling unit, then
* the wear-leveling unit calculates the data CRC and stores it in the
* @data_crc field. And of course, the @copy_flag is %in this case.
*
* The @data_size field is used only for static volumes because UBI has to know
* how many bytes of data are stored in this eraseblock. For dynamic volumes,
* this field usually contains zero. The only exception is when the data of the
* physical eraseblock was moved to another physical eraseblock for
* wear-leveling reasons. In this case, UBI calculates CRC checksum of the
* contents and uses both @data_crc and @data_size fields. In this case, the
* @data_size field contains data size.
*
* The @used_ebs field is used only for static volumes and indicates how many
* eraseblocks the data of the volume takes. For dynamic volumes this field is
* not used and always contains zero.
*
* The @data_pad is calculated when volumes are created using the alignment
* parameter. So, effectively, the @data_pad field reduces the size of logical
* eraseblocks of this volume. This is very handy when one uses block-oriented
* software (say, cramfs) on top of the UBI volume.
*/
struct ubi_vid_hdr {
ubi32_t magic;
uint8_t version;
uint8_t vol_type;
uint8_t copy_flag;
uint8_t compat;
ubi32_t vol_id;
ubi32_t lnum;
ubi32_t leb_ver; /* obsolete, to be removed, don't use */
ubi32_t data_size;
ubi32_t used_ebs;
ubi32_t data_pad;
ubi32_t data_crc;
uint8_t padding1[4];
ubi64_t sqnum;
uint8_t padding2[12];
ubi32_t hdr_crc;
} __attribute__ ((packed));
/* Internal UBI volumes count */
#define UBI_INT_VOL_COUNT 1
/*
* Starting ID of internal volumes. There is reserved room for 4096 internal
* volumes.
*/
#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
/* The layout volume contains the volume table */
#define UBI_LAYOUT_VOL_ID UBI_INTERNAL_VOL_START
#define UBI_LAYOUT_VOLUME_EBS 2
#define UBI_LAYOUT_VOLUME_NAME "layout volume"
#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
/* The maximum number of volumes per one UBI device */
#define UBI_MAX_VOLUMES 128
/* The maximum volume name length */
#define UBI_VOL_NAME_MAX 127
/* Size of the volume table record */
#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
/* Size of the volume table record without the ending CRC */
#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(ubi32_t))
/**
* struct ubi_vtbl_record - a record in the volume table.
* @reserved_pebs: how many physical eraseblocks are reserved for this volume
* @alignment: volume alignment
* @data_pad: how many bytes are unused at the end of the each physical
* eraseblock to satisfy the requested alignment
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
* @upd_marker: if volume update was started but not finished
* @name_len: volume name length
* @name: the volume name
* @padding2: reserved, zeroes
* @crc: a CRC32 checksum of the record
*
* The volume table records are stored in the volume table, which is stored in
* the layout volume. The layout volume consists of 2 logical eraseblock, each
* of which contains a copy of the volume table (i.e., the volume table is
* duplicated). The volume table is an array of &struct ubi_vtbl_record
* objects indexed by the volume ID.
*
* If the size of the logical eraseblock is large enough to fit
* %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES
* records. Otherwise, it contains as many records as it can fit (i.e., size of
* logical eraseblock divided by sizeof(struct ubi_vtbl_record)).
*
* The @upd_marker flag is used to implement volume update. It is set to %1
* before update and set to %0 after the update. So if the update operation was
* interrupted, UBI knows that the volume is corrupted.
*
* The @alignment field is specified when the volume is created and cannot be
* later changed. It may be useful, for example, when a block-oriented file
* system works on top of UBI. The @data_pad field is calculated using the
* logical eraseblock size and @alignment. The alignment must be multiple to the
* minimal flash I/O unit. If @alignment is 1, all the available space of
* the physical eraseblocks is used.
*
* Empty records contain all zeroes and the CRC checksum of those zeroes.
*/
struct ubi_vtbl_record {
ubi32_t reserved_pebs;
ubi32_t alignment;
ubi32_t data_pad;
uint8_t vol_type;
uint8_t upd_marker;
ubi16_t name_len;
uint8_t name[UBI_VOL_NAME_MAX+1];
uint8_t padding2[24];
ubi32_t crc;
} __attribute__ ((packed));
#endif /* !__UBI_HEADER_H__ */

View file

@ -0,0 +1,161 @@
/*
* Copyright (c) International Business Machines Corp., 2006
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Artem Bityutskiy (Битюцкий Артём)
*/
#ifndef __UBI_USER_H__
#define __UBI_USER_H__
/*
* UBI volume creation
* ~~~~~~~~~~~~~~~~~~~
*
* UBI volumes are created via the %UBI_IOCMKVOL IOCTL command of UBI character
* device. A &struct ubi_mkvol_req object has to be properly filled and a
* pointer to it has to be passed to the IOCTL.
*
* UBI volume deletion
* ~~~~~~~~~~~~~~~~~~~
*
* To delete a volume, the %UBI_IOCRMVOL IOCTL command of the UBI character
* device should be used. A pointer to the 32-bit volume ID hast to be passed
* to the IOCTL.
*
* UBI volume re-size
* ~~~~~~~~~~~~~~~~~~
*
* To re-size a volume, the %UBI_IOCRSVOL IOCTL command of the UBI character
* device should be used. A &struct ubi_rsvol_req object has to be properly
* filled and a pointer to it has to be passed to the IOCTL.
*
* UBI volume update
* ~~~~~~~~~~~~~~~~~
*
* Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the
* corresponding UBI volume character device. A pointer to a 64-bit update
* size should be passed to the IOCTL. After then, UBI expects user to write
* this number of bytes to the volume character device. The update is finished
* when the claimed number of bytes is passed. So, the volume update sequence
* is something like:
*
* fd = open("/dev/my_volume");
* ioctl(fd, UBI_IOCVOLUP, &image_size);
* write(fd, buf, image_size);
* close(fd);
*/
/*
* When a new volume is created, users may either specify the volume number they
* want to create or to let UBI automatically assign a volume number using this
* constant.
*/
#define UBI_VOL_NUM_AUTO (-1)
/* Maximum volume name length */
#define UBI_MAX_VOLUME_NAME 127
/* IOCTL commands of UBI character devices */
#define UBI_IOC_MAGIC 'o'
/* Create an UBI volume */
#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req)
/* Remove an UBI volume */
#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t)
/* Re-size an UBI volume */
#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req)
/* IOCTL commands of UBI volume character devices */
#define UBI_VOL_IOC_MAGIC 'O'
/* Start UBI volume update */
#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t)
/* An eraseblock erasure command, used for debugging, disabled by default */
#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)
/*
* UBI volume type constants.
*
* @UBI_DYNAMIC_VOLUME: dynamic volume
* @UBI_STATIC_VOLUME: static volume
*/
enum {
UBI_DYNAMIC_VOLUME = 3,
UBI_STATIC_VOLUME = 4
};
/**
* struct ubi_mkvol_req - volume description data structure used in
* volume creation requests.
* @vol_id: volume number
* @alignment: volume alignment
* @bytes: volume size in bytes
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
* @padding1: reserved for future, not used
* @name_len: volume name length
* @padding2: reserved for future, not used
* @name: volume name
*
* This structure is used by userspace programs when creating new volumes. The
* @used_bytes field is only necessary when creating static volumes.
*
* The @alignment field specifies the required alignment of the volume logical
* eraseblock. This means, that the size of logical eraseblocks will be aligned
* to this number, i.e.,
* (UBI device logical eraseblock size) mod (@alignment) = 0.
*
* To put it differently, the logical eraseblock of this volume may be slightly
* shortened in order to make it properly aligned. The alignment has to be
* multiple of the flash minimal input/output unit, or %1 to utilize the entire
* available space of logical eraseblocks.
*
* The @alignment field may be useful, for example, when one wants to maintain
* a block device on top of an UBI volume. In this case, it is desirable to fit
* an integer number of blocks in logical eraseblocks of this UBI volume. With
* alignment it is possible to update this volume using plane UBI volume image
* BLOBs, without caring about how to properly align them.
*/
struct ubi_mkvol_req {
int32_t vol_id;
int32_t alignment;
int64_t bytes;
int8_t vol_type;
int8_t padding1;
int16_t name_len;
int8_t padding2[4];
char name[UBI_MAX_VOLUME_NAME+1];
} __attribute__ ((packed));
/**
* struct ubi_rsvol_req - a data structure used in volume re-size requests.
* @vol_id: ID of the volume to re-size
* @bytes: new size of the volume in bytes
*
* Re-sizing is possible for both dynamic and static volumes. But while dynamic
* volumes may be re-sized arbitrarily, static volumes cannot be made to be
* smaller then the number of bytes they bear. To arbitrarily shrink a static
* volume, it must be wiped out first (by means of volume update operation with
* zero number of bytes).
*/
struct ubi_rsvol_req {
int64_t bytes;
int32_t vol_id;
} __attribute__ ((packed));
#endif /* __UBI_USER_H__ */

View file

@ -84,6 +84,7 @@ struct nand_write_options {
};
typedef struct nand_write_options nand_write_options_t;
typedef struct mtd_oob_ops mtd_oob_ops_t;
struct nand_read_options {
u_char *buffer; /* memory block in which read image is written*/
@ -107,7 +108,7 @@ struct nand_erase_options {
typedef struct nand_erase_options nand_erase_options_t;
int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts);
int nand_write_opts(nand_info_t *mtd, loff_t to, mtd_oob_ops_t *ops);
int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts);
int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts);