Merge branch 'master' of /home/stefan/git/u-boot/u-boot
This commit is contained in:
commit
5a7ddf4e1f
23
Makefile
23
Makefile
@ -210,7 +210,7 @@ LIBS += cpu/ixp/npe/libnpe.a
|
||||
endif
|
||||
LIBS += lib_$(ARCH)/lib$(ARCH).a
|
||||
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
|
||||
fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a
|
||||
fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/yaffs2/libyaffs2.a
|
||||
LIBS += net/libnet.a
|
||||
LIBS += disk/libdisk.a
|
||||
LIBS += drivers/bios_emulator/libatibiosemu.a
|
||||
@ -378,6 +378,7 @@ TAG_SUBDIRS += fs/cramfs
|
||||
TAG_SUBDIRS += fs/fat
|
||||
TAG_SUBDIRS += fs/fdos
|
||||
TAG_SUBDIRS += fs/jffs2
|
||||
TAG_SUBDIRS += fs/yaffs2
|
||||
TAG_SUBDIRS += net
|
||||
TAG_SUBDIRS += disk
|
||||
TAG_SUBDIRS += common
|
||||
@ -2010,8 +2011,11 @@ TASREG_config : unconfig
|
||||
#########################################################################
|
||||
|
||||
MPC8313ERDB_33_config \
|
||||
MPC8313ERDB_66_config: unconfig
|
||||
MPC8313ERDB_66_config \
|
||||
MPC8313ERDB_NAND_33_config \
|
||||
MPC8313ERDB_NAND_66_config: unconfig
|
||||
@mkdir -p $(obj)include
|
||||
@mkdir -p $(obj)board/freescale/mpc8313erdb
|
||||
@if [ "$(findstring _33_,$@)" ] ; then \
|
||||
$(XECHO) -n "...33M ..." ; \
|
||||
echo "#define CFG_33MHZ" >>$(obj)include/config.h ; \
|
||||
@ -2019,6 +2023,11 @@ MPC8313ERDB_66_config: unconfig
|
||||
if [ "$(findstring _66_,$@)" ] ; then \
|
||||
$(XECHO) -n "...66M..." ; \
|
||||
echo "#define CFG_66MHZ" >>$(obj)include/config.h ; \
|
||||
fi ; \
|
||||
if [ "$(findstring _NAND_,$@)" ] ; then \
|
||||
$(XECHO) -n "...NAND..." ; \
|
||||
echo "TEXT_BASE = 0x00100000" > $(obj)/board/freescale/mpc8313erdb/config.tmp ; \
|
||||
echo "#define CONFIG_NAND_U_BOOT" >>$(obj)include/config.h ; \
|
||||
fi ;
|
||||
@$(MKCONFIG) -a MPC8313ERDB ppc mpc83xx mpc8313erdb freescale
|
||||
|
||||
@ -2368,13 +2377,13 @@ at91rm9200dk_config : unconfig
|
||||
@$(MKCONFIG) $(@:_config=) arm arm920t at91rm9200dk atmel at91rm9200
|
||||
|
||||
at91sam9261ek_config : unconfig
|
||||
@$(MKCONFIG) $(@:_config=) arm arm926ejs at91sam9261ek atmel at91sam9
|
||||
@$(MKCONFIG) $(@:_config=) arm arm926ejs at91sam9261ek atmel at91
|
||||
|
||||
at91sam9263ek_config : unconfig
|
||||
@$(MKCONFIG) $(@:_config=) arm arm926ejs at91sam9263ek atmel at91sam9
|
||||
@$(MKCONFIG) $(@:_config=) arm arm926ejs at91sam9263ek atmel at91
|
||||
|
||||
at91sam9rlek_config : unconfig
|
||||
@$(MKCONFIG) $(@:_config=) arm arm926ejs at91sam9rlek atmel at91sam9
|
||||
@$(MKCONFIG) $(@:_config=) arm arm926ejs at91sam9rlek atmel at91
|
||||
|
||||
cmc_pu2_config : unconfig
|
||||
@$(MKCONFIG) $(@:_config=) arm arm920t cmc_pu2 NULL at91rm9200
|
||||
@ -2396,10 +2405,10 @@ mp2usb_config : unconfig
|
||||
#########################################################################
|
||||
|
||||
at91cap9adk_config : unconfig
|
||||
@$(MKCONFIG) $(@:_config=) arm arm926ejs at91cap9adk atmel at91sam9
|
||||
@$(MKCONFIG) $(@:_config=) arm arm926ejs at91cap9adk atmel at91
|
||||
|
||||
at91sam9260ek_config : unconfig
|
||||
@$(MKCONFIG) $(@:_config=) arm arm926ejs at91sam9260ek atmel at91sam9
|
||||
@$(MKCONFIG) $(@:_config=) arm arm926ejs at91sam9260ek atmel at91
|
||||
|
||||
########################################################################
|
||||
## ARM Integrator boards - see doc/README-integrator for more info.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
MACRO_NAND_CTL_SETCLE((unsigned long)base);
|
||||
break;
|
||||
case NAND_CTL_CLRCLE:
|
||||
MACRO_NAND_CTL_CLRCLE((unsigned long)base);
|
||||
break;
|
||||
case NAND_CTL_SETALE:
|
||||
MACRO_NAND_CTL_SETALE((unsigned long)base);
|
||||
break;
|
||||
case NAND_CTL_CLRALE:
|
||||
MACRO_NAND_CTL_CLRALE((unsigned long)base);
|
||||
break;
|
||||
case NAND_CTL_SETNCE:
|
||||
MACRO_NAND_ENABLE_CE((unsigned long)base);
|
||||
break;
|
||||
case NAND_CTL_CLRNCE:
|
||||
MACRO_NAND_DISABLE_CE((unsigned long)base);
|
||||
break;
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
if ( ctrl & NAND_CLE )
|
||||
MACRO_NAND_CTL_SETCLE((unsigned long)base);
|
||||
else
|
||||
MACRO_NAND_CTL_CLRCLE((unsigned long)base);
|
||||
if ( ctrl & NAND_ALE )
|
||||
MACRO_NAND_CTL_CLRCLE((unsigned long)base);
|
||||
else
|
||||
MACRO_NAND_CTL_CLRALE((unsigned long)base);
|
||||
if ( ctrl & NAND_NCE )
|
||||
MACRO_NAND_ENABLE_CE((unsigned long)base);
|
||||
else
|
||||
MACRO_NAND_DISABLE_CE((unsigned long)base);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) | CFG_NAND_CLE);
|
||||
break;
|
||||
case NAND_CTL_CLRCLE:
|
||||
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) & ~CFG_NAND_CLE);
|
||||
break;
|
||||
case NAND_CTL_SETALE:
|
||||
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) | CFG_NAND_ALE);
|
||||
break;
|
||||
case NAND_CTL_CLRALE:
|
||||
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) & ~CFG_NAND_ALE);
|
||||
break;
|
||||
case NAND_CTL_SETNCE:
|
||||
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) & ~CFG_NAND_CE);
|
||||
break;
|
||||
case NAND_CTL_CLRNCE:
|
||||
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) | CFG_NAND_CE);
|
||||
break;
|
||||
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);
|
||||
else
|
||||
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) & ~CFG_NAND_CLE);
|
||||
if ( ctrl & NAND_ALE )
|
||||
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) | CFG_NAND_ALE);
|
||||
else
|
||||
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) & ~CFG_NAND_ALE);
|
||||
if ( ctrl & NAND_NCE )
|
||||
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) & ~CFG_NAND_CE);
|
||||
else
|
||||
out_be32((void *)GPIO0_OR, in_be32((void *)GPIO0_OR) | CFG_NAND_CE);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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:
|
||||
nand_baseaddr |= SET_CLE;
|
||||
break;
|
||||
case NAND_CTL_CLRCLE:
|
||||
nand_baseaddr &= CLR_CLE;
|
||||
break;
|
||||
case NAND_CTL_SETALE:
|
||||
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;
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
if ( ctrl & NAND_CLE )
|
||||
nand_baseaddr |= SET_CLE;
|
||||
else
|
||||
nand_baseaddr &= CLR_CLE;
|
||||
if ( ctrl & NAND_ALE )
|
||||
nand_baseaddr |= SET_ALE;
|
||||
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;
|
||||
|
@ -1 +1,7 @@
|
||||
ifndef NAND_SPL
|
||||
sinclude $(OBJTREE)/board/$(BOARDDIR)/config.tmp
|
||||
endif
|
||||
|
||||
ifndef TEXT_BASE
|
||||
TEXT_BASE = 0xFE000000
|
||||
endif
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include <pci.h>
|
||||
#include <mpc83xx.h>
|
||||
#include <vsc7385.h>
|
||||
#include <ns16550.h>
|
||||
#include <nand.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
@ -50,6 +52,7 @@ int checkboard(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NAND_SPL
|
||||
static struct pci_region pci_regions[] = {
|
||||
{
|
||||
bus_start: CFG_PCI1_MEM_BASE,
|
||||
@ -128,3 +131,32 @@ void ft_board_setup(void *blob, bd_t *bd)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#else /* CONFIG_NAND_SPL */
|
||||
void board_init_f(ulong bootflag)
|
||||
{
|
||||
board_early_init_f();
|
||||
NS16550_init((NS16550_t)(CFG_IMMR + 0x4500),
|
||||
CFG_NS16550_CLK / 16 / CONFIG_BAUDRATE);
|
||||
puts("NAND boot... ");
|
||||
init_timebase();
|
||||
initdram(0);
|
||||
relocate_code(CFG_NAND_U_BOOT_RELOC + 0x10000, (gd_t *)gd,
|
||||
CFG_NAND_U_BOOT_RELOC);
|
||||
}
|
||||
|
||||
void board_init_r(gd_t *gd, ulong dest_addr)
|
||||
{
|
||||
nand_boot();
|
||||
}
|
||||
|
||||
void putc(char c)
|
||||
{
|
||||
if (gd->flags & GD_FLG_SILENT)
|
||||
return;
|
||||
|
||||
if (c == '\n')
|
||||
NS16550_putc((NS16550_t)(CFG_IMMR + 0x4500), '\r');
|
||||
|
||||
NS16550_putc((NS16550_t)(CFG_IMMR + 0x4500), c);
|
||||
}
|
||||
#endif
|
||||
|
@ -58,8 +58,10 @@ static void resume_from_sleep(void)
|
||||
*/
|
||||
static long fixed_sdram(void)
|
||||
{
|
||||
volatile immap_t *im = (volatile immap_t *)CFG_IMMR;
|
||||
u32 msize = CFG_DDR_SIZE * 1024 * 1024;
|
||||
|
||||
#ifndef CFG_RAMBOOT
|
||||
volatile immap_t *im = (volatile immap_t *)CFG_IMMR;
|
||||
u32 msize_log2 = __ilog2(msize);
|
||||
|
||||
im->sysconf.ddrlaw[0].bar = CFG_DDR_SDRAM_BASE >> 12;
|
||||
@ -100,6 +102,7 @@ static long fixed_sdram(void)
|
||||
|
||||
/* enable DDR controller */
|
||||
im->ddr.sdram_cfg |= SDRAM_CFG_MEM_EN;
|
||||
#endif
|
||||
|
||||
return msize;
|
||||
}
|
||||
|
@ -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:
|
||||
this->IO_ADDR_W += 2;
|
||||
break;
|
||||
case NAND_CTL_CLRCLE:
|
||||
this->IO_ADDR_W -= 2;
|
||||
break;
|
||||
case NAND_CTL_SETALE:
|
||||
this->IO_ADDR_W += 1;
|
||||
break;
|
||||
case NAND_CTL_CLRALE:
|
||||
this->IO_ADDR_W -= 1;
|
||||
break;
|
||||
case NAND_CTL_SETNCE:
|
||||
case NAND_CTL_CLRNCE:
|
||||
/* nop */
|
||||
break;
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
if ( ctrl & NAND_CLE )
|
||||
this->IO_ADDR_W += 2;
|
||||
else
|
||||
this->IO_ADDR_W -= 2;
|
||||
if ( ctrl & NAND_ALE )
|
||||
this->IO_ADDR_W += 1;
|
||||
else
|
||||
this->IO_ADDR_W -= 1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
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, &(alpr_ndfc->term));
|
||||
break;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
if ( ctrl & NAND_CLE )
|
||||
hwctl |= 0x1;
|
||||
else
|
||||
hwctl &= ~0x1;
|
||||
if ( ctrl & NAND_ALE )
|
||||
hwctl |= 0x2;
|
||||
else
|
||||
hwctl &= ~0x2;
|
||||
if ( (ctrl & NAND_NCE) != NAND_NCE)
|
||||
writeb(0x00, &(alpr_ndfc->term));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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:
|
||||
hwctl |= 0x1;
|
||||
break;
|
||||
case NAND_CTL_CLRCLE:
|
||||
hwctl &= ~0x1;
|
||||
break;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
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;
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
if ( ctrl & NAND_CLE )
|
||||
hwctl |= 0x1;
|
||||
else
|
||||
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 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));
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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:
|
||||
set_bit (SC3_NAND_CLE, sc3_control_base);
|
||||
break;
|
||||
case NAND_CTL_CLRCLE:
|
||||
clear_bit (SC3_NAND_CLE, sc3_control_base);
|
||||
break;
|
||||
|
||||
case NAND_CTL_SETALE:
|
||||
set_bit (SC3_NAND_ALE, sc3_control_base);
|
||||
break;
|
||||
case NAND_CTL_CLRALE:
|
||||
clear_bit (SC3_NAND_ALE, sc3_control_base);
|
||||
break;
|
||||
|
||||
case NAND_CTL_SETNCE:
|
||||
set_bit (SC3_NAND_CE, sc3_control_base);
|
||||
break;
|
||||
case NAND_CTL_CLRNCE:
|
||||
clear_bit (SC3_NAND_CE, sc3_control_base);
|
||||
break;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
if ( ctrl & NAND_CLE )
|
||||
set_bit (SC3_NAND_CLE, sc3_control_base);
|
||||
else
|
||||
clear_bit (SC3_NAND_CLE, sc3_control_base);
|
||||
if ( ctrl & NAND_ALE )
|
||||
set_bit (SC3_NAND_ALE, sc3_control_base);
|
||||
else
|
||||
clear_bit (SC3_NAND_ALE, sc3_control_base);
|
||||
if ( ctrl & NAND_NCE )
|
||||
set_bit (SC3_NAND_CE, sc3_control_base);
|
||||
else
|
||||
clear_bit (SC3_NAND_CE, sc3_control_base);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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:
|
||||
hwctl |= 0x1;
|
||||
break;
|
||||
case NAND_CTL_CLRCLE:
|
||||
hwctl &= ~0x1;
|
||||
break;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
case NAND_CTL_SETALE:
|
||||
hwctl |= 0x2;
|
||||
break;
|
||||
|
||||
case NAND_CTL_CLRALE:
|
||||
hwctl &= ~0x2;
|
||||
break;
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
if ( ctrl & NAND_CLE )
|
||||
hwctl |= 0x1;
|
||||
else
|
||||
hwctl &= ~0x1;
|
||||
if ( ctrl & NAND_ALE )
|
||||
hwctl |= 0x2;
|
||||
else
|
||||
hwctl &= ~0x2;
|
||||
}
|
||||
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ COBJS-$(CONFIG_CMD_TERMINAL) += cmd_terminal.o
|
||||
COBJS-$(CONFIG_CMD_UNIVERSE) += cmd_universe.o
|
||||
COBJS-$(CONFIG_CMD_USB) += cmd_usb.o
|
||||
COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o
|
||||
COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o
|
||||
COBJS-y += cmd_vfd.o
|
||||
COBJS-y += command.o
|
||||
COBJS-y += console.o
|
||||
|
@ -14,6 +14,12 @@
|
||||
#include <linux/mtd/nftl.h>
|
||||
#include <linux/mtd/doc2000.h>
|
||||
|
||||
/*
|
||||
* ! BROKEN !
|
||||
*
|
||||
* TODO: must be implemented and tested by someone with HW
|
||||
*/
|
||||
#if 0
|
||||
#ifdef CFG_DOC_SUPPORT_2000
|
||||
#define DoC_is_2000(doc) (doc->ChipID == DOC_ChipID_Doc2k)
|
||||
#else
|
||||
@ -1629,3 +1635,6 @@ void doc_probe(unsigned long physadr)
|
||||
puts ("No DiskOnChip found\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
void doc_probe(unsigned long physadr) {}
|
||||
#endif
|
||||
|
@ -18,6 +18,7 @@
|
||||
*
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
|
||||
#if defined(CONFIG_CMD_NAND)
|
||||
|
||||
@ -34,48 +35,58 @@
|
||||
int mtdparts_init(void);
|
||||
int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
|
||||
int find_dev_and_part(const char *id, struct mtd_device **dev,
|
||||
u8 *part_num, struct part_info **part);
|
||||
u8 *part_num, struct part_info **part);
|
||||
#endif
|
||||
|
||||
static int nand_dump_oob(nand_info_t *nand, ulong off)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nand_dump(nand_info_t *nand, ulong off)
|
||||
static int nand_dump(nand_info_t *nand, ulong off, int only_oob)
|
||||
{
|
||||
int i;
|
||||
u_char *buf, *p;
|
||||
u_char *datbuf, *oobbuf, *p;
|
||||
|
||||
buf = malloc(nand->oobblock + nand->oobsize);
|
||||
if (!buf) {
|
||||
datbuf = malloc(nand->writesize + nand->oobsize);
|
||||
oobbuf = malloc(nand->oobsize);
|
||||
if (!datbuf || !oobbuf) {
|
||||
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);
|
||||
loff_t addr = (loff_t) off;
|
||||
struct mtd_oob_ops ops;
|
||||
memset(&ops, 0, sizeof(ops));
|
||||
ops.datbuf = datbuf;
|
||||
ops.oobbuf = oobbuf; /* must exist, but oob data will be appended to ops.datbuf */
|
||||
ops.len = nand->writesize;
|
||||
ops.ooblen = nand->oobsize;
|
||||
ops.mode = MTD_OOB_RAW;
|
||||
i = nand->read_oob(nand, addr, &ops);
|
||||
if (i < 0) {
|
||||
printf("Error (%d) reading page %08lx\n", i, off);
|
||||
free(buf);
|
||||
free(datbuf);
|
||||
free(oobbuf);
|
||||
return 1;
|
||||
}
|
||||
printf("Page %08lx dump:\n", off);
|
||||
i = nand->oobblock >> 4; p = buf;
|
||||
i = nand->writesize >> 4;
|
||||
p = datbuf;
|
||||
|
||||
while (i--) {
|
||||
printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x"
|
||||
" %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
|
||||
p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
|
||||
if (!only_oob)
|
||||
printf("\t%02x %02x %02x %02x %02x %02x %02x %02x"
|
||||
" %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
|
||||
p[8], p[9], p[10], p[11], p[12], p[13], p[14],
|
||||
p[15]);
|
||||
p += 16;
|
||||
}
|
||||
puts("OOB:\n");
|
||||
i = nand->oobsize >> 3;
|
||||
while (i--) {
|
||||
printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
|
||||
printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
|
||||
p += 8;
|
||||
}
|
||||
free(buf);
|
||||
free(datbuf);
|
||||
free(oobbuf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -155,7 +166,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;
|
||||
@ -182,8 +193,8 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {
|
||||
if (nand_info[i].name)
|
||||
printf("Device %d: %s, sector size %u KiB\n",
|
||||
i, nand_info[i].name,
|
||||
nand_info[i].erasesize >> 10);
|
||||
i, nand_info[i].name,
|
||||
nand_info[i].erasesize >> 10);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -196,7 +207,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
puts("\nno devices available\n");
|
||||
else
|
||||
printf("\nDevice %d: %s\n", nand_curr_device,
|
||||
nand_info[nand_curr_device].name);
|
||||
nand_info[nand_curr_device].name);
|
||||
return 0;
|
||||
}
|
||||
dev = (int)simple_strtoul(argv[2], NULL, 10);
|
||||
@ -299,15 +310,14 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
off = (int)simple_strtoul(argv[2], NULL, 16);
|
||||
|
||||
if (s != NULL && strcmp(s, ".oob") == 0)
|
||||
ret = nand_dump_oob(nand, off);
|
||||
ret = nand_dump(nand, off, 1);
|
||||
else
|
||||
ret = nand_dump(nand, off);
|
||||
ret = nand_dump(nand, off, 0);
|
||||
|
||||
return ret == 0 ? 1 : 0;
|
||||
|
||||
}
|
||||
|
||||
/* read write */
|
||||
if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
|
||||
int read;
|
||||
|
||||
@ -322,43 +332,29 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
return 1;
|
||||
|
||||
s = strchr(cmd, '.');
|
||||
if (s != NULL &&
|
||||
(!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) {
|
||||
if (read) {
|
||||
/* read */
|
||||
nand_read_options_t opts;
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.buffer = (u_char*) addr;
|
||||
opts.length = size;
|
||||
opts.offset = off;
|
||||
opts.quiet = quiet;
|
||||
ret = nand_read_opts(nand, &opts);
|
||||
} else {
|
||||
/* write */
|
||||
nand_write_options_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);
|
||||
}
|
||||
if (!s || !strcmp(s, ".jffs2") ||
|
||||
!strcmp(s, ".e") || !strcmp(s, ".i")) {
|
||||
if (read)
|
||||
ret = nand_read_skip_bad(nand, off, &size,
|
||||
(u_char *)addr);
|
||||
else
|
||||
ret = nand_write_skip_bad(nand, off, &size,
|
||||
(u_char *)addr);
|
||||
} 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);
|
||||
else
|
||||
ret = nand_write(nand, off, &size, (u_char *)addr);
|
||||
printf("Unknown nand command suffix '%s'.\n", s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf(" %d bytes %s: %s\n", size,
|
||||
@ -381,6 +377,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(cmd, "biterr") == 0) {
|
||||
/* todo */
|
||||
return 1;
|
||||
@ -395,7 +392,12 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
if (!strcmp("status", argv[2]))
|
||||
status = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ! BROKEN !
|
||||
*
|
||||
* TODO: must be implemented and tested by someone with HW
|
||||
*/
|
||||
#if 0
|
||||
if (status) {
|
||||
ulong block_start = 0;
|
||||
ulong off;
|
||||
@ -406,28 +408,28 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
nand_chip->cmdfunc (nand, NAND_CMD_STATUS, -1, -1);
|
||||
printf("device is %swrite protected\n",
|
||||
(nand_chip->read_byte(nand) & 0x80 ?
|
||||
"NOT " : "" ) );
|
||||
"NOT " : ""));
|
||||
|
||||
for (off = 0; off < nand->size; off += nand->oobblock) {
|
||||
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->oobblock
|
||||
if (off == nand->size - nand->writesize
|
||||
|| (s != last_status && off != 0)) {
|
||||
|
||||
printf("%08lx - %08lx: %8lu pages %s%s%s\n",
|
||||
printf("%08lx - %08lx: %8d pages %s%s%s\n",
|
||||
block_start,
|
||||
off-1,
|
||||
(off-block_start)/nand->oobblock,
|
||||
(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");
|
||||
@ -436,6 +438,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -443,6 +446,12 @@ 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;
|
||||
|
||||
/*
|
||||
* ! BROKEN !
|
||||
*
|
||||
* TODO: must be implemented and tested by someone with HW
|
||||
*/
|
||||
#if 0
|
||||
if (!nand_unlock(nand, off, size)) {
|
||||
puts("NAND flash successfully unlocked\n");
|
||||
} else {
|
||||
@ -450,6 +459,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
"write and erase will probably fail\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -459,54 +469,47 @@ usage:
|
||||
}
|
||||
|
||||
U_BOOT_CMD(nand, 5, 1, do_nand,
|
||||
"nand - NAND sub-system\n",
|
||||
"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 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 unlock [offset] [size] - unlock section\n");
|
||||
"nand - NAND sub-system\n",
|
||||
"info - show available NAND devices\n"
|
||||
"nand device [dev] - show or set current device\n"
|
||||
"nand read - addr off|partition size\n"
|
||||
"nand write - addr off|partition size\n"
|
||||
" read/write 'size' bytes starting at offset 'off'\n"
|
||||
" to/from memory address 'addr', skipping bad blocks.\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]\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,
|
||||
ulong offset, ulong addr, char *cmd)
|
||||
ulong offset, ulong addr, char *cmd)
|
||||
{
|
||||
int r;
|
||||
char *ep, *s;
|
||||
size_t cnt;
|
||||
image_header_t *hdr;
|
||||
int jffs2 = 0;
|
||||
#if defined(CONFIG_FIT)
|
||||
const void *fit_hdr = NULL;
|
||||
#endif
|
||||
|
||||
s = strchr(cmd, '.');
|
||||
if (s != NULL &&
|
||||
(!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i")))
|
||||
jffs2 = 1;
|
||||
(strcmp(s, ".jffs2") && !strcmp(s, ".e") && !strcmp(s, ".i"))) {
|
||||
printf("Unknown nand load suffix '%s'\n", s);
|
||||
show_boot_progress(-53);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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 {
|
||||
r = nand_read(nand, offset, &cnt, (u_char *) addr);
|
||||
}
|
||||
|
||||
cnt = nand->writesize;
|
||||
r = nand_read(nand, offset, &cnt, (u_char *) addr);
|
||||
if (r) {
|
||||
puts("** Read error\n");
|
||||
show_boot_progress (-56);
|
||||
@ -536,19 +539,10 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
|
||||
puts ("** Unknown image type\n");
|
||||
return 1;
|
||||
}
|
||||
show_boot_progress (57);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* FIXME: skip bad blocks */
|
||||
r = nand_read(nand, offset, &cnt, (u_char *) addr);
|
||||
if (r) {
|
||||
puts("** Read error\n");
|
||||
show_boot_progress (-58);
|
||||
@ -614,7 +608,7 @@ int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
else
|
||||
addr = CFG_LOAD_ADDR;
|
||||
return nand_load_image(cmdtp, &nand_info[dev->id->num],
|
||||
part->offset, addr, argv[0]);
|
||||
part->offset, addr, argv[0]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -669,7 +663,7 @@ usage:
|
||||
|
||||
U_BOOT_CMD(nboot, 4, 1, do_nandboot,
|
||||
"nboot - boot from NAND device\n",
|
||||
"[.jffs2] [partition] | [[[loadAddr] dev] offset]\n");
|
||||
"[partition] | [[[loadAddr] dev] offset]\n");
|
||||
|
||||
#endif
|
||||
|
||||
@ -726,10 +720,10 @@ void archflashwp(void *archdata, int wp);
|
||||
#define CONFIG_MTD_NAND_ECC_JFFS2
|
||||
|
||||
/* bits for nand_legacy_rw() `cmd'; or together as needed */
|
||||
#define NANDRW_READ 0x01
|
||||
#define NANDRW_WRITE 0x00
|
||||
#define NANDRW_JFFS2 0x02
|
||||
#define NANDRW_JFFS2_SKIP 0x04
|
||||
#define NANDRW_READ 0x01
|
||||
#define NANDRW_WRITE 0x00
|
||||
#define NANDRW_JFFS2 0x02
|
||||
#define NANDRW_JFFS2_SKIP 0x04
|
||||
|
||||
/*
|
||||
* Imports from nand_legacy.c
|
||||
@ -839,11 +833,11 @@ int do_nand (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
|
||||
if (strncmp (argv[1], "read", 4) == 0 ||
|
||||
strncmp (argv[1], "write", 5) == 0) {
|
||||
ulong addr = simple_strtoul (argv[2], NULL, 16);
|
||||
off_t off = simple_strtoul (argv[3], NULL, 16);
|
||||
size_t size = simple_strtoul (argv[4], NULL, 16);
|
||||
int cmd = (strncmp (argv[1], "read", 4) == 0) ?
|
||||
NANDRW_READ : NANDRW_WRITE;
|
||||
ulong addr = simple_strtoul (argv[2], NULL, 16);
|
||||
off_t off = simple_strtoul (argv[3], NULL, 16);
|
||||
size_t size = simple_strtoul (argv[4], NULL, 16);
|
||||
int cmd = (strncmp (argv[1], "read", 4) == 0) ?
|
||||
NANDRW_READ : NANDRW_WRITE;
|
||||
size_t total;
|
||||
int ret;
|
||||
char *cmdtail = strchr (argv[1], '.');
|
||||
@ -892,8 +886,7 @@ int do_nand (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
|
||||
ret = nand_legacy_rw (nand_dev_desc + curr_device,
|
||||
cmd, off, size,
|
||||
&total,
|
||||
(u_char *) addr);
|
||||
&total, (u_char *) addr);
|
||||
|
||||
printf (" %d bytes %s: %s\n", total,
|
||||
(cmd & NANDRW_READ) ? "read" : "written",
|
||||
@ -1000,11 +993,11 @@ int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
show_boot_progress (55);
|
||||
|
||||
printf ("\nLoading from device %d: %s at 0x%lx (offset 0x%lx)\n",
|
||||
dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR,
|
||||
offset);
|
||||
dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR,
|
||||
offset);
|
||||
|
||||
if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ, offset,
|
||||
SECTORSIZE, NULL, (u_char *)addr)) {
|
||||
SECTORSIZE, NULL, (u_char *)addr)) {
|
||||
printf ("** Read error on %d\n", dev);
|
||||
show_boot_progress (-56);
|
||||
return 1;
|
||||
@ -1035,8 +1028,8 @@ int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
show_boot_progress (57);
|
||||
|
||||
if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ,
|
||||
offset + SECTORSIZE, cnt, NULL,
|
||||
(u_char *)(addr+SECTORSIZE))) {
|
||||
offset + SECTORSIZE, cnt, NULL,
|
||||
(u_char *)(addr+SECTORSIZE))) {
|
||||
printf ("** Read error on %d\n", dev);
|
||||
show_boot_progress (-58);
|
||||
return 1;
|
||||
|
@ -38,7 +38,7 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
||||
onenand_init();
|
||||
return 0;
|
||||
}
|
||||
onenand_print_device_info(onenand_chip.device_id, 1);
|
||||
printf("%s\n", onenand_mtd.name);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
|
215
common/cmd_yaffs2.c
Normal file
215
common/cmd_yaffs2.c
Normal file
@ -0,0 +1,215 @@
|
||||
#include <common.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <command.h>
|
||||
|
||||
#ifdef YAFFS2_DEBUG
|
||||
#define PRINTF(fmt,args...) printf (fmt ,##args)
|
||||
#else
|
||||
#define PRINTF(fmt,args...)
|
||||
#endif
|
||||
|
||||
extern void cmd_yaffs_mount(char *mp);
|
||||
extern void cmd_yaffs_umount(char *mp);
|
||||
extern void cmd_yaffs_read_file(char *fn);
|
||||
extern void cmd_yaffs_write_file(char *fn,char bval,int sizeOfFile);
|
||||
extern void cmd_yaffs_ls(const char *mountpt, int longlist);
|
||||
extern void cmd_yaffs_mwrite_file(char *fn, char *addr, int size);
|
||||
extern void cmd_yaffs_mread_file(char *fn, char *addr);
|
||||
extern void cmd_yaffs_mkdir(const char *dir);
|
||||
extern void cmd_yaffs_rmdir(const char *dir);
|
||||
extern void cmd_yaffs_rm(const char *path);
|
||||
extern void cmd_yaffs_mv(const char *oldPath, const char *newPath);
|
||||
|
||||
extern int yaffs_DumpDevStruct(const char *path);
|
||||
|
||||
|
||||
int do_ymount (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
{
|
||||
char *mtpoint = argv[1];
|
||||
cmd_yaffs_mount(mtpoint);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int do_yumount (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
{
|
||||
char *mtpoint = argv[1];
|
||||
cmd_yaffs_umount(mtpoint);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int do_yls (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
{
|
||||
char *dirname = argv[argc-1];
|
||||
|
||||
cmd_yaffs_ls(dirname, (argc>2)?1:0);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int do_yrd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
{
|
||||
char *filename = argv[1];
|
||||
printf ("Reading file %s ", filename);
|
||||
|
||||
cmd_yaffs_read_file(filename);
|
||||
|
||||
printf ("done\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
int do_ywr (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
{
|
||||
char *filename = argv[1];
|
||||
ulong value = simple_strtoul(argv[2], NULL, 16);
|
||||
ulong numValues = simple_strtoul(argv[3], NULL, 16);
|
||||
|
||||
printf ("Writing value (%x) %x times to %s... ", value, numValues, filename);
|
||||
|
||||
cmd_yaffs_write_file(filename,value,numValues);
|
||||
|
||||
printf ("done\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
int do_yrdm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
{
|
||||
char *filename = argv[1];
|
||||
ulong addr = simple_strtoul(argv[2], NULL, 16);
|
||||
|
||||
cmd_yaffs_mread_file(filename, (char *)addr);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int do_ywrm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
{
|
||||
char *filename = argv[1];
|
||||
ulong addr = simple_strtoul(argv[2], NULL, 16);
|
||||
ulong size = simple_strtoul(argv[3], NULL, 16);
|
||||
|
||||
cmd_yaffs_mwrite_file(filename, (char *)addr, size);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int do_ymkdir (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
{
|
||||
char *dirname = argv[1];
|
||||
|
||||
cmd_yaffs_mkdir(dirname);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int do_yrmdir (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
{
|
||||
char *dirname = argv[1];
|
||||
|
||||
cmd_yaffs_rmdir(dirname);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int do_yrm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
{
|
||||
char *path = argv[1];
|
||||
|
||||
cmd_yaffs_rm(path);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int do_ymv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
{
|
||||
char *oldPath = argv[1];
|
||||
char *newPath = argv[2];
|
||||
|
||||
cmd_yaffs_mv(newPath, oldPath);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int do_ydump (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
||||
{
|
||||
char *dirname = argv[1];
|
||||
if (yaffs_DumpDevStruct(dirname) != 0)
|
||||
printf("yaffs_DumpDevStruct returning error when dumping path: , %s\n", dirname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
U_BOOT_CMD(
|
||||
ymount, 3, 0, do_ymount,
|
||||
"ymount\t- mount yaffs\n",
|
||||
"\n"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
yumount, 3, 0, do_yumount,
|
||||
"yumount\t- unmount yaffs\n",
|
||||
"\n"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
yls, 4, 0, do_yls,
|
||||
"yls\t- yaffs ls\n",
|
||||
"[-l] name\n"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
yrd, 2, 0, do_yrd,
|
||||
"yrd\t- read file from yaffs\n",
|
||||
"filename\n"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
ywr, 4, 0, do_ywr,
|
||||
"ywr\t- write file to yaffs\n",
|
||||
"filename value num_vlues\n"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
yrdm, 3, 0, do_yrdm,
|
||||
"yrdm\t- read file to memory from yaffs\n",
|
||||
"filename offset\n"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
ywrm, 4, 0, do_ywrm,
|
||||
"ywrm\t- write file from memory to yaffs\n",
|
||||
"filename offset size\n"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
ymkdir, 2, 0, do_ymkdir,
|
||||
"ymkdir\t- YAFFS mkdir\n",
|
||||
"dirname\n"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
yrmdir, 2, 0, do_yrmdir,
|
||||
"yrmdir\t- YAFFS rmdir\n",
|
||||
"dirname\n"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
yrm, 2, 0, do_yrm,
|
||||
"yrm\t- YAFFS rm\n",
|
||||
"path\n"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
ymv, 4, 0, do_ymv,
|
||||
"ymv\t- YAFFS mv\n",
|
||||
"oldPath newPath\n"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
ydump, 2, 0, do_ydump,
|
||||
"ydump\t- YAFFS device struct\n",
|
||||
"dirname\n"
|
||||
);
|
@ -159,22 +159,23 @@ int writeenv(size_t offset, u_char *buf)
|
||||
{
|
||||
size_t end = offset + CFG_ENV_RANGE;
|
||||
size_t amount_saved = 0;
|
||||
size_t blocksize;
|
||||
size_t blocksize, len;
|
||||
|
||||
u_char *char_ptr;
|
||||
|
||||
blocksize = nand_info[0].erasesize;
|
||||
len = min(blocksize, CFG_ENV_SIZE);
|
||||
|
||||
while (amount_saved < CFG_ENV_SIZE && offset < end) {
|
||||
if (nand_block_isbad(&nand_info[0], offset)) {
|
||||
offset += blocksize;
|
||||
} else {
|
||||
char_ptr = &buf[amount_saved];
|
||||
if (nand_write(&nand_info[0], offset, &blocksize,
|
||||
if (nand_write(&nand_info[0], offset, &len,
|
||||
char_ptr))
|
||||
return 1;
|
||||
offset += blocksize;
|
||||
amount_saved += blocksize;
|
||||
amount_saved += len;
|
||||
}
|
||||
}
|
||||
if (amount_saved != CFG_ENV_SIZE)
|
||||
@ -261,21 +262,22 @@ int readenv (size_t offset, u_char * buf)
|
||||
{
|
||||
size_t end = offset + CFG_ENV_RANGE;
|
||||
size_t amount_loaded = 0;
|
||||
size_t blocksize;
|
||||
size_t blocksize, len;
|
||||
|
||||
u_char *char_ptr;
|
||||
|
||||
blocksize = nand_info[0].erasesize;
|
||||
len = min(blocksize, CFG_ENV_SIZE);
|
||||
|
||||
while (amount_loaded < CFG_ENV_SIZE && offset < end) {
|
||||
if (nand_block_isbad(&nand_info[0], offset)) {
|
||||
offset += blocksize;
|
||||
} else {
|
||||
char_ptr = &buf[amount_loaded];
|
||||
if (nand_read(&nand_info[0], offset, &blocksize, char_ptr))
|
||||
if (nand_read(&nand_info[0], offset, &len, char_ptr))
|
||||
return 1;
|
||||
offset += blocksize;
|
||||
amount_loaded += blocksize;
|
||||
amount_loaded += len;
|
||||
}
|
||||
}
|
||||
if (amount_loaded != CFG_ENV_SIZE)
|
||||
@ -345,12 +347,10 @@ void env_relocate_spec (void)
|
||||
void env_relocate_spec (void)
|
||||
{
|
||||
#if !defined(ENV_IS_EMBEDDED)
|
||||
size_t total;
|
||||
int ret;
|
||||
|
||||
total = CFG_ENV_SIZE;
|
||||
ret = readenv(CFG_ENV_OFFSET, (u_char *) env_ptr);
|
||||
if (ret || total != CFG_ENV_SIZE)
|
||||
if (ret)
|
||||
return use_default();
|
||||
|
||||
if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
|
||||
|
@ -1,3 +1,3 @@
|
||||
PLATFORM_CPPFLAGS += -march=armv5te
|
||||
PLATFORM_CPPFLAGS += $(call cc-option,-mtune=arm926ejs,)
|
||||
LDSCRIPT := $(SRCTREE)/cpu/arm926ejs/at91sam9/u-boot.lds
|
||||
LDSCRIPT := $(SRCTREE)/cpu/arm926ejs/at91/u-boot.lds
|
@ -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 */
|
||||
@ -88,18 +89,27 @@ static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
|
||||
|
||||
#ifdef CFG_NAND_HW_ECC
|
||||
#ifdef CFG_NAND_LARGEPAGE
|
||||
static struct nand_oobinfo davinci_nand_oobinfo = {
|
||||
static struct nand_ecclayout davinci_nand_ecclayout = {
|
||||
.useecc = MTD_NANDECC_AUTOPLACE,
|
||||
.eccbytes = 12,
|
||||
.eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
|
||||
.oobfree = { {2, 6}, {12, 12}, {28, 12}, {44, 12}, {60, 4} }
|
||||
.oobfree = {
|
||||
{.offset = 2, .length = 6},
|
||||
{.offset = 12, .length = 12},
|
||||
{.offset = 28, .length = 12},
|
||||
{.offset = 44, .length = 12},
|
||||
{.offset = 60, .length = 4}
|
||||
}
|
||||
};
|
||||
#elif defined(CFG_NAND_SMALLPAGE)
|
||||
static struct nand_oobinfo davinci_nand_oobinfo = {
|
||||
static struct nand_ecclayout davinci_nand_ecclayout = {
|
||||
.useecc = MTD_NANDECC_AUTOPLACE,
|
||||
.eccbytes = 3,
|
||||
.eccpos = {0, 1, 2},
|
||||
.oobfree = { {6, 2}, {8, 8} }
|
||||
.oobfree = {
|
||||
{.offset = 6, .length = 2},
|
||||
{.offset = 8, .length = 8}
|
||||
}
|
||||
};
|
||||
#else
|
||||
#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!"
|
||||
@ -145,7 +155,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 +291,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 +316,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 +372,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->ecc.layout = &davinci_nand_ecclayout;
|
||||
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;
|
||||
|
112
cpu/mpc83xx/nand_init.c
Normal file
112
cpu/mpc83xx/nand_init.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <mpc83xx.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* Breathe some life into the CPU...
|
||||
*
|
||||
* Set up the memory map,
|
||||
* initialize a bunch of registers,
|
||||
* initialize the UPM's
|
||||
*/
|
||||
void cpu_init_f (volatile immap_t * im)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Pointer is writable since we allocated a register for it */
|
||||
gd = (gd_t *) (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET);
|
||||
|
||||
/* Clear initial global data */
|
||||
for (i = 0; i < sizeof(gd_t); i++)
|
||||
((char *)gd)[i] = 0;
|
||||
|
||||
/* system performance tweaking */
|
||||
|
||||
#ifdef CFG_ACR_PIPE_DEP
|
||||
/* Arbiter pipeline depth */
|
||||
im->arbiter.acr = (im->arbiter.acr & ~ACR_PIPE_DEP) |
|
||||
(CFG_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT);
|
||||
#endif
|
||||
|
||||
#ifdef CFG_ACR_RPTCNT
|
||||
/* Arbiter repeat count */
|
||||
im->arbiter.acr = (im->arbiter.acr & ~(ACR_RPTCNT)) |
|
||||
(CFG_ACR_RPTCNT << ACR_RPTCNT_SHIFT);
|
||||
#endif
|
||||
|
||||
#ifdef CFG_SPCR_OPT
|
||||
/* Optimize transactions between CSB and other devices */
|
||||
im->sysconf.spcr = (im->sysconf.spcr & ~SPCR_OPT) |
|
||||
(CFG_SPCR_OPT << SPCR_OPT_SHIFT);
|
||||
#endif
|
||||
|
||||
/* Enable Time Base & Decrimenter (so we will have udelay()) */
|
||||
im->sysconf.spcr |= SPCR_TBEN;
|
||||
|
||||
/* DDR control driver register */
|
||||
#ifdef CFG_DDRCDR
|
||||
im->sysconf.ddrcdr = CFG_DDRCDR;
|
||||
#endif
|
||||
/* Output buffer impedance register */
|
||||
#ifdef CFG_OBIR
|
||||
im->sysconf.obir = CFG_OBIR;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Memory Controller:
|
||||
*/
|
||||
|
||||
/* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary
|
||||
* addresses - these have to be modified later when FLASH size
|
||||
* has been determined
|
||||
*/
|
||||
|
||||
#if defined(CFG_NAND_BR_PRELIM) \
|
||||
&& defined(CFG_NAND_OR_PRELIM) \
|
||||
&& defined(CFG_NAND_LBLAWBAR_PRELIM) \
|
||||
&& defined(CFG_NAND_LBLAWAR_PRELIM)
|
||||
im->lbus.bank[0].br = CFG_NAND_BR_PRELIM;
|
||||
im->lbus.bank[0].or = CFG_NAND_OR_PRELIM;
|
||||
im->sysconf.lblaw[0].bar = CFG_NAND_LBLAWBAR_PRELIM;
|
||||
im->sysconf.lblaw[0].ar = CFG_NAND_LBLAWAR_PRELIM;
|
||||
#else
|
||||
#error CFG_NAND_BR_PRELIM, CFG_NAND_OR_PRELIM, CFG_NAND_LBLAWBAR_PRELIM & CFG_NAND_LBLAWAR_PRELIM must be defined
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Get timebase clock frequency (like cpu_clk in Hz)
|
||||
*/
|
||||
unsigned long get_tbclk(void)
|
||||
{
|
||||
return (gd->bus_clk + 3L) / 4L;
|
||||
}
|
||||
|
||||
void puts(const char *str)
|
||||
{
|
||||
while (*str)
|
||||
putc(*str++);
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
* Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
|
||||
* Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
|
||||
* Copyright (C) 2000, 2001,2002 Wolfgang Denk <wd@denx.de>
|
||||
* Copyright Freescale Semiconductor, Inc. 2004, 2006. All rights reserved.
|
||||
* Copyright Freescale Semiconductor, Inc. 2004, 2006, 2008.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
@ -57,6 +57,10 @@
|
||||
#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_NAND_SPL) && !defined(CFG_RAMBOOT)
|
||||
#define CFG_FLASHBOOT
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set up GOT: Global Offset Table
|
||||
*
|
||||
@ -64,16 +68,16 @@
|
||||
*/
|
||||
START_GOT
|
||||
GOT_ENTRY(_GOT2_TABLE_)
|
||||
GOT_ENTRY(_FIXUP_TABLE_)
|
||||
GOT_ENTRY(__bss_start)
|
||||
GOT_ENTRY(_end)
|
||||
|
||||
#ifndef CONFIG_NAND_SPL
|
||||
GOT_ENTRY(_FIXUP_TABLE_)
|
||||
GOT_ENTRY(_start)
|
||||
GOT_ENTRY(_start_of_vectors)
|
||||
GOT_ENTRY(_end_of_vectors)
|
||||
GOT_ENTRY(transfer_to_handler)
|
||||
|
||||
GOT_ENTRY(__init_end)
|
||||
GOT_ENTRY(_end)
|
||||
GOT_ENTRY(__bss_start)
|
||||
#endif
|
||||
END_GOT
|
||||
|
||||
/*
|
||||
@ -165,7 +169,7 @@ boot_warm: /* time t 5 */
|
||||
|
||||
bl init_e300_core
|
||||
|
||||
#ifndef CFG_RAMBOOT
|
||||
#ifdef CFG_FLASHBOOT
|
||||
|
||||
/* Inflate flash location so it appears everywhere, calculate */
|
||||
/* the absolute address in final location of the FLASH, jump */
|
||||
@ -181,7 +185,7 @@ in_flash:
|
||||
#if 1 /* Remapping flash with LAW0. */
|
||||
bl remap_flash_by_law0
|
||||
#endif
|
||||
#endif /* CFG_RAMBOOT */
|
||||
#endif /* CFG_FLASHBOOT */
|
||||
|
||||
/* setup the bats */
|
||||
bl setup_bats
|
||||
@ -239,6 +243,7 @@ in_flash:
|
||||
/* run 1st part of board init code (in Flash)*/
|
||||
bl board_init_f
|
||||
|
||||
#ifndef CONFIG_NAND_SPL
|
||||
/*
|
||||
* Vector Table
|
||||
*/
|
||||
@ -428,6 +433,7 @@ int_return:
|
||||
lwz r1,GPR1(r1)
|
||||
SYNC
|
||||
rfi
|
||||
#endif /* !CONFIG_NAND_SPL */
|
||||
|
||||
/*
|
||||
* This code initialises the E300 processor core
|
||||
@ -496,27 +502,146 @@ init_e300_core: /* time t 10 */
|
||||
SYNC
|
||||
mtspr HID2, r3
|
||||
|
||||
/* clear all BAT's */
|
||||
/*----------------------------------*/
|
||||
/* Done! */
|
||||
/*------------------------------*/
|
||||
blr
|
||||
|
||||
xor r0, r0, r0
|
||||
mtspr DBAT0U, r0
|
||||
mtspr DBAT0L, r0
|
||||
mtspr DBAT1U, r0
|
||||
mtspr DBAT1L, r0
|
||||
mtspr DBAT2U, r0
|
||||
mtspr DBAT2L, r0
|
||||
mtspr DBAT3U, r0
|
||||
mtspr DBAT3L, r0
|
||||
mtspr IBAT0U, r0
|
||||
mtspr IBAT0L, r0
|
||||
mtspr IBAT1U, r0
|
||||
mtspr IBAT1L, r0
|
||||
mtspr IBAT2U, r0
|
||||
mtspr IBAT2L, r0
|
||||
mtspr IBAT3U, r0
|
||||
mtspr IBAT3L, r0
|
||||
SYNC
|
||||
/* setup_bats - set them up to some initial state */
|
||||
.globl setup_bats
|
||||
setup_bats:
|
||||
addis r0, r0, 0x0000
|
||||
|
||||
/* IBAT 0 */
|
||||
addis r4, r0, CFG_IBAT0L@h
|
||||
ori r4, r4, CFG_IBAT0L@l
|
||||
addis r3, r0, CFG_IBAT0U@h
|
||||
ori r3, r3, CFG_IBAT0U@l
|
||||
mtspr IBAT0L, r4
|
||||
mtspr IBAT0U, r3
|
||||
|
||||
/* DBAT 0 */
|
||||
addis r4, r0, CFG_DBAT0L@h
|
||||
ori r4, r4, CFG_DBAT0L@l
|
||||
addis r3, r0, CFG_DBAT0U@h
|
||||
ori r3, r3, CFG_DBAT0U@l
|
||||
mtspr DBAT0L, r4
|
||||
mtspr DBAT0U, r3
|
||||
|
||||
/* IBAT 1 */
|
||||
addis r4, r0, CFG_IBAT1L@h
|
||||
ori r4, r4, CFG_IBAT1L@l
|
||||
addis r3, r0, CFG_IBAT1U@h
|
||||
ori r3, r3, CFG_IBAT1U@l
|
||||
mtspr IBAT1L, r4
|
||||
mtspr IBAT1U, r3
|
||||
|
||||
/* DBAT 1 */
|
||||
addis r4, r0, CFG_DBAT1L@h
|
||||
ori r4, r4, CFG_DBAT1L@l
|
||||
addis r3, r0, CFG_DBAT1U@h
|
||||
ori r3, r3, CFG_DBAT1U@l
|
||||
mtspr DBAT1L, r4
|
||||
mtspr DBAT1U, r3
|
||||
|
||||
/* IBAT 2 */
|
||||
addis r4, r0, CFG_IBAT2L@h
|
||||
ori r4, r4, CFG_IBAT2L@l
|
||||
addis r3, r0, CFG_IBAT2U@h
|
||||
ori r3, r3, CFG_IBAT2U@l
|
||||
mtspr IBAT2L, r4
|
||||
mtspr IBAT2U, r3
|
||||
|
||||
/* DBAT 2 */
|
||||
addis r4, r0, CFG_DBAT2L@h
|
||||
ori r4, r4, CFG_DBAT2L@l
|
||||
addis r3, r0, CFG_DBAT2U@h
|
||||
ori r3, r3, CFG_DBAT2U@l
|
||||
mtspr DBAT2L, r4
|
||||
mtspr DBAT2U, r3
|
||||
|
||||
/* IBAT 3 */
|
||||
addis r4, r0, CFG_IBAT3L@h
|
||||
ori r4, r4, CFG_IBAT3L@l
|
||||
addis r3, r0, CFG_IBAT3U@h
|
||||
ori r3, r3, CFG_IBAT3U@l
|
||||
mtspr IBAT3L, r4
|
||||
mtspr IBAT3U, r3
|
||||
|
||||
/* DBAT 3 */
|
||||
addis r4, r0, CFG_DBAT3L@h
|
||||
ori r4, r4, CFG_DBAT3L@l
|
||||
addis r3, r0, CFG_DBAT3U@h
|
||||
ori r3, r3, CFG_DBAT3U@l
|
||||
mtspr DBAT3L, r4
|
||||
mtspr DBAT3U, r3
|
||||
|
||||
#ifdef CONFIG_HIGH_BATS
|
||||
/* IBAT 4 */
|
||||
addis r4, r0, CFG_IBAT4L@h
|
||||
ori r4, r4, CFG_IBAT4L@l
|
||||
addis r3, r0, CFG_IBAT4U@h
|
||||
ori r3, r3, CFG_IBAT4U@l
|
||||
mtspr IBAT4L, r4
|
||||
mtspr IBAT4U, r3
|
||||
|
||||
/* DBAT 4 */
|
||||
addis r4, r0, CFG_DBAT4L@h
|
||||
ori r4, r4, CFG_DBAT4L@l
|
||||
addis r3, r0, CFG_DBAT4U@h
|
||||
ori r3, r3, CFG_DBAT4U@l
|
||||
mtspr DBAT4L, r4
|
||||
mtspr DBAT4U, r3
|
||||
|
||||
/* IBAT 5 */
|
||||
addis r4, r0, CFG_IBAT5L@h
|
||||
ori r4, r4, CFG_IBAT5L@l
|
||||
addis r3, r0, CFG_IBAT5U@h
|
||||
ori r3, r3, CFG_IBAT5U@l
|
||||
mtspr IBAT5L, r4
|
||||
mtspr IBAT5U, r3
|
||||
|
||||
/* DBAT 5 */
|
||||
addis r4, r0, CFG_DBAT5L@h
|
||||
ori r4, r4, CFG_DBAT5L@l
|
||||
addis r3, r0, CFG_DBAT5U@h
|
||||
ori r3, r3, CFG_DBAT5U@l
|
||||
mtspr DBAT5L, r4
|
||||
mtspr DBAT5U, r3
|
||||
|
||||
/* IBAT 6 */
|
||||
addis r4, r0, CFG_IBAT6L@h
|
||||
ori r4, r4, CFG_IBAT6L@l
|
||||
addis r3, r0, CFG_IBAT6U@h
|
||||
ori r3, r3, CFG_IBAT6U@l
|
||||
mtspr IBAT6L, r4
|
||||
mtspr IBAT6U, r3
|
||||
|
||||
/* DBAT 6 */
|
||||
addis r4, r0, CFG_DBAT6L@h
|
||||
ori r4, r4, CFG_DBAT6L@l
|
||||
addis r3, r0, CFG_DBAT6U@h
|
||||
ori r3, r3, CFG_DBAT6U@l
|
||||
mtspr DBAT6L, r4
|
||||
mtspr DBAT6U, r3
|
||||
|
||||
/* IBAT 7 */
|
||||
addis r4, r0, CFG_IBAT7L@h
|
||||
ori r4, r4, CFG_IBAT7L@l
|
||||
addis r3, r0, CFG_IBAT7U@h
|
||||
ori r3, r3, CFG_IBAT7U@l
|
||||
mtspr IBAT7L, r4
|
||||
mtspr IBAT7U, r3
|
||||
|
||||
/* DBAT 7 */
|
||||
addis r4, r0, CFG_DBAT7L@h
|
||||
ori r4, r4, CFG_DBAT7L@l
|
||||
addis r3, r0, CFG_DBAT7U@h
|
||||
ori r3, r3, CFG_DBAT7U@l
|
||||
mtspr DBAT7L, r4
|
||||
mtspr DBAT7U, r3
|
||||
#endif
|
||||
|
||||
isync
|
||||
|
||||
/* invalidate all tlb's
|
||||
*
|
||||
@ -537,202 +662,6 @@ init_e300_core: /* time t 10 */
|
||||
* based on code in "flush_tlbs" from arch/ppc/kernel/head.S
|
||||
*
|
||||
*/
|
||||
|
||||
li r3, 32
|
||||
mtctr r3
|
||||
li r3, 0
|
||||
1: tlbie r3
|
||||
addi r3, r3, 0x1000
|
||||
bdnz 1b
|
||||
SYNC
|
||||
|
||||
/* Done! */
|
||||
/*------------------------------*/
|
||||
blr
|
||||
|
||||
.globl invalidate_bats
|
||||
invalidate_bats:
|
||||
/* invalidate BATs */
|
||||
mtspr IBAT0U, r0
|
||||
mtspr IBAT1U, r0
|
||||
mtspr IBAT2U, r0
|
||||
mtspr IBAT3U, r0
|
||||
#ifdef CONFIG_HIGH_BATS
|
||||
mtspr IBAT4U, r0
|
||||
mtspr IBAT5U, r0
|
||||
mtspr IBAT6U, r0
|
||||
mtspr IBAT7U, r0
|
||||
#endif
|
||||
isync
|
||||
mtspr DBAT0U, r0
|
||||
mtspr DBAT1U, r0
|
||||
mtspr DBAT2U, r0
|
||||
mtspr DBAT3U, r0
|
||||
#ifdef CONFIG_HIGH_BATS
|
||||
mtspr DBAT4U, r0
|
||||
mtspr DBAT5U, r0
|
||||
mtspr DBAT6U, r0
|
||||
mtspr DBAT7U, r0
|
||||
#endif
|
||||
isync
|
||||
sync
|
||||
blr
|
||||
|
||||
/* setup_bats - set them up to some initial state */
|
||||
.globl setup_bats
|
||||
setup_bats:
|
||||
addis r0, r0, 0x0000
|
||||
|
||||
/* IBAT 0 */
|
||||
addis r4, r0, CFG_IBAT0L@h
|
||||
ori r4, r4, CFG_IBAT0L@l
|
||||
addis r3, r0, CFG_IBAT0U@h
|
||||
ori r3, r3, CFG_IBAT0U@l
|
||||
mtspr IBAT0L, r4
|
||||
mtspr IBAT0U, r3
|
||||
isync
|
||||
|
||||
/* DBAT 0 */
|
||||
addis r4, r0, CFG_DBAT0L@h
|
||||
ori r4, r4, CFG_DBAT0L@l
|
||||
addis r3, r0, CFG_DBAT0U@h
|
||||
ori r3, r3, CFG_DBAT0U@l
|
||||
mtspr DBAT0L, r4
|
||||
mtspr DBAT0U, r3
|
||||
isync
|
||||
|
||||
/* IBAT 1 */
|
||||
addis r4, r0, CFG_IBAT1L@h
|
||||
ori r4, r4, CFG_IBAT1L@l
|
||||
addis r3, r0, CFG_IBAT1U@h
|
||||
ori r3, r3, CFG_IBAT1U@l
|
||||
mtspr IBAT1L, r4
|
||||
mtspr IBAT1U, r3
|
||||
isync
|
||||
|
||||
/* DBAT 1 */
|
||||
addis r4, r0, CFG_DBAT1L@h
|
||||
ori r4, r4, CFG_DBAT1L@l
|
||||
addis r3, r0, CFG_DBAT1U@h
|
||||
ori r3, r3, CFG_DBAT1U@l
|
||||
mtspr DBAT1L, r4
|
||||
mtspr DBAT1U, r3
|
||||
isync
|
||||
|
||||
/* IBAT 2 */
|
||||
addis r4, r0, CFG_IBAT2L@h
|
||||
ori r4, r4, CFG_IBAT2L@l
|
||||
addis r3, r0, CFG_IBAT2U@h
|
||||
ori r3, r3, CFG_IBAT2U@l
|
||||
mtspr IBAT2L, r4
|
||||
mtspr IBAT2U, r3
|
||||
isync
|
||||
|
||||
/* DBAT 2 */
|
||||
addis r4, r0, CFG_DBAT2L@h
|
||||
ori r4, r4, CFG_DBAT2L@l
|
||||
addis r3, r0, CFG_DBAT2U@h
|
||||
ori r3, r3, CFG_DBAT2U@l
|
||||
mtspr DBAT2L, r4
|
||||
mtspr DBAT2U, r3
|
||||
isync
|
||||
|
||||
/* IBAT 3 */
|
||||
addis r4, r0, CFG_IBAT3L@h
|
||||
ori r4, r4, CFG_IBAT3L@l
|
||||
addis r3, r0, CFG_IBAT3U@h
|
||||
ori r3, r3, CFG_IBAT3U@l
|
||||
mtspr IBAT3L, r4
|
||||
mtspr IBAT3U, r3
|
||||
isync
|
||||
|
||||
/* DBAT 3 */
|
||||
addis r4, r0, CFG_DBAT3L@h
|
||||
ori r4, r4, CFG_DBAT3L@l
|
||||
addis r3, r0, CFG_DBAT3U@h
|
||||
ori r3, r3, CFG_DBAT3U@l
|
||||
mtspr DBAT3L, r4
|
||||
mtspr DBAT3U, r3
|
||||
isync
|
||||
|
||||
#ifdef CONFIG_HIGH_BATS
|
||||
/* IBAT 4 */
|
||||
addis r4, r0, CFG_IBAT4L@h
|
||||
ori r4, r4, CFG_IBAT4L@l
|
||||
addis r3, r0, CFG_IBAT4U@h
|
||||
ori r3, r3, CFG_IBAT4U@l
|
||||
mtspr IBAT4L, r4
|
||||
mtspr IBAT4U, r3
|
||||
isync
|
||||
|
||||
/* DBAT 4 */
|
||||
addis r4, r0, CFG_DBAT4L@h
|
||||
ori r4, r4, CFG_DBAT4L@l
|
||||
addis r3, r0, CFG_DBAT4U@h
|
||||
ori r3, r3, CFG_DBAT4U@l
|
||||
mtspr DBAT4L, r4
|
||||
mtspr DBAT4U, r3
|
||||
isync
|
||||
|
||||
/* IBAT 5 */
|
||||
addis r4, r0, CFG_IBAT5L@h
|
||||
ori r4, r4, CFG_IBAT5L@l
|
||||
addis r3, r0, CFG_IBAT5U@h
|
||||
ori r3, r3, CFG_IBAT5U@l
|
||||
mtspr IBAT5L, r4
|
||||
mtspr IBAT5U, r3
|
||||
isync
|
||||
|
||||
/* DBAT 5 */
|
||||
addis r4, r0, CFG_DBAT5L@h
|
||||
ori r4, r4, CFG_DBAT5L@l
|
||||
addis r3, r0, CFG_DBAT5U@h
|
||||
ori r3, r3, CFG_DBAT5U@l
|
||||
mtspr DBAT5L, r4
|
||||
mtspr DBAT5U, r3
|
||||
isync
|
||||
|
||||
/* IBAT 6 */
|
||||
addis r4, r0, CFG_IBAT6L@h
|
||||
ori r4, r4, CFG_IBAT6L@l
|
||||
addis r3, r0, CFG_IBAT6U@h
|
||||
ori r3, r3, CFG_IBAT6U@l
|
||||
mtspr IBAT6L, r4
|
||||
mtspr IBAT6U, r3
|
||||
isync
|
||||
|
||||
/* DBAT 6 */
|
||||
addis r4, r0, CFG_DBAT6L@h
|
||||
ori r4, r4, CFG_DBAT6L@l
|
||||
addis r3, r0, CFG_DBAT6U@h
|
||||
ori r3, r3, CFG_DBAT6U@l
|
||||
mtspr DBAT6L, r4
|
||||
mtspr DBAT6U, r3
|
||||
isync
|
||||
|
||||
/* IBAT 7 */
|
||||
addis r4, r0, CFG_IBAT7L@h
|
||||
ori r4, r4, CFG_IBAT7L@l
|
||||
addis r3, r0, CFG_IBAT7U@h
|
||||
ori r3, r3, CFG_IBAT7U@l
|
||||
mtspr IBAT7L, r4
|
||||
mtspr IBAT7U, r3
|
||||
isync
|
||||
|
||||
/* DBAT 7 */
|
||||
addis r4, r0, CFG_DBAT7L@h
|
||||
ori r4, r4, CFG_DBAT7L@l
|
||||
addis r3, r0, CFG_DBAT7U@h
|
||||
ori r3, r3, CFG_DBAT7U@l
|
||||
mtspr DBAT7L, r4
|
||||
mtspr DBAT7U, r3
|
||||
isync
|
||||
#endif
|
||||
|
||||
/* Invalidate TLBs.
|
||||
* -> for (val = 0; val < 0x20000; val+=0x1000)
|
||||
* -> tlbie(val);
|
||||
*/
|
||||
lis r3, 0
|
||||
lis r5, 2
|
||||
|
||||
@ -874,7 +803,7 @@ relocate_code:
|
||||
mr r3, r5 /* Destination Address */
|
||||
lis r4, CFG_MONITOR_BASE@h /* Source Address */
|
||||
ori r4, r4, CFG_MONITOR_BASE@l
|
||||
lwz r5, GOT(__init_end)
|
||||
lwz r5, GOT(__bss_start)
|
||||
sub r5, r5, r4
|
||||
li r6, CFG_CACHELINE_SIZE /* Cache Line Size */
|
||||
|
||||
@ -987,6 +916,7 @@ in_ram:
|
||||
stw r0,0(r3)
|
||||
bdnz 1b
|
||||
|
||||
#ifndef CONFIG_NAND_SPL
|
||||
/*
|
||||
* Now adjust the fixups and the pointers to the fixups
|
||||
* in case we need to move ourselves again.
|
||||
@ -1004,6 +934,8 @@ in_ram:
|
||||
stw r0,0(r4)
|
||||
bdnz 3b
|
||||
4:
|
||||
#endif
|
||||
|
||||
clear_bss:
|
||||
/*
|
||||
* Now clear BSS segment
|
||||
@ -1037,6 +969,7 @@ clear_bss:
|
||||
mr r4, r10 /* Destination Address */
|
||||
bl board_init_r
|
||||
|
||||
#ifndef CONFIG_NAND_SPL
|
||||
/*
|
||||
* Copy exception vector code to low memory
|
||||
*
|
||||
@ -1119,6 +1052,7 @@ trap_reloc:
|
||||
stw r0, 4(r7)
|
||||
|
||||
blr
|
||||
#endif /* !CONFIG_NAND_SPL */
|
||||
|
||||
#ifdef CFG_INIT_RAM_LOCK
|
||||
lock_ram_in_cache:
|
||||
@ -1142,6 +1076,7 @@ lock_ram_in_cache:
|
||||
sync
|
||||
blr
|
||||
|
||||
#ifndef CONFIG_NAND_SPL
|
||||
.globl unlock_ram_in_cache
|
||||
unlock_ram_in_cache:
|
||||
/* invalidate the INIT_RAM section */
|
||||
@ -1165,8 +1100,10 @@ unlock_ram_in_cache:
|
||||
mtspr HID0, r3 /* no invalidate, unlock */
|
||||
sync
|
||||
blr
|
||||
#endif
|
||||
#endif /* !CONFIG_NAND_SPL */
|
||||
#endif /* CFG_INIT_RAM_LOCK */
|
||||
|
||||
#ifdef CFG_FLASHBOOT
|
||||
map_flash_by_law1:
|
||||
/* When booting from ROM (Flash or EPROM), clear the */
|
||||
/* Address Mask in OR0 so ROM appears everywhere */
|
||||
@ -1245,3 +1182,4 @@ remap_flash_by_law0:
|
||||
stw r4, LBLAWBAR1(r3)
|
||||
stw r4, LBLAWAR1(r3) /* Off LBIU LAW1 */
|
||||
blr
|
||||
#endif /* CFG_FLASHBOOT */
|
||||
|
@ -44,65 +44,39 @@
|
||||
#include <asm/io.h>
|
||||
#include <ppc4xx.h>
|
||||
|
||||
static u8 hwctl = 0;
|
||||
/*
|
||||
* We need to store the info, which chip-select (CS) is used for the
|
||||
* chip number. For example on Sequoia NAND chip #0 uses
|
||||
* CS #3.
|
||||
*/
|
||||
static int ndfc_cs[NDFC_MAX_BANKS];
|
||||
|
||||
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:
|
||||
hwctl |= 0x1;
|
||||
break;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
|
||||
|
||||
case NAND_CTL_CLRCLE:
|
||||
hwctl &= ~0x1;
|
||||
break;
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
return;
|
||||
|
||||
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);
|
||||
if (ctrl & NAND_CLE)
|
||||
out_8((u8 *)(base + NDFC_CMD), cmd & 0xFF);
|
||||
else
|
||||
out_8((u8 *)(base + NDFC_DATA), byte);
|
||||
}
|
||||
|
||||
static u_char ndfc_read_byte(struct mtd_info *mtdinfo)
|
||||
{
|
||||
struct nand_chip *this = mtdinfo->priv;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
|
||||
|
||||
return (in_8((u8 *)(base + NDFC_DATA)));
|
||||
out_8((u8 *)(base + NDFC_ALE), cmd & 0xFF);
|
||||
}
|
||||
|
||||
static int ndfc_dev_ready(struct mtd_info *mtdinfo)
|
||||
{
|
||||
struct nand_chip *this = mtdinfo->priv;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
|
||||
|
||||
while (!(in_be32((u32 *)(base + NDFC_STAT)) & NDFC_STAT_IS_READY))
|
||||
;
|
||||
|
||||
return 1;
|
||||
return (in_be32((u32 *)(base + NDFC_STAT)) & NDFC_STAT_IS_READY);
|
||||
}
|
||||
|
||||
static void ndfc_enable_hwecc(struct mtd_info *mtdinfo, int mode)
|
||||
{
|
||||
struct nand_chip *this = mtdinfo->priv;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
|
||||
u32 ccr;
|
||||
|
||||
ccr = in_be32((u32 *)(base + NDFC_CCR));
|
||||
@ -114,7 +88,7 @@ static int ndfc_calculate_ecc(struct mtd_info *mtdinfo,
|
||||
const u_char *dat, u_char *ecc_code)
|
||||
{
|
||||
struct nand_chip *this = mtdinfo->priv;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
|
||||
u32 ecc;
|
||||
u8 *p = (u8 *)&ecc;
|
||||
|
||||
@ -139,7 +113,7 @@ static int ndfc_calculate_ecc(struct mtd_info *mtdinfo,
|
||||
static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtdinfo->priv;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
|
||||
uint32_t *p = (uint32_t *) buf;
|
||||
|
||||
for (;len > 0; len -= 4)
|
||||
@ -154,7 +128,7 @@ static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len)
|
||||
static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtdinfo->priv;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
|
||||
uint32_t *p = (uint32_t *) buf;
|
||||
|
||||
for (; len > 0; len -= 4)
|
||||
@ -164,7 +138,7 @@ static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len
|
||||
static int ndfc_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtdinfo->priv;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
|
||||
uint32_t *p = (uint32_t *) buf;
|
||||
|
||||
for (; len > 0; len -= 4)
|
||||
@ -181,29 +155,43 @@ void board_nand_select_device(struct nand_chip *nand, int chip)
|
||||
* Don't use "chip" to address the NAND device,
|
||||
* generate the cs from the address where it is encoded.
|
||||
*/
|
||||
int cs = (ulong)nand->IO_ADDR_W & 0x00000003;
|
||||
ulong base = (ulong)nand->IO_ADDR_W & 0xfffffffc;
|
||||
ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00;
|
||||
int cs = ndfc_cs[chip];
|
||||
|
||||
/* Set NandFlash Core Configuration Register */
|
||||
/* 1 col x 2 rows */
|
||||
out_be32((u32 *)(base + NDFC_CCR), 0x00000000 | (cs << 24));
|
||||
out_be32((u32 *)(base + NDFC_BCFG0 + (cs << 2)), 0x80002222);
|
||||
}
|
||||
|
||||
int board_nand_init(struct nand_chip *nand)
|
||||
{
|
||||
int cs = (ulong)nand->IO_ADDR_W & 0x00000003;
|
||||
ulong base = (ulong)nand->IO_ADDR_W & 0xfffffffc;
|
||||
ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00;
|
||||
static int chip = 0;
|
||||
|
||||
nand->hwcontrol = 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;
|
||||
/*
|
||||
* Save chip-select for this chip #
|
||||
*/
|
||||
ndfc_cs[chip] = cs;
|
||||
|
||||
nand->eccmode = NAND_ECC_HW3_256;
|
||||
nand->enable_hwecc = ndfc_enable_hwecc;
|
||||
nand->calculate_ecc = ndfc_calculate_ecc;
|
||||
nand->correct_data = nand_correct_data;
|
||||
/*
|
||||
* Select required NAND chip in NDFC
|
||||
*/
|
||||
board_nand_select_device(nand, chip);
|
||||
|
||||
nand->IO_ADDR_R = (void __iomem *)(base + NDFC_DATA);
|
||||
nand->IO_ADDR_W = (void __iomem *)(base + NDFC_DATA);
|
||||
nand->cmd_ctrl = ndfc_hwcontrol;
|
||||
nand->chip_delay = 50;
|
||||
nand->read_buf = ndfc_read_buf;
|
||||
nand->dev_ready = ndfc_dev_ready;
|
||||
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;
|
||||
@ -218,11 +206,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||
mtebc(pb0ap, CFG_EBC_PB0AP);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Select required NAND chip in NDFC
|
||||
*/
|
||||
board_nand_select_device(nand, cs);
|
||||
out_be32((u32 *)(base + NDFC_BCFG0 + (cs << 2)), 0x80002222);
|
||||
chip++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -57,14 +57,9 @@ Commands:
|
||||
Print information about all of the NAND devices found.
|
||||
|
||||
nand read addr ofs|partition size
|
||||
Read `size' bytes from `ofs' in NAND flash to `addr'. If a page
|
||||
cannot be read because it is marked bad or an uncorrectable data
|
||||
error is found the command stops with an error.
|
||||
|
||||
nand read.jffs2 addr ofs|partition size
|
||||
Like `read', but the data for blocks that are marked bad is read as
|
||||
0xff. This gives a readable JFFS2 image that can be processed by
|
||||
the JFFS2 commands such as ls and fsload.
|
||||
Read `size' bytes from `ofs' in NAND flash to `addr'. Blocks that
|
||||
are marked bad are skipped. If a page cannot be read because an
|
||||
uncorrectable data error is found, the command stops with an error.
|
||||
|
||||
nand read.oob addr ofs|partition size
|
||||
Read `size' bytes from the out-of-band data area corresponding to
|
||||
@ -73,17 +68,15 @@ Commands:
|
||||
for bad blocks or ECC errors.
|
||||
|
||||
nand write addr ofs|partition size
|
||||
Write `size' bytes from `addr' to `ofs' in NAND flash. If a page
|
||||
cannot be written because it is marked bad or the write fails the
|
||||
command stops with an error.
|
||||
Write `size' bytes from `addr' to `ofs' in NAND flash. Blocks that
|
||||
are marked bad are skipped. If a page cannot be read because an
|
||||
uncorrectable data error is found, the command stops with an error.
|
||||
|
||||
nand write.jffs2 addr ofs|partition size
|
||||
Like `write', but blocks that are marked bad are skipped and the
|
||||
data is written to the next block instead. This allows writing
|
||||
a JFFS2 image, as long as the image is short enough to fit even
|
||||
after skipping the bad blocks. Compact images, such as those
|
||||
produced by mkfs.jffs2 should work well, but loading an image copied
|
||||
from another flash is going to be trouble if there are any bad blocks.
|
||||
As JFFS2 skips blocks similarly, this allows writing a JFFS2 image,
|
||||
as long as the image is short enough to fit even after skipping the
|
||||
bad blocks. Compact images, such as those produced by mkfs.jffs2
|
||||
should work well, but loading an image copied from another flash is
|
||||
going to be trouble if there are any bad blocks.
|
||||
|
||||
nand write.oob addr ofs|partition size
|
||||
Write `size' bytes from `addr' to the out-of-band data area
|
||||
@ -215,12 +208,6 @@ JFFS2 related commands:
|
||||
using both the new code which is able to skip bad blocks
|
||||
"nand erase clean" additionally writes JFFS2-cleanmarkers in the oob.
|
||||
|
||||
"nand write.jffs2"
|
||||
like "nand write" but skip found bad eraseblocks
|
||||
|
||||
"nand read.jffs2"
|
||||
like "nand read" but skip found bad eraseblocks
|
||||
|
||||
Miscellaneous and testing commands:
|
||||
"markbad [offset]"
|
||||
create an artificial bad block (for testing bad block handling)
|
||||
|
@ -32,6 +32,7 @@ COBJS-y += nand_ecc.o
|
||||
COBJS-y += nand_bbt.o
|
||||
COBJS-y += nand_util.o
|
||||
|
||||
COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
|
||||
COBJS-y += fsl_upm.o
|
||||
|
||||
COBJS := $(COBJS-y)
|
||||
|
File diff suppressed because it is too large
Load Diff
767
drivers/mtd/nand/fsl_elbc_nand.c
Normal file
767
drivers/mtd/nand/fsl_elbc_nand.c
Normal file
@ -0,0 +1,767 @@
|
||||
/* Freescale Enhanced Local Bus Controller FCM NAND driver
|
||||
*
|
||||
* Copyright (c) 2006-2008 Freescale Semiconductor
|
||||
*
|
||||
* Authors: Nick Spence <nick.spence@freescale.com>,
|
||||
* Scott Wood <scottwood@freescale.com>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/nand_ecc.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#define DEBUG_ELBC
|
||||
#define vdbg(format, arg...) printf("DEBUG: " format, ##arg)
|
||||
#else
|
||||
#define vdbg(format, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
/* Can't use plain old DEBUG because the linux mtd
|
||||
* headers define it as a macro.
|
||||
*/
|
||||
#ifdef DEBUG_ELBC
|
||||
#define dbg(format, arg...) printf("DEBUG: " format, ##arg)
|
||||
#else
|
||||
#define dbg(format, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define MAX_BANKS 8
|
||||
#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
|
||||
#define FCM_TIMEOUT_MSECS 10 /* Maximum number of mSecs to wait for FCM */
|
||||
|
||||
#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
|
||||
|
||||
struct fsl_elbc_ctrl;
|
||||
|
||||
/* mtd information per set */
|
||||
|
||||
struct fsl_elbc_mtd {
|
||||
struct mtd_info mtd;
|
||||
struct nand_chip chip;
|
||||
struct fsl_elbc_ctrl *ctrl;
|
||||
|
||||
struct device *dev;
|
||||
int bank; /* Chip select bank number */
|
||||
u8 __iomem *vbase; /* Chip select base virtual address */
|
||||
int page_size; /* NAND page size (0=512, 1=2048) */
|
||||
unsigned int fmr; /* FCM Flash Mode Register value */
|
||||
};
|
||||
|
||||
/* overview of the fsl elbc controller */
|
||||
|
||||
struct fsl_elbc_ctrl {
|
||||
struct nand_hw_control controller;
|
||||
struct fsl_elbc_mtd *chips[MAX_BANKS];
|
||||
|
||||
/* device info */
|
||||
lbus83xx_t *regs;
|
||||
u8 __iomem *addr; /* Address of assigned FCM buffer */
|
||||
unsigned int page; /* Last page written to / read from */
|
||||
unsigned int read_bytes; /* Number of bytes read during command */
|
||||
unsigned int column; /* Saved column from SEQIN */
|
||||
unsigned int index; /* Pointer to next byte to 'read' */
|
||||
unsigned int status; /* status read from LTESR after last op */
|
||||
unsigned int mdr; /* UPM/FCM Data Register value */
|
||||
unsigned int use_mdr; /* Non zero if the MDR is to be set */
|
||||
unsigned int oob; /* Non zero if operating on OOB data */
|
||||
uint8_t *oob_poi; /* Place to write ECC after read back */
|
||||
};
|
||||
|
||||
/* These map to the positions used by the FCM hardware ECC generator */
|
||||
|
||||
/* Small Page FLASH with FMR[ECCM] = 0 */
|
||||
static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = {
|
||||
.eccbytes = 3,
|
||||
.eccpos = {6, 7, 8},
|
||||
.oobfree = { {0, 5}, {9, 7} },
|
||||
.oobavail = 12,
|
||||
};
|
||||
|
||||
/* Small Page FLASH with FMR[ECCM] = 1 */
|
||||
static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = {
|
||||
.eccbytes = 3,
|
||||
.eccpos = {8, 9, 10},
|
||||
.oobfree = { {0, 5}, {6, 2}, {11, 5} },
|
||||
.oobavail = 12,
|
||||
};
|
||||
|
||||
/* Large Page FLASH with FMR[ECCM] = 0 */
|
||||
static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = {
|
||||
.eccbytes = 12,
|
||||
.eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56},
|
||||
.oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} },
|
||||
.oobavail = 48,
|
||||
};
|
||||
|
||||
/* Large Page FLASH with FMR[ECCM] = 1 */
|
||||
static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = {
|
||||
.eccbytes = 12,
|
||||
.eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
|
||||
.oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} },
|
||||
.oobavail = 48,
|
||||
};
|
||||
|
||||
/*=================================*/
|
||||
|
||||
/*
|
||||
* Set up the FCM hardware block and page address fields, and the fcm
|
||||
* structure addr field to point to the correct FCM buffer in memory
|
||||
*/
|
||||
static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
lbus83xx_t *lbc = ctrl->regs;
|
||||
int buf_num;
|
||||
|
||||
ctrl->page = page_addr;
|
||||
|
||||
if (priv->page_size) {
|
||||
out_be32(&lbc->fbar, page_addr >> 6);
|
||||
out_be32(&lbc->fpar,
|
||||
((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
|
||||
(oob ? FPAR_LP_MS : 0) | column);
|
||||
buf_num = (page_addr & 1) << 2;
|
||||
} else {
|
||||
out_be32(&lbc->fbar, page_addr >> 5);
|
||||
out_be32(&lbc->fpar,
|
||||
((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
|
||||
(oob ? FPAR_SP_MS : 0) | column);
|
||||
buf_num = page_addr & 7;
|
||||
}
|
||||
|
||||
ctrl->addr = priv->vbase + buf_num * 1024;
|
||||
ctrl->index = column;
|
||||
|
||||
/* for OOB data point to the second half of the buffer */
|
||||
if (oob)
|
||||
ctrl->index += priv->page_size ? 2048 : 512;
|
||||
|
||||
vdbg("set_addr: bank=%d, ctrl->addr=0x%p (0x%p), "
|
||||
"index %x, pes %d ps %d\n",
|
||||
buf_num, ctrl->addr, priv->vbase, ctrl->index,
|
||||
chip->phys_erase_shift, chip->page_shift);
|
||||
}
|
||||
|
||||
/*
|
||||
* execute FCM command and wait for it to complete
|
||||
*/
|
||||
static int fsl_elbc_run_command(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
lbus83xx_t *lbc = ctrl->regs;
|
||||
long long end_tick;
|
||||
u32 ltesr;
|
||||
|
||||
/* Setup the FMR[OP] to execute without write protection */
|
||||
out_be32(&lbc->fmr, priv->fmr | 3);
|
||||
if (ctrl->use_mdr)
|
||||
out_be32(&lbc->mdr, ctrl->mdr);
|
||||
|
||||
vdbg("fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
|
||||
in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
|
||||
vdbg("fsl_elbc_run_command: fbar=%08x fpar=%08x "
|
||||
"fbcr=%08x bank=%d\n",
|
||||
in_be32(&lbc->fbar), in_be32(&lbc->fpar),
|
||||
in_be32(&lbc->fbcr), priv->bank);
|
||||
|
||||
/* execute special operation */
|
||||
out_be32(&lbc->lsor, priv->bank);
|
||||
|
||||
/* wait for FCM complete flag or timeout */
|
||||
end_tick = usec2ticks(FCM_TIMEOUT_MSECS * 1000) + get_ticks();
|
||||
|
||||
ltesr = 0;
|
||||
while (end_tick > get_ticks()) {
|
||||
ltesr = in_be32(&lbc->ltesr);
|
||||
if (ltesr & LTESR_CC)
|
||||
break;
|
||||
}
|
||||
|
||||
ctrl->status = ltesr & LTESR_NAND_MASK;
|
||||
out_be32(&lbc->ltesr, ctrl->status);
|
||||
out_be32(&lbc->lteatr, 0);
|
||||
|
||||
/* store mdr value in case it was needed */
|
||||
if (ctrl->use_mdr)
|
||||
ctrl->mdr = in_be32(&lbc->mdr);
|
||||
|
||||
ctrl->use_mdr = 0;
|
||||
|
||||
vdbg("fsl_elbc_run_command: stat=%08x mdr=%08x fmr=%08x\n",
|
||||
ctrl->status, ctrl->mdr, in_be32(&lbc->fmr));
|
||||
|
||||
/* returns 0 on success otherwise non-zero) */
|
||||
return ctrl->status == LTESR_CC ? 0 : -EIO;
|
||||
}
|
||||
|
||||
static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
|
||||
{
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
lbus83xx_t *lbc = ctrl->regs;
|
||||
|
||||
if (priv->page_size) {
|
||||
out_be32(&lbc->fir,
|
||||
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
|
||||
(FIR_OP_CA << FIR_OP1_SHIFT) |
|
||||
(FIR_OP_PA << FIR_OP2_SHIFT) |
|
||||
(FIR_OP_CW1 << FIR_OP3_SHIFT) |
|
||||
(FIR_OP_RBW << FIR_OP4_SHIFT));
|
||||
|
||||
out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
|
||||
(NAND_CMD_READSTART << FCR_CMD1_SHIFT));
|
||||
} else {
|
||||
out_be32(&lbc->fir,
|
||||
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
|
||||
(FIR_OP_CA << FIR_OP1_SHIFT) |
|
||||
(FIR_OP_PA << FIR_OP2_SHIFT) |
|
||||
(FIR_OP_RBW << FIR_OP3_SHIFT));
|
||||
|
||||
if (oob)
|
||||
out_be32(&lbc->fcr,
|
||||
NAND_CMD_READOOB << FCR_CMD0_SHIFT);
|
||||
else
|
||||
out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
/* cmdfunc send commands to the FCM */
|
||||
static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
lbus83xx_t *lbc = ctrl->regs;
|
||||
|
||||
ctrl->use_mdr = 0;
|
||||
|
||||
/* clear the read buffer */
|
||||
ctrl->read_bytes = 0;
|
||||
if (command != NAND_CMD_PAGEPROG)
|
||||
ctrl->index = 0;
|
||||
|
||||
switch (command) {
|
||||
/* READ0 and READ1 read the entire buffer to use hardware ECC. */
|
||||
case NAND_CMD_READ1:
|
||||
column += 256;
|
||||
|
||||
/* fall-through */
|
||||
case NAND_CMD_READ0:
|
||||
vdbg("fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
|
||||
" 0x%x, column: 0x%x.\n", page_addr, column);
|
||||
|
||||
out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
|
||||
set_addr(mtd, 0, page_addr, 0);
|
||||
|
||||
ctrl->read_bytes = mtd->writesize + mtd->oobsize;
|
||||
ctrl->index += column;
|
||||
|
||||
fsl_elbc_do_read(chip, 0);
|
||||
fsl_elbc_run_command(mtd);
|
||||
return;
|
||||
|
||||
/* READOOB reads only the OOB because no ECC is performed. */
|
||||
case NAND_CMD_READOOB:
|
||||
vdbg("fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
|
||||
" 0x%x, column: 0x%x.\n", page_addr, column);
|
||||
|
||||
out_be32(&lbc->fbcr, mtd->oobsize - column);
|
||||
set_addr(mtd, column, page_addr, 1);
|
||||
|
||||
ctrl->read_bytes = mtd->writesize + mtd->oobsize;
|
||||
|
||||
fsl_elbc_do_read(chip, 1);
|
||||
fsl_elbc_run_command(mtd);
|
||||
|
||||
return;
|
||||
|
||||
/* READID must read all 5 possible bytes while CEB is active */
|
||||
case NAND_CMD_READID:
|
||||
vdbg("fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
|
||||
|
||||
out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) |
|
||||
(FIR_OP_UA << FIR_OP1_SHIFT) |
|
||||
(FIR_OP_RBW << FIR_OP2_SHIFT));
|
||||
out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
|
||||
/* 5 bytes for manuf, device and exts */
|
||||
out_be32(&lbc->fbcr, 5);
|
||||
ctrl->read_bytes = 5;
|
||||
ctrl->use_mdr = 1;
|
||||
ctrl->mdr = 0;
|
||||
|
||||
set_addr(mtd, 0, 0, 0);
|
||||
fsl_elbc_run_command(mtd);
|
||||
return;
|
||||
|
||||
/* ERASE1 stores the block and page address */
|
||||
case NAND_CMD_ERASE1:
|
||||
vdbg("fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
|
||||
"page_addr: 0x%x.\n", page_addr);
|
||||
set_addr(mtd, 0, page_addr, 0);
|
||||
return;
|
||||
|
||||
/* ERASE2 uses the block and page address from ERASE1 */
|
||||
case NAND_CMD_ERASE2:
|
||||
vdbg("fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
|
||||
|
||||
out_be32(&lbc->fir,
|
||||
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
|
||||
(FIR_OP_PA << FIR_OP1_SHIFT) |
|
||||
(FIR_OP_CM1 << FIR_OP2_SHIFT));
|
||||
|
||||
out_be32(&lbc->fcr,
|
||||
(NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
|
||||
(NAND_CMD_ERASE2 << FCR_CMD1_SHIFT));
|
||||
|
||||
out_be32(&lbc->fbcr, 0);
|
||||
ctrl->read_bytes = 0;
|
||||
|
||||
fsl_elbc_run_command(mtd);
|
||||
return;
|
||||
|
||||
/* SEQIN sets up the addr buffer and all registers except the length */
|
||||
case NAND_CMD_SEQIN: {
|
||||
u32 fcr;
|
||||
vdbg("fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
|
||||
"page_addr: 0x%x, column: 0x%x.\n",
|
||||
page_addr, column);
|
||||
|
||||
ctrl->column = column;
|
||||
ctrl->oob = 0;
|
||||
|
||||
if (priv->page_size) {
|
||||
fcr = (NAND_CMD_SEQIN << FCR_CMD0_SHIFT) |
|
||||
(NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT);
|
||||
|
||||
out_be32(&lbc->fir,
|
||||
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
|
||||
(FIR_OP_CA << FIR_OP1_SHIFT) |
|
||||
(FIR_OP_PA << FIR_OP2_SHIFT) |
|
||||
(FIR_OP_WB << FIR_OP3_SHIFT) |
|
||||
(FIR_OP_CW1 << FIR_OP4_SHIFT));
|
||||
} else {
|
||||
fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) |
|
||||
(NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
|
||||
|
||||
out_be32(&lbc->fir,
|
||||
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
|
||||
(FIR_OP_CM2 << FIR_OP1_SHIFT) |
|
||||
(FIR_OP_CA << FIR_OP2_SHIFT) |
|
||||
(FIR_OP_PA << FIR_OP3_SHIFT) |
|
||||
(FIR_OP_WB << FIR_OP4_SHIFT) |
|
||||
(FIR_OP_CW1 << FIR_OP5_SHIFT));
|
||||
|
||||
if (column >= mtd->writesize) {
|
||||
/* OOB area --> READOOB */
|
||||
column -= mtd->writesize;
|
||||
fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
|
||||
ctrl->oob = 1;
|
||||
} else if (column < 256) {
|
||||
/* First 256 bytes --> READ0 */
|
||||
fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
|
||||
} else {
|
||||
/* Second 256 bytes --> READ1 */
|
||||
fcr |= NAND_CMD_READ1 << FCR_CMD0_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
out_be32(&lbc->fcr, fcr);
|
||||
set_addr(mtd, column, page_addr, ctrl->oob);
|
||||
return;
|
||||
}
|
||||
|
||||
/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
|
||||
case NAND_CMD_PAGEPROG: {
|
||||
int full_page;
|
||||
vdbg("fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
|
||||
"writing %d bytes.\n", ctrl->index);
|
||||
|
||||
/* if the write did not start at 0 or is not a full page
|
||||
* then set the exact length, otherwise use a full page
|
||||
* write so the HW generates the ECC.
|
||||
*/
|
||||
if (ctrl->oob || ctrl->column != 0 ||
|
||||
ctrl->index != mtd->writesize + mtd->oobsize) {
|
||||
out_be32(&lbc->fbcr, ctrl->index);
|
||||
full_page = 0;
|
||||
} else {
|
||||
out_be32(&lbc->fbcr, 0);
|
||||
full_page = 1;
|
||||
}
|
||||
|
||||
fsl_elbc_run_command(mtd);
|
||||
|
||||
/* Read back the page in order to fill in the ECC for the
|
||||
* caller. Is this really needed?
|
||||
*/
|
||||
if (full_page && ctrl->oob_poi) {
|
||||
out_be32(&lbc->fbcr, 3);
|
||||
set_addr(mtd, 6, page_addr, 1);
|
||||
|
||||
ctrl->read_bytes = mtd->writesize + 9;
|
||||
|
||||
fsl_elbc_do_read(chip, 1);
|
||||
fsl_elbc_run_command(mtd);
|
||||
|
||||
memcpy_fromio(ctrl->oob_poi + 6,
|
||||
&ctrl->addr[ctrl->index], 3);
|
||||
ctrl->index += 3;
|
||||
}
|
||||
|
||||
ctrl->oob_poi = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* CMD_STATUS must read the status byte while CEB is active */
|
||||
/* Note - it does not wait for the ready line */
|
||||
case NAND_CMD_STATUS:
|
||||
out_be32(&lbc->fir,
|
||||
(FIR_OP_CM0 << FIR_OP0_SHIFT) |
|
||||
(FIR_OP_RBW << FIR_OP1_SHIFT));
|
||||
out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
|
||||
out_be32(&lbc->fbcr, 1);
|
||||
set_addr(mtd, 0, 0, 0);
|
||||
ctrl->read_bytes = 1;
|
||||
|
||||
fsl_elbc_run_command(mtd);
|
||||
|
||||
/* The chip always seems to report that it is
|
||||
* write-protected, even when it is not.
|
||||
*/
|
||||
out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP);
|
||||
return;
|
||||
|
||||
/* RESET without waiting for the ready line */
|
||||
case NAND_CMD_RESET:
|
||||
dbg("fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
|
||||
out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
|
||||
out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
|
||||
fsl_elbc_run_command(mtd);
|
||||
return;
|
||||
|
||||
default:
|
||||
printf("fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
|
||||
command);
|
||||
}
|
||||
}
|
||||
|
||||
static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
|
||||
{
|
||||
/* The hardware does not seem to support multiple
|
||||
* chips per bank.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Write buf to the FCM Controller Data Buffer
|
||||
*/
|
||||
static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
unsigned int bufsize = mtd->writesize + mtd->oobsize;
|
||||
|
||||
if (len <= 0) {
|
||||
printf("write_buf of %d bytes", len);
|
||||
ctrl->status = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((unsigned int)len > bufsize - ctrl->index) {
|
||||
printf("write_buf beyond end of buffer "
|
||||
"(%d requested, %u available)\n",
|
||||
len, bufsize - ctrl->index);
|
||||
len = bufsize - ctrl->index;
|
||||
}
|
||||
|
||||
memcpy_toio(&ctrl->addr[ctrl->index], buf, len);
|
||||
/*
|
||||
* This is workaround for the weird elbc hangs during nand write,
|
||||
* Scott Wood says: "...perhaps difference in how long it takes a
|
||||
* write to make it through the localbus compared to a write to IMMR
|
||||
* is causing problems, and sync isn't helping for some reason."
|
||||
* Reading back the last byte helps though.
|
||||
*/
|
||||
in_8(&ctrl->addr[ctrl->index] + len - 1);
|
||||
|
||||
ctrl->index += len;
|
||||
}
|
||||
|
||||
/*
|
||||
* read a byte from either the FCM hardware buffer if it has any data left
|
||||
* otherwise issue a command to read a single byte.
|
||||
*/
|
||||
static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
|
||||
/* If there are still bytes in the FCM, then use the next byte. */
|
||||
if (ctrl->index < ctrl->read_bytes)
|
||||
return in_8(&ctrl->addr[ctrl->index++]);
|
||||
|
||||
printf("read_byte beyond end of buffer\n");
|
||||
return ERR_BYTE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from the FCM Controller Data Buffer
|
||||
*/
|
||||
static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
int avail;
|
||||
|
||||
if (len < 0)
|
||||
return;
|
||||
|
||||
avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index);
|
||||
memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail);
|
||||
ctrl->index += avail;
|
||||
|
||||
if (len > avail)
|
||||
printf("read_buf beyond end of buffer "
|
||||
"(%d requested, %d available)\n",
|
||||
len, avail);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify buffer against the FCM Controller Data Buffer
|
||||
*/
|
||||
static int fsl_elbc_verify_buf(struct mtd_info *mtd,
|
||||
const u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
int i;
|
||||
|
||||
if (len < 0) {
|
||||
printf("write_buf of %d bytes", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((unsigned int)len > ctrl->read_bytes - ctrl->index) {
|
||||
printf("verify_buf beyond end of buffer "
|
||||
"(%d requested, %u available)\n",
|
||||
len, ctrl->read_bytes - ctrl->index);
|
||||
|
||||
ctrl->index = ctrl->read_bytes;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i])
|
||||
break;
|
||||
|
||||
ctrl->index += len;
|
||||
return i == len && ctrl->status == LTESR_CC ? 0 : -EIO;
|
||||
}
|
||||
|
||||
/* This function is called after Program and Erase Operations to
|
||||
* check for success or failure.
|
||||
*/
|
||||
static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
{
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
lbus83xx_t *lbc = ctrl->regs;
|
||||
|
||||
if (ctrl->status != LTESR_CC)
|
||||
return NAND_STATUS_FAIL;
|
||||
|
||||
/* Use READ_STATUS command, but wait for the device to be ready */
|
||||
ctrl->use_mdr = 0;
|
||||
out_be32(&lbc->fir,
|
||||
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
|
||||
(FIR_OP_RBW << FIR_OP1_SHIFT));
|
||||
out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
|
||||
out_be32(&lbc->fbcr, 1);
|
||||
set_addr(mtd, 0, 0, 0);
|
||||
ctrl->read_bytes = 1;
|
||||
|
||||
fsl_elbc_run_command(mtd);
|
||||
|
||||
if (ctrl->status != LTESR_CC)
|
||||
return NAND_STATUS_FAIL;
|
||||
|
||||
/* The chip always seems to report that it is
|
||||
* write-protected, even when it is not.
|
||||
*/
|
||||
out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP);
|
||||
return fsl_elbc_read_byte(mtd);
|
||||
}
|
||||
|
||||
static int fsl_elbc_read_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
uint8_t *buf)
|
||||
{
|
||||
fsl_elbc_read_buf(mtd, buf, mtd->writesize);
|
||||
fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
|
||||
mtd->ecc_stats.failed++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ECC will be calculated automatically, and errors will be detected in
|
||||
* waitfunc.
|
||||
*/
|
||||
static void fsl_elbc_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
const uint8_t *buf)
|
||||
{
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
|
||||
fsl_elbc_write_buf(mtd, buf, mtd->writesize);
|
||||
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
ctrl->oob_poi = chip->oob_poi;
|
||||
}
|
||||
|
||||
static struct fsl_elbc_ctrl *elbc_ctrl;
|
||||
|
||||
static void fsl_elbc_ctrl_init(void)
|
||||
{
|
||||
immap_t *im = (immap_t *)CFG_IMMR;
|
||||
|
||||
elbc_ctrl = kzalloc(sizeof(*elbc_ctrl), GFP_KERNEL);
|
||||
if (!elbc_ctrl)
|
||||
return;
|
||||
|
||||
elbc_ctrl->regs = &im->lbus;
|
||||
|
||||
/* clear event registers */
|
||||
out_be32(&elbc_ctrl->regs->ltesr, LTESR_NAND_MASK);
|
||||
out_be32(&elbc_ctrl->regs->lteatr, 0);
|
||||
|
||||
/* Enable interrupts for any detected events */
|
||||
out_be32(&elbc_ctrl->regs->lteir, LTESR_NAND_MASK);
|
||||
|
||||
elbc_ctrl->read_bytes = 0;
|
||||
elbc_ctrl->index = 0;
|
||||
elbc_ctrl->addr = NULL;
|
||||
}
|
||||
|
||||
int board_nand_init(struct nand_chip *nand)
|
||||
{
|
||||
struct fsl_elbc_mtd *priv;
|
||||
uint32_t br, or;
|
||||
|
||||
if (!elbc_ctrl) {
|
||||
fsl_elbc_ctrl_init();
|
||||
if (!elbc_ctrl)
|
||||
return -1;
|
||||
}
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->ctrl = elbc_ctrl;
|
||||
priv->vbase = nand->IO_ADDR_R;
|
||||
|
||||
/* Find which chip select it is connected to. It'd be nice
|
||||
* if we could pass more than one datum to the NAND driver...
|
||||
*/
|
||||
for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) {
|
||||
br = in_be32(&elbc_ctrl->regs->bank[priv->bank].br);
|
||||
or = in_be32(&elbc_ctrl->regs->bank[priv->bank].or);
|
||||
|
||||
if ((br & BR_V) && (br & BR_MSEL) == BR_MS_FCM &&
|
||||
(br & or & BR_BA) == (phys_addr_t)nand->IO_ADDR_R)
|
||||
break;
|
||||
}
|
||||
|
||||
if (priv->bank >= MAX_BANKS) {
|
||||
printf("fsl_elbc_nand: address did not match any "
|
||||
"chip selects\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
elbc_ctrl->chips[priv->bank] = priv;
|
||||
|
||||
/* fill in nand_chip structure */
|
||||
/* set up function call table */
|
||||
nand->read_byte = fsl_elbc_read_byte;
|
||||
nand->write_buf = fsl_elbc_write_buf;
|
||||
nand->read_buf = fsl_elbc_read_buf;
|
||||
nand->verify_buf = fsl_elbc_verify_buf;
|
||||
nand->select_chip = fsl_elbc_select_chip;
|
||||
nand->cmdfunc = fsl_elbc_cmdfunc;
|
||||
nand->waitfunc = fsl_elbc_wait;
|
||||
|
||||
/* set up nand options */
|
||||
nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR;
|
||||
|
||||
nand->controller = &elbc_ctrl->controller;
|
||||
nand->priv = priv;
|
||||
|
||||
nand->ecc.read_page = fsl_elbc_read_page;
|
||||
nand->ecc.write_page = fsl_elbc_write_page;
|
||||
|
||||
/* If CS Base Register selects full hardware ECC then use it */
|
||||
if ((br & BR_DECC) == BR_DECC_CHK_GEN) {
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
|
||||
nand->ecc.layout = (priv->fmr & FMR_ECCM) ?
|
||||
&fsl_elbc_oob_sp_eccm1 :
|
||||
&fsl_elbc_oob_sp_eccm0;
|
||||
|
||||
nand->ecc.size = 512;
|
||||
nand->ecc.bytes = 3;
|
||||
nand->ecc.steps = 1;
|
||||
} else {
|
||||
/* otherwise fall back to default software ECC */
|
||||
nand->ecc.mode = NAND_ECC_SOFT;
|
||||
}
|
||||
|
||||
priv->fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT);
|
||||
|
||||
/* adjust Option Register and ECC to match Flash page size */
|
||||
if (or & OR_FCM_PGS) {
|
||||
priv->page_size = 1;
|
||||
|
||||
/* adjust ecc setup if needed */
|
||||
if ((br & BR_DECC) == BR_DECC_CHK_GEN) {
|
||||
nand->ecc.steps = 4;
|
||||
nand->ecc.layout = (priv->fmr & FMR_ECCM) ?
|
||||
&fsl_elbc_oob_lp_eccm1 :
|
||||
&fsl_elbc_oob_lp_eccm0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -20,8 +20,6 @@
|
||||
#include <linux/mtd/fsl_upm.h>
|
||||
#include <nand.h>
|
||||
|
||||
static int fsl_upm_in_pattern;
|
||||
|
||||
static void fsl_upm_start_pattern(struct fsl_upm *upm, u32 pat_offset)
|
||||
{
|
||||
clrsetbits_be32(upm->mxmr, MxMR_MAD_MSK, MxMR_OP_RUNP | pat_offset);
|
||||
@ -51,49 +49,38 @@ static void fsl_upm_run_pattern(struct fsl_upm *upm, int width, u32 cmd)
|
||||
}
|
||||
}
|
||||
|
||||
static void nand_hwcontrol (struct mtd_info *mtd, int cmd)
|
||||
static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_upm_nand *fun = chip->priv;
|
||||
|
||||
switch (cmd) {
|
||||
case NAND_CTL_SETCLE:
|
||||
fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset);
|
||||
fsl_upm_in_pattern++;
|
||||
break;
|
||||
case NAND_CTL_SETALE:
|
||||
fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset);
|
||||
fsl_upm_in_pattern++;
|
||||
break;
|
||||
case NAND_CTL_CLRCLE:
|
||||
case NAND_CTL_CLRALE:
|
||||
if (!(ctrl & fun->last_ctrl)) {
|
||||
fsl_upm_end_pattern(&fun->upm);
|
||||
fsl_upm_in_pattern--;
|
||||
break;
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
return;
|
||||
|
||||
fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE);
|
||||
}
|
||||
}
|
||||
|
||||
static void nand_write_byte(struct mtd_info *mtd, u_char byte)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
if (ctrl & NAND_ALE)
|
||||
fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset);
|
||||
else if (ctrl & NAND_CLE)
|
||||
fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset);
|
||||
}
|
||||
|
||||
if (fsl_upm_in_pattern) {
|
||||
struct fsl_upm_nand *fun = chip->priv;
|
||||
fsl_upm_run_pattern(&fun->upm, fun->width, cmd);
|
||||
|
||||
fsl_upm_run_pattern(&fun->upm, fun->width, byte);
|
||||
|
||||
/*
|
||||
* Some boards/chips needs this. At least on MPC8360E-RDK we
|
||||
* need it. Probably weird chip, because I don't see any need
|
||||
* for this on MPC8555E + Samsung K9F1G08U0A. Usually here are
|
||||
* 0-2 unexpected busy states per block read.
|
||||
*/
|
||||
if (fun->wait_pattern) {
|
||||
while (!fun->dev_ready())
|
||||
debug("unexpected busy state\n");
|
||||
}
|
||||
} else {
|
||||
out_8(chip->IO_ADDR_W, byte);
|
||||
/*
|
||||
* Some boards/chips needs this. At least on MPC8360E-RDK we
|
||||
* need it. Probably weird chip, because I don't see any need
|
||||
* for this on MPC8555E + Samsung K9F1G08U0A. Usually here are
|
||||
* 0-2 unexpected busy states per block read.
|
||||
*/
|
||||
if (fun->wait_pattern) {
|
||||
while (!fun->dev_ready())
|
||||
debug("unexpected busy state\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,13 +135,14 @@ int fsl_upm_nand_init(struct nand_chip *chip, struct fsl_upm_nand *fun)
|
||||
if (fun->width != 8 && fun->width != 16 && fun->width != 32)
|
||||
return -ENOSYS;
|
||||
|
||||
fun->last_ctrl = NAND_CLE;
|
||||
|
||||
chip->priv = fun;
|
||||
chip->chip_delay = fun->chip_delay;
|
||||
chip->eccmode = NAND_ECC_SOFT;
|
||||
chip->hwcontrol = nand_hwcontrol;
|
||||
chip->ecc.mode = NAND_ECC_SOFT;
|
||||
chip->cmd_ctrl = fun_cmd_ctrl;
|
||||
chip->read_byte = nand_read_byte;
|
||||
chip->read_buf = nand_read_buf;
|
||||
chip->write_byte = nand_write_byte;
|
||||
chip->write_buf = nand_write_buf;
|
||||
chip->verify_buf = nand_verify_buf;
|
||||
if (fun->dev_ready)
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -2,8 +2,8 @@
|
||||
* drivers/mtd/nandids.c
|
||||
*
|
||||
* 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,13 +28,15 @@
|
||||
* 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},
|
||||
{"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, 0},
|
||||
{"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0},
|
||||
{"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, 0},
|
||||
{"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0},
|
||||
{"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0},
|
||||
{"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0},
|
||||
{"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0},
|
||||
{"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 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"}
|
||||
};
|
||||
|
@ -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));
|
||||
}
|
||||
cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
|
||||
cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
|
||||
cleanmarker.totlen = cpu_to_je32(8);
|
||||
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;
|
||||
result = meminfo->write_oob(meminfo,
|
||||
erase.addr + clmpos,
|
||||
clmlen,
|
||||
&written,
|
||||
(unsigned char *)
|
||||
&cleanmarker);
|
||||
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);
|
||||
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 + meminfo->oobsize,
|
||||
&chip->ops);
|
||||
if (result != 0) {
|
||||
printf("\n%s: MTD writeoob failure: %d\n",
|
||||
mtd_device, result);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
printf("%s: MTD writeoob at 0x%08x\n",mtd_device, erase.addr + meminfo->oobsize );
|
||||
}
|
||||
|
||||
if (!opts->quiet) {
|
||||
@ -232,11 +193,11 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
||||
percent_complete = percent;
|
||||
|
||||
printf("\rErasing at 0x%x -- %3d%% complete.",
|
||||
erase.addr, percent);
|
||||
erase.addr, percent);
|
||||
|
||||
if (opts->jffs2 && result == 0)
|
||||
printf(" Cleanmarker written at 0x%x.",
|
||||
erase.addr);
|
||||
printf(" Cleanmarker written at 0x%x.",
|
||||
erase.addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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,443 +227,29 @@ 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_write_opts: - write image to NAND flash with support for various options
|
||||
*
|
||||
* @param meminfo NAND device to erase
|
||||
* @param opts write options (@see nand_write_options)
|
||||
* @return 0 in case of success
|
||||
*
|
||||
* This code is ported from nandwrite.c from Linux mtd utils by
|
||||
* Steven J. Hill and Thomas Gleixner.
|
||||
*/
|
||||
int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
|
||||
{
|
||||
int imglen = 0;
|
||||
int pagelen;
|
||||
int baderaseblock;
|
||||
int blockstart = -1;
|
||||
loff_t offs;
|
||||
int readlen;
|
||||
int oobinfochanged = 0;
|
||||
int percent_complete = -1;
|
||||
struct nand_oobinfo old_oobinfo;
|
||||
ulong mtdoffset = opts->offset;
|
||||
ulong erasesize_blockalign;
|
||||
u_char *buffer = opts->buffer;
|
||||
size_t written;
|
||||
int result;
|
||||
|
||||
if (opts->pad && opts->writeoob) {
|
||||
printf("Can't pad when oob data is present.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* set erasesize to specified number of blocks - to match
|
||||
* jffs2 (virtual) block size */
|
||||
if (opts->blockalign == 0) {
|
||||
erasesize_blockalign = meminfo->erasesize;
|
||||
} else {
|
||||
erasesize_blockalign = meminfo->erasesize * opts->blockalign;
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
printf("Unknown flash (not normal NAND)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read the current oob info */
|
||||
memcpy(&old_oobinfo, &meminfo->oobinfo, sizeof(old_oobinfo));
|
||||
|
||||
/* write without ecc? */
|
||||
if (opts->noecc) {
|
||||
memcpy(&meminfo->oobinfo, &none_oobinfo,
|
||||
sizeof(meminfo->oobinfo));
|
||||
oobinfochanged = 1;
|
||||
}
|
||||
|
||||
/* autoplace ECC? */
|
||||
if (opts->autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
|
||||
|
||||
memcpy(&meminfo->oobinfo, &autoplace_oobinfo,
|
||||
sizeof(meminfo->oobinfo));
|
||||
oobinfochanged = 1;
|
||||
}
|
||||
|
||||
/* force OOB layout for jffs2 or yaffs? */
|
||||
if (opts->forcejffs2 || opts->forceyaffs) {
|
||||
struct nand_oobinfo *oobsel =
|
||||
opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
|
||||
|
||||
if (meminfo->oobsize == 8) {
|
||||
if (opts->forceyaffs) {
|
||||
printf("YAFSS cannot operate on "
|
||||
"256 Byte page size\n");
|
||||
goto restoreoob;
|
||||
}
|
||||
/* Adjust number of ecc bytes */
|
||||
jffs2_oobinfo.eccbytes = 3;
|
||||
}
|
||||
|
||||
memcpy(&meminfo->oobinfo, oobsel, sizeof(meminfo->oobinfo));
|
||||
}
|
||||
|
||||
/* get image length */
|
||||
imglen = opts->length;
|
||||
pagelen = meminfo->oobblock
|
||||
+ ((opts->writeoob != 0) ? meminfo->oobsize : 0);
|
||||
|
||||
/* check, if file is pagealigned */
|
||||
if ((!opts->pad) && ((imglen % pagelen) != 0)) {
|
||||
printf("Input block length is not page aligned\n");
|
||||
goto restoreoob;
|
||||
}
|
||||
|
||||
/* check, if length fits into device */
|
||||
if (((imglen / pagelen) * meminfo->oobblock)
|
||||
> (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);
|
||||
printf("Input block does not fit into device\n");
|
||||
goto restoreoob;
|
||||
}
|
||||
|
||||
if (!opts->quiet)
|
||||
printf("\n");
|
||||
|
||||
/* get data from input and write to the device */
|
||||
while (imglen && (mtdoffset < meminfo->size)) {
|
||||
|
||||
WATCHDOG_RESET ();
|
||||
|
||||
/*
|
||||
* new eraseblock, check for bad block(s). Stay in the
|
||||
* loop to be sure if the offset changes because of
|
||||
* a bad block, that the next block that will be
|
||||
* written to is also checked. Thus avoiding errors if
|
||||
* the block(s) after the skipped block(s) is also bad
|
||||
* (number of blocks depending on the blockalign
|
||||
*/
|
||||
while (blockstart != (mtdoffset & (~erasesize_blockalign+1))) {
|
||||
blockstart = mtdoffset & (~erasesize_blockalign+1);
|
||||
offs = blockstart;
|
||||
baderaseblock = 0;
|
||||
|
||||
/* check all the blocks in an erase block for
|
||||
* bad blocks */
|
||||
do {
|
||||
int ret = meminfo->block_isbad(meminfo, offs);
|
||||
|
||||
if (ret < 0) {
|
||||
printf("Bad block check failed\n");
|
||||
goto restoreoob;
|
||||
}
|
||||
if (ret == 1) {
|
||||
baderaseblock = 1;
|
||||
if (!opts->quiet)
|
||||
printf("\rBad block at 0x%lx "
|
||||
"in erase block from "
|
||||
"0x%x will be skipped\n",
|
||||
(long) offs,
|
||||
blockstart);
|
||||
}
|
||||
|
||||
if (baderaseblock) {
|
||||
mtdoffset = blockstart
|
||||
+ erasesize_blockalign;
|
||||
}
|
||||
offs += erasesize_blockalign
|
||||
/ opts->blockalign;
|
||||
} while (offs < blockstart + erasesize_blockalign);
|
||||
}
|
||||
|
||||
readlen = meminfo->oobblock;
|
||||
if (opts->pad && (imglen < readlen)) {
|
||||
readlen = imglen;
|
||||
memset(data_buf + readlen, 0xff,
|
||||
meminfo->oobblock - readlen);
|
||||
}
|
||||
|
||||
/* read page data from input memory buffer */
|
||||
memcpy(data_buf, buffer, readlen);
|
||||
buffer += readlen;
|
||||
|
||||
if (opts->writeoob) {
|
||||
/* read OOB data from input memory block, exit
|
||||
* on failure */
|
||||
memcpy(oob_buf, buffer, meminfo->oobsize);
|
||||
buffer += meminfo->oobsize;
|
||||
|
||||
/* write OOB data first, as ecc will be placed
|
||||
* in there*/
|
||||
result = meminfo->write_oob(meminfo,
|
||||
mtdoffset,
|
||||
meminfo->oobsize,
|
||||
&written,
|
||||
(unsigned char *)
|
||||
&oob_buf);
|
||||
|
||||
if (result != 0) {
|
||||
printf("\nMTD writeoob failure: %d\n",
|
||||
result);
|
||||
goto restoreoob;
|
||||
}
|
||||
imglen -= meminfo->oobsize;
|
||||
}
|
||||
|
||||
/* write out the page data */
|
||||
result = meminfo->write(meminfo,
|
||||
mtdoffset,
|
||||
meminfo->oobblock,
|
||||
&written,
|
||||
(unsigned char *) &data_buf);
|
||||
|
||||
if (result != 0) {
|
||||
printf("writing NAND page at offset 0x%lx failed\n",
|
||||
mtdoffset);
|
||||
goto restoreoob;
|
||||
}
|
||||
imglen -= readlen;
|
||||
|
||||
if (!opts->quiet) {
|
||||
unsigned long long n = (unsigned long long)
|
||||
(opts->length-imglen) * 100;
|
||||
int percent;
|
||||
|
||||
do_div(n, opts->length);
|
||||
percent = (int)n;
|
||||
|
||||
/* output progress message only at whole percent
|
||||
* steps to reduce the number of messages printed
|
||||
* on (slow) serial consoles
|
||||
*/
|
||||
if (percent != percent_complete) {
|
||||
printf("\rWriting data at 0x%lx "
|
||||
"-- %3d%% complete.",
|
||||
mtdoffset, percent);
|
||||
percent_complete = percent;
|
||||
}
|
||||
}
|
||||
|
||||
mtdoffset += meminfo->oobblock;
|
||||
}
|
||||
|
||||
if (!opts->quiet)
|
||||
printf("\n");
|
||||
|
||||
restoreoob:
|
||||
if (oobinfochanged) {
|
||||
memcpy(&meminfo->oobinfo, &old_oobinfo,
|
||||
sizeof(meminfo->oobinfo));
|
||||
}
|
||||
|
||||
if (imglen > 0) {
|
||||
printf("Data did not fit into device, due to bad blocks\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* return happy */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_read_opts: - read image from NAND flash with support for various options
|
||||
*
|
||||
* @param meminfo NAND device to erase
|
||||
* @param opts read options (@see struct nand_read_options)
|
||||
* @return 0 in case of success
|
||||
*
|
||||
*/
|
||||
int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)
|
||||
{
|
||||
int imglen = opts->length;
|
||||
int pagelen;
|
||||
int baderaseblock;
|
||||
int blockstart = -1;
|
||||
int percent_complete = -1;
|
||||
loff_t offs;
|
||||
size_t readlen;
|
||||
ulong mtdoffset = opts->offset;
|
||||
u_char *buffer = opts->buffer;
|
||||
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)) {
|
||||
printf("Unknown flash (not normal NAND)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pagelen = meminfo->oobblock
|
||||
+ ((opts->readoob != 0) ? meminfo->oobsize : 0);
|
||||
|
||||
/* check, if length is not larger than device */
|
||||
if (((imglen / pagelen) * meminfo->oobblock)
|
||||
> (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);
|
||||
printf("Input block is larger than device\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!opts->quiet)
|
||||
printf("\n");
|
||||
|
||||
/* get data from input and write to the device */
|
||||
while (imglen && (mtdoffset < meminfo->size)) {
|
||||
|
||||
WATCHDOG_RESET ();
|
||||
|
||||
/*
|
||||
* new eraseblock, check for bad block(s). Stay in the
|
||||
* loop to be sure if the offset changes because of
|
||||
* a bad block, that the next block that will be
|
||||
* written to is also checked. Thus avoiding errors if
|
||||
* the block(s) after the skipped block(s) is also bad
|
||||
* (number of blocks depending on the blockalign
|
||||
*/
|
||||
while (blockstart != (mtdoffset & (~meminfo->erasesize+1))) {
|
||||
blockstart = mtdoffset & (~meminfo->erasesize+1);
|
||||
offs = blockstart;
|
||||
baderaseblock = 0;
|
||||
|
||||
/* check all the blocks in an erase block for
|
||||
* bad blocks */
|
||||
do {
|
||||
int ret = meminfo->block_isbad(meminfo, offs);
|
||||
|
||||
if (ret < 0) {
|
||||
printf("Bad block check failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (ret == 1) {
|
||||
baderaseblock = 1;
|
||||
if (!opts->quiet)
|
||||
printf("\rBad block at 0x%lx "
|
||||
"in erase block from "
|
||||
"0x%x will be skipped\n",
|
||||
(long) offs,
|
||||
blockstart);
|
||||
}
|
||||
|
||||
if (baderaseblock) {
|
||||
mtdoffset = blockstart
|
||||
+ meminfo->erasesize;
|
||||
}
|
||||
offs += meminfo->erasesize;
|
||||
|
||||
} while (offs < blockstart + meminfo->erasesize);
|
||||
}
|
||||
|
||||
|
||||
/* read page data to memory buffer */
|
||||
result = meminfo->read(meminfo,
|
||||
mtdoffset,
|
||||
meminfo->oobblock,
|
||||
&readlen,
|
||||
(unsigned char *) &data_buf);
|
||||
|
||||
if (result != 0) {
|
||||
printf("reading NAND page at offset 0x%lx failed\n",
|
||||
mtdoffset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (imglen < readlen) {
|
||||
readlen = imglen;
|
||||
}
|
||||
|
||||
memcpy(buffer, data_buf, readlen);
|
||||
buffer += readlen;
|
||||
imglen -= readlen;
|
||||
|
||||
if (opts->readoob) {
|
||||
result = meminfo->read_oob(meminfo,
|
||||
mtdoffset,
|
||||
meminfo->oobsize,
|
||||
&readlen,
|
||||
(unsigned char *)
|
||||
&oob_buf);
|
||||
|
||||
if (result != 0) {
|
||||
printf("\nMTD readoob failure: %d\n",
|
||||
result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (imglen < readlen) {
|
||||
readlen = imglen;
|
||||
}
|
||||
|
||||
memcpy(buffer, oob_buf, readlen);
|
||||
|
||||
buffer += readlen;
|
||||
imglen -= readlen;
|
||||
}
|
||||
|
||||
if (!opts->quiet) {
|
||||
unsigned long long n = (unsigned long long)
|
||||
(opts->length-imglen) * 100;
|
||||
int percent;
|
||||
|
||||
do_div(n, opts->length);
|
||||
percent = (int)n;
|
||||
|
||||
/* output progress message only at whole percent
|
||||
* steps to reduce the number of messages printed
|
||||
* on (slow) serial consoles
|
||||
*/
|
||||
if (percent != percent_complete) {
|
||||
if (!opts->quiet)
|
||||
printf("\rReading data from 0x%lx "
|
||||
"-- %3d%% complete.",
|
||||
mtdoffset, percent);
|
||||
percent_complete = percent;
|
||||
}
|
||||
}
|
||||
|
||||
mtdoffset += meminfo->oobblock;
|
||||
}
|
||||
|
||||
if (!opts->quiet)
|
||||
printf("\n");
|
||||
|
||||
if (imglen > 0) {
|
||||
printf("Could not read entire image due to bad blocks\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* return happy */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
/******************************************************************************
|
||||
* Support for locking / unlocking operations of some NAND devices
|
||||
*****************************************************************************/
|
||||
@ -784,7 +334,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 +363,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 +389,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 +425,186 @@ int nand_unlock(nand_info_t *meminfo, ulong start, ulong length)
|
||||
this->select_chip(meminfo, -1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* get_len_incl_bad
|
||||
*
|
||||
* Check if length including bad blocks fits into device.
|
||||
*
|
||||
* @param nand NAND device
|
||||
* @param offset offset in flash
|
||||
* @param length image length
|
||||
* @return image length including bad blocks
|
||||
*/
|
||||
static size_t get_len_incl_bad (nand_info_t *nand, size_t offset,
|
||||
const size_t length)
|
||||
{
|
||||
size_t len_incl_bad = 0;
|
||||
size_t len_excl_bad = 0;
|
||||
size_t block_len;
|
||||
|
||||
while (len_excl_bad < length) {
|
||||
block_len = nand->erasesize - (offset & (nand->erasesize - 1));
|
||||
|
||||
if (!nand_block_isbad (nand, offset & ~(nand->erasesize - 1)))
|
||||
len_excl_bad += block_len;
|
||||
|
||||
len_incl_bad += block_len;
|
||||
offset += block_len;
|
||||
|
||||
if ((offset + len_incl_bad) >= nand->size)
|
||||
break;
|
||||
}
|
||||
|
||||
return len_incl_bad;
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_write_skip_bad:
|
||||
*
|
||||
* Write image to NAND flash.
|
||||
* Blocks that are marked bad are skipped and the is written to the next
|
||||
* block instead as long as the image is short enough to fit even after
|
||||
* skipping the bad blocks.
|
||||
*
|
||||
* @param nand NAND device
|
||||
* @param offset offset in flash
|
||||
* @param length buffer length
|
||||
* @param buf buffer to read from
|
||||
* @return 0 in case of success
|
||||
*/
|
||||
int nand_write_skip_bad(nand_info_t *nand, size_t offset, size_t *length,
|
||||
u_char *buffer)
|
||||
{
|
||||
int rval;
|
||||
size_t left_to_write = *length;
|
||||
size_t len_incl_bad;
|
||||
u_char *p_buffer = buffer;
|
||||
|
||||
/* Reject writes, which are not page aligned */
|
||||
if ((offset & (nand->writesize - 1)) != 0 ||
|
||||
(*length & (nand->writesize - 1)) != 0) {
|
||||
printf ("Attempt to write non page aligned data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len_incl_bad = get_len_incl_bad (nand, offset, *length);
|
||||
|
||||
if ((offset + len_incl_bad) >= nand->size) {
|
||||
printf ("Attempt to write outside the flash area\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (len_incl_bad == *length) {
|
||||
rval = nand_write (nand, offset, length, buffer);
|
||||
if (rval != 0) {
|
||||
printf ("NAND write to offset %x failed %d\n",
|
||||
offset, rval);
|
||||
return rval;
|
||||
}
|
||||
}
|
||||
|
||||
while (left_to_write > 0) {
|
||||
size_t block_offset = offset & (nand->erasesize - 1);
|
||||
size_t write_size;
|
||||
|
||||
if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) {
|
||||
printf ("Skip bad block 0x%08x\n",
|
||||
offset & ~(nand->erasesize - 1));
|
||||
offset += nand->erasesize - block_offset;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (left_to_write < (nand->erasesize - block_offset))
|
||||
write_size = left_to_write;
|
||||
else
|
||||
write_size = nand->erasesize - block_offset;
|
||||
|
||||
rval = nand_write (nand, offset, &write_size, p_buffer);
|
||||
if (rval != 0) {
|
||||
printf ("NAND write to offset %x failed %d\n",
|
||||
offset, rval);
|
||||
*length -= left_to_write;
|
||||
return rval;
|
||||
}
|
||||
|
||||
left_to_write -= write_size;
|
||||
offset += write_size;
|
||||
p_buffer += write_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_read_skip_bad:
|
||||
*
|
||||
* Read image from NAND flash.
|
||||
* Blocks that are marked bad are skipped and the next block is readen
|
||||
* instead as long as the image is short enough to fit even after skipping the
|
||||
* bad blocks.
|
||||
*
|
||||
* @param nand NAND device
|
||||
* @param offset offset in flash
|
||||
* @param length buffer length, on return holds remaining bytes to read
|
||||
* @param buffer buffer to write to
|
||||
* @return 0 in case of success
|
||||
*/
|
||||
int nand_read_skip_bad(nand_info_t *nand, size_t offset, size_t *length,
|
||||
u_char *buffer)
|
||||
{
|
||||
int rval;
|
||||
size_t left_to_read = *length;
|
||||
size_t len_incl_bad;
|
||||
u_char *p_buffer = buffer;
|
||||
|
||||
len_incl_bad = get_len_incl_bad (nand, offset, *length);
|
||||
|
||||
if ((offset + len_incl_bad) >= nand->size) {
|
||||
printf ("Attempt to read outside the flash area\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (len_incl_bad == *length) {
|
||||
rval = nand_read (nand, offset, length, buffer);
|
||||
if (rval != 0) {
|
||||
printf ("NAND read from offset %x failed %d\n",
|
||||
offset, rval);
|
||||
return rval;
|
||||
}
|
||||
}
|
||||
|
||||
while (left_to_read > 0) {
|
||||
size_t block_offset = offset & (nand->erasesize - 1);
|
||||
size_t read_length;
|
||||
|
||||
if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) {
|
||||
printf ("Skipping bad block 0x%08x\n",
|
||||
offset & ~(nand->erasesize - 1));
|
||||
offset += nand->erasesize - block_offset;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (left_to_read < (nand->erasesize - block_offset))
|
||||
read_length = left_to_read;
|
||||
else
|
||||
read_length = nand->erasesize - block_offset;
|
||||
|
||||
rval = nand_read (nand, offset, &read_length, p_buffer);
|
||||
if (rval != 0) {
|
||||
printf ("NAND read from offset %x failed %d\n",
|
||||
offset, rval);
|
||||
*length -= left_to_read;
|
||||
return rval;
|
||||
}
|
||||
|
||||
left_to_read -= read_length;
|
||||
offset += read_length;
|
||||
p_buffer += read_length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY) */
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <malloc.h>
|
||||
|
||||
/* It should access 16-bit instead of 8-bit */
|
||||
static inline void *memcpy_16(void *dst, const void *src, unsigned int len)
|
||||
@ -1110,21 +1111,21 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
|
||||
*
|
||||
* Print device ID
|
||||
*/
|
||||
void onenand_print_device_info(int device, int verbose)
|
||||
char * onenand_print_device_info(int device)
|
||||
{
|
||||
int vcc, demuxed, ddp, density;
|
||||
|
||||
if (!verbose)
|
||||
return;
|
||||
char *dev_info = malloc(80);
|
||||
|
||||
vcc = device & ONENAND_DEVICE_VCC_MASK;
|
||||
demuxed = device & ONENAND_DEVICE_IS_DEMUX;
|
||||
ddp = device & ONENAND_DEVICE_IS_DDP;
|
||||
density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
|
||||
printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n",
|
||||
sprintf(dev_info, "%sOneNAND%s %dMB %sV 16-bit (0x%02x)",
|
||||
demuxed ? "" : "Muxed ",
|
||||
ddp ? "(DDP)" : "",
|
||||
(16 << density), vcc ? "2.65/3.3" : "1.8", device);
|
||||
|
||||
return dev_info;
|
||||
}
|
||||
|
||||
static const struct onenand_manufacturers onenand_manuf_ids[] = {
|
||||
@ -1203,7 +1204,7 @@ static int onenand_probe(struct mtd_info *mtd)
|
||||
}
|
||||
|
||||
/* Flash device information */
|
||||
onenand_print_device_info(dev_id, 0);
|
||||
mtd->name = onenand_print_device_info(dev_id);
|
||||
this->device_id = dev_id;
|
||||
|
||||
density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
|
||||
@ -1239,6 +1240,17 @@ static int onenand_probe(struct mtd_info *mtd)
|
||||
this->options |= ONENAND_CONT_LOCK;
|
||||
}
|
||||
|
||||
mtd->erase = onenand_erase;
|
||||
mtd->read = onenand_read;
|
||||
mtd->write = onenand_write;
|
||||
mtd->read_ecc = onenand_read_ecc;
|
||||
mtd->write_ecc = onenand_write_ecc;
|
||||
mtd->read_oob = onenand_read_oob;
|
||||
mtd->write_oob = onenand_write_oob;
|
||||
mtd->sync = onenand_sync;
|
||||
mtd->block_isbad = onenand_block_isbad;
|
||||
mtd->block_markbad = onenand_block_markbad;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
#
|
||||
#
|
||||
|
||||
SUBDIRS := jffs2 cramfs fdos fat reiserfs ext2
|
||||
SUBDIRS := jffs2 cramfs fdos fat reiserfs ext2 yaffs2
|
||||
|
||||
$(obj).depend all:
|
||||
@for dir in $(SUBDIRS) ; do \
|
||||
|
56
fs/yaffs2/Makefile
Normal file
56
fs/yaffs2/Makefile
Normal file
@ -0,0 +1,56 @@
|
||||
# Makefile for YAFFS direct test
|
||||
#
|
||||
#
|
||||
# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
|
||||
#
|
||||
# Copyright (C) 2003 Aleph One Ltd.
|
||||
#
|
||||
#
|
||||
# Created by Charles Manning <charles@aleph1.co.uk>
|
||||
#
|
||||
# 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
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# NB Warning this Makefile does not include header dependencies.
|
||||
#
|
||||
# $Id: Makefile,v 1.15 2007/07/18 19:40:38 charles Exp $
|
||||
|
||||
#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
|
||||
include $(TOPDIR)/config.mk
|
||||
|
||||
LIB = $(obj)libyaffs2.a
|
||||
|
||||
COBJS-$(CONFIG_YAFFS2) := \
|
||||
yaffscfg.o yaffs_ecc.o yaffsfs.o yaffs_guts.o yaffs_packedtags1.o \
|
||||
yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o \
|
||||
yaffs_nand.o yaffs_checkptrw.o yaffs_qsort.o yaffs_mtdif.o \
|
||||
yaffs_mtdif2.o
|
||||
|
||||
SRCS := $(COBJS-y:.o=.c)
|
||||
OBJS := $(addprefix $(obj),$(COBJS-y))
|
||||
|
||||
# -DCONFIG_YAFFS_NO_YAFFS1
|
||||
CFLAGS += -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -DNO_Y_INLINE -DLINUX_VERSION_CODE=0x20622
|
||||
|
||||
all: $(LIB)
|
||||
|
||||
$(LIB): $(obj).depend $(OBJS)
|
||||
$(AR) $(ARFLAGS) $@ $(OBJS)
|
||||
|
||||
.PHONY: clean distclean
|
||||
clean:
|
||||
rm -f $(OBJS)
|
||||
|
||||
distclean: clean
|
||||
rm -f $(LIB) core *.bak .depend
|
||||
|
||||
#########################################################################
|
||||
|
||||
# defines $(obj).depend target
|
||||
include $(SRCTREE)/rules.mk
|
||||
|
||||
sinclude $(obj).depend
|
||||
|
||||
#########################################################################
|
||||
|
201
fs/yaffs2/README-linux
Normal file
201
fs/yaffs2/README-linux
Normal file
@ -0,0 +1,201 @@
|
||||
Welcome to YAFFS, the first file system developed specifically for NAND flash.
|
||||
|
||||
It is now YAFFS2 - original YAFFS (AYFFS1) only supports 512-byte page
|
||||
NAND and is now deprectated. YAFFS2 supports 512b page in 'YAFFS1
|
||||
compatibility' mode (CONFIG_YAFFS_YAFFS1) and 2K or larger page NAND
|
||||
in YAFFS2 mode (CONFIG_YAFFS_YAFFS2).
|
||||
|
||||
|
||||
A note on licencing
|
||||
-------------------
|
||||
YAFFS is available under the GPL and via alternative licensing
|
||||
arrangements with Aleph One. If you're using YAFFS as a Linux kernel
|
||||
file system then it will be under the GPL. For use in other situations
|
||||
you should discuss licensing issues with Aleph One.
|
||||
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
Page - NAND addressable unit (normally 512b or 2Kbyte size) - can
|
||||
be read, written, marked bad. Has associated OOB.
|
||||
Block - Eraseable unit. 64 Pages. (128K on 2K NAND, 32K on 512b NAND)
|
||||
OOB - 'spare area' of each page for ECC, bad block marked and YAFFS
|
||||
tags. 16 bytes per 512b - 64 bytes for 2K page size.
|
||||
Chunk - Basic YAFFS addressable unit. Same size as Page.
|
||||
Object - YAFFS Object: File, Directory, Link, Device etc.
|
||||
|
||||
YAFFS design
|
||||
------------
|
||||
|
||||
YAFFS is a log-structured filesystem. It is designed particularly for
|
||||
NAND (as opposed to NOR) flash, to be flash-friendly, robust due to
|
||||
journalling, and to have low RAM and boot time overheads. File data is
|
||||
stored in 'chunks'. Chunks are the same size as NAND pages. Each page
|
||||
is marked with file id and chunk number. These marking 'tags' are
|
||||
stored in the OOB (or 'spare') region of the flash. The chunk number
|
||||
is determined by dividing the file position by the chunk size. Each
|
||||
chunk has a number of valid bytes, which equals the page size for all
|
||||
except the last chunk in a file.
|
||||
|
||||
File 'headers' are stored as the first page in a file, marked as a
|
||||
different type to data pages. The same mechanism is used to store
|
||||
directories, device files, links etc. The first page describes which
|
||||
type of object it is.
|
||||
|
||||
YAFFS2 never re-writes a page, because the spec of NAND chips does not
|
||||
allow it. (YAFFS1 used to mark a block 'deleted' in the OOB). Deletion
|
||||
is managed by moving deleted objects to the special, hidden 'unlinked'
|
||||
directory. These records are preserved until all the pages containing
|
||||
the object have been erased (We know when this happen by keeping a
|
||||
count of chunks remaining on the system for each object - when it
|
||||
reaches zero the object really is gone).
|
||||
|
||||
When data in a file is overwritten, the relevant chunks are replaced
|
||||
by writing new pages to flash containing the new data but the same
|
||||
tags.
|
||||
|
||||
Pages are also marked with a short (2 bit) serial number that
|
||||
increments each time the page at this position is incremented. The
|
||||
reason for this is that if power loss/crash/other act of demonic
|
||||
forces happens before the replaced page is marked as discarded, it is
|
||||
possible to have two pages with the same tags. The serial number is
|
||||
used to arbitrate.
|
||||
|
||||
A block containing only discarded pages (termed a dirty block) is an
|
||||
obvious candidate for garbage collection. Otherwise valid pages can be
|
||||
copied off a block thus rendering the whole block discarded and ready
|
||||
for garbage collection.
|
||||
|
||||
In theory you don't need to hold the file structure in RAM... you
|
||||
could just scan the whole flash looking for pages when you need them.
|
||||
In practice though you'd want better file access times than that! The
|
||||
mechanism proposed here is to have a list of __u16 page addresses
|
||||
associated with each file. Since there are 2^18 pages in a 128MB NAND,
|
||||
a __u16 is insufficient to uniquely identify a page but is does
|
||||
identify a group of 4 pages - a small enough region to search
|
||||
exhaustively. This mechanism is clearly expandable to larger NAND
|
||||
devices - within reason. The RAM overhead with this approach is approx
|
||||
2 bytes per page - 512kB of RAM for a whole 128MB NAND.
|
||||
|
||||
Boot-time scanning to build the file structure lists only requires
|
||||
one pass reading NAND. If proper shutdowns happen the current RAM
|
||||
summary of the filesystem status is saved to flash, called
|
||||
'checkpointing'. This saves re-scanning the flash on startup, and gives
|
||||
huge boot/mount time savings.
|
||||
|
||||
YAFFS regenerates its state by 'replaying the tape' - i.e. by
|
||||
scanning the chunks in their allocation order (i.e. block sequence ID
|
||||
order), which is usually different form the media block order. Each
|
||||
block is still only read once - starting from the end of the media and
|
||||
working back.
|
||||
|
||||
YAFFS tags in YAFFS1 mode:
|
||||
|
||||
18-bit Object ID (2^18 files, i.e. > 260,000 files). File id 0- is not
|
||||
valid and indicates a deleted page. File od 0x3ffff is also not valid.
|
||||
Synonymous with inode.
|
||||
2-bit serial number
|
||||
20-bit Chunk ID within file. Limit of 2^20 chunks/pages per file (i.e.
|
||||
> 500MB max file size). Chunk ID 0 is the file header for the file.
|
||||
10-bit counter of the number of bytes used in the page.
|
||||
12 bit ECC on tags
|
||||
|
||||
YAFFS tags in YAFFS2 mode:
|
||||
4 bytes 32-bit chunk ID
|
||||
4 bytes 32-bit object ID
|
||||
2 bytes Number of data bytes in this chunk
|
||||
4 bytes Sequence number for this block
|
||||
3 bytes ECC on tags
|
||||
12 bytes ECC on data (3 bytes per 256 bytes of data)
|
||||
|
||||
|
||||
Page allocation and garbage collection
|
||||
|
||||
Pages are allocated sequentially from the currently selected block.
|
||||
When all the pages in the block are filled, another clean block is
|
||||
selected for allocation. At least two or three clean blocks are
|
||||
reserved for garbage collection purposes. If there are insufficient
|
||||
clean blocks available, then a dirty block ( ie one containing only
|
||||
discarded pages) is erased to free it up as a clean block. If no dirty
|
||||
blocks are available, then the dirtiest block is selected for garbage
|
||||
collection.
|
||||
|
||||
Garbage collection is performed by copying the valid data pages into
|
||||
new data pages thus rendering all the pages in this block dirty and
|
||||
freeing it up for erasure. I also like the idea of selecting a block
|
||||
at random some small percentage of the time - thus reducing the chance
|
||||
of wear differences.
|
||||
|
||||
YAFFS is single-threaded. Garbage-collection is done as a parasitic
|
||||
task of writing data. So each time some data is written, a bit of
|
||||
pending garbage collection is done. More pages are garbage-collected
|
||||
when free space is tight.
|
||||
|
||||
|
||||
Flash writing
|
||||
|
||||
YAFFS only ever writes each page once, complying with the requirements
|
||||
of the most restricitve NAND devices.
|
||||
|
||||
Wear levelling
|
||||
|
||||
This comes as a side-effect of the block-allocation strategy. Data is
|
||||
always written on the next free block, so they are all used equally.
|
||||
Blocks containing data that is written but never erased will not get
|
||||
back into the free list, so wear is levelled over only blocks which
|
||||
are free or become free, not blocks which never change.
|
||||
|
||||
|
||||
|
||||
Some helpful info
|
||||
-----------------
|
||||
|
||||
Formatting a YAFFS device is simply done by erasing it.
|
||||
|
||||
Making an initial filesystem can be tricky because YAFFS uses the OOB
|
||||
and thus the bytes that get written depend on the YAFFS data (tags),
|
||||
and the ECC bytes and bad block markers which are dictated by the
|
||||
hardware and/or the MTD subsystem. The data layout also depends on the
|
||||
device page size (512b or 2K). Because YAFFS is only responsible for
|
||||
some of the OOB data, generating a filesystem offline requires
|
||||
detailed knowledge of what the other parts (MTD and NAND
|
||||
driver/hardware) are going to do.
|
||||
|
||||
To make a YAFFS filesystem you have 3 options:
|
||||
|
||||
1) Boot the system with an empty NAND device mounted as YAFFS and copy
|
||||
stuff on.
|
||||
|
||||
2) Make a filesystem image offline, then boot the system and use
|
||||
MTDutils to write an image to flash.
|
||||
|
||||
3) Make a filesystem image offline and use some tool like a bootloader to
|
||||
write it to flash.
|
||||
|
||||
Option 1 avoids a lot of issues because all the parts
|
||||
(YAFFS/MTD/hardware) all take care of their own bits and (if you have
|
||||
put things together properly) it will 'just work'. YAFFS just needs to
|
||||
know how many bytes of the OOB it can use. However sometimes it is not
|
||||
practical.
|
||||
|
||||
Option 2 lets MTD/hardware take care of the ECC so the filesystem
|
||||
image just had to know which bytes to use for YAFFS Tags.
|
||||
|
||||
Option 3 is hardest as the image creator needs to know exactly what
|
||||
ECC bytes, endianness and algorithm to use as well as which bytes are
|
||||
available to YAFFS.
|
||||
|
||||
mkyaffs2image creates an image suitable for option 3 for the
|
||||
particular case of yaffs2 on 2K page NAND with default MTD layout.
|
||||
|
||||
mkyaffsimage creates an equivalent image for 512b page NAND (i.e.
|
||||
yaffs1 format).
|
||||
|
||||
Bootloaders
|
||||
-----------
|
||||
|
||||
A bootloader using YAFFS needs to know how MTD is laying out the OOB
|
||||
so that it can skip bad blocks.
|
||||
|
||||
YAFFS Tracing
|
||||
-------------
|
275
fs/yaffs2/devextras.h
Normal file
275
fs/yaffs2/devextras.h
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is just holds extra declarations used during development.
|
||||
* Most of these are from kernel includes placed here so we can use them in
|
||||
* applications.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __EXTRAS_H__
|
||||
#define __EXTRAS_H__
|
||||
|
||||
#if defined WIN32
|
||||
#define __inline__ __inline
|
||||
#define new newHack
|
||||
#endif
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 1 /* !(defined __KERNEL__) || (defined WIN32) */
|
||||
|
||||
/* User space defines */
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
typedef unsigned char __u8;
|
||||
typedef unsigned short __u16;
|
||||
typedef unsigned __u32;
|
||||
#endif
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
/*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
#define prefetch(x) 1
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static __inline__ void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static __inline__ void list_add_tail(struct list_head *new,
|
||||
struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_del(struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty on entry does not return true after this, the entry is
|
||||
* in an undefined state.
|
||||
*/
|
||||
static __inline__ void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static __inline__ void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static __inline__ int list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static __inline__ void list_splice(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
|
||||
if (first != list) {
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
|
||||
pos = pos->next, prefetch(pos->next))
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal
|
||||
* of list entry
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
/*
|
||||
* File types
|
||||
*/
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_FIFO 1
|
||||
#define DT_CHR 2
|
||||
#define DT_DIR 4
|
||||
#define DT_BLK 6
|
||||
#define DT_REG 8
|
||||
#define DT_LNK 10
|
||||
#define DT_SOCK 12
|
||||
#define DT_WHT 14
|
||||
|
||||
#ifndef WIN32
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
#include <sys/stat.h>
|
||||
#else
|
||||
#include "common.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Attribute flags. These should be or-ed together to figure out what
|
||||
* has been changed!
|
||||
*/
|
||||
#define ATTR_MODE 1
|
||||
#define ATTR_UID 2
|
||||
#define ATTR_GID 4
|
||||
#define ATTR_SIZE 8
|
||||
#define ATTR_ATIME 16
|
||||
#define ATTR_MTIME 32
|
||||
#define ATTR_CTIME 64
|
||||
#define ATTR_ATIME_SET 128
|
||||
#define ATTR_MTIME_SET 256
|
||||
#define ATTR_FORCE 512 /* Not a change, but a change it */
|
||||
#define ATTR_ATTR_FLAG 1024
|
||||
|
||||
struct iattr {
|
||||
unsigned int ia_valid;
|
||||
unsigned ia_mode;
|
||||
unsigned ia_uid;
|
||||
unsigned ia_gid;
|
||||
unsigned ia_size;
|
||||
unsigned ia_atime;
|
||||
unsigned ia_mtime;
|
||||
unsigned ia_ctime;
|
||||
unsigned int ia_attr_flags;
|
||||
};
|
||||
|
||||
#define KERN_DEBUG
|
||||
|
||||
#else
|
||||
|
||||
#ifndef WIN32
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/stat.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined WIN32
|
||||
#undef new
|
||||
#endif
|
||||
|
||||
#endif
|
405
fs/yaffs2/yaffs_checkptrw.c
Normal file
405
fs/yaffs2/yaffs_checkptrw.c
Normal file
@ -0,0 +1,405 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
|
||||
const char *yaffs_checkptrw_c_version =
|
||||
"$Id: yaffs_checkptrw.c,v 1.14 2007/05/15 20:07:40 charles Exp $";
|
||||
|
||||
|
||||
#include "yaffs_checkptrw.h"
|
||||
|
||||
|
||||
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
|
||||
{
|
||||
|
||||
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT,
|
||||
(TSTR("checkpt blocks available = %d" TENDSTR),
|
||||
blocksAvailable));
|
||||
|
||||
|
||||
return (blocksAvailable <= 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
static int yaffs_CheckpointErase(yaffs_Device *dev)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
|
||||
if(!dev->eraseBlockInNAND)
|
||||
return 0;
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
|
||||
dev->internalStartBlock,dev->internalEndBlock));
|
||||
|
||||
for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
|
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
|
||||
if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i));
|
||||
if(dev->eraseBlockInNAND(dev,i- dev->blockOffset /* realign */)){
|
||||
bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
|
||||
dev->nErasedBlocks++;
|
||||
dev->nFreeChunks += dev->nChunksPerBlock;
|
||||
}
|
||||
else {
|
||||
dev->markNANDBlockBad(dev,i);
|
||||
bi->blockState = YAFFS_BLOCK_STATE_DEAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dev->blocksInCheckpoint = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
|
||||
{
|
||||
int i;
|
||||
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
|
||||
T(YAFFS_TRACE_CHECKPOINT,
|
||||
(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
|
||||
dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock));
|
||||
|
||||
if(dev->checkpointNextBlock >= 0 &&
|
||||
dev->checkpointNextBlock <= dev->internalEndBlock &&
|
||||
blocksAvailable > 0){
|
||||
|
||||
for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
|
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
|
||||
if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){
|
||||
dev->checkpointNextBlock = i + 1;
|
||||
dev->checkpointCurrentBlock = i;
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
|
||||
|
||||
dev->checkpointNextBlock = -1;
|
||||
dev->checkpointCurrentBlock = -1;
|
||||
}
|
||||
|
||||
static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
|
||||
{
|
||||
int i;
|
||||
yaffs_ExtendedTags tags;
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
|
||||
dev->blocksInCheckpoint, dev->checkpointNextBlock));
|
||||
|
||||
if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
|
||||
for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
|
||||
int chunk = i * dev->nChunksPerBlock;
|
||||
int realignedChunk = chunk - dev->chunkOffset;
|
||||
|
||||
dev->readChunkWithTagsFromNAND(dev,realignedChunk,NULL,&tags);
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
|
||||
i, tags.objectId,tags.sequenceNumber,tags.eccResult));
|
||||
|
||||
if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
|
||||
/* Right kind of block */
|
||||
dev->checkpointNextBlock = tags.objectId;
|
||||
dev->checkpointCurrentBlock = i;
|
||||
dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
|
||||
dev->blocksInCheckpoint++;
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
|
||||
|
||||
dev->checkpointNextBlock = -1;
|
||||
dev->checkpointCurrentBlock = -1;
|
||||
}
|
||||
|
||||
|
||||
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
|
||||
{
|
||||
|
||||
/* Got the functions we need? */
|
||||
if (!dev->writeChunkWithTagsToNAND ||
|
||||
!dev->readChunkWithTagsFromNAND ||
|
||||
!dev->eraseBlockInNAND ||
|
||||
!dev->markNANDBlockBad)
|
||||
return 0;
|
||||
|
||||
if(forWriting && !yaffs_CheckpointSpaceOk(dev))
|
||||
return 0;
|
||||
|
||||
if(!dev->checkpointBuffer)
|
||||
dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
|
||||
if(!dev->checkpointBuffer)
|
||||
return 0;
|
||||
|
||||
|
||||
dev->checkpointPageSequence = 0;
|
||||
|
||||
dev->checkpointOpenForWrite = forWriting;
|
||||
|
||||
dev->checkpointByteCount = 0;
|
||||
dev->checkpointSum = 0;
|
||||
dev->checkpointXor = 0;
|
||||
dev->checkpointCurrentBlock = -1;
|
||||
dev->checkpointCurrentChunk = -1;
|
||||
dev->checkpointNextBlock = dev->internalStartBlock;
|
||||
|
||||
/* Erase all the blocks in the checkpoint area */
|
||||
if(forWriting){
|
||||
memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
|
||||
dev->checkpointByteOffset = 0;
|
||||
return yaffs_CheckpointErase(dev);
|
||||
|
||||
|
||||
} else {
|
||||
int i;
|
||||
/* Set to a value that will kick off a read */
|
||||
dev->checkpointByteOffset = dev->nDataBytesPerChunk;
|
||||
/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
|
||||
* going to be way more than we need */
|
||||
dev->blocksInCheckpoint = 0;
|
||||
dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
|
||||
dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
|
||||
for(i = 0; i < dev->checkpointMaxBlocks; i++)
|
||||
dev->checkpointBlockList[i] = -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
|
||||
{
|
||||
__u32 compositeSum;
|
||||
compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
|
||||
*sum = compositeSum;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
|
||||
{
|
||||
|
||||
int chunk;
|
||||
int realignedChunk;
|
||||
|
||||
yaffs_ExtendedTags tags;
|
||||
|
||||
if(dev->checkpointCurrentBlock < 0){
|
||||
yaffs_CheckpointFindNextErasedBlock(dev);
|
||||
dev->checkpointCurrentChunk = 0;
|
||||
}
|
||||
|
||||
if(dev->checkpointCurrentBlock < 0)
|
||||
return 0;
|
||||
|
||||
tags.chunkDeleted = 0;
|
||||
tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
|
||||
tags.chunkId = dev->checkpointPageSequence + 1;
|
||||
tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
|
||||
tags.byteCount = dev->nDataBytesPerChunk;
|
||||
if(dev->checkpointCurrentChunk == 0){
|
||||
/* First chunk we write for the block? Set block state to
|
||||
checkpoint */
|
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock);
|
||||
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
|
||||
dev->blocksInCheckpoint++;
|
||||
}
|
||||
|
||||
chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
|
||||
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
|
||||
chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId));
|
||||
|
||||
realignedChunk = chunk - dev->chunkOffset;
|
||||
|
||||
dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags);
|
||||
dev->checkpointByteOffset = 0;
|
||||
dev->checkpointPageSequence++;
|
||||
dev->checkpointCurrentChunk++;
|
||||
if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){
|
||||
dev->checkpointCurrentChunk = 0;
|
||||
dev->checkpointCurrentBlock = -1;
|
||||
}
|
||||
memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
|
||||
{
|
||||
int i=0;
|
||||
int ok = 1;
|
||||
|
||||
|
||||
__u8 * dataBytes = (__u8 *)data;
|
||||
|
||||
|
||||
|
||||
if(!dev->checkpointBuffer)
|
||||
return 0;
|
||||
|
||||
if(!dev->checkpointOpenForWrite)
|
||||
return -1;
|
||||
|
||||
while(i < nBytes && ok) {
|
||||
|
||||
|
||||
|
||||
dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
|
||||
dev->checkpointSum += *dataBytes;
|
||||
dev->checkpointXor ^= *dataBytes;
|
||||
|
||||
dev->checkpointByteOffset++;
|
||||
i++;
|
||||
dataBytes++;
|
||||
dev->checkpointByteCount++;
|
||||
|
||||
|
||||
if(dev->checkpointByteOffset < 0 ||
|
||||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
|
||||
ok = yaffs_CheckpointFlushBuffer(dev);
|
||||
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
|
||||
{
|
||||
int i=0;
|
||||
int ok = 1;
|
||||
yaffs_ExtendedTags tags;
|
||||
|
||||
|
||||
int chunk;
|
||||
int realignedChunk;
|
||||
|
||||
__u8 *dataBytes = (__u8 *)data;
|
||||
|
||||
if(!dev->checkpointBuffer)
|
||||
return 0;
|
||||
|
||||
if(dev->checkpointOpenForWrite)
|
||||
return -1;
|
||||
|
||||
while(i < nBytes && ok) {
|
||||
|
||||
|
||||
if(dev->checkpointByteOffset < 0 ||
|
||||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
|
||||
|
||||
if(dev->checkpointCurrentBlock < 0){
|
||||
yaffs_CheckpointFindNextCheckpointBlock(dev);
|
||||
dev->checkpointCurrentChunk = 0;
|
||||
}
|
||||
|
||||
if(dev->checkpointCurrentBlock < 0)
|
||||
ok = 0;
|
||||
else {
|
||||
|
||||
chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
|
||||
dev->checkpointCurrentChunk;
|
||||
|
||||
realignedChunk = chunk - dev->chunkOffset;
|
||||
|
||||
/* read in the next chunk */
|
||||
/* printf("read checkpoint page %d\n",dev->checkpointPage); */
|
||||
dev->readChunkWithTagsFromNAND(dev, realignedChunk,
|
||||
dev->checkpointBuffer,
|
||||
&tags);
|
||||
|
||||
if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
|
||||
tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
|
||||
ok = 0;
|
||||
|
||||
dev->checkpointByteOffset = 0;
|
||||
dev->checkpointPageSequence++;
|
||||
dev->checkpointCurrentChunk++;
|
||||
|
||||
if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
|
||||
dev->checkpointCurrentBlock = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(ok){
|
||||
*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
|
||||
dev->checkpointSum += *dataBytes;
|
||||
dev->checkpointXor ^= *dataBytes;
|
||||
dev->checkpointByteOffset++;
|
||||
i++;
|
||||
dataBytes++;
|
||||
dev->checkpointByteCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int yaffs_CheckpointClose(yaffs_Device *dev)
|
||||
{
|
||||
|
||||
if(dev->checkpointOpenForWrite){
|
||||
if(dev->checkpointByteOffset != 0)
|
||||
yaffs_CheckpointFlushBuffer(dev);
|
||||
} else {
|
||||
int i;
|
||||
for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){
|
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointBlockList[i]);
|
||||
if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
|
||||
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
|
||||
else {
|
||||
// Todo this looks odd...
|
||||
}
|
||||
}
|
||||
YFREE(dev->checkpointBlockList);
|
||||
dev->checkpointBlockList = NULL;
|
||||
}
|
||||
|
||||
dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
|
||||
dev->nErasedBlocks -= dev->blocksInCheckpoint;
|
||||
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
|
||||
dev->checkpointByteCount));
|
||||
|
||||
if(dev->checkpointBuffer){
|
||||
/* free the buffer */
|
||||
YFREE(dev->checkpointBuffer);
|
||||
dev->checkpointBuffer = NULL;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
|
||||
{
|
||||
/* Erase the first checksum block */
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
|
||||
|
||||
if(!yaffs_CheckpointSpaceOk(dev))
|
||||
return 0;
|
||||
|
||||
return yaffs_CheckpointErase(dev);
|
||||
}
|
35
fs/yaffs2/yaffs_checkptrw.h
Normal file
35
fs/yaffs2/yaffs_checkptrw.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_CHECKPTRW_H__
|
||||
#define __YAFFS_CHECKPTRW_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
|
||||
|
||||
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes);
|
||||
|
||||
int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes);
|
||||
|
||||
int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
|
||||
|
||||
int yaffs_CheckpointClose(yaffs_Device *dev);
|
||||
|
||||
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
|
||||
|
||||
|
||||
#endif
|
||||
|
333
fs/yaffs2/yaffs_ecc.c
Normal file
333
fs/yaffs2/yaffs_ecc.c
Normal file
@ -0,0 +1,333 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code implements the ECC algorithm used in SmartMedia.
|
||||
*
|
||||
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
|
||||
* The two unused bit are set to 1.
|
||||
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
|
||||
* blocks are used on a 512-byte NAND page.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Table generated by gen-ecc.c
|
||||
* Using a table means we do not have to calculate p1..p4 and p1'..p4'
|
||||
* for each byte of data. These are instead provided in a table in bits7..2.
|
||||
* Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
|
||||
* this bytes influence on the line parity.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
const char *yaffs_ecc_c_version =
|
||||
"$Id: yaffs_ecc.c,v 1.9 2007/02/14 01:09:06 wookey Exp $";
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
#include "yaffs_ecc.h"
|
||||
|
||||
static const unsigned char column_parity_table[] = {
|
||||
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
|
||||
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
|
||||
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
|
||||
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
|
||||
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
|
||||
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
|
||||
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
|
||||
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
|
||||
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
|
||||
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
|
||||
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
|
||||
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
|
||||
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
|
||||
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
|
||||
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
|
||||
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
|
||||
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
|
||||
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
|
||||
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
|
||||
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
|
||||
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
|
||||
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
|
||||
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
|
||||
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
|
||||
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
|
||||
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
|
||||
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
|
||||
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
|
||||
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
|
||||
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
|
||||
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
|
||||
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
|
||||
};
|
||||
|
||||
/* Count the bits in an unsigned char or a U32 */
|
||||
|
||||
static int yaffs_CountBits(unsigned char x)
|
||||
{
|
||||
int r = 0;
|
||||
while (x) {
|
||||
if (x & 1)
|
||||
r++;
|
||||
x >>= 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int yaffs_CountBits32(unsigned x)
|
||||
{
|
||||
int r = 0;
|
||||
while (x) {
|
||||
if (x & 1)
|
||||
r++;
|
||||
x >>= 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Calculate the ECC for a 256-byte block of data */
|
||||
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
unsigned char col_parity = 0;
|
||||
unsigned char line_parity = 0;
|
||||
unsigned char line_parity_prime = 0;
|
||||
unsigned char t;
|
||||
unsigned char b;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
b = column_parity_table[*data++];
|
||||
col_parity ^= b;
|
||||
|
||||
if (b & 0x01) // odd number of bits in the byte
|
||||
{
|
||||
line_parity ^= i;
|
||||
line_parity_prime ^= ~i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ecc[2] = (~col_parity) | 0x03;
|
||||
|
||||
t = 0;
|
||||
if (line_parity & 0x80)
|
||||
t |= 0x80;
|
||||
if (line_parity_prime & 0x80)
|
||||
t |= 0x40;
|
||||
if (line_parity & 0x40)
|
||||
t |= 0x20;
|
||||
if (line_parity_prime & 0x40)
|
||||
t |= 0x10;
|
||||
if (line_parity & 0x20)
|
||||
t |= 0x08;
|
||||
if (line_parity_prime & 0x20)
|
||||
t |= 0x04;
|
||||
if (line_parity & 0x10)
|
||||
t |= 0x02;
|
||||
if (line_parity_prime & 0x10)
|
||||
t |= 0x01;
|
||||
ecc[1] = ~t;
|
||||
|
||||
t = 0;
|
||||
if (line_parity & 0x08)
|
||||
t |= 0x80;
|
||||
if (line_parity_prime & 0x08)
|
||||
t |= 0x40;
|
||||
if (line_parity & 0x04)
|
||||
t |= 0x20;
|
||||
if (line_parity_prime & 0x04)
|
||||
t |= 0x10;
|
||||
if (line_parity & 0x02)
|
||||
t |= 0x08;
|
||||
if (line_parity_prime & 0x02)
|
||||
t |= 0x04;
|
||||
if (line_parity & 0x01)
|
||||
t |= 0x02;
|
||||
if (line_parity_prime & 0x01)
|
||||
t |= 0x01;
|
||||
ecc[0] = ~t;
|
||||
|
||||
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
|
||||
// Swap the bytes into the wrong order
|
||||
t = ecc[0];
|
||||
ecc[0] = ecc[1];
|
||||
ecc[1] = t;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Correct the ECC on a 256 byte block of data */
|
||||
|
||||
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
|
||||
const unsigned char *test_ecc)
|
||||
{
|
||||
unsigned char d0, d1, d2; /* deltas */
|
||||
|
||||
d0 = read_ecc[0] ^ test_ecc[0];
|
||||
d1 = read_ecc[1] ^ test_ecc[1];
|
||||
d2 = read_ecc[2] ^ test_ecc[2];
|
||||
|
||||
if ((d0 | d1 | d2) == 0)
|
||||
return 0; /* no error */
|
||||
|
||||
if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
|
||||
((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
|
||||
((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
|
||||
/* Single bit (recoverable) error in data */
|
||||
|
||||
unsigned byte;
|
||||
unsigned bit;
|
||||
|
||||
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
|
||||
// swap the bytes to correct for the wrong order
|
||||
unsigned char t;
|
||||
|
||||
t = d0;
|
||||
d0 = d1;
|
||||
d1 = t;
|
||||
#endif
|
||||
|
||||
bit = byte = 0;
|
||||
|
||||
if (d1 & 0x80)
|
||||
byte |= 0x80;
|
||||
if (d1 & 0x20)
|
||||
byte |= 0x40;
|
||||
if (d1 & 0x08)
|
||||
byte |= 0x20;
|
||||
if (d1 & 0x02)
|
||||
byte |= 0x10;
|
||||
if (d0 & 0x80)
|
||||
byte |= 0x08;
|
||||
if (d0 & 0x20)
|
||||
byte |= 0x04;
|
||||
if (d0 & 0x08)
|
||||
byte |= 0x02;
|
||||
if (d0 & 0x02)
|
||||
byte |= 0x01;
|
||||
|
||||
if (d2 & 0x80)
|
||||
bit |= 0x04;
|
||||
if (d2 & 0x20)
|
||||
bit |= 0x02;
|
||||
if (d2 & 0x08)
|
||||
bit |= 0x01;
|
||||
|
||||
data[byte] ^= (1 << bit);
|
||||
|
||||
return 1; /* Corrected the error */
|
||||
}
|
||||
|
||||
if ((yaffs_CountBits(d0) +
|
||||
yaffs_CountBits(d1) +
|
||||
yaffs_CountBits(d2)) == 1) {
|
||||
/* Reccoverable error in ecc */
|
||||
|
||||
read_ecc[0] = test_ecc[0];
|
||||
read_ecc[1] = test_ecc[1];
|
||||
read_ecc[2] = test_ecc[2];
|
||||
|
||||
return 1; /* Corrected the error */
|
||||
}
|
||||
|
||||
/* Unrecoverable error */
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ECCxxxOther does ECC calcs on arbitrary n bytes of data
|
||||
*/
|
||||
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
|
||||
yaffs_ECCOther * eccOther)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
unsigned char col_parity = 0;
|
||||
unsigned line_parity = 0;
|
||||
unsigned line_parity_prime = 0;
|
||||
unsigned char b;
|
||||
|
||||
for (i = 0; i < nBytes; i++) {
|
||||
b = column_parity_table[*data++];
|
||||
col_parity ^= b;
|
||||
|
||||
if (b & 0x01) {
|
||||
/* odd number of bits in the byte */
|
||||
line_parity ^= i;
|
||||
line_parity_prime ^= ~i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
eccOther->colParity = (col_parity >> 2) & 0x3f;
|
||||
eccOther->lineParity = line_parity;
|
||||
eccOther->lineParityPrime = line_parity_prime;
|
||||
}
|
||||
|
||||
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
|
||||
yaffs_ECCOther * read_ecc,
|
||||
const yaffs_ECCOther * test_ecc)
|
||||
{
|
||||
unsigned char cDelta; /* column parity delta */
|
||||
unsigned lDelta; /* line parity delta */
|
||||
unsigned lDeltaPrime; /* line parity delta */
|
||||
unsigned bit;
|
||||
|
||||
cDelta = read_ecc->colParity ^ test_ecc->colParity;
|
||||
lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
|
||||
lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
|
||||
|
||||
if ((cDelta | lDelta | lDeltaPrime) == 0)
|
||||
return 0; /* no error */
|
||||
|
||||
if (lDelta == ~lDeltaPrime &&
|
||||
(((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15))
|
||||
{
|
||||
/* Single bit (recoverable) error in data */
|
||||
|
||||
bit = 0;
|
||||
|
||||
if (cDelta & 0x20)
|
||||
bit |= 0x04;
|
||||
if (cDelta & 0x08)
|
||||
bit |= 0x02;
|
||||
if (cDelta & 0x02)
|
||||
bit |= 0x01;
|
||||
|
||||
if(lDelta >= nBytes)
|
||||
return -1;
|
||||
|
||||
data[lDelta] ^= (1 << bit);
|
||||
|
||||
return 1; /* corrected */
|
||||
}
|
||||
|
||||
if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
|
||||
yaffs_CountBits(cDelta)) == 1) {
|
||||
/* Reccoverable error in ecc */
|
||||
|
||||
*read_ecc = *test_ecc;
|
||||
return 1; /* corrected */
|
||||
}
|
||||
|
||||
/* Unrecoverable error */
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
44
fs/yaffs2/yaffs_ecc.h
Normal file
44
fs/yaffs2/yaffs_ecc.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code implements the ECC algorithm used in SmartMedia.
|
||||
*
|
||||
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
|
||||
* The two unused bit are set to 1.
|
||||
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
|
||||
* blocks are used on a 512-byte NAND page.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_ECC_H__
|
||||
#define __YAFFS_ECC_H__
|
||||
|
||||
typedef struct {
|
||||
unsigned char colParity;
|
||||
unsigned lineParity;
|
||||
unsigned lineParityPrime;
|
||||
} yaffs_ECCOther;
|
||||
|
||||
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
|
||||
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
|
||||
const unsigned char *test_ecc);
|
||||
|
||||
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
|
||||
yaffs_ECCOther * ecc);
|
||||
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
|
||||
yaffs_ECCOther * read_ecc,
|
||||
const yaffs_ECCOther * test_ecc);
|
||||
#endif
|
31
fs/yaffs2/yaffs_flashif.h
Normal file
31
fs/yaffs2/yaffs_flashif.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_FLASH_H__
|
||||
#define __YAFFS_FLASH_H__
|
||||
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
|
||||
int yflash_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare);
|
||||
int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags);
|
||||
int yflash_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);
|
||||
int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
|
||||
int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
|
||||
int yflash_InitialiseNAND(yaffs_Device *dev);
|
||||
int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
||||
int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
|
||||
|
||||
#endif
|
7491
fs/yaffs2/yaffs_guts.c
Normal file
7491
fs/yaffs2/yaffs_guts.c
Normal file
File diff suppressed because it is too large
Load Diff
908
fs/yaffs2/yaffs_guts.h
Normal file
908
fs/yaffs2/yaffs_guts.h
Normal file
@ -0,0 +1,908 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_GUTS_H__
|
||||
#define __YAFFS_GUTS_H__
|
||||
|
||||
#include "devextras.h"
|
||||
#include "yportenv.h"
|
||||
|
||||
#define YAFFS_OK 1
|
||||
#define YAFFS_FAIL 0
|
||||
|
||||
/* Give us a Y=0x59,
|
||||
* Give us an A=0x41,
|
||||
* Give us an FF=0xFF
|
||||
* Give us an S=0x53
|
||||
* And what have we got...
|
||||
*/
|
||||
#define YAFFS_MAGIC 0x5941FF53
|
||||
|
||||
#define YAFFS_NTNODES_LEVEL0 16
|
||||
#define YAFFS_TNODES_LEVEL0_BITS 4
|
||||
#define YAFFS_TNODES_LEVEL0_MASK 0xf
|
||||
|
||||
#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
|
||||
#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
|
||||
#define YAFFS_TNODES_INTERNAL_MASK 0x7
|
||||
#define YAFFS_TNODES_MAX_LEVEL 6
|
||||
|
||||
#ifndef CONFIG_YAFFS_NO_YAFFS1
|
||||
#define YAFFS_BYTES_PER_SPARE 16
|
||||
#define YAFFS_BYTES_PER_CHUNK 512
|
||||
#define YAFFS_CHUNK_SIZE_SHIFT 9
|
||||
#define YAFFS_CHUNKS_PER_BLOCK 32
|
||||
#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
|
||||
#endif
|
||||
|
||||
#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
|
||||
#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
|
||||
|
||||
#define YAFFS_MAX_CHUNK_ID 0x000FFFFF
|
||||
|
||||
#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
|
||||
|
||||
#define YAFFS_ALLOCATION_NOBJECTS 100
|
||||
#define YAFFS_ALLOCATION_NTNODES 100
|
||||
#define YAFFS_ALLOCATION_NLINKS 100
|
||||
|
||||
#define YAFFS_NOBJECT_BUCKETS 256
|
||||
|
||||
|
||||
#define YAFFS_OBJECT_SPACE 0x40000
|
||||
|
||||
#define YAFFS_CHECKPOINT_VERSION 3
|
||||
|
||||
#ifdef CONFIG_YAFFS_UNICODE
|
||||
#define YAFFS_MAX_NAME_LENGTH 127
|
||||
#define YAFFS_MAX_ALIAS_LENGTH 79
|
||||
#else
|
||||
#define YAFFS_MAX_NAME_LENGTH 255
|
||||
#define YAFFS_MAX_ALIAS_LENGTH 159
|
||||
#endif
|
||||
|
||||
#define YAFFS_SHORT_NAME_LENGTH 15
|
||||
|
||||
/* Some special object ids for pseudo objects */
|
||||
#define YAFFS_OBJECTID_ROOT 1
|
||||
#define YAFFS_OBJECTID_LOSTNFOUND 2
|
||||
#define YAFFS_OBJECTID_UNLINKED 3
|
||||
#define YAFFS_OBJECTID_DELETED 4
|
||||
|
||||
/* Sseudo object ids for checkpointing */
|
||||
#define YAFFS_OBJECTID_SB_HEADER 0x10
|
||||
#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
|
||||
#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
|
||||
|
||||
/* */
|
||||
|
||||
#define YAFFS_MAX_SHORT_OP_CACHES 20
|
||||
|
||||
#define YAFFS_N_TEMP_BUFFERS 4
|
||||
|
||||
/* We limit the number attempts at sucessfully saving a chunk of data.
|
||||
* Small-page devices have 32 pages per block; large-page devices have 64.
|
||||
* Default to something in the order of 5 to 10 blocks worth of chunks.
|
||||
*/
|
||||
#define YAFFS_WR_ATTEMPTS (5*64)
|
||||
|
||||
/* Sequence numbers are used in YAFFS2 to determine block allocation order.
|
||||
* The range is limited slightly to help distinguish bad numbers from good.
|
||||
* This also allows us to perhaps in the future use special numbers for
|
||||
* special purposes.
|
||||
* EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years,
|
||||
* and is a larger number than the lifetime of a 2GB device.
|
||||
*/
|
||||
#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
|
||||
#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00
|
||||
|
||||
/* ChunkCache is used for short read/write operations.*/
|
||||
typedef struct {
|
||||
struct yaffs_ObjectStruct *object;
|
||||
int chunkId;
|
||||
int lastUse;
|
||||
int dirty;
|
||||
int nBytes; /* Only valid if the cache is dirty */
|
||||
int locked; /* Can't push out or flush while locked. */
|
||||
#ifdef CONFIG_YAFFS_YAFFS2
|
||||
__u8 *data;
|
||||
#else
|
||||
__u8 data[YAFFS_BYTES_PER_CHUNK];
|
||||
#endif
|
||||
} yaffs_ChunkCache;
|
||||
|
||||
|
||||
|
||||
/* Tags structures in RAM
|
||||
* NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
|
||||
* the structure size will get blown out.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_YAFFS_NO_YAFFS1
|
||||
typedef struct {
|
||||
unsigned chunkId:20;
|
||||
unsigned serialNumber:2;
|
||||
unsigned byteCount:10;
|
||||
unsigned objectId:18;
|
||||
unsigned ecc:12;
|
||||
unsigned unusedStuff:2;
|
||||
|
||||
} yaffs_Tags;
|
||||
|
||||
typedef union {
|
||||
yaffs_Tags asTags;
|
||||
__u8 asBytes[8];
|
||||
} yaffs_TagsUnion;
|
||||
|
||||
#endif
|
||||
|
||||
/* Stuff used for extended tags in YAFFS2 */
|
||||
|
||||
typedef enum {
|
||||
YAFFS_ECC_RESULT_UNKNOWN,
|
||||
YAFFS_ECC_RESULT_NO_ERROR,
|
||||
YAFFS_ECC_RESULT_FIXED,
|
||||
YAFFS_ECC_RESULT_UNFIXED
|
||||
} yaffs_ECCResult;
|
||||
|
||||
typedef enum {
|
||||
YAFFS_OBJECT_TYPE_UNKNOWN,
|
||||
YAFFS_OBJECT_TYPE_FILE,
|
||||
YAFFS_OBJECT_TYPE_SYMLINK,
|
||||
YAFFS_OBJECT_TYPE_DIRECTORY,
|
||||
YAFFS_OBJECT_TYPE_HARDLINK,
|
||||
YAFFS_OBJECT_TYPE_SPECIAL
|
||||
} yaffs_ObjectType;
|
||||
|
||||
#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
|
||||
|
||||
typedef struct {
|
||||
|
||||
unsigned validMarker0;
|
||||
unsigned chunkUsed; /* Status of the chunk: used or unused */
|
||||
unsigned objectId; /* If 0 then this is not part of an object (unused) */
|
||||
unsigned chunkId; /* If 0 then this is a header, else a data chunk */
|
||||
unsigned byteCount; /* Only valid for data chunks */
|
||||
|
||||
/* The following stuff only has meaning when we read */
|
||||
yaffs_ECCResult eccResult;
|
||||
unsigned blockBad;
|
||||
|
||||
/* YAFFS 1 stuff */
|
||||
unsigned chunkDeleted; /* The chunk is marked deleted */
|
||||
unsigned serialNumber; /* Yaffs1 2-bit serial number */
|
||||
|
||||
/* YAFFS2 stuff */
|
||||
unsigned sequenceNumber; /* The sequence number of this block */
|
||||
|
||||
/* Extra info if this is an object header (YAFFS2 only) */
|
||||
|
||||
unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */
|
||||
unsigned extraParentObjectId; /* The parent object */
|
||||
unsigned extraIsShrinkHeader; /* Is it a shrink header? */
|
||||
unsigned extraShadows; /* Does this shadow another object? */
|
||||
|
||||
yaffs_ObjectType extraObjectType; /* What object type? */
|
||||
|
||||
unsigned extraFileLength; /* Length if it is a file */
|
||||
unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */
|
||||
|
||||
unsigned validMarker1;
|
||||
|
||||
} yaffs_ExtendedTags;
|
||||
|
||||
/* Spare structure for YAFFS1 */
|
||||
typedef struct {
|
||||
__u8 tagByte0;
|
||||
__u8 tagByte1;
|
||||
__u8 tagByte2;
|
||||
__u8 tagByte3;
|
||||
__u8 pageStatus; /* set to 0 to delete the chunk */
|
||||
__u8 blockStatus;
|
||||
__u8 tagByte4;
|
||||
__u8 tagByte5;
|
||||
__u8 ecc1[3];
|
||||
__u8 tagByte6;
|
||||
__u8 tagByte7;
|
||||
__u8 ecc2[3];
|
||||
} yaffs_Spare;
|
||||
|
||||
/*Special structure for passing through to mtd */
|
||||
struct yaffs_NANDSpare {
|
||||
yaffs_Spare spare;
|
||||
int eccres1;
|
||||
int eccres2;
|
||||
};
|
||||
|
||||
/* Block data in RAM */
|
||||
|
||||
typedef enum {
|
||||
YAFFS_BLOCK_STATE_UNKNOWN = 0,
|
||||
|
||||
YAFFS_BLOCK_STATE_SCANNING,
|
||||
YAFFS_BLOCK_STATE_NEEDS_SCANNING,
|
||||
/* The block might have something on it (ie it is allocating or full, perhaps empty)
|
||||
* but it needs to be scanned to determine its true state.
|
||||
* This state is only valid during yaffs_Scan.
|
||||
* NB We tolerate empty because the pre-scanner might be incapable of deciding
|
||||
* However, if this state is returned on a YAFFS2 device, then we expect a sequence number
|
||||
*/
|
||||
|
||||
YAFFS_BLOCK_STATE_EMPTY,
|
||||
/* This block is empty */
|
||||
|
||||
YAFFS_BLOCK_STATE_ALLOCATING,
|
||||
/* This block is partially allocated.
|
||||
* At least one page holds valid data.
|
||||
* This is the one currently being used for page
|
||||
* allocation. Should never be more than one of these
|
||||
*/
|
||||
|
||||
YAFFS_BLOCK_STATE_FULL,
|
||||
/* All the pages in this block have been allocated.
|
||||
*/
|
||||
|
||||
YAFFS_BLOCK_STATE_DIRTY,
|
||||
/* All pages have been allocated and deleted.
|
||||
* Erase me, reuse me.
|
||||
*/
|
||||
|
||||
YAFFS_BLOCK_STATE_CHECKPOINT,
|
||||
/* This block is assigned to holding checkpoint data.
|
||||
*/
|
||||
|
||||
YAFFS_BLOCK_STATE_COLLECTING,
|
||||
/* This block is being garbage collected */
|
||||
|
||||
YAFFS_BLOCK_STATE_DEAD
|
||||
/* This block has failed and is not in use */
|
||||
} yaffs_BlockState;
|
||||
|
||||
#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
int softDeletions:10; /* number of soft deleted pages */
|
||||
int pagesInUse:10; /* number of pages in use */
|
||||
unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
|
||||
__u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
|
||||
/* and retire the block. */
|
||||
__u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */
|
||||
__u32 gcPrioritise: 1; /* An ECC check or blank check has failed on this block.
|
||||
It should be prioritised for GC */
|
||||
__u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
|
||||
|
||||
#ifdef CONFIG_YAFFS_YAFFS2
|
||||
__u32 hasShrinkHeader:1; /* This block has at least one shrink object header */
|
||||
__u32 sequenceNumber; /* block sequence number for yaffs2 */
|
||||
#endif
|
||||
|
||||
} yaffs_BlockInfo;
|
||||
|
||||
/* -------------------------- Object structure -------------------------------*/
|
||||
/* This is the object structure as stored on NAND */
|
||||
|
||||
typedef struct {
|
||||
yaffs_ObjectType type;
|
||||
|
||||
/* Apply to everything */
|
||||
int parentObjectId;
|
||||
__u16 sum__NoLongerUsed; /* checksum of name. No longer used */
|
||||
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
|
||||
|
||||
/* Thes following apply to directories, files, symlinks - not hard links */
|
||||
__u32 yst_mode; /* protection */
|
||||
|
||||
#ifdef CONFIG_YAFFS_WINCE
|
||||
__u32 notForWinCE[5];
|
||||
#else
|
||||
__u32 yst_uid;
|
||||
__u32 yst_gid;
|
||||
__u32 yst_atime;
|
||||
__u32 yst_mtime;
|
||||
__u32 yst_ctime;
|
||||
#endif
|
||||
|
||||
/* File size applies to files only */
|
||||
int fileSize;
|
||||
|
||||
/* Equivalent object id applies to hard links only. */
|
||||
int equivalentObjectId;
|
||||
|
||||
/* Alias is for symlinks only. */
|
||||
YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
|
||||
|
||||
__u32 yst_rdev; /* device stuff for block and char devices (major/min) */
|
||||
|
||||
#ifdef CONFIG_YAFFS_WINCE
|
||||
__u32 win_ctime[2];
|
||||
__u32 win_atime[2];
|
||||
__u32 win_mtime[2];
|
||||
__u32 roomToGrow[4];
|
||||
#else
|
||||
__u32 roomToGrow[10];
|
||||
#endif
|
||||
|
||||
int shadowsObject; /* This object header shadows the specified object if > 0 */
|
||||
|
||||
/* isShrink applies to object headers written when we shrink the file (ie resize) */
|
||||
__u32 isShrink;
|
||||
|
||||
} yaffs_ObjectHeader;
|
||||
|
||||
/*--------------------------- Tnode -------------------------- */
|
||||
|
||||
union yaffs_Tnode_union {
|
||||
#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
|
||||
union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
|
||||
#else
|
||||
union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
|
||||
#endif
|
||||
/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
|
||||
|
||||
};
|
||||
|
||||
typedef union yaffs_Tnode_union yaffs_Tnode;
|
||||
|
||||
struct yaffs_TnodeList_struct {
|
||||
struct yaffs_TnodeList_struct *next;
|
||||
yaffs_Tnode *tnodes;
|
||||
};
|
||||
|
||||
typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
|
||||
|
||||
/*------------------------ Object -----------------------------*/
|
||||
/* An object can be one of:
|
||||
* - a directory (no data, has children links
|
||||
* - a regular file (data.... not prunes :->).
|
||||
* - a symlink [symbolic link] (the alias).
|
||||
* - a hard link
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
__u32 fileSize;
|
||||
__u32 scannedFileSize;
|
||||
__u32 shrinkSize;
|
||||
int topLevel;
|
||||
yaffs_Tnode *top;
|
||||
} yaffs_FileStructure;
|
||||
|
||||
typedef struct {
|
||||
struct list_head children; /* list of child links */
|
||||
} yaffs_DirectoryStructure;
|
||||
|
||||
typedef struct {
|
||||
YCHAR *alias;
|
||||
} yaffs_SymLinkStructure;
|
||||
|
||||
typedef struct {
|
||||
struct yaffs_ObjectStruct *equivalentObject;
|
||||
__u32 equivalentObjectId;
|
||||
} yaffs_HardLinkStructure;
|
||||
|
||||
typedef union {
|
||||
yaffs_FileStructure fileVariant;
|
||||
yaffs_DirectoryStructure directoryVariant;
|
||||
yaffs_SymLinkStructure symLinkVariant;
|
||||
yaffs_HardLinkStructure hardLinkVariant;
|
||||
} yaffs_ObjectVariant;
|
||||
|
||||
struct yaffs_ObjectStruct {
|
||||
__u8 deleted:1; /* This should only apply to unlinked files. */
|
||||
__u8 softDeleted:1; /* it has also been soft deleted */
|
||||
__u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/
|
||||
__u8 fake:1; /* A fake object has no presence on NAND. */
|
||||
__u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */
|
||||
__u8 unlinkAllowed:1;
|
||||
__u8 dirty:1; /* the object needs to be written to flash */
|
||||
__u8 valid:1; /* When the file system is being loaded up, this
|
||||
* object might be created before the data
|
||||
* is available (ie. file data records appear before the header).
|
||||
*/
|
||||
__u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */
|
||||
|
||||
__u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is
|
||||
* still in the inode cache. Free of object is defered.
|
||||
* until the inode is released.
|
||||
*/
|
||||
|
||||
__u8 serial; /* serial number of chunk in NAND. Cached here */
|
||||
__u16 sum; /* sum of the name to speed searching */
|
||||
|
||||
struct yaffs_DeviceStruct *myDev; /* The device I'm on */
|
||||
|
||||
struct list_head hashLink; /* list of objects in this hash bucket */
|
||||
|
||||
struct list_head hardLinks; /* all the equivalent hard linked objects */
|
||||
|
||||
/* directory structure stuff */
|
||||
/* also used for linking up the free list */
|
||||
struct yaffs_ObjectStruct *parent;
|
||||
struct list_head siblings;
|
||||
|
||||
/* Where's my object header in NAND? */
|
||||
int chunkId;
|
||||
|
||||
int nDataChunks; /* Number of data chunks attached to the file. */
|
||||
|
||||
__u32 objectId; /* the object id value */
|
||||
|
||||
__u32 yst_mode;
|
||||
|
||||
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
|
||||
YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
|
||||
#endif
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
/* #ifndef __KERNEL__ */
|
||||
__u32 inUse;
|
||||
/* #endif */
|
||||
|
||||
#ifdef CONFIG_YAFFS_WINCE
|
||||
__u32 win_ctime[2];
|
||||
__u32 win_mtime[2];
|
||||
__u32 win_atime[2];
|
||||
#else
|
||||
__u32 yst_uid;
|
||||
__u32 yst_gid;
|
||||
__u32 yst_atime;
|
||||
__u32 yst_mtime;
|
||||
__u32 yst_ctime;
|
||||
#endif
|
||||
|
||||
__u32 yst_rdev;
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
/* #ifndef __KERNEL__ */
|
||||
struct inode *myInode;
|
||||
/* #endif */
|
||||
|
||||
yaffs_ObjectType variantType;
|
||||
|
||||
yaffs_ObjectVariant variant;
|
||||
|
||||
};
|
||||
|
||||
typedef struct yaffs_ObjectStruct yaffs_Object;
|
||||
|
||||
struct yaffs_ObjectList_struct {
|
||||
yaffs_Object *objects;
|
||||
struct yaffs_ObjectList_struct *next;
|
||||
};
|
||||
|
||||
typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
|
||||
|
||||
typedef struct {
|
||||
struct list_head list;
|
||||
int count;
|
||||
} yaffs_ObjectBucket;
|
||||
|
||||
|
||||
/* yaffs_CheckpointObject holds the definition of an object as dumped
|
||||
* by checkpointing.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int structType;
|
||||
__u32 objectId;
|
||||
__u32 parentId;
|
||||
int chunkId;
|
||||
|
||||
yaffs_ObjectType variantType:3;
|
||||
__u8 deleted:1;
|
||||
__u8 softDeleted:1;
|
||||
__u8 unlinked:1;
|
||||
__u8 fake:1;
|
||||
__u8 renameAllowed:1;
|
||||
__u8 unlinkAllowed:1;
|
||||
__u8 serial;
|
||||
|
||||
int nDataChunks;
|
||||
__u32 fileSizeOrEquivalentObjectId;
|
||||
|
||||
}yaffs_CheckpointObject;
|
||||
|
||||
/*--------------------- Temporary buffers ----------------
|
||||
*
|
||||
* These are chunk-sized working buffers. Each device has a few
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
__u8 *buffer;
|
||||
int line; /* track from whence this buffer was allocated */
|
||||
int maxLine;
|
||||
} yaffs_TempBuffer;
|
||||
|
||||
/*----------------- Device ---------------------------------*/
|
||||
|
||||
struct yaffs_DeviceStruct {
|
||||
struct list_head devList;
|
||||
const char *name;
|
||||
|
||||
/* Entry parameters set up way early. Yaffs sets up the rest.*/
|
||||
int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
|
||||
int nChunksPerBlock; /* does not need to be a power of 2 */
|
||||
int nBytesPerSpare; /* spare area size */
|
||||
int startBlock; /* Start block we're allowed to use */
|
||||
int endBlock; /* End block we're allowed to use */
|
||||
int nReservedBlocks; /* We want this tuneable so that we can reduce */
|
||||
/* reserved blocks on NOR and RAM. */
|
||||
|
||||
|
||||
/* Stuff used by the shared space checkpointing mechanism */
|
||||
/* If this value is zero, then this mechanism is disabled */
|
||||
|
||||
int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */
|
||||
|
||||
|
||||
|
||||
|
||||
int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
|
||||
* the number of short op caches (don't use too many)
|
||||
*/
|
||||
|
||||
int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
|
||||
|
||||
int useNANDECC; /* Flag to decide whether or not to use NANDECC */
|
||||
|
||||
void *genericDevice; /* Pointer to device context
|
||||
* On an mtd this holds the mtd pointer.
|
||||
*/
|
||||
void *superBlock;
|
||||
|
||||
/* NAND access functions (Must be set before calling YAFFS)*/
|
||||
|
||||
int (*writeChunkToNAND) (struct yaffs_DeviceStruct * dev,
|
||||
int chunkInNAND, const __u8 * data,
|
||||
const yaffs_Spare * spare);
|
||||
int (*readChunkFromNAND) (struct yaffs_DeviceStruct * dev,
|
||||
int chunkInNAND, __u8 * data,
|
||||
yaffs_Spare * spare);
|
||||
int (*eraseBlockInNAND) (struct yaffs_DeviceStruct * dev,
|
||||
int blockInNAND);
|
||||
int (*initialiseNAND) (struct yaffs_DeviceStruct * dev);
|
||||
|
||||
#ifdef CONFIG_YAFFS_YAFFS2
|
||||
int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev,
|
||||
int chunkInNAND, const __u8 * data,
|
||||
const yaffs_ExtendedTags * tags);
|
||||
int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev,
|
||||
int chunkInNAND, __u8 * data,
|
||||
yaffs_ExtendedTags * tags);
|
||||
int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
|
||||
int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,
|
||||
yaffs_BlockState * state, int *sequenceNumber);
|
||||
#endif
|
||||
|
||||
int isYaffs2;
|
||||
|
||||
/* The removeObjectCallback function must be supplied by OS flavours that
|
||||
* need it. The Linux kernel does not use this, but yaffs direct does use
|
||||
* it to implement the faster readdir
|
||||
*/
|
||||
void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
|
||||
|
||||
/* Callback to mark the superblock dirsty */
|
||||
void (*markSuperBlockDirty)(void * superblock);
|
||||
|
||||
int wideTnodesDisabled; /* Set to disable wide tnodes */
|
||||
|
||||
|
||||
/* End of stuff that must be set before initialisation. */
|
||||
|
||||
/* Checkpoint control. Can be set before or after initialisation */
|
||||
__u8 skipCheckpointRead;
|
||||
__u8 skipCheckpointWrite;
|
||||
|
||||
/* Runtime parameters. Set up by YAFFS. */
|
||||
|
||||
__u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */
|
||||
__u16 chunkGroupSize; /* == 2^^chunkGroupBits */
|
||||
|
||||
/* Stuff to support wide tnodes */
|
||||
__u32 tnodeWidth;
|
||||
__u32 tnodeMask;
|
||||
|
||||
/* Stuff to support various file offses to chunk/offset translations */
|
||||
/* "Crumbs" for nDataBytesPerChunk not being a power of 2 */
|
||||
__u32 crumbMask;
|
||||
__u32 crumbShift;
|
||||
__u32 crumbsPerChunk;
|
||||
|
||||
/* Straight shifting for nDataBytesPerChunk being a power of 2 */
|
||||
__u32 chunkShift;
|
||||
__u32 chunkMask;
|
||||
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
#ifndef __KERNEL__
|
||||
|
||||
struct semaphore sem; /* Semaphore for waiting on erasure.*/
|
||||
struct semaphore grossLock; /* Gross locking semaphore */
|
||||
void (*putSuperFunc) (struct super_block * sb);
|
||||
#endif
|
||||
#endif
|
||||
__u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
|
||||
* at compile time so we have to allocate it.
|
||||
*/
|
||||
|
||||
int isMounted;
|
||||
|
||||
int isCheckpointed;
|
||||
|
||||
|
||||
/* Stuff to support block offsetting to support start block zero */
|
||||
int internalStartBlock;
|
||||
int internalEndBlock;
|
||||
int blockOffset;
|
||||
int chunkOffset;
|
||||
|
||||
|
||||
/* Runtime checkpointing stuff */
|
||||
int checkpointPageSequence; /* running sequence number of checkpoint pages */
|
||||
int checkpointByteCount;
|
||||
int checkpointByteOffset;
|
||||
__u8 *checkpointBuffer;
|
||||
int checkpointOpenForWrite;
|
||||
int blocksInCheckpoint;
|
||||
int checkpointCurrentChunk;
|
||||
int checkpointCurrentBlock;
|
||||
int checkpointNextBlock;
|
||||
int *checkpointBlockList;
|
||||
int checkpointMaxBlocks;
|
||||
__u32 checkpointSum;
|
||||
__u32 checkpointXor;
|
||||
|
||||
/* Block Info */
|
||||
yaffs_BlockInfo *blockInfo;
|
||||
__u8 *chunkBits; /* bitmap of chunks in use */
|
||||
unsigned blockInfoAlt:1; /* was allocated using alternative strategy */
|
||||
unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */
|
||||
int chunkBitmapStride; /* Number of bytes of chunkBits per block.
|
||||
* Must be consistent with nChunksPerBlock.
|
||||
*/
|
||||
|
||||
int nErasedBlocks;
|
||||
int allocationBlock; /* Current block being allocated off */
|
||||
__u32 allocationPage;
|
||||
int allocationBlockFinder; /* Used to search for next allocation block */
|
||||
|
||||
/* Runtime state */
|
||||
int nTnodesCreated;
|
||||
yaffs_Tnode *freeTnodes;
|
||||
int nFreeTnodes;
|
||||
yaffs_TnodeList *allocatedTnodeList;
|
||||
|
||||
int isDoingGC;
|
||||
|
||||
int nObjectsCreated;
|
||||
yaffs_Object *freeObjects;
|
||||
int nFreeObjects;
|
||||
|
||||
yaffs_ObjectList *allocatedObjectList;
|
||||
|
||||
yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
|
||||
|
||||
int nFreeChunks;
|
||||
|
||||
int currentDirtyChecker; /* Used to find current dirtiest block */
|
||||
|
||||
__u32 *gcCleanupList; /* objects to delete at the end of a GC. */
|
||||
int nonAggressiveSkip; /* GC state/mode */
|
||||
|
||||
/* Statistcs */
|
||||
int nPageWrites;
|
||||
int nPageReads;
|
||||
int nBlockErasures;
|
||||
int nErasureFailures;
|
||||
int nGCCopies;
|
||||
int garbageCollections;
|
||||
int passiveGarbageCollections;
|
||||
int nRetriedWrites;
|
||||
int nRetiredBlocks;
|
||||
int eccFixed;
|
||||
int eccUnfixed;
|
||||
int tagsEccFixed;
|
||||
int tagsEccUnfixed;
|
||||
int nDeletions;
|
||||
int nUnmarkedDeletions;
|
||||
|
||||
int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
|
||||
|
||||
/* Special directories */
|
||||
yaffs_Object *rootDir;
|
||||
yaffs_Object *lostNFoundDir;
|
||||
|
||||
/* Buffer areas for storing data to recover from write failures TODO
|
||||
* __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
|
||||
* yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];
|
||||
*/
|
||||
|
||||
int bufferedBlock; /* Which block is buffered here? */
|
||||
int doingBufferedBlockRewrite;
|
||||
|
||||
yaffs_ChunkCache *srCache;
|
||||
int srLastUse;
|
||||
|
||||
int cacheHits;
|
||||
|
||||
/* Stuff for background deletion and unlinked files.*/
|
||||
yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
|
||||
yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
|
||||
yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/
|
||||
int nDeletedFiles; /* Count of files awaiting deletion;*/
|
||||
int nUnlinkedFiles; /* Count of unlinked files. */
|
||||
int nBackgroundDeletions; /* Count of background deletions. */
|
||||
|
||||
|
||||
yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
|
||||
int maxTemp;
|
||||
int unmanagedTempAllocations;
|
||||
int unmanagedTempDeallocations;
|
||||
|
||||
/* yaffs2 runtime stuff */
|
||||
unsigned sequenceNumber; /* Sequence number of currently allocating block */
|
||||
unsigned oldestDirtySequence;
|
||||
|
||||
};
|
||||
|
||||
typedef struct yaffs_DeviceStruct yaffs_Device;
|
||||
|
||||
/* The static layout of bllock usage etc is stored in the super block header */
|
||||
typedef struct {
|
||||
int StructType;
|
||||
int version;
|
||||
int checkpointStartBlock;
|
||||
int checkpointEndBlock;
|
||||
int startBlock;
|
||||
int endBlock;
|
||||
int rfu[100];
|
||||
} yaffs_SuperBlockHeader;
|
||||
|
||||
/* The CheckpointDevice structure holds the device information that changes at runtime and
|
||||
* must be preserved over unmount/mount cycles.
|
||||
*/
|
||||
typedef struct {
|
||||
int structType;
|
||||
int nErasedBlocks;
|
||||
int allocationBlock; /* Current block being allocated off */
|
||||
__u32 allocationPage;
|
||||
int nFreeChunks;
|
||||
|
||||
int nDeletedFiles; /* Count of files awaiting deletion;*/
|
||||
int nUnlinkedFiles; /* Count of unlinked files. */
|
||||
int nBackgroundDeletions; /* Count of background deletions. */
|
||||
|
||||
/* yaffs2 runtime stuff */
|
||||
unsigned sequenceNumber; /* Sequence number of currently allocating block */
|
||||
unsigned oldestDirtySequence;
|
||||
|
||||
} yaffs_CheckpointDevice;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int structType;
|
||||
__u32 magic;
|
||||
__u32 version;
|
||||
__u32 head;
|
||||
} yaffs_CheckpointValidity;
|
||||
|
||||
/* Function to manipulate block info */
|
||||
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
|
||||
{
|
||||
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
|
||||
blk));
|
||||
YBUG();
|
||||
}
|
||||
return &dev->blockInfo[blk - dev->internalStartBlock];
|
||||
}
|
||||
|
||||
/*----------------------- YAFFS Functions -----------------------*/
|
||||
|
||||
int yaffs_GutsInitialise(yaffs_Device * dev);
|
||||
void yaffs_Deinitialise(yaffs_Device * dev);
|
||||
|
||||
int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev);
|
||||
|
||||
int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName,
|
||||
yaffs_Object * newDir, const YCHAR * newName);
|
||||
|
||||
int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name);
|
||||
int yaffs_DeleteFile(yaffs_Object * obj);
|
||||
|
||||
int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize);
|
||||
int yaffs_GetObjectFileLength(yaffs_Object * obj);
|
||||
int yaffs_GetObjectInode(yaffs_Object * obj);
|
||||
unsigned yaffs_GetObjectType(yaffs_Object * obj);
|
||||
int yaffs_GetObjectLinkCount(yaffs_Object * obj);
|
||||
|
||||
int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr);
|
||||
int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr);
|
||||
|
||||
/* File operations */
|
||||
int yaffs_ReadDataFromFile(yaffs_Object * obj, __u8 * buffer, loff_t offset,
|
||||
int nBytes);
|
||||
int yaffs_WriteDataToFile(yaffs_Object * obj, const __u8 * buffer, loff_t offset,
|
||||
int nBytes, int writeThrough);
|
||||
int yaffs_ResizeFile(yaffs_Object * obj, loff_t newSize);
|
||||
|
||||
yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name,
|
||||
__u32 mode, __u32 uid, __u32 gid);
|
||||
int yaffs_FlushFile(yaffs_Object * obj, int updateTime);
|
||||
|
||||
/* Flushing and checkpointing */
|
||||
void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
|
||||
|
||||
int yaffs_CheckpointSave(yaffs_Device *dev);
|
||||
int yaffs_CheckpointRestore(yaffs_Device *dev);
|
||||
|
||||
/* Directory operations */
|
||||
yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name,
|
||||
__u32 mode, __u32 uid, __u32 gid);
|
||||
yaffs_Object *yaffs_FindObjectByName(yaffs_Object * theDir, const YCHAR * name);
|
||||
int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir,
|
||||
int (*fn) (yaffs_Object *));
|
||||
|
||||
yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number);
|
||||
|
||||
/* Link operations */
|
||||
yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name,
|
||||
yaffs_Object * equivalentObject);
|
||||
|
||||
yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj);
|
||||
|
||||
/* Symlink operations */
|
||||
yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name,
|
||||
__u32 mode, __u32 uid, __u32 gid,
|
||||
const YCHAR * alias);
|
||||
YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj);
|
||||
|
||||
/* Special inodes (fifos, sockets and devices) */
|
||||
yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name,
|
||||
__u32 mode, __u32 uid, __u32 gid, __u32 rdev);
|
||||
|
||||
/* Special directories */
|
||||
yaffs_Object *yaffs_Root(yaffs_Device * dev);
|
||||
yaffs_Object *yaffs_LostNFound(yaffs_Device * dev);
|
||||
|
||||
#ifdef CONFIG_YAFFS_WINCE
|
||||
/* CONFIG_YAFFS_WINCE special stuff */
|
||||
void yfsd_WinFileTimeNow(__u32 target[2]);
|
||||
#endif
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
#ifndef __KERNEL__
|
||||
void yaffs_HandleDeferedFree(yaffs_Object * obj);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Debug dump */
|
||||
int yaffs_DumpObject(yaffs_Object * obj);
|
||||
|
||||
void yaffs_GutsTest(yaffs_Device * dev);
|
||||
|
||||
/* A few useful functions */
|
||||
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
|
||||
void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn);
|
||||
int yaffs_CheckFF(__u8 * buffer, int nBytes);
|
||||
void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
|
||||
|
||||
#endif
|
26
fs/yaffs2/yaffs_malloc.h
Normal file
26
fs/yaffs2/yaffs_malloc.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef __YAFFS_MALLOC_H__
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
void *yaffs_malloc(size_t size);
|
||||
void yaffs_free(void *ptr);
|
||||
|
||||
#endif
|
||||
|
246
fs/yaffs2/yaffs_mtdif.c
Normal file
246
fs/yaffs2/yaffs_mtdif.c
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
const char *yaffs_mtdif_c_version =
|
||||
"$Id: yaffs_mtdif.c,v 1.19 2007/02/14 01:09:06 wookey Exp $";
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
|
||||
#include "yaffs_mtdif.h"
|
||||
|
||||
#include "linux/mtd/mtd.h"
|
||||
#include "linux/types.h"
|
||||
#include "linux/time.h"
|
||||
#include "linux/mtd/nand.h"
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
|
||||
static struct nand_oobinfo yaffs_oobinfo = {
|
||||
.useecc = 1,
|
||||
.eccbytes = 6,
|
||||
.eccpos = {8, 9, 10, 13, 14, 15}
|
||||
};
|
||||
|
||||
static struct nand_oobinfo yaffs_noeccinfo = {
|
||||
.useecc = 0,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
|
||||
{
|
||||
oob[0] = spare->tagByte0;
|
||||
oob[1] = spare->tagByte1;
|
||||
oob[2] = spare->tagByte2;
|
||||
oob[3] = spare->tagByte3;
|
||||
oob[4] = spare->tagByte4;
|
||||
oob[5] = spare->tagByte5 & 0x3f;
|
||||
oob[5] |= spare->blockStatus == 'Y' ? 0: 0x80;
|
||||
oob[5] |= spare->pageStatus == 0 ? 0: 0x40;
|
||||
oob[6] = spare->tagByte6;
|
||||
oob[7] = spare->tagByte7;
|
||||
}
|
||||
|
||||
static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
|
||||
{
|
||||
struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
|
||||
spare->tagByte0 = oob[0];
|
||||
spare->tagByte1 = oob[1];
|
||||
spare->tagByte2 = oob[2];
|
||||
spare->tagByte3 = oob[3];
|
||||
spare->tagByte4 = oob[4];
|
||||
spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
|
||||
spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
|
||||
spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
|
||||
spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
|
||||
spare->tagByte6 = oob[6];
|
||||
spare->tagByte7 = oob[7];
|
||||
spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
|
||||
|
||||
nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
|
||||
}
|
||||
#endif
|
||||
|
||||
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data, const yaffs_Spare * spare)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
struct mtd_oob_ops ops;
|
||||
#endif
|
||||
size_t dummy;
|
||||
int retval = 0;
|
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
__u8 spareAsBytes[8]; /* OOB */
|
||||
|
||||
if (data && !spare)
|
||||
retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data);
|
||||
else if (spare) {
|
||||
if (dev->useNANDECC) {
|
||||
translate_spare2oob(spare, spareAsBytes);
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.ooblen = 8; /* temp hack */
|
||||
} else {
|
||||
ops.mode = MTD_OOB_RAW;
|
||||
ops.ooblen = YAFFS_BYTES_PER_SPARE;
|
||||
}
|
||||
ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
|
||||
ops.datbuf = (u8 *)data;
|
||||
ops.ooboffs = 0;
|
||||
ops.oobbuf = spareAsBytes;
|
||||
retval = mtd->write_oob(mtd, addr, &ops);
|
||||
}
|
||||
#else
|
||||
__u8 *spareAsBytes = (__u8 *) spare;
|
||||
|
||||
if (data && spare) {
|
||||
if (dev->useNANDECC)
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, spareAsBytes,
|
||||
&yaffs_oobinfo);
|
||||
else
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, spareAsBytes,
|
||||
&yaffs_noeccinfo);
|
||||
} else {
|
||||
if (data)
|
||||
retval =
|
||||
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||
data);
|
||||
if (spare)
|
||||
retval =
|
||||
mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
|
||||
&dummy, spareAsBytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
|
||||
yaffs_Spare * spare)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
struct mtd_oob_ops ops;
|
||||
#endif
|
||||
size_t dummy;
|
||||
int retval = 0;
|
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
__u8 spareAsBytes[8]; /* OOB */
|
||||
|
||||
if (data && !spare)
|
||||
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data);
|
||||
else if (spare) {
|
||||
if (dev->useNANDECC) {
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.ooblen = 8; /* temp hack */
|
||||
} else {
|
||||
ops.mode = MTD_OOB_RAW;
|
||||
ops.ooblen = YAFFS_BYTES_PER_SPARE;
|
||||
}
|
||||
ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
|
||||
ops.datbuf = data;
|
||||
ops.ooboffs = 0;
|
||||
ops.oobbuf = spareAsBytes;
|
||||
retval = mtd->read_oob(mtd, addr, &ops);
|
||||
if (dev->useNANDECC)
|
||||
translate_oob2spare(spare, spareAsBytes);
|
||||
}
|
||||
#else
|
||||
__u8 *spareAsBytes = (__u8 *) spare;
|
||||
|
||||
if (data && spare) {
|
||||
if (dev->useNANDECC) {
|
||||
/* Careful, this call adds 2 ints */
|
||||
/* to the end of the spare data. Calling function */
|
||||
/* should allocate enough memory for spare, */
|
||||
/* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
|
||||
retval =
|
||||
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, spareAsBytes,
|
||||
&yaffs_oobinfo);
|
||||
} else {
|
||||
retval =
|
||||
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, spareAsBytes,
|
||||
&yaffs_noeccinfo);
|
||||
}
|
||||
} else {
|
||||
if (data)
|
||||
retval =
|
||||
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||
data);
|
||||
if (spare)
|
||||
retval =
|
||||
mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
|
||||
&dummy, spareAsBytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
__u32 addr =
|
||||
((loff_t) blockNumber) * dev->nDataBytesPerChunk
|
||||
* dev->nChunksPerBlock;
|
||||
struct erase_info ei;
|
||||
int retval = 0;
|
||||
|
||||
ei.mtd = mtd;
|
||||
ei.addr = addr;
|
||||
ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
|
||||
ei.time = 1000;
|
||||
ei.retries = 2;
|
||||
ei.callback = NULL;
|
||||
ei.priv = (u_long) dev;
|
||||
|
||||
/* Todo finish off the ei if required */
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
sema_init(&dev->sem, 0);
|
||||
#endif
|
||||
|
||||
retval = mtd->erase(mtd, &ei);
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
int nandmtd_InitialiseNAND(yaffs_Device * dev)
|
||||
{
|
||||
return YAFFS_OK;
|
||||
}
|
27
fs/yaffs2/yaffs_mtdif.h
Normal file
27
fs/yaffs2/yaffs_mtdif.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_MTDIF_H__
|
||||
#define __YAFFS_MTDIF_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data, const yaffs_Spare * spare);
|
||||
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
|
||||
yaffs_Spare * spare);
|
||||
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber);
|
||||
int nandmtd_InitialiseNAND(yaffs_Device * dev);
|
||||
#endif
|
235
fs/yaffs2/yaffs_mtdif2.c
Normal file
235
fs/yaffs2/yaffs_mtdif2.c
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* mtd interface for YAFFS2 */
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
#include "asm/errno.h"
|
||||
|
||||
const char *yaffs_mtdif2_c_version =
|
||||
"$Id: yaffs_mtdif2.c,v 1.17 2007/02/14 01:09:06 wookey Exp $";
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
|
||||
#include "yaffs_mtdif2.h"
|
||||
|
||||
#include "linux/mtd/mtd.h"
|
||||
#include "linux/types.h"
|
||||
#include "linux/time.h"
|
||||
|
||||
#include "yaffs_packedtags2.h"
|
||||
|
||||
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data,
|
||||
const yaffs_ExtendedTags * tags)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
struct mtd_oob_ops ops;
|
||||
#else
|
||||
size_t dummy;
|
||||
#endif
|
||||
int retval = 0;
|
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||
|
||||
yaffs_PackedTags2 pt;
|
||||
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR
|
||||
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
|
||||
TENDSTR), chunkInNAND, data, tags));
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
if (tags)
|
||||
yaffs_PackTags2(&pt, tags);
|
||||
else
|
||||
BUG(); /* both tags and data should always be present */
|
||||
|
||||
if (data) {
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.ooblen = sizeof(pt);
|
||||
ops.len = dev->nDataBytesPerChunk;
|
||||
ops.ooboffs = 0;
|
||||
ops.datbuf = (__u8 *)data;
|
||||
ops.oobbuf = (void *)&pt;
|
||||
retval = mtd->write_oob(mtd, addr, &ops);
|
||||
} else
|
||||
BUG(); /* both tags and data should always be present */
|
||||
#else
|
||||
if (tags) {
|
||||
yaffs_PackTags2(&pt, tags);
|
||||
}
|
||||
|
||||
if (data && tags) {
|
||||
if (dev->useNANDECC)
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, (__u8 *) & pt, NULL);
|
||||
else
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, (__u8 *) & pt, NULL);
|
||||
} else {
|
||||
if (data)
|
||||
retval =
|
||||
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||
data);
|
||||
if (tags)
|
||||
retval =
|
||||
mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
|
||||
(__u8 *) & pt);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
__u8 * data, yaffs_ExtendedTags * tags)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
struct mtd_oob_ops ops;
|
||||
#endif
|
||||
size_t dummy;
|
||||
int retval = 0;
|
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||
|
||||
yaffs_PackedTags2 pt;
|
||||
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR
|
||||
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
|
||||
TENDSTR), chunkInNAND, data, tags));
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
if (data && !tags)
|
||||
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data);
|
||||
else if (tags) {
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.ooblen = sizeof(pt);
|
||||
ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
|
||||
ops.ooboffs = 0;
|
||||
ops.datbuf = data;
|
||||
ops.oobbuf = dev->spareBuffer;
|
||||
retval = mtd->read_oob(mtd, addr, &ops);
|
||||
}
|
||||
#else
|
||||
if (data && tags) {
|
||||
if (dev->useNANDECC) {
|
||||
retval =
|
||||
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, dev->spareBuffer,
|
||||
NULL);
|
||||
} else {
|
||||
retval =
|
||||
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, dev->spareBuffer,
|
||||
NULL);
|
||||
}
|
||||
} else {
|
||||
if (data)
|
||||
retval =
|
||||
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||
data);
|
||||
if (tags)
|
||||
retval =
|
||||
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
|
||||
dev->spareBuffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy(&pt, dev->spareBuffer, sizeof(pt));
|
||||
|
||||
if (tags)
|
||||
yaffs_UnpackTags2(tags, &pt);
|
||||
|
||||
if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
|
||||
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
int retval;
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
|
||||
|
||||
retval =
|
||||
mtd->block_markbad(mtd,
|
||||
blockNo * dev->nChunksPerBlock *
|
||||
dev->nDataBytesPerChunk);
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
return YAFFS_FAIL;
|
||||
|
||||
}
|
||||
|
||||
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState * state, int *sequenceNumber)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
int retval;
|
||||
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
|
||||
retval =
|
||||
mtd->block_isbad(mtd,
|
||||
blockNo * dev->nChunksPerBlock *
|
||||
dev->nDataBytesPerChunk);
|
||||
|
||||
if (retval) {
|
||||
T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
|
||||
|
||||
*state = YAFFS_BLOCK_STATE_DEAD;
|
||||
*sequenceNumber = 0;
|
||||
} else {
|
||||
yaffs_ExtendedTags t;
|
||||
nandmtd2_ReadChunkWithTagsFromNAND(dev,
|
||||
blockNo *
|
||||
dev->nChunksPerBlock, NULL,
|
||||
&t);
|
||||
|
||||
if (t.chunkUsed) {
|
||||
*sequenceNumber = t.sequenceNumber;
|
||||
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
} else {
|
||||
*sequenceNumber = 0;
|
||||
*state = YAFFS_BLOCK_STATE_EMPTY;
|
||||
}
|
||||
}
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
|
||||
*state));
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
return YAFFS_FAIL;
|
||||
}
|
29
fs/yaffs2/yaffs_mtdif2.h
Normal file
29
fs/yaffs2/yaffs_mtdif2.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_MTDIF2_H__
|
||||
#define __YAFFS_MTDIF2_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data,
|
||||
const yaffs_ExtendedTags * tags);
|
||||
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
__u8 * data, yaffs_ExtendedTags * tags);
|
||||
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
||||
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState * state, int *sequenceNumber);
|
||||
|
||||
#endif
|
134
fs/yaffs2/yaffs_nand.c
Normal file
134
fs/yaffs2/yaffs_nand.c
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
const char *yaffs_nand_c_version =
|
||||
"$Id: yaffs_nand.c,v 1.7 2007/02/14 01:09:06 wookey Exp $";
|
||||
|
||||
#include "yaffs_nand.h"
|
||||
#include "yaffs_tagscompat.h"
|
||||
#include "yaffs_tagsvalidity.h"
|
||||
|
||||
|
||||
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
__u8 * buffer,
|
||||
yaffs_ExtendedTags * tags)
|
||||
{
|
||||
int result;
|
||||
yaffs_ExtendedTags localTags;
|
||||
|
||||
int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
|
||||
|
||||
/* If there are no tags provided, use local tags to get prioritised gc working */
|
||||
if(!tags)
|
||||
tags = &localTags;
|
||||
|
||||
if (dev->readChunkWithTagsFromNAND)
|
||||
result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
|
||||
tags);
|
||||
else
|
||||
result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
|
||||
realignedChunkInNAND,
|
||||
buffer,
|
||||
tags);
|
||||
if(tags &&
|
||||
tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){
|
||||
|
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
|
||||
yaffs_HandleChunkError(dev,bi);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
|
||||
int chunkInNAND,
|
||||
const __u8 * buffer,
|
||||
yaffs_ExtendedTags * tags)
|
||||
{
|
||||
chunkInNAND -= dev->chunkOffset;
|
||||
|
||||
|
||||
if (tags) {
|
||||
tags->sequenceNumber = dev->sequenceNumber;
|
||||
tags->chunkUsed = 1;
|
||||
if (!yaffs_ValidateTags(tags)) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR("Writing uninitialised tags" TENDSTR)));
|
||||
YBUG();
|
||||
}
|
||||
T(YAFFS_TRACE_WRITE,
|
||||
(TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
|
||||
tags->objectId, tags->chunkId));
|
||||
} else {
|
||||
T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
|
||||
YBUG();
|
||||
}
|
||||
|
||||
if (dev->writeChunkWithTagsToNAND)
|
||||
return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
|
||||
tags);
|
||||
else
|
||||
return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
|
||||
chunkInNAND,
|
||||
buffer,
|
||||
tags);
|
||||
}
|
||||
|
||||
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
|
||||
{
|
||||
blockNo -= dev->blockOffset;
|
||||
|
||||
;
|
||||
if (dev->markNANDBlockBad)
|
||||
return dev->markNANDBlockBad(dev, blockNo);
|
||||
else
|
||||
return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
|
||||
}
|
||||
|
||||
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
|
||||
int blockNo,
|
||||
yaffs_BlockState * state,
|
||||
unsigned *sequenceNumber)
|
||||
{
|
||||
blockNo -= dev->blockOffset;
|
||||
|
||||
if (dev->queryNANDBlock)
|
||||
return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
|
||||
else
|
||||
return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
|
||||
state,
|
||||
sequenceNumber);
|
||||
}
|
||||
|
||||
|
||||
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
||||
int blockInNAND)
|
||||
{
|
||||
int result;
|
||||
|
||||
blockInNAND -= dev->blockOffset;
|
||||
|
||||
|
||||
dev->nBlockErasures++;
|
||||
result = dev->eraseBlockInNAND(dev, blockInNAND);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
|
||||
{
|
||||
return dev->initialiseNAND(dev);
|
||||
}
|
44
fs/yaffs2/yaffs_nand.h
Normal file
44
fs/yaffs2/yaffs_nand.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_NAND_H__
|
||||
#define __YAFFS_NAND_H__
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
|
||||
|
||||
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
__u8 * buffer,
|
||||
yaffs_ExtendedTags * tags);
|
||||
|
||||
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
|
||||
int chunkInNAND,
|
||||
const __u8 * buffer,
|
||||
yaffs_ExtendedTags * tags);
|
||||
|
||||
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo);
|
||||
|
||||
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
|
||||
int blockNo,
|
||||
yaffs_BlockState * state,
|
||||
unsigned *sequenceNumber);
|
||||
|
||||
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
||||
int blockInNAND);
|
||||
|
||||
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
|
||||
|
||||
#endif
|
||||
|
39
fs/yaffs2/yaffs_nandemul2k.h
Normal file
39
fs/yaffs2/yaffs_nandemul2k.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/* Interface to emulated NAND functions (2k page size) */
|
||||
|
||||
#ifndef __YAFFS_NANDEMUL2K_H__
|
||||
#define __YAFFS_NANDEMUL2K_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND, const __u8 * data,
|
||||
yaffs_ExtendedTags * tags);
|
||||
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND, __u8 * data,
|
||||
yaffs_ExtendedTags * tags);
|
||||
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
||||
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState * state, int *sequenceNumber);
|
||||
int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
||||
int blockInNAND);
|
||||
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
|
||||
int nandemul2k_GetBytesPerChunk(void);
|
||||
int nandemul2k_GetChunksPerBlock(void);
|
||||
int nandemul2k_GetNumberOfBlocks(void);
|
||||
|
||||
#endif
|
55
fs/yaffs2/yaffs_packedtags1.c
Normal file
55
fs/yaffs2/yaffs_packedtags1.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
#include "yaffs_packedtags1.h"
|
||||
#include "yportenv.h"
|
||||
|
||||
void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t)
|
||||
{
|
||||
pt->chunkId = t->chunkId;
|
||||
pt->serialNumber = t->serialNumber;
|
||||
pt->byteCount = t->byteCount;
|
||||
pt->objectId = t->objectId;
|
||||
pt->ecc = 0;
|
||||
pt->deleted = (t->chunkDeleted) ? 0 : 1;
|
||||
pt->unusedStuff = 0;
|
||||
pt->shouldBeFF = 0xFFFFFFFF;
|
||||
|
||||
}
|
||||
|
||||
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt)
|
||||
{
|
||||
static const __u8 allFF[] =
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff };
|
||||
|
||||
if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
|
||||
t->blockBad = 0;
|
||||
if (pt->shouldBeFF != 0xFFFFFFFF) {
|
||||
t->blockBad = 1;
|
||||
}
|
||||
t->chunkUsed = 1;
|
||||
t->objectId = pt->objectId;
|
||||
t->chunkId = pt->chunkId;
|
||||
t->byteCount = pt->byteCount;
|
||||
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
t->chunkDeleted = (pt->deleted) ? 0 : 1;
|
||||
t->serialNumber = pt->serialNumber;
|
||||
} else {
|
||||
memset(t, 0, sizeof(yaffs_ExtendedTags));
|
||||
|
||||
}
|
||||
}
|
37
fs/yaffs2/yaffs_packedtags1.h
Normal file
37
fs/yaffs2/yaffs_packedtags1.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
|
||||
|
||||
#ifndef __YAFFS_PACKEDTAGS1_H__
|
||||
#define __YAFFS_PACKEDTAGS1_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned chunkId:20;
|
||||
unsigned serialNumber:2;
|
||||
unsigned byteCount:10;
|
||||
unsigned objectId:18;
|
||||
unsigned ecc:12;
|
||||
unsigned deleted:1;
|
||||
unsigned unusedStuff:1;
|
||||
unsigned shouldBeFF;
|
||||
|
||||
} yaffs_PackedTags1;
|
||||
|
||||
void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t);
|
||||
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt);
|
||||
#endif
|
185
fs/yaffs2/yaffs_packedtags2.c
Normal file
185
fs/yaffs2/yaffs_packedtags2.c
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
#include "yaffs_packedtags2.h"
|
||||
#include "yportenv.h"
|
||||
#include "yaffs_tagsvalidity.h"
|
||||
|
||||
/* This code packs a set of extended tags into a binary structure for
|
||||
* NAND storage
|
||||
*/
|
||||
|
||||
/* Some of the information is "extra" struff which can be packed in to
|
||||
* speed scanning
|
||||
* This is defined by having the EXTRA_HEADER_INFO_FLAG set.
|
||||
*/
|
||||
|
||||
/* Extra flags applied to chunkId */
|
||||
|
||||
#define EXTRA_HEADER_INFO_FLAG 0x80000000
|
||||
#define EXTRA_SHRINK_FLAG 0x40000000
|
||||
#define EXTRA_SHADOWS_FLAG 0x20000000
|
||||
#define EXTRA_SPARE_FLAGS 0x10000000
|
||||
|
||||
#define ALL_EXTRA_FLAGS 0xF0000000
|
||||
|
||||
/* Also, the top 4 bits of the object Id are set to the object type. */
|
||||
#define EXTRA_OBJECT_TYPE_SHIFT (28)
|
||||
#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
|
||||
|
||||
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
|
||||
{
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
|
||||
pt->t.objectId, pt->t.chunkId, pt->t.byteCount,
|
||||
pt->t.sequenceNumber));
|
||||
}
|
||||
|
||||
static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
|
||||
{
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR
|
||||
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte "
|
||||
"%d del %d ser %d seq %d"
|
||||
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
|
||||
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
|
||||
t->sequenceNumber));
|
||||
|
||||
}
|
||||
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
|
||||
{
|
||||
pt->t.chunkId = t->chunkId;
|
||||
pt->t.sequenceNumber = t->sequenceNumber;
|
||||
pt->t.byteCount = t->byteCount;
|
||||
pt->t.objectId = t->objectId;
|
||||
|
||||
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
|
||||
/* Store the extra header info instead */
|
||||
/* We save the parent object in the chunkId */
|
||||
pt->t.chunkId = EXTRA_HEADER_INFO_FLAG
|
||||
| t->extraParentObjectId;
|
||||
if (t->extraIsShrinkHeader) {
|
||||
pt->t.chunkId |= EXTRA_SHRINK_FLAG;
|
||||
}
|
||||
if (t->extraShadows) {
|
||||
pt->t.chunkId |= EXTRA_SHADOWS_FLAG;
|
||||
}
|
||||
|
||||
pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
pt->t.objectId |=
|
||||
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
|
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
|
||||
pt->t.byteCount = t->extraEquivalentObjectId;
|
||||
} else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) {
|
||||
pt->t.byteCount = t->extraFileLength;
|
||||
} else {
|
||||
pt->t.byteCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_DumpPackedTags2(pt);
|
||||
yaffs_DumpTags2(t);
|
||||
|
||||
#ifndef YAFFS_IGNORE_TAGS_ECC
|
||||
{
|
||||
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
|
||||
sizeof(yaffs_PackedTags2TagsPart),
|
||||
&pt->ecc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
|
||||
{
|
||||
|
||||
memset(t, 0, sizeof(yaffs_ExtendedTags));
|
||||
|
||||
yaffs_InitialiseTags(t);
|
||||
|
||||
if (pt->t.sequenceNumber != 0xFFFFFFFF) {
|
||||
/* Page is in use */
|
||||
#ifdef YAFFS_IGNORE_TAGS_ECC
|
||||
{
|
||||
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
}
|
||||
#else
|
||||
{
|
||||
yaffs_ECCOther ecc;
|
||||
int result;
|
||||
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
|
||||
sizeof
|
||||
(yaffs_PackedTags2TagsPart),
|
||||
&ecc);
|
||||
result =
|
||||
yaffs_ECCCorrectOther((unsigned char *)&pt->t,
|
||||
sizeof
|
||||
(yaffs_PackedTags2TagsPart),
|
||||
&pt->ecc, &ecc);
|
||||
switch(result){
|
||||
case 0:
|
||||
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
break;
|
||||
case 1:
|
||||
t->eccResult = YAFFS_ECC_RESULT_FIXED;
|
||||
break;
|
||||
case -1:
|
||||
t->eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||
break;
|
||||
default:
|
||||
t->eccResult = YAFFS_ECC_RESULT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
t->blockBad = 0;
|
||||
t->chunkUsed = 1;
|
||||
t->objectId = pt->t.objectId;
|
||||
t->chunkId = pt->t.chunkId;
|
||||
t->byteCount = pt->t.byteCount;
|
||||
t->chunkDeleted = 0;
|
||||
t->serialNumber = 0;
|
||||
t->sequenceNumber = pt->t.sequenceNumber;
|
||||
|
||||
/* Do extra header info stuff */
|
||||
|
||||
if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) {
|
||||
t->chunkId = 0;
|
||||
t->byteCount = 0;
|
||||
|
||||
t->extraHeaderInfoAvailable = 1;
|
||||
t->extraParentObjectId =
|
||||
pt->t.chunkId & (~(ALL_EXTRA_FLAGS));
|
||||
t->extraIsShrinkHeader =
|
||||
(pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
|
||||
t->extraShadows =
|
||||
(pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
|
||||
t->extraObjectType =
|
||||
pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT;
|
||||
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
|
||||
t->extraEquivalentObjectId = pt->t.byteCount;
|
||||
} else {
|
||||
t->extraFileLength = pt->t.byteCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_DumpPackedTags2(pt);
|
||||
yaffs_DumpTags2(t);
|
||||
|
||||
}
|
38
fs/yaffs2/yaffs_packedtags2.h
Normal file
38
fs/yaffs2/yaffs_packedtags2.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
|
||||
|
||||
#ifndef __YAFFS_PACKEDTAGS2_H__
|
||||
#define __YAFFS_PACKEDTAGS2_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
#include "yaffs_ecc.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned sequenceNumber;
|
||||
unsigned objectId;
|
||||
unsigned chunkId;
|
||||
unsigned byteCount;
|
||||
} yaffs_PackedTags2TagsPart;
|
||||
|
||||
typedef struct {
|
||||
yaffs_PackedTags2TagsPart t;
|
||||
yaffs_ECCOther ecc;
|
||||
} yaffs_PackedTags2;
|
||||
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt);
|
||||
#endif
|
163
fs/yaffs2/yaffs_qsort.c
Normal file
163
fs/yaffs2/yaffs_qsort.c
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
#include "yportenv.h"
|
||||
//#include <linux/string.h>
|
||||
|
||||
/*
|
||||
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
|
||||
*/
|
||||
#define swapcode(TYPE, parmi, parmj, n) { \
|
||||
long i = (n) / sizeof (TYPE); \
|
||||
register TYPE *pi = (TYPE *) (parmi); \
|
||||
register TYPE *pj = (TYPE *) (parmj); \
|
||||
do { \
|
||||
register TYPE t = *pi; \
|
||||
*pi++ = *pj; \
|
||||
*pj++ = t; \
|
||||
} while (--i > 0); \
|
||||
}
|
||||
|
||||
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
|
||||
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
|
||||
|
||||
static __inline void
|
||||
swapfunc(char *a, char *b, int n, int swaptype)
|
||||
{
|
||||
if (swaptype <= 1)
|
||||
swapcode(long, a, b, n)
|
||||
else
|
||||
swapcode(char, a, b, n)
|
||||
}
|
||||
|
||||
#define swap(a, b) \
|
||||
if (swaptype == 0) { \
|
||||
long t = *(long *)(a); \
|
||||
*(long *)(a) = *(long *)(b); \
|
||||
*(long *)(b) = t; \
|
||||
} else \
|
||||
swapfunc(a, b, es, swaptype)
|
||||
|
||||
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
|
||||
|
||||
static __inline char *
|
||||
med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
|
||||
{
|
||||
return cmp(a, b) < 0 ?
|
||||
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
|
||||
:(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
|
||||
}
|
||||
|
||||
#ifndef min
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
void
|
||||
yaffs_qsort(void *aa, size_t n, size_t es,
|
||||
int (*cmp)(const void *, const void *))
|
||||
{
|
||||
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
|
||||
int d, r, swaptype, swap_cnt;
|
||||
register char *a = aa;
|
||||
|
||||
loop: SWAPINIT(a, es);
|
||||
swap_cnt = 0;
|
||||
if (n < 7) {
|
||||
for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
|
||||
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
|
||||
pl -= es)
|
||||
swap(pl, pl - es);
|
||||
return;
|
||||
}
|
||||
pm = (char *)a + (n / 2) * es;
|
||||
if (n > 7) {
|
||||
pl = (char *)a;
|
||||
pn = (char *)a + (n - 1) * es;
|
||||
if (n > 40) {
|
||||
d = (n / 8) * es;
|
||||
pl = med3(pl, pl + d, pl + 2 * d, cmp);
|
||||
pm = med3(pm - d, pm, pm + d, cmp);
|
||||
pn = med3(pn - 2 * d, pn - d, pn, cmp);
|
||||
}
|
||||
pm = med3(pl, pm, pn, cmp);
|
||||
}
|
||||
swap(a, pm);
|
||||
pa = pb = (char *)a + es;
|
||||
|
||||
pc = pd = (char *)a + (n - 1) * es;
|
||||
for (;;) {
|
||||
while (pb <= pc && (r = cmp(pb, a)) <= 0) {
|
||||
if (r == 0) {
|
||||
swap_cnt = 1;
|
||||
swap(pa, pb);
|
||||
pa += es;
|
||||
}
|
||||
pb += es;
|
||||
}
|
||||
while (pb <= pc && (r = cmp(pc, a)) >= 0) {
|
||||
if (r == 0) {
|
||||
swap_cnt = 1;
|
||||
swap(pc, pd);
|
||||
pd -= es;
|
||||
}
|
||||
pc -= es;
|
||||
}
|
||||
if (pb > pc)
|
||||
break;
|
||||
swap(pb, pc);
|
||||
swap_cnt = 1;
|
||||
pb += es;
|
||||
pc -= es;
|
||||
}
|
||||
if (swap_cnt == 0) { /* Switch to insertion sort */
|
||||
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
|
||||
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
|
||||
pl -= es)
|
||||
swap(pl, pl - es);
|
||||
return;
|
||||
}
|
||||
|
||||
pn = (char *)a + n * es;
|
||||
r = min(pa - (char *)a, pb - pa);
|
||||
vecswap(a, pb - r, r);
|
||||
r = min((long)(pd - pc), (long)(pn - pd - es));
|
||||
vecswap(pb, pn - r, r);
|
||||
if ((r = pb - pa) > es)
|
||||
yaffs_qsort(a, r / es, es, cmp);
|
||||
if ((r = pd - pc) > es) {
|
||||
/* Iterate rather than recurse to save stack space */
|
||||
a = pn - r;
|
||||
n = r / es;
|
||||
goto loop;
|
||||
}
|
||||
/* yaffs_qsort(pn - r, r / es, es, cmp);*/
|
||||
}
|
23
fs/yaffs2/yaffs_qsort.h
Normal file
23
fs/yaffs2/yaffs_qsort.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __YAFFS_QSORT_H__
|
||||
#define __YAFFS_QSORT_H__
|
||||
|
||||
extern void yaffs_qsort (void *const base, size_t total_elems, size_t size,
|
||||
int (*cmp)(const void *, const void *));
|
||||
|
||||
#endif
|
32
fs/yaffs2/yaffs_ramdisk.h
Normal file
32
fs/yaffs2/yaffs_ramdisk.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* yaffs_ramdisk.h: yaffs ram disk component
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_RAMDISK_H__
|
||||
#define __YAFFS_RAMDISK_H__
|
||||
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
|
||||
int yramdisk_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags);
|
||||
int yramdisk_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
|
||||
int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
|
||||
int yramdisk_InitialiseNAND(yaffs_Device *dev);
|
||||
int yramdisk_MarkNANDBlockBad(yaffs_Device *dev,int blockNumber);
|
||||
int yramdisk_QueryNANDBlock(yaffs_Device *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
|
||||
#endif
|
533
fs/yaffs2/yaffs_tagscompat.c
Normal file
533
fs/yaffs2/yaffs_tagscompat.c
Normal file
@ -0,0 +1,533 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
#include "yaffs_tagscompat.h"
|
||||
#include "yaffs_ecc.h"
|
||||
|
||||
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
|
||||
#ifdef NOTYET
|
||||
static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND);
|
||||
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data,
|
||||
const yaffs_Spare * spare);
|
||||
static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
|
||||
const yaffs_Spare * spare);
|
||||
static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND);
|
||||
#endif
|
||||
|
||||
static const char yaffs_countBitsTable[256] = {
|
||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
|
||||
};
|
||||
|
||||
int yaffs_CountBits(__u8 x)
|
||||
{
|
||||
int retVal;
|
||||
retVal = yaffs_countBitsTable[x];
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/********** Tags ECC calculations *********/
|
||||
|
||||
void yaffs_CalcECC(const __u8 * data, yaffs_Spare * spare)
|
||||
{
|
||||
yaffs_ECCCalculate(data, spare->ecc1);
|
||||
yaffs_ECCCalculate(&data[256], spare->ecc2);
|
||||
}
|
||||
|
||||
void yaffs_CalcTagsECC(yaffs_Tags * tags)
|
||||
{
|
||||
/* Calculate an ecc */
|
||||
|
||||
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
|
||||
unsigned i, j;
|
||||
unsigned ecc = 0;
|
||||
unsigned bit = 0;
|
||||
|
||||
tags->ecc = 0;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (j = 1; j & 0xff; j <<= 1) {
|
||||
bit++;
|
||||
if (b[i] & j) {
|
||||
ecc ^= bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tags->ecc = ecc;
|
||||
|
||||
}
|
||||
|
||||
int yaffs_CheckECCOnTags(yaffs_Tags * tags)
|
||||
{
|
||||
unsigned ecc = tags->ecc;
|
||||
|
||||
yaffs_CalcTagsECC(tags);
|
||||
|
||||
ecc ^= tags->ecc;
|
||||
|
||||
if (ecc && ecc <= 64) {
|
||||
/* TODO: Handle the failure better. Retire? */
|
||||
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
|
||||
|
||||
ecc--;
|
||||
|
||||
b[ecc / 8] ^= (1 << (ecc & 7));
|
||||
|
||||
/* Now recvalc the ecc */
|
||||
yaffs_CalcTagsECC(tags);
|
||||
|
||||
return 1; /* recovered error */
|
||||
} else if (ecc) {
|
||||
/* Wierd ecc failure value */
|
||||
/* TODO Need to do somethiong here */
|
||||
return -1; /* unrecovered error */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/********** Tags **********/
|
||||
|
||||
static void yaffs_LoadTagsIntoSpare(yaffs_Spare * sparePtr,
|
||||
yaffs_Tags * tagsPtr)
|
||||
{
|
||||
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
|
||||
|
||||
yaffs_CalcTagsECC(tagsPtr);
|
||||
|
||||
sparePtr->tagByte0 = tu->asBytes[0];
|
||||
sparePtr->tagByte1 = tu->asBytes[1];
|
||||
sparePtr->tagByte2 = tu->asBytes[2];
|
||||
sparePtr->tagByte3 = tu->asBytes[3];
|
||||
sparePtr->tagByte4 = tu->asBytes[4];
|
||||
sparePtr->tagByte5 = tu->asBytes[5];
|
||||
sparePtr->tagByte6 = tu->asBytes[6];
|
||||
sparePtr->tagByte7 = tu->asBytes[7];
|
||||
}
|
||||
|
||||
static void yaffs_GetTagsFromSpare(yaffs_Device * dev, yaffs_Spare * sparePtr,
|
||||
yaffs_Tags * tagsPtr)
|
||||
{
|
||||
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
|
||||
int result;
|
||||
|
||||
tu->asBytes[0] = sparePtr->tagByte0;
|
||||
tu->asBytes[1] = sparePtr->tagByte1;
|
||||
tu->asBytes[2] = sparePtr->tagByte2;
|
||||
tu->asBytes[3] = sparePtr->tagByte3;
|
||||
tu->asBytes[4] = sparePtr->tagByte4;
|
||||
tu->asBytes[5] = sparePtr->tagByte5;
|
||||
tu->asBytes[6] = sparePtr->tagByte6;
|
||||
tu->asBytes[7] = sparePtr->tagByte7;
|
||||
|
||||
result = yaffs_CheckECCOnTags(tagsPtr);
|
||||
if (result > 0) {
|
||||
dev->tagsEccFixed++;
|
||||
} else if (result < 0) {
|
||||
dev->tagsEccUnfixed++;
|
||||
}
|
||||
}
|
||||
|
||||
static void yaffs_SpareInitialise(yaffs_Spare * spare)
|
||||
{
|
||||
memset(spare, 0xFF, sizeof(yaffs_Spare));
|
||||
}
|
||||
|
||||
static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND, const __u8 * data,
|
||||
yaffs_Spare * spare)
|
||||
{
|
||||
if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
|
||||
chunkInNAND));
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
dev->nPageWrites++;
|
||||
return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
|
||||
}
|
||||
|
||||
static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND,
|
||||
__u8 * data,
|
||||
yaffs_Spare * spare,
|
||||
yaffs_ECCResult * eccResult,
|
||||
int doErrorCorrection)
|
||||
{
|
||||
int retVal;
|
||||
yaffs_Spare localSpare;
|
||||
|
||||
dev->nPageReads++;
|
||||
|
||||
if (!spare && data) {
|
||||
/* If we don't have a real spare, then we use a local one. */
|
||||
/* Need this for the calculation of the ecc */
|
||||
spare = &localSpare;
|
||||
}
|
||||
|
||||
if (!dev->useNANDECC) {
|
||||
retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
|
||||
if (data && doErrorCorrection) {
|
||||
/* Do ECC correction */
|
||||
/* Todo handle any errors */
|
||||
int eccResult1, eccResult2;
|
||||
__u8 calcEcc[3];
|
||||
|
||||
yaffs_ECCCalculate(data, calcEcc);
|
||||
eccResult1 =
|
||||
yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
|
||||
yaffs_ECCCalculate(&data[256], calcEcc);
|
||||
eccResult2 =
|
||||
yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
|
||||
|
||||
if (eccResult1 > 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>yaffs ecc error fix performed on chunk %d:0"
|
||||
TENDSTR), chunkInNAND));
|
||||
dev->eccFixed++;
|
||||
} else if (eccResult1 < 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>yaffs ecc error unfixed on chunk %d:0"
|
||||
TENDSTR), chunkInNAND));
|
||||
dev->eccUnfixed++;
|
||||
}
|
||||
|
||||
if (eccResult2 > 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>yaffs ecc error fix performed on chunk %d:1"
|
||||
TENDSTR), chunkInNAND));
|
||||
dev->eccFixed++;
|
||||
} else if (eccResult2 < 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>yaffs ecc error unfixed on chunk %d:1"
|
||||
TENDSTR), chunkInNAND));
|
||||
dev->eccUnfixed++;
|
||||
}
|
||||
|
||||
if (eccResult1 || eccResult2) {
|
||||
/* We had a data problem on this page */
|
||||
yaffs_HandleReadDataError(dev, chunkInNAND);
|
||||
}
|
||||
|
||||
if (eccResult1 < 0 || eccResult2 < 0)
|
||||
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||
else if (eccResult1 > 0 || eccResult2 > 0)
|
||||
*eccResult = YAFFS_ECC_RESULT_FIXED;
|
||||
else
|
||||
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
}
|
||||
} else {
|
||||
/* Must allocate enough memory for spare+2*sizeof(int) */
|
||||
/* for ecc results from device. */
|
||||
struct yaffs_NANDSpare nspare;
|
||||
retVal =
|
||||
dev->readChunkFromNAND(dev, chunkInNAND, data,
|
||||
(yaffs_Spare *) & nspare);
|
||||
memcpy(spare, &nspare, sizeof(yaffs_Spare));
|
||||
if (data && doErrorCorrection) {
|
||||
if (nspare.eccres1 > 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>mtd ecc error fix performed on chunk %d:0"
|
||||
TENDSTR), chunkInNAND));
|
||||
} else if (nspare.eccres1 < 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>mtd ecc error unfixed on chunk %d:0"
|
||||
TENDSTR), chunkInNAND));
|
||||
}
|
||||
|
||||
if (nspare.eccres2 > 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>mtd ecc error fix performed on chunk %d:1"
|
||||
TENDSTR), chunkInNAND));
|
||||
} else if (nspare.eccres2 < 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>mtd ecc error unfixed on chunk %d:1"
|
||||
TENDSTR), chunkInNAND));
|
||||
}
|
||||
|
||||
if (nspare.eccres1 || nspare.eccres2) {
|
||||
/* We had a data problem on this page */
|
||||
yaffs_HandleReadDataError(dev, chunkInNAND);
|
||||
}
|
||||
|
||||
if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
|
||||
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||
else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
|
||||
*eccResult = YAFFS_ECC_RESULT_FIXED;
|
||||
else
|
||||
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
#ifdef NOTYET
|
||||
static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND)
|
||||
{
|
||||
|
||||
static int init = 0;
|
||||
static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
|
||||
static __u8 data[YAFFS_BYTES_PER_CHUNK];
|
||||
/* Might as well always allocate the larger size for */
|
||||
/* dev->useNANDECC == true; */
|
||||
static __u8 spare[sizeof(struct yaffs_NANDSpare)];
|
||||
|
||||
dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
|
||||
|
||||
if (!init) {
|
||||
memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
|
||||
init = 1;
|
||||
}
|
||||
|
||||
if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
|
||||
return YAFFS_FAIL;
|
||||
if (memcmp(cmpbuf, spare, 16))
|
||||
return YAFFS_FAIL;
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Functions for robustisizing
|
||||
*/
|
||||
|
||||
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND)
|
||||
{
|
||||
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
|
||||
|
||||
/* Mark the block for retirement */
|
||||
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
|
||||
T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
|
||||
(TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
|
||||
|
||||
/* TODO:
|
||||
* Just do a garbage collection on the affected block
|
||||
* then retire the block
|
||||
* NB recursion
|
||||
*/
|
||||
}
|
||||
|
||||
#ifdef NOTYET
|
||||
static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND)
|
||||
{
|
||||
}
|
||||
|
||||
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data,
|
||||
const yaffs_Spare * spare)
|
||||
{
|
||||
}
|
||||
|
||||
static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
|
||||
const yaffs_Spare * spare)
|
||||
{
|
||||
}
|
||||
|
||||
static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
|
||||
{
|
||||
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
|
||||
|
||||
/* Mark the block for retirement */
|
||||
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
|
||||
/* Delete the chunk */
|
||||
yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
|
||||
}
|
||||
|
||||
static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1,
|
||||
const yaffs_Spare * s0, const yaffs_Spare * s1)
|
||||
{
|
||||
|
||||
if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
|
||||
s0->tagByte0 != s1->tagByte0 ||
|
||||
s0->tagByte1 != s1->tagByte1 ||
|
||||
s0->tagByte2 != s1->tagByte2 ||
|
||||
s0->tagByte3 != s1->tagByte3 ||
|
||||
s0->tagByte4 != s1->tagByte4 ||
|
||||
s0->tagByte5 != s1->tagByte5 ||
|
||||
s0->tagByte6 != s1->tagByte6 ||
|
||||
s0->tagByte7 != s1->tagByte7 ||
|
||||
s0->ecc1[0] != s1->ecc1[0] ||
|
||||
s0->ecc1[1] != s1->ecc1[1] ||
|
||||
s0->ecc1[2] != s1->ecc1[2] ||
|
||||
s0->ecc2[0] != s1->ecc2[0] ||
|
||||
s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* NOTYET */
|
||||
|
||||
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
|
||||
int chunkInNAND,
|
||||
const __u8 * data,
|
||||
const yaffs_ExtendedTags *
|
||||
eTags)
|
||||
{
|
||||
yaffs_Spare spare;
|
||||
yaffs_Tags tags;
|
||||
|
||||
yaffs_SpareInitialise(&spare);
|
||||
|
||||
if (eTags->chunkDeleted) {
|
||||
spare.pageStatus = 0;
|
||||
} else {
|
||||
tags.objectId = eTags->objectId;
|
||||
tags.chunkId = eTags->chunkId;
|
||||
tags.byteCount = eTags->byteCount;
|
||||
tags.serialNumber = eTags->serialNumber;
|
||||
|
||||
if (!dev->useNANDECC && data) {
|
||||
yaffs_CalcECC(data, &spare);
|
||||
}
|
||||
yaffs_LoadTagsIntoSpare(&spare, &tags);
|
||||
|
||||
}
|
||||
|
||||
return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
|
||||
}
|
||||
|
||||
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
|
||||
int chunkInNAND,
|
||||
__u8 * data,
|
||||
yaffs_ExtendedTags * eTags)
|
||||
{
|
||||
|
||||
yaffs_Spare spare;
|
||||
yaffs_Tags tags;
|
||||
yaffs_ECCResult eccResult;
|
||||
|
||||
static yaffs_Spare spareFF;
|
||||
static int init;
|
||||
|
||||
if (!init) {
|
||||
memset(&spareFF, 0xFF, sizeof(spareFF));
|
||||
init = 1;
|
||||
}
|
||||
|
||||
if (yaffs_ReadChunkFromNAND
|
||||
(dev, chunkInNAND, data, &spare, &eccResult, 1)) {
|
||||
/* eTags may be NULL */
|
||||
if (eTags) {
|
||||
|
||||
int deleted =
|
||||
(yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
|
||||
|
||||
eTags->chunkDeleted = deleted;
|
||||
eTags->eccResult = eccResult;
|
||||
eTags->blockBad = 0; /* We're reading it */
|
||||
/* therefore it is not a bad block */
|
||||
eTags->chunkUsed =
|
||||
(memcmp(&spareFF, &spare, sizeof(spareFF)) !=
|
||||
0) ? 1 : 0;
|
||||
|
||||
if (eTags->chunkUsed) {
|
||||
yaffs_GetTagsFromSpare(dev, &spare, &tags);
|
||||
|
||||
eTags->objectId = tags.objectId;
|
||||
eTags->chunkId = tags.chunkId;
|
||||
eTags->byteCount = tags.byteCount;
|
||||
eTags->serialNumber = tags.serialNumber;
|
||||
}
|
||||
}
|
||||
|
||||
return YAFFS_OK;
|
||||
} else {
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
|
||||
int blockInNAND)
|
||||
{
|
||||
|
||||
yaffs_Spare spare;
|
||||
|
||||
memset(&spare, 0xff, sizeof(yaffs_Spare));
|
||||
|
||||
spare.blockStatus = 'Y';
|
||||
|
||||
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
|
||||
&spare);
|
||||
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
|
||||
NULL, &spare);
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo, yaffs_BlockState *
|
||||
state,
|
||||
int *sequenceNumber)
|
||||
{
|
||||
|
||||
yaffs_Spare spare0, spare1;
|
||||
static yaffs_Spare spareFF;
|
||||
static int init;
|
||||
yaffs_ECCResult dummy;
|
||||
|
||||
if (!init) {
|
||||
memset(&spareFF, 0xFF, sizeof(spareFF));
|
||||
init = 1;
|
||||
}
|
||||
|
||||
*sequenceNumber = 0;
|
||||
|
||||
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
|
||||
&spare0, &dummy, 1);
|
||||
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
|
||||
&spare1, &dummy, 1);
|
||||
|
||||
if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
|
||||
*state = YAFFS_BLOCK_STATE_DEAD;
|
||||
else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
|
||||
*state = YAFFS_BLOCK_STATE_EMPTY;
|
||||
else
|
||||
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
|
||||
return YAFFS_OK;
|
||||
}
|
40
fs/yaffs2/yaffs_tagscompat.h
Normal file
40
fs/yaffs2/yaffs_tagscompat.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_TAGSCOMPAT_H__
|
||||
#define __YAFFS_TAGSCOMPAT_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
|
||||
int chunkInNAND,
|
||||
const __u8 * data,
|
||||
const yaffs_ExtendedTags *
|
||||
tags);
|
||||
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
|
||||
int chunkInNAND,
|
||||
__u8 * data,
|
||||
yaffs_ExtendedTags *
|
||||
tags);
|
||||
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo);
|
||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo, yaffs_BlockState *
|
||||
state, int *sequenceNumber);
|
||||
|
||||
void yaffs_CalcTagsECC(yaffs_Tags * tags);
|
||||
int yaffs_CheckECCOnTags(yaffs_Tags * tags);
|
||||
int yaffs_CountBits(__u8 byte);
|
||||
|
||||
#endif
|
31
fs/yaffs2/yaffs_tagsvalidity.c
Normal file
31
fs/yaffs2/yaffs_tagsvalidity.c
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
#include "yaffs_tagsvalidity.h"
|
||||
|
||||
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags)
|
||||
{
|
||||
memset(tags, 0, sizeof(yaffs_ExtendedTags));
|
||||
tags->validMarker0 = 0xAAAAAAAA;
|
||||
tags->validMarker1 = 0x55555555;
|
||||
}
|
||||
|
||||
int yaffs_ValidateTags(yaffs_ExtendedTags * tags)
|
||||
{
|
||||
return (tags->validMarker0 == 0xAAAAAAAA &&
|
||||
tags->validMarker1 == 0x55555555);
|
||||
|
||||
}
|
24
fs/yaffs2/yaffs_tagsvalidity.h
Normal file
24
fs/yaffs2/yaffs_tagsvalidity.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __YAFFS_TAGS_VALIDITY_H__
|
||||
#define __YAFFS_TAGS_VALIDITY_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
|
||||
int yaffs_ValidateTags(yaffs_ExtendedTags * tags);
|
||||
#endif
|
417
fs/yaffs2/yaffscfg.c
Normal file
417
fs/yaffs2/yaffscfg.c
Normal file
@ -0,0 +1,417 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* yaffscfg.c The configuration for the "direct" use of yaffs.
|
||||
*
|
||||
* This file is intended to be modified to your requirements.
|
||||
* There is no need to redistribute this file.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
#include <config.h>
|
||||
#include "nand.h"
|
||||
#include "yaffscfg.h"
|
||||
#include "yaffsfs.h"
|
||||
#include "yaffs_packedtags2.h"
|
||||
#include "yaffs_mtdif.h"
|
||||
#include "yaffs_mtdif2.h"
|
||||
#if 0
|
||||
#include <errno.h>
|
||||
#else
|
||||
#include "malloc.h"
|
||||
#endif
|
||||
|
||||
unsigned yaffs_traceMask = 0xFFFFFFFF;
|
||||
static int yaffs_errno = 0;
|
||||
|
||||
void yaffsfs_SetError(int err)
|
||||
{
|
||||
//Do whatever to set error
|
||||
yaffs_errno = err;
|
||||
}
|
||||
|
||||
int yaffsfs_GetError(void)
|
||||
{
|
||||
return yaffs_errno;
|
||||
}
|
||||
|
||||
void yaffsfs_Lock(void)
|
||||
{
|
||||
}
|
||||
|
||||
void yaffsfs_Unlock(void)
|
||||
{
|
||||
}
|
||||
|
||||
__u32 yaffsfs_CurrentTime(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *yaffs_malloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void yaffs_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void yaffsfs_LocalInitialisation(void)
|
||||
{
|
||||
// Define locking semaphore.
|
||||
}
|
||||
|
||||
// Configuration for:
|
||||
// /ram 2MB ramdisk
|
||||
// /boot 2MB boot disk (flash)
|
||||
// /flash 14MB flash disk (flash)
|
||||
// NB Though /boot and /flash occupy the same physical device they
|
||||
// are still disticnt "yaffs_Devices. You may think of these as "partitions"
|
||||
// using non-overlapping areas in the same device.
|
||||
//
|
||||
|
||||
#include "yaffs_ramdisk.h"
|
||||
#include "yaffs_flashif.h"
|
||||
|
||||
static int isMounted = 0;
|
||||
#define MOUNT_POINT "/flash"
|
||||
extern nand_info_t nand_info[];
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
static yaffs_Device ramDev;
|
||||
static yaffs_Device bootDev;
|
||||
static yaffs_Device flashDev;
|
||||
#endif
|
||||
|
||||
static yaffsfs_DeviceConfiguration yaffsfs_config[] = {
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
{ "/ram", &ramDev},
|
||||
{ "/boot", &bootDev},
|
||||
{ "/flash", &flashDev},
|
||||
#else
|
||||
{ MOUNT_POINT, 0},
|
||||
#endif
|
||||
{(void *)0,(void *)0}
|
||||
};
|
||||
|
||||
|
||||
int yaffs_StartUp(void)
|
||||
{
|
||||
struct mtd_info *mtd = &nand_info[0];
|
||||
int yaffsVersion = 2;
|
||||
int nBlocks;
|
||||
|
||||
yaffs_Device *flashDev = calloc(1, sizeof(yaffs_Device));
|
||||
yaffsfs_config[0].dev = flashDev;
|
||||
|
||||
// Stuff to configure YAFFS
|
||||
// Stuff to initialise anything special (eg lock semaphore).
|
||||
yaffsfs_LocalInitialisation();
|
||||
|
||||
// Set up devices
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
// /ram
|
||||
ramDev.nBytesPerChunk = 512;
|
||||
ramDev.nChunksPerBlock = 32;
|
||||
ramDev.nReservedBlocks = 2; // Set this smaller for RAM
|
||||
ramDev.startBlock = 1; // Can't use block 0
|
||||
ramDev.endBlock = 127; // Last block in 2MB.
|
||||
ramDev.useNANDECC = 1;
|
||||
ramDev.nShortOpCaches = 0; // Disable caching on this device.
|
||||
ramDev.genericDevice = (void *) 0; // Used to identify the device in fstat.
|
||||
ramDev.writeChunkWithTagsToNAND = yramdisk_WriteChunkWithTagsToNAND;
|
||||
ramDev.readChunkWithTagsFromNAND = yramdisk_ReadChunkWithTagsFromNAND;
|
||||
ramDev.eraseBlockInNAND = yramdisk_EraseBlockInNAND;
|
||||
ramDev.initialiseNAND = yramdisk_InitialiseNAND;
|
||||
|
||||
// /boot
|
||||
bootDev.nBytesPerChunk = 612;
|
||||
bootDev.nChunksPerBlock = 32;
|
||||
bootDev.nReservedBlocks = 5;
|
||||
bootDev.startBlock = 1; // Can't use block 0
|
||||
bootDev.endBlock = 127; // Last block in 2MB.
|
||||
bootDev.useNANDECC = 0; // use YAFFS's ECC
|
||||
bootDev.nShortOpCaches = 10; // Use caches
|
||||
bootDev.genericDevice = (void *) 1; // Used to identify the device in fstat.
|
||||
bootDev.writeChunkToNAND = yflash_WriteChunkToNAND;
|
||||
bootDev.readChunkFromNAND = yflash_ReadChunkFromNAND;
|
||||
bootDev.eraseBlockInNAND = yflash_EraseBlockInNAND;
|
||||
bootDev.initialiseNAND = yflash_InitialiseNAND;
|
||||
#endif
|
||||
|
||||
// /flash
|
||||
flashDev->nReservedBlocks = 5;
|
||||
// flashDev->nShortOpCaches = (options.no_cache) ? 0 : 10;
|
||||
flashDev->nShortOpCaches = 10; // Use caches
|
||||
flashDev->useNANDECC = 0; // do not use YAFFS's ECC
|
||||
|
||||
if (yaffsVersion == 2)
|
||||
{
|
||||
flashDev->writeChunkWithTagsToNAND = nandmtd2_WriteChunkWithTagsToNAND;
|
||||
flashDev->readChunkWithTagsFromNAND = nandmtd2_ReadChunkWithTagsFromNAND;
|
||||
flashDev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
|
||||
flashDev->queryNANDBlock = nandmtd2_QueryNANDBlock;
|
||||
flashDev->spareBuffer = YMALLOC(mtd->oobsize);
|
||||
flashDev->isYaffs2 = 1;
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
flashDev->nDataBytesPerChunk = mtd->writesize;
|
||||
flashDev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
|
||||
#else
|
||||
flashDev->nDataBytesPerChunk = mtd->oobblock;
|
||||
flashDev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
|
||||
#endif
|
||||
nBlocks = mtd->size / mtd->erasesize;
|
||||
|
||||
flashDev->nCheckpointReservedBlocks = 10;
|
||||
flashDev->startBlock = 0;
|
||||
flashDev->endBlock = nBlocks - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
flashDev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
|
||||
flashDev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
|
||||
flashDev->isYaffs2 = 0;
|
||||
nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
|
||||
flashDev->startBlock = 320;
|
||||
flashDev->endBlock = nBlocks - 1;
|
||||
flashDev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
|
||||
flashDev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
|
||||
}
|
||||
|
||||
/* ... and common functions */
|
||||
flashDev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
|
||||
flashDev->initialiseNAND = nandmtd_InitialiseNAND;
|
||||
|
||||
yaffs_initialise(yaffsfs_config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void make_a_file(char *yaffsName,char bval,int sizeOfFile)
|
||||
{
|
||||
int outh;
|
||||
int i;
|
||||
unsigned char buffer[100];
|
||||
|
||||
outh = yaffs_open(yaffsName, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE);
|
||||
if (outh < 0)
|
||||
{
|
||||
printf("Error opening file: %d\n", outh);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(buffer,bval,100);
|
||||
|
||||
do{
|
||||
i = sizeOfFile;
|
||||
if(i > 100) i = 100;
|
||||
sizeOfFile -= i;
|
||||
|
||||
yaffs_write(outh,buffer,i);
|
||||
|
||||
} while (sizeOfFile > 0);
|
||||
|
||||
|
||||
yaffs_close(outh);
|
||||
}
|
||||
|
||||
void read_a_file(char *fn)
|
||||
{
|
||||
int h;
|
||||
int i = 0;
|
||||
unsigned char b;
|
||||
|
||||
h = yaffs_open(fn, O_RDWR,0);
|
||||
if(h<0)
|
||||
{
|
||||
printf("File not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
while(yaffs_read(h,&b,1)> 0)
|
||||
{
|
||||
printf("%02x ",b);
|
||||
i++;
|
||||
if(i > 32)
|
||||
{
|
||||
printf("\n");
|
||||
i = 0;;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
yaffs_close(h);
|
||||
}
|
||||
|
||||
void cmd_yaffs_mount(char *mp)
|
||||
{
|
||||
yaffs_StartUp();
|
||||
int retval = yaffs_mount(mp);
|
||||
if( retval != -1)
|
||||
isMounted = 1;
|
||||
else
|
||||
printf("Error mounting %s, return value: %d\n", mp, yaffsfs_GetError());
|
||||
}
|
||||
|
||||
static void checkMount(void)
|
||||
{
|
||||
if( !isMounted )
|
||||
{
|
||||
cmd_yaffs_mount(MOUNT_POINT);
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_yaffs_umount(char *mp)
|
||||
{
|
||||
checkMount();
|
||||
if( yaffs_unmount(mp) == -1)
|
||||
printf("Error umounting %s, return value: %d\n", mp, yaffsfs_GetError());
|
||||
}
|
||||
|
||||
void cmd_yaffs_write_file(char *yaffsName,char bval,int sizeOfFile)
|
||||
{
|
||||
checkMount();
|
||||
make_a_file(yaffsName,bval,sizeOfFile);
|
||||
}
|
||||
|
||||
|
||||
void cmd_yaffs_read_file(char *fn)
|
||||
{
|
||||
checkMount();
|
||||
read_a_file(fn);
|
||||
}
|
||||
|
||||
|
||||
void cmd_yaffs_mread_file(char *fn, char *addr)
|
||||
{
|
||||
int h;
|
||||
struct yaffs_stat s;
|
||||
|
||||
checkMount();
|
||||
|
||||
yaffs_stat(fn,&s);
|
||||
|
||||
printf ("Copy %s to 0x%08x... ", fn, addr);
|
||||
h = yaffs_open(fn, O_RDWR,0);
|
||||
if(h<0)
|
||||
{
|
||||
printf("File not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
yaffs_read(h,addr,(int)s.st_size);
|
||||
printf("\t[DONE]\n");
|
||||
|
||||
yaffs_close(h);
|
||||
}
|
||||
|
||||
|
||||
void cmd_yaffs_mwrite_file(char *fn, char *addr, int size)
|
||||
{
|
||||
int outh;
|
||||
|
||||
checkMount();
|
||||
outh = yaffs_open(fn, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE);
|
||||
if (outh < 0)
|
||||
{
|
||||
printf("Error opening file: %d\n", outh);
|
||||
}
|
||||
|
||||
yaffs_write(outh,addr,size);
|
||||
|
||||
yaffs_close(outh);
|
||||
}
|
||||
|
||||
|
||||
void cmd_yaffs_ls(const char *mountpt, int longlist)
|
||||
{
|
||||
int i;
|
||||
yaffs_DIR *d;
|
||||
yaffs_dirent *de;
|
||||
struct yaffs_stat stat;
|
||||
char tempstr[255];
|
||||
|
||||
checkMount();
|
||||
d = yaffs_opendir(mountpt);
|
||||
|
||||
if(!d)
|
||||
{
|
||||
printf("opendir failed\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
for(i = 0; (de = yaffs_readdir(d)) != NULL; i++)
|
||||
{
|
||||
if (longlist)
|
||||
{
|
||||
sprintf(tempstr, "%s/%s", mountpt, de->d_name);
|
||||
yaffs_stat(tempstr, &stat);
|
||||
printf("%-25s\t%7d\n",de->d_name, stat.st_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s\n",de->d_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void cmd_yaffs_mkdir(const char *dir)
|
||||
{
|
||||
checkMount();
|
||||
|
||||
int retval = yaffs_mkdir(dir, 0);
|
||||
|
||||
if ( retval < 0)
|
||||
printf("yaffs_mkdir returning error: %d\n", retval);
|
||||
}
|
||||
|
||||
void cmd_yaffs_rmdir(const char *dir)
|
||||
{
|
||||
checkMount();
|
||||
|
||||
int retval = yaffs_rmdir(dir);
|
||||
|
||||
if ( retval < 0)
|
||||
printf("yaffs_rmdir returning error: %d\n", retval);
|
||||
}
|
||||
|
||||
void cmd_yaffs_rm(const char *path)
|
||||
{
|
||||
checkMount();
|
||||
|
||||
int retval = yaffs_unlink(path);
|
||||
|
||||
if ( retval < 0)
|
||||
printf("yaffs_unlink returning error: %d\n", retval);
|
||||
}
|
||||
|
||||
void cmd_yaffs_mv(const char *oldPath, const char *newPath)
|
||||
{
|
||||
checkMount();
|
||||
|
||||
int retval = yaffs_rename(newPath, oldPath);
|
||||
|
||||
if ( retval < 0)
|
||||
printf("yaffs_unlink returning error: %d\n", retval);
|
||||
}
|
46
fs/yaffs2/yaffscfg.h
Normal file
46
fs/yaffs2/yaffscfg.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Header file for using yaffs in an application via
|
||||
* a direct interface.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __YAFFSCFG_H__
|
||||
#define __YAFFSCFG_H__
|
||||
|
||||
|
||||
#include "devextras.h"
|
||||
|
||||
#define YAFFSFS_N_HANDLES 200
|
||||
|
||||
|
||||
typedef struct {
|
||||
const char *prefix;
|
||||
struct yaffs_DeviceStruct *dev;
|
||||
} yaffsfs_DeviceConfiguration;
|
||||
|
||||
|
||||
void yaffsfs_Lock(void);
|
||||
void yaffsfs_Unlock(void);
|
||||
|
||||
__u32 yaffsfs_CurrentTime(void);
|
||||
|
||||
void yaffsfs_SetError(int err);
|
||||
int yaffsfs_GetError(void);
|
||||
|
||||
#endif
|
||||
|
1510
fs/yaffs2/yaffsfs.c
Normal file
1510
fs/yaffs2/yaffsfs.c
Normal file
File diff suppressed because it is too large
Load Diff
233
fs/yaffs2/yaffsfs.h
Normal file
233
fs/yaffs2/yaffsfs.h
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Header file for using yaffs in an application via
|
||||
* a direct interface.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __YAFFSFS_H__
|
||||
#define __YAFFSFS_H__
|
||||
|
||||
#include "yaffscfg.h"
|
||||
#include "yportenv.h"
|
||||
|
||||
|
||||
//typedef long off_t;
|
||||
//typedef long dev_t;
|
||||
//typedef unsigned long mode_t;
|
||||
|
||||
|
||||
#ifndef NAME_MAX
|
||||
#define NAME_MAX 256
|
||||
#endif
|
||||
|
||||
#ifndef O_RDONLY
|
||||
#define O_RDONLY 00
|
||||
#endif
|
||||
|
||||
#ifndef O_WRONLY
|
||||
#define O_WRONLY 01
|
||||
#endif
|
||||
|
||||
#ifndef O_RDWR
|
||||
#define O_RDWR 02
|
||||
#endif
|
||||
|
||||
#ifndef O_CREAT
|
||||
#define O_CREAT 0100
|
||||
#endif
|
||||
|
||||
#ifndef O_EXCL
|
||||
#define O_EXCL 0200
|
||||
#endif
|
||||
|
||||
#ifndef O_TRUNC
|
||||
#define O_TRUNC 01000
|
||||
#endif
|
||||
|
||||
#ifndef O_APPEND
|
||||
#define O_APPEND 02000
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_CUR
|
||||
#define SEEK_CUR 1
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_END
|
||||
#define SEEK_END 2
|
||||
#endif
|
||||
|
||||
#ifndef EBUSY
|
||||
#define EBUSY 16
|
||||
#endif
|
||||
|
||||
#ifndef ENODEV
|
||||
#define ENODEV 19
|
||||
#endif
|
||||
|
||||
#ifndef EINVAL
|
||||
#define EINVAL 22
|
||||
#endif
|
||||
|
||||
#ifndef EBADF
|
||||
#define EBADF 9
|
||||
#endif
|
||||
|
||||
#ifndef EACCESS
|
||||
#define EACCESS 13
|
||||
#endif
|
||||
|
||||
#ifndef EXDEV
|
||||
#define EXDEV 18
|
||||
#endif
|
||||
|
||||
#ifndef ENOENT
|
||||
#define ENOENT 2
|
||||
#endif
|
||||
|
||||
#ifndef ENOSPC
|
||||
#define ENOSPC 28
|
||||
#endif
|
||||
|
||||
#ifndef ENOTEMPTY
|
||||
#define ENOTEMPTY 39
|
||||
#endif
|
||||
|
||||
#ifndef ENOMEM
|
||||
#define ENOMEM 12
|
||||
#endif
|
||||
|
||||
#ifndef EEXIST
|
||||
#define EEXIST 17
|
||||
#endif
|
||||
|
||||
#ifndef ENOTDIR
|
||||
#define ENOTDIR 20
|
||||
#endif
|
||||
|
||||
#ifndef EISDIR
|
||||
#define EISDIR 21
|
||||
#endif
|
||||
|
||||
|
||||
// Mode flags
|
||||
|
||||
#ifndef S_IFMT
|
||||
#define S_IFMT 0170000
|
||||
#endif
|
||||
|
||||
#ifndef S_IFLNK
|
||||
#define S_IFLNK 0120000
|
||||
#endif
|
||||
|
||||
#ifndef S_IFDIR
|
||||
#define S_IFDIR 0040000
|
||||
#endif
|
||||
|
||||
#ifndef S_IFREG
|
||||
#define S_IFREG 0100000
|
||||
#endif
|
||||
|
||||
#ifndef S_IREAD
|
||||
#define S_IREAD 0000400
|
||||
#endif
|
||||
|
||||
#ifndef S_IWRITE
|
||||
#define S_IWRITE 0000200
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
struct yaffs_dirent{
|
||||
long d_ino; /* inode number */
|
||||
off_t d_off; /* offset to this dirent */
|
||||
unsigned short d_reclen; /* length of this d_name */
|
||||
char d_name [NAME_MAX+1]; /* file name (null-terminated) */
|
||||
unsigned d_dont_use; /* debug pointer, not for public consumption */
|
||||
};
|
||||
|
||||
typedef struct yaffs_dirent yaffs_dirent;
|
||||
|
||||
|
||||
typedef struct __opaque yaffs_DIR;
|
||||
|
||||
|
||||
|
||||
struct yaffs_stat{
|
||||
int st_dev; /* device */
|
||||
int st_ino; /* inode */
|
||||
mode_t st_mode; /* protection */
|
||||
int st_nlink; /* number of hard links */
|
||||
int st_uid; /* user ID of owner */
|
||||
int st_gid; /* group ID of owner */
|
||||
unsigned st_rdev; /* device type (if inode device) */
|
||||
off_t st_size; /* total size, in bytes */
|
||||
unsigned long st_blksize; /* blocksize for filesystem I/O */
|
||||
unsigned long st_blocks; /* number of blocks allocated */
|
||||
unsigned long yst_atime; /* time of last access */
|
||||
unsigned long yst_mtime; /* time of last modification */
|
||||
unsigned long yst_ctime; /* time of last change */
|
||||
};
|
||||
|
||||
int yaffs_open(const char *path, int oflag, int mode) ;
|
||||
int yaffs_read(int fd, void *buf, unsigned int nbyte) ;
|
||||
int yaffs_write(int fd, const void *buf, unsigned int nbyte) ;
|
||||
int yaffs_close(int fd) ;
|
||||
off_t yaffs_lseek(int fd, off_t offset, int whence) ;
|
||||
int yaffs_truncate(int fd, off_t newSize);
|
||||
|
||||
int yaffs_unlink(const char *path) ;
|
||||
int yaffs_rename(const char *oldPath, const char *newPath) ;
|
||||
|
||||
int yaffs_stat(const char *path, struct yaffs_stat *buf) ;
|
||||
int yaffs_lstat(const char *path, struct yaffs_stat *buf) ;
|
||||
int yaffs_fstat(int fd, struct yaffs_stat *buf) ;
|
||||
|
||||
int yaffs_chmod(const char *path, mode_t mode);
|
||||
int yaffs_fchmod(int fd, mode_t mode);
|
||||
|
||||
int yaffs_mkdir(const char *path, mode_t mode) ;
|
||||
int yaffs_rmdir(const char *path) ;
|
||||
|
||||
yaffs_DIR *yaffs_opendir(const char *dirname) ;
|
||||
struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) ;
|
||||
void yaffs_rewinddir(yaffs_DIR *dirp) ;
|
||||
int yaffs_closedir(yaffs_DIR *dirp) ;
|
||||
|
||||
int yaffs_mount(const char *path) ;
|
||||
int yaffs_unmount(const char *path) ;
|
||||
|
||||
int yaffs_symlink(const char *oldpath, const char *newpath);
|
||||
int yaffs_readlink(const char *path, char *buf, int bufsiz);
|
||||
|
||||
int yaffs_link(const char *oldpath, const char *newpath);
|
||||
int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev);
|
||||
|
||||
loff_t yaffs_freespace(const char *path);
|
||||
|
||||
void yaffs_initialise(yaffsfs_DeviceConfiguration *configList);
|
||||
|
||||
int yaffs_StartUp(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
21
fs/yaffs2/yaffsinterface.h
Normal file
21
fs/yaffs2/yaffsinterface.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFSINTERFACE_H__
|
||||
#define __YAFFSINTERFACE_H__
|
||||
|
||||
int yaffs_Initialise(unsigned nBlocks);
|
||||
|
||||
#endif
|
94
fs/yaffs2/ydirectenv.h
Normal file
94
fs/yaffs2/ydirectenv.h
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ydirectenv.h: Environment wrappers for YAFFS direct.
|
||||
*/
|
||||
|
||||
#ifndef __YDIRECTENV_H__
|
||||
#define __YDIRECTENV_H__
|
||||
|
||||
// Direct interface
|
||||
|
||||
#include "devextras.h"
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
#include "stdlib.h"
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "assert.h"
|
||||
#endif
|
||||
#include "yaffs_malloc.h"
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
#define YBUG() assert(1)
|
||||
#endif
|
||||
|
||||
#define YCHAR char
|
||||
#define YUCHAR unsigned char
|
||||
#define _Y(x) x
|
||||
#define yaffs_strcpy(a,b) strcpy(a,b)
|
||||
#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
|
||||
#define yaffs_strncmp(a,b,c) strncmp(a,b,c)
|
||||
#define yaffs_strlen(s) strlen(s)
|
||||
#define yaffs_sprintf sprintf
|
||||
#define yaffs_toupper(a) toupper(a)
|
||||
|
||||
#ifdef NO_Y_INLINE
|
||||
#define Y_INLINE
|
||||
#else
|
||||
#define Y_INLINE inline
|
||||
#endif
|
||||
|
||||
#define YMALLOC(x) yaffs_malloc(x)
|
||||
#define YFREE(x) free(x)
|
||||
#define YMALLOC_ALT(x) yaffs_malloc(x)
|
||||
#define YFREE_ALT(x) free(x)
|
||||
|
||||
#define YMALLOC_DMA(x) yaffs_malloc(x)
|
||||
|
||||
#define YYIELD() do {} while(0)
|
||||
|
||||
|
||||
|
||||
//#define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s))
|
||||
//#define YALERT(s) YINFO(s)
|
||||
|
||||
|
||||
#define TENDSTR "\n"
|
||||
#define TSTR(x) x
|
||||
#define TOUT(p) printf p
|
||||
|
||||
|
||||
#define YAFFS_LOSTNFOUND_NAME "lost+found"
|
||||
#define YAFFS_LOSTNFOUND_PREFIX "obj"
|
||||
//#define YPRINTF(x) printf x
|
||||
|
||||
#include "yaffscfg.h"
|
||||
|
||||
#define Y_CURRENT_TIME yaffsfs_CurrentTime()
|
||||
#define Y_TIME_CONVERT(x) x
|
||||
|
||||
#define YAFFS_ROOT_MODE 0666
|
||||
#define YAFFS_LOSTNFOUND_MODE 0666
|
||||
|
||||
#define yaffs_SumCompare(x,y) ((x) == (y))
|
||||
#define yaffs_strcmp(a,b) strcmp(a,b)
|
||||
|
||||
#endif
|
||||
|
||||
|
193
fs/yaffs2/yportenv.h
Normal file
193
fs/yaffs2/yportenv.h
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __YPORTENV_H__
|
||||
#define __YPORTENV_H__
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#ifndef CONFIG_YAFFS_DIRECT
|
||||
#define CONFIG_YAFFS_DIRECT
|
||||
#endif
|
||||
|
||||
#if defined CONFIG_YAFFS_WINCE
|
||||
|
||||
#include "ywinceenv.h"
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#elif 0 /* defined __KERNEL__ */
|
||||
|
||||
#include "moduleconfig.h"
|
||||
|
||||
/* Linux kernel */
|
||||
#include <linux/version.h>
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
|
||||
#include <linux/config.h>
|
||||
#endif
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#define YCHAR char
|
||||
#define YUCHAR unsigned char
|
||||
#define _Y(x) x
|
||||
#define yaffs_strcpy(a,b) strcpy(a,b)
|
||||
#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
|
||||
#define yaffs_strncmp(a,b,c) strncmp(a,b,c)
|
||||
#define yaffs_strlen(s) strlen(s)
|
||||
#define yaffs_sprintf sprintf
|
||||
#define yaffs_toupper(a) toupper(a)
|
||||
|
||||
#define Y_INLINE inline
|
||||
|
||||
#define YAFFS_LOSTNFOUND_NAME "lost+found"
|
||||
#define YAFFS_LOSTNFOUND_PREFIX "obj"
|
||||
|
||||
/* #define YPRINTF(x) printk x */
|
||||
#define YMALLOC(x) kmalloc(x,GFP_KERNEL)
|
||||
#define YFREE(x) kfree(x)
|
||||
#define YMALLOC_ALT(x) vmalloc(x)
|
||||
#define YFREE_ALT(x) vfree(x)
|
||||
#define YMALLOC_DMA(x) YMALLOC(x)
|
||||
|
||||
// KR - added for use in scan so processes aren't blocked indefinitely.
|
||||
#define YYIELD() schedule()
|
||||
|
||||
#define YAFFS_ROOT_MODE 0666
|
||||
#define YAFFS_LOSTNFOUND_MODE 0666
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
|
||||
#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
|
||||
#define Y_TIME_CONVERT(x) (x).tv_sec
|
||||
#else
|
||||
#define Y_CURRENT_TIME CURRENT_TIME
|
||||
#define Y_TIME_CONVERT(x) (x)
|
||||
#endif
|
||||
|
||||
#define yaffs_SumCompare(x,y) ((x) == (y))
|
||||
#define yaffs_strcmp(a,b) strcmp(a,b)
|
||||
|
||||
#define TENDSTR "\n"
|
||||
#define TSTR(x) KERN_WARNING x
|
||||
#define TOUT(p) printk p
|
||||
|
||||
#define yaffs_trace(mask, fmt, args...) \
|
||||
do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
|
||||
printk(KERN_WARNING "yaffs: " fmt, ## args); \
|
||||
} while (0)
|
||||
|
||||
#define compile_time_assertion(assertion) \
|
||||
({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
|
||||
|
||||
#elif defined CONFIG_YAFFS_DIRECT
|
||||
|
||||
/* Direct interface */
|
||||
#include "ydirectenv.h"
|
||||
|
||||
#elif defined CONFIG_YAFFS_UTIL
|
||||
|
||||
/* Stuff for YAFFS utilities */
|
||||
|
||||
#include "stdlib.h"
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
|
||||
#include "devextras.h"
|
||||
|
||||
#define YMALLOC(x) malloc(x)
|
||||
#define YFREE(x) free(x)
|
||||
#define YMALLOC_ALT(x) malloc(x)
|
||||
#define YFREE_ALT(x) free(x)
|
||||
|
||||
#define YCHAR char
|
||||
#define YUCHAR unsigned char
|
||||
#define _Y(x) x
|
||||
#define yaffs_strcpy(a,b) strcpy(a,b)
|
||||
#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
|
||||
#define yaffs_strlen(s) strlen(s)
|
||||
#define yaffs_sprintf sprintf
|
||||
#define yaffs_toupper(a) toupper(a)
|
||||
|
||||
#define Y_INLINE inline
|
||||
|
||||
/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */
|
||||
/* #define YALERT(s) YINFO(s) */
|
||||
|
||||
#define TENDSTR "\n"
|
||||
#define TSTR(x) x
|
||||
#define TOUT(p) printf p
|
||||
|
||||
#define YAFFS_LOSTNFOUND_NAME "lost+found"
|
||||
#define YAFFS_LOSTNFOUND_PREFIX "obj"
|
||||
/* #define YPRINTF(x) printf x */
|
||||
|
||||
#define YAFFS_ROOT_MODE 0666
|
||||
#define YAFFS_LOSTNFOUND_MODE 0666
|
||||
|
||||
#define yaffs_SumCompare(x,y) ((x) == (y))
|
||||
#define yaffs_strcmp(a,b) strcmp(a,b)
|
||||
|
||||
#else
|
||||
/* Should have specified a configuration type */
|
||||
#error Unknown configuration
|
||||
|
||||
#endif
|
||||
|
||||
/* see yaffs_fs.c */
|
||||
extern unsigned int yaffs_traceMask;
|
||||
extern unsigned int yaffs_wr_attempts;
|
||||
|
||||
/*
|
||||
* Tracing flags.
|
||||
* The flags masked in YAFFS_TRACE_ALWAYS are always traced.
|
||||
*/
|
||||
|
||||
#define YAFFS_TRACE_OS 0x00000002
|
||||
#define YAFFS_TRACE_ALLOCATE 0x00000004
|
||||
#define YAFFS_TRACE_SCAN 0x00000008
|
||||
#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
|
||||
#define YAFFS_TRACE_ERASE 0x00000020
|
||||
#define YAFFS_TRACE_GC 0x00000040
|
||||
#define YAFFS_TRACE_WRITE 0x00000080
|
||||
#define YAFFS_TRACE_TRACING 0x00000100
|
||||
#define YAFFS_TRACE_DELETION 0x00000200
|
||||
#define YAFFS_TRACE_BUFFERS 0x00000400
|
||||
#define YAFFS_TRACE_NANDACCESS 0x00000800
|
||||
#define YAFFS_TRACE_GC_DETAIL 0x00001000
|
||||
#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
|
||||
#define YAFFS_TRACE_MTD 0x00004000
|
||||
#define YAFFS_TRACE_CHECKPOINT 0x00008000
|
||||
|
||||
#define YAFFS_TRACE_VERIFY 0x00010000
|
||||
#define YAFFS_TRACE_VERIFY_NAND 0x00020000
|
||||
#define YAFFS_TRACE_VERIFY_FULL 0x00040000
|
||||
#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
|
||||
|
||||
|
||||
#define YAFFS_TRACE_ERROR 0x40000000
|
||||
#define YAFFS_TRACE_BUG 0x80000000
|
||||
#define YAFFS_TRACE_ALWAYS 0xF0000000
|
||||
|
||||
|
||||
#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0)
|
||||
|
||||
#ifndef CONFIG_YAFFS_WINCE
|
||||
#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))
|
||||
#endif
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user