diff options
37 files changed, 4604 insertions, 3211 deletions
| diff --git a/board/bf537-stamp/nand.c b/board/bf537-stamp/nand.c index 6ff0f4f96..bdf1d6ee4 100644 --- a/board/bf537-stamp/nand.c +++ b/board/bf537-stamp/nand.c @@ -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;  } diff --git a/board/dave/PPChameleonEVB/nand.c b/board/dave/PPChameleonEVB/nand.c index 09c0b043e..4bc4257c8 100644 --- a/board/dave/PPChameleonEVB/nand.c +++ b/board/dave/PPChameleonEVB/nand.c @@ -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; diff --git a/board/delta/nand.c b/board/delta/nand.c index 5024056bc..51520f5fb 100644 --- a/board/delta/nand.c +++ b/board/delta/nand.c @@ -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;  } diff --git a/board/esd/common/esd405ep_nand.c b/board/esd/common/esd405ep_nand.c index 7bf68473d..4bf81ab4a 100644 --- a/board/esd/common/esd405ep_nand.c +++ b/board/esd/common/esd405ep_nand.c @@ -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; diff --git a/board/freescale/m5329evb/nand.c b/board/freescale/m5329evb/nand.c index 344a61489..f84912e37 100644 --- a/board/freescale/m5329evb/nand.c +++ b/board/freescale/m5329evb/nand.c @@ -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; diff --git a/board/nc650/nand.c b/board/nc650/nand.c index 8617f7445..faec6053f 100644 --- a/board/nc650/nand.c +++ b/board/nc650/nand.c @@ -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; diff --git a/board/netstar/nand.c b/board/netstar/nand.c index b76d2a332..302d78efe 100644 --- a/board/netstar/nand.c +++ b/board/netstar/nand.c @@ -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;  } diff --git a/board/prodrive/alpr/nand.c b/board/prodrive/alpr/nand.c index 097e18371..3224d3dd6 100644 --- a/board/prodrive/alpr/nand.c +++ b/board/prodrive/alpr/nand.c @@ -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) -{ -	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; -	} -} +static void alpr_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{	 +    struct nand_chip *this = mtd->priv; -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 (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)); +	} +	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; diff --git a/board/prodrive/pdnb3/nand.c b/board/prodrive/pdnb3/nand.c index b1e704104..281ae70af 100644 --- a/board/prodrive/pdnb3/nand.c +++ b/board/prodrive/pdnb3/nand.c @@ -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; diff --git a/board/sc3/sc3nand.c b/board/sc3/sc3nand.c index 009567b50..2f2e74589 100644 --- a/board/sc3/sc3nand.c +++ b/board/sc3/sc3nand.c @@ -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; diff --git a/board/tqc/tqm8272/tqm8272.c b/board/tqc/tqm8272/tqm8272.c index cde02961b..5148f3de5 100644 --- a/board/tqc/tqm8272/tqm8272.c +++ b/board/tqc/tqm8272/tqm8272.c @@ -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; diff --git a/board/zylonite/nand.c b/board/zylonite/nand.c index ca1657843..47d5d4b0d 100644 --- a/board/zylonite/nand.c +++ b/board/zylonite/nand.c @@ -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;  } diff --git a/common/cmd_doc.c b/common/cmd_doc.c index d7b2f535f..9d5b3001c 100644 --- a/common/cmd_doc.c +++ b/common/cmd_doc.c @@ -14,6 +14,7 @@  #include <linux/mtd/nftl.h>  #include <linux/mtd/doc2000.h> +#if 0  #ifdef CFG_DOC_SUPPORT_2000  #define DoC_is_2000(doc) (doc->ChipID == DOC_ChipID_Doc2k)  #else @@ -1629,3 +1630,6 @@ void doc_probe(unsigned long physadr)  		puts ("No DiskOnChip found\n");  	}  } +#else +void doc_probe(unsigned long physadr) {} +#endif diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 9e38bf768..3e76d8207 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -18,6 +18,7 @@   *   */  #include <common.h> +#include <linux/mtd/mtd.h>  #if defined(CONFIG_CMD_NAND) @@ -34,7 +35,7 @@  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) @@ -47,32 +48,38 @@ static int nand_dump(nand_info_t *nand, ulong off)  	int i;  	u_char *buf, *p; -	buf = malloc(nand->oobblock + nand->oobsize); +	buf = malloc(nand->writesize + nand->oobsize);  	if (!buf) {  		puts("No memory for page buffer\n");  		return 1;  	} -	off &= ~(nand->oobblock - 1); -	i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize); +	off &= ~(nand->writesize - 1); +#if 0 +	i = nand_read_raw(nand, buf, off, nand->writesize, nand->oobsize); +#else +	size_t dummy; +	loff_t addr = (loff_t) off; +	i = nand->read(nand, addr, nand->writesize, &dummy, buf); +#endif  	if (i < 0) {  		printf("Error (%d) reading page %08lx\n", i, off);  		free(buf);  		return 1;  	}  	printf("Page %08lx dump:\n", off); -	i = nand->oobblock >> 4; p = buf; +	i = nand->writesize >> 4; p = buf;  	while (i--) { -		printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x" -			"  %02x %02x %02x %02x %02x %02x %02x %02x\n", -			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]); +		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); @@ -155,7 +162,7 @@ out:  int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  { -	int i, dev, ret; +	int i, dev, ret = 0;  	ulong addr, off;  	size_t size;  	char *cmd, *s; @@ -182,8 +189,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;  	} @@ -192,11 +199,11 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		if (argc < 3) {  			if ((nand_curr_device < 0) || -			    (nand_curr_device >= CFG_MAX_NAND_DEVICE)) +				(nand_curr_device >= CFG_MAX_NAND_DEVICE))  				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); @@ -219,11 +226,11 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  	}  	if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 && -	    strncmp(cmd, "dump", 4) != 0 && -	    strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 && -	    strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 && -	    strcmp(cmd, "biterr") != 0 && -	    strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 ) +		strncmp(cmd, "dump", 4) != 0 && +		strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 && +		strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 && +		strcmp(cmd, "biterr") != 0 && +		strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 )  		goto usage;  	/* the following commands operate on the current device */ @@ -250,7 +257,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  	if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) {  		nand_erase_options_t opts;  		/* "clean" at index 2 means request to write cleanmarker */ -		int clean = argc > 2 && !strcmp("clean", argv[2]); +		int clean = !strcmp("clean", argv[2]);  		int o = clean ? 3 : 2;  		int scrub = !strcmp(cmd, "scrub"); @@ -260,6 +267,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  			return 1;  		memset(&opts, 0, sizeof(opts)); +  		opts.offset = off;  		opts.length = size;  		opts.jffs2  = clean; @@ -320,40 +328,41 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		printf("\nNAND %s: ", read ? "read" : "write");  		if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)  			return 1; - +		  		s = strchr(cmd, '.');  		if (s != NULL && -		    (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) { +			(!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); +				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; +				mtd_oob_ops_t opts;  				memset(&opts, 0, sizeof(opts)); -				opts.buffer	= (u_char*) addr; -				opts.length	= size; -				opts.offset	= off; -				/* opts.forcejffs2 = 1; */ -				opts.pad	= 1; -				opts.blockalign = 1; -				opts.quiet      = quiet; -				ret = nand_write_opts(nand, &opts); +				opts.datbuf = (u_char*) addr; +				opts.len = size; +				opts.ooblen = 64; +				opts.mode = MTD_OOB_AUTO; +				ret = nand_write_opts(nand, off, &opts);  			}  		} else if (s != NULL && !strcmp(s, ".oob")) { -			/* read out-of-band data */ +			/* out-of-band data */ +			mtd_oob_ops_t ops = { +				.oobbuf = (u8 *)addr, +				.ooblen = size, +				.mode = MTD_OOB_RAW +			}; +  			if (read) -				ret = nand->read_oob(nand, off, size, &size, -						     (u_char *) addr); +				ret = nand->read_oob(nand, off, &ops);  			else -				ret = nand->write_oob(nand, off, size, &size, -						      (u_char *) addr); +				ret = nand->write_oob(nand, off, &ops);  		} else {  			if (read)  				ret = nand_read(nand, off, &size, (u_char *)addr); @@ -397,44 +406,44 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		}  		if (status) { -			ulong block_start = 0; +//			ulong block_start = 0;  			ulong off; -			int last_status = -1; +//			int last_status = -1;  			struct nand_chip *nand_chip = nand->priv;  			/* check the WP bit */  			nand_chip->cmdfunc (nand, NAND_CMD_STATUS, -1, -1);  			printf("device is %swrite protected\n",  			       (nand_chip->read_byte(nand) & 0x80 ? -				"NOT " : "" ) ); - -			for (off = 0; off < nand->size; off += nand->oobblock) { -				int s = nand_get_lock_status(nand, off); - -				/* print message only if status has changed -				 * or at end of chip -				 */ -				if (off == nand->size - nand->oobblock -				    || (s != last_status && off != 0))	{ +			       "NOT " : "" ) ); -					printf("%08lx - %08lx: %8lu pages %s%s%s\n", -					       block_start, -					       off-1, -					       (off-block_start)/nand->oobblock, -					       ((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""), -					       ((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""), -					       ((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : "")); -				} - -				last_status = s; -		       } -		} else { -			if (!nand_lock(nand, tight)) { -				puts("NAND flash successfully locked\n"); -			} else { -				puts("Error locking NAND flash\n"); -				return 1; +			for (off = 0; off < nand->size; off += nand->writesize) { +//				int s = nand_get_lock_status(nand, off); +// +//				/* print message only if status has changed +//				 * or at end of chip +//				 */ +//				if (off == nand->size - nand->writesize +//				    || (s != last_status && off != 0))	{ +// +//					printf("%08lx - %08lx: %8d pages %s%s%s\n", +//					       block_start, +//					       off-1, +//					       (off-block_start)/nand->writesize, +//					       ((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""), +//					       ((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""), +//					       ((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : "")); +//				} +// +//				last_status = s;  			} +		} else { +//			if (!nand_lock(nand, tight)) { +//				puts("NAND flash successfully locked\n"); +//			} else { +//				puts("Error locking NAND flash\n"); +//				return 1; +//			}  		}  		return 0;  	} @@ -443,13 +452,13 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)  			return 1; -		if (!nand_unlock(nand, off, size)) { -			puts("NAND flash successfully unlocked\n"); -		} else { -			puts("Error unlocking NAND flash, " -			     "write and erase will probably fail\n"); -			return 1; -		} +//		if (!nand_unlock(nand, off, size)) { +//			puts("NAND flash successfully unlocked\n"); +//		} else { +//			puts("Error unlocking NAND flash, " +//			     "write and erase will probably fail\n"); +//			return 1; +//		}  		return 0;  	} @@ -459,24 +468,26 @@ 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[.jffs2] - addr off|partition size\n" +           "nand write[.jffs2] - addr off|partition size\n" +           "    read/write 'size' bytes starting at offset 'off'\n" +           "    to/from memory address 'addr'\n" +           "nand erase [clean] [off size] - erase 'size' bytes from\n" +           "    offset 'off' (entire device if not specified)\n" +           "nand bad - show bad blocks\n" +           "nand dump[.oob] off - dump page\n" +           "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n" +           "nand markbad off - mark bad block at offset (UNSAFE)\n" +           "nand biterr off - make a bit error at offset (UNSAFE)\n" +           "nand lock [tight] [status]\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; @@ -494,19 +505,8 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,  	printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset); -	cnt = nand->oobblock; -	if (jffs2) { -		nand_read_options_t opts; -		memset(&opts, 0, sizeof(opts)); -		opts.buffer	= (u_char*) addr; -		opts.length	= cnt; -		opts.offset	= offset; -		opts.quiet      = 1; -		r = nand_read_opts(nand, &opts); -	} else { -		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); @@ -537,18 +537,7 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,  		return 1;  	} -	if (jffs2) { -		nand_read_options_t opts; -		memset(&opts, 0, sizeof(opts)); -		opts.buffer	= (u_char*) addr; -		opts.length	= cnt; -		opts.offset	= offset; -		opts.quiet      = 1; -		r = nand_read_opts(nand, &opts); -	} else { -		r = nand_read(nand, offset, &cnt, (u_char *) addr); -	} - +	r = nand_read(nand, offset, &cnt, (u_char *) addr);  	if (r) {  		puts("** Read error\n");  		show_boot_progress (-58); @@ -614,7 +603,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 @@ -704,8 +693,8 @@ void archflashwp(void *archdata, int wp);  #define ROUND_DOWN(value,boundary)      ((value) & (~((boundary)-1))) -#undef	NAND_DEBUG -#undef	PSYCHO_DEBUG +#undef  NAND_DEBUG +#undef  PSYCHO_DEBUG  /* ****************** WARNING *********************   * When ALLOW_ERASE_BAD_DEBUG is non-zero the erase command will @@ -720,16 +709,16 @@ void archflashwp(void *archdata, int wp);   * and attempting to program or erase bad blocks can affect   * the data in _other_ (good) blocks.   */ -#define	 ALLOW_ERASE_BAD_DEBUG 0 +#define  ALLOW_ERASE_BAD_DEBUG 0  #define CONFIG_MTD_NAND_ECC  /* enable ECC */  #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 @@ -737,15 +726,15 @@ void archflashwp(void *archdata, int wp);  extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];  extern int curr_device;  extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs, -			    size_t len, int clean); +                size_t len, int clean);  extern int nand_legacy_rw(struct nand_chip *nand, int cmd, size_t start, -			 size_t len, size_t *retlen, u_char *buf); +             size_t len, size_t *retlen, u_char *buf);  extern void nand_print(struct nand_chip *nand);  extern void nand_print_bad(struct nand_chip *nand);  extern int nand_read_oob(struct nand_chip *nand, size_t ofs, -			       size_t len, size_t *retlen, u_char *buf); +                   size_t len, size_t *retlen, u_char *buf);  extern int nand_write_oob(struct nand_chip *nand, size_t ofs, -				size_t len, size_t *retlen, const u_char *buf); +                size_t len, size_t *retlen, const u_char *buf);  int do_nand (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) @@ -878,7 +867,7 @@ int do_nand (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  			else if (cmdtail && !strcmp (cmdtail, ".i")) {  				cmd |= NANDRW_JFFS2;	/* skip bad blocks (on read too) */  				if (cmd & NANDRW_READ) -					cmd |= NANDRW_JFFS2_SKIP;	/* skip bad blocks (on read too) */ +					cmd |= NANDRW_JFFS2_SKIP;   /* skip bad blocks (on read too) */  			}  #endif /* CFG_NAND_SKIP_BAD_DOT_I */  			else if (cmdtail) { @@ -928,7 +917,7 @@ int do_nand (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  }  U_BOOT_CMD( -	nand,	5,	1,	do_nand, +	nand,   5,  1,  do_nand,  	"nand    - legacy NAND sub-system\n",  	"info  - show available NAND devices\n"  	"nand device [dev] - show or set current device\n" @@ -992,7 +981,7 @@ int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  	dev = simple_strtoul(boot_device, &ep, 16);  	if ((dev >= CFG_MAX_NAND_DEVICE) || -	    (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN)) { +		(nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN)) {  		printf ("\n** Device %d not available\n", dev);  		show_boot_progress (-55);  		return 1; @@ -1000,11 +989,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 +1024,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; @@ -1077,7 +1066,7 @@ int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  }  U_BOOT_CMD( -	nboot,	4,	1,	do_nandboot, +	nboot,  4,  1,  do_nandboot,  	"nboot   - boot from NAND device\n",  	"loadAddr dev\n"  ); diff --git a/cpu/arm926ejs/davinci/nand.c b/cpu/arm926ejs/davinci/nand.c index 36468e6c3..43041b635 100644 --- a/cpu/arm926ejs/davinci/nand.c +++ b/cpu/arm926ejs/davinci/nand.c @@ -42,6 +42,7 @@   */  #include <common.h> +#include <asm/io.h>  #ifdef CFG_USE_NAND  #if !defined(CFG_NAND_LEGACY) @@ -52,23 +53,23 @@  extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; -static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd) +static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)  {  	struct		nand_chip *this = mtd->priv;  	u_int32_t	IO_ADDR_W = (u_int32_t)this->IO_ADDR_W;  	IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); -	switch (cmd) { -		case NAND_CTL_SETCLE: +	if (ctrl & NAND_CTRL_CHANGE) { +		if ( ctrl & NAND_CLE )  			IO_ADDR_W |= MASK_CLE; -			break; -		case NAND_CTL_SETALE: +		if ( ctrl & NAND_ALE )  			IO_ADDR_W |= MASK_ALE; -			break; +		this->IO_ADDR_W = (void __iomem *) IO_ADDR_W;  	} -	this->IO_ADDR_W = (void *)IO_ADDR_W; +    if (cmd != NAND_CMD_NONE) +		writeb(cmd, this->IO_ADDR_W);  }  /* Set WP on deselect, write enable on select */ @@ -145,7 +146,7 @@ static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u  	int			region, n;  	struct nand_chip	*this = mtd->priv; -	n = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1; +	n = (this->ecc.size/512);  	region = 1;  	while (n--) { @@ -281,7 +282,7 @@ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char *  	int			block_count = 0, i, rc;  	this = mtd->priv; -	block_count = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1; +	block_count = (this->ecc.size/512);  	for (i = 0; i < block_count; i++) {  		if (memcmp(read_ecc, calc_ecc, 3) != 0) {  			rc = nand_davinci_compare_ecc(read_ecc, calc_ecc, dat); @@ -306,7 +307,7 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd)  	return(emif_addr->NANDFSR & 0x1);  } -static int nand_davinci_waitfunc(struct mtd_info *mtd, struct nand_chip *this, int state) +static int nand_davinci_waitfunc(struct mtd_info *mtd, struct nand_chip *this)  {  	while(!nand_davinci_dev_ready(mtd)) {;}  	*NAND_CE0CLE = NAND_STATUS; @@ -362,22 +363,26 @@ int board_nand_init(struct nand_chip *nand)  #endif  #ifdef CFG_NAND_HW_ECC  #ifdef CFG_NAND_LARGEPAGE -	nand->eccmode     = NAND_ECC_HW12_2048; +	nand->ecc.mode     = NAND_ECC_HW; +    nand->ecc.size = 2048; +    nand->ecc.bytes = 12;  #elif defined(CFG_NAND_SMALLPAGE) -	nand->eccmode     = NAND_ECC_HW3_512; +	nand->ecc.mode     = NAND_ECC_HW; +    nand->ecc.size = 512; +    nand->ecc.bytes = 3;  #else  #error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!"  #endif -	nand->autooob	  = &davinci_nand_oobinfo; -	nand->calculate_ecc = nand_davinci_calculate_ecc; -	nand->correct_data  = nand_davinci_correct_data; -	nand->enable_hwecc  = nand_davinci_enable_hwecc; +//	nand->autooob	  = &davinci_nand_oobinfo; +	nand->ecc.calculate = nand_davinci_calculate_ecc; +	nand->ecc.correct  = nand_davinci_correct_data; +	nand->ecc.hwctl  = nand_davinci_enable_hwecc;	  #else -	nand->eccmode     = NAND_ECC_SOFT; +	nand->ecc.mode     = NAND_ECC_SOFT;  #endif  	/* Set address of hardware control function */ -	nand->hwcontrol = nand_davinci_hwcontrol; +	nand->cmd_ctrl = nand_davinci_hwcontrol;  	nand->dev_ready = nand_davinci_dev_ready;  	nand->waitfunc = nand_davinci_waitfunc; diff --git a/cpu/ppc4xx/ndfc.c b/cpu/ppc4xx/ndfc.c index 5b2ae88d9..7818eb9c5 100644 --- a/cpu/ppc4xx/ndfc.c +++ b/cpu/ppc4xx/ndfc.c @@ -46,38 +46,22 @@  static u8 hwctl = 0; -static void ndfc_hwcontrol(struct mtd_info *mtdinfo, int cmd) +static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)  { -	switch (cmd) { -	case NAND_CTL_SETCLE: -		hwctl |= 0x1; -		break; +    struct nand_chip *this = mtd->priv; -	case NAND_CTL_CLRCLE: -		hwctl &= ~0x1; -		break; - -	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;  	} -} - -static void ndfc_write_byte(struct mtd_info *mtdinfo, u_char byte) -{ -	struct nand_chip *this = mtdinfo->priv; -	ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc; - -	if (hwctl & 0x1) -		out_8((u8 *)(base + NDFC_CMD), byte); -	else if (hwctl & 0x2) -		out_8((u8 *)(base + NDFC_ALE), byte); -	else -		out_8((u8 *)(base + NDFC_DATA), byte); +	if (cmd != NAND_CMD_NONE) +		writeb(cmd, this->IO_ADDR_W);  }  static u_char ndfc_read_byte(struct mtd_info *mtdinfo) @@ -194,16 +178,17 @@ int board_nand_init(struct nand_chip *nand)  	int cs = (ulong)nand->IO_ADDR_W & 0x00000003;  	ulong base = (ulong)nand->IO_ADDR_W & 0xfffffffc; -	nand->hwcontrol  = ndfc_hwcontrol; +	nand->cmd_ctrl  = ndfc_hwcontrol;  	nand->read_byte  = ndfc_read_byte;  	nand->read_buf   = ndfc_read_buf; -	nand->write_byte = ndfc_write_byte;  	nand->dev_ready  = ndfc_dev_ready; -	nand->eccmode = NAND_ECC_HW3_256; -	nand->enable_hwecc = ndfc_enable_hwecc; -	nand->calculate_ecc = ndfc_calculate_ecc; -	nand->correct_data = nand_correct_data; +    nand->ecc.correct = nand_correct_data; +    nand->ecc.hwctl = ndfc_enable_hwecc; +    nand->ecc.calculate = ndfc_calculate_ecc; +    nand->ecc.mode = NAND_ECC_HW; +    nand->ecc.size = 256; +    nand->ecc.bytes = 3;  #ifndef CONFIG_NAND_SPL  	nand->write_buf  = ndfc_write_buf; diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index fdd85c159..a03f982be 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -16,7 +16,7 @@   *   * Interface to generic NAND code for M-Systems DiskOnChip devices   * - * $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $ + * $Id: diskonchip.c,v 1.55 2005/11/07 11:14:30 gleixner Exp $   */  #include <common.h> @@ -39,13 +39,13 @@  #include <linux/mtd/inftl.h>  /* Where to look for the devices? */ -#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS -#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0 +#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS +#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0  #endif  static unsigned long __initdata doc_locations[] = {  #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) -#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH +#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH  	0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,  	0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,  	0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, @@ -65,7 +65,7 @@ static unsigned long __initdata doc_locations[] = {  	0xff000000,  #elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)  	0xff000000, -##else +#else  #warning Unknown architecture for DiskOnChip. No default probe locations defined  #endif  	0xffffffff }; @@ -77,7 +77,7 @@ struct doc_priv {  	unsigned long physadr;  	u_char ChipID;  	u_char CDSNControl; -	int chips_per_floor; /* The number of chips detected on each floor */ +	int chips_per_floor;	/* The number of chips detected on each floor */  	int curfloor;  	int curchip;  	int mh0_page; @@ -85,14 +85,10 @@ struct doc_priv {  	struct mtd_info *nextdoc;  }; -/* Max number of eraseblocks to scan (from start of device) for the (I)NFTL -   MediaHeader.  The spec says to just keep going, I think, but that's just -   silly. */ -#define MAX_MEDIAHEADER_SCAN 8 -  /* This is the syndrome computed by the HW ecc generator upon reading an empty     page, one with all 0xff for data and stored ecc code. */  static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a }; +  /* This is the ecc value computed by the HW ecc generator upon writing an empty     page, one with all 0xff for data. */  static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 }; @@ -103,35 +99,36 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };  #define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)  #define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k) -static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd); +static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd, +			      unsigned int bitmask);  static void doc200x_select_chip(struct mtd_info *mtd, int chip); -static int debug=0; +static int debug = 0;  module_param(debug, int, 0); -static int try_dword=1; +static int try_dword = 1;  module_param(try_dword, int, 0); -static int no_ecc_failures=0; +static int no_ecc_failures = 0;  module_param(no_ecc_failures, int, 0); -#ifdef CONFIG_MTD_PARTITIONS -static int no_autopart=0; +static int no_autopart = 0;  module_param(no_autopart, int, 0); -#endif -#ifdef MTD_NAND_DISKONCHIP_BBTWRITE -static int inftl_bbt_write=1; +static int show_firmware_partition = 0; +module_param(show_firmware_partition, int, 0); + +#ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE +static int inftl_bbt_write = 1;  #else -static int inftl_bbt_write=0; +static int inftl_bbt_write = 0;  #endif  module_param(inftl_bbt_write, int, 0); -static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS; +static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;  module_param(doc_config_location, ulong, 0);  MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip"); -  /* Sector size for HW ECC */  #define SECTOR_SIZE 512  /* The sector bytes are packed into NB_DATA 10 bit words */ @@ -155,7 +152,7 @@ static struct rs_control *rs_decoder;   * some comments, improved a minor bit and converted it to make use   * of the generic Reed-Solomon libary. tglx   */ -static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) +static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)  {  	int i, j, nerr, errpos[8];  	uint8_t parity; @@ -176,11 +173,11 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)  	 *  s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]  	 *  where x = alpha^(FCR + i)  	 */ -	for(j = 1; j < NROOTS; j++) { -		if(ds[j] == 0) +	for (j = 1; j < NROOTS; j++) { +		if (ds[j] == 0)  			continue;  		tmp = rs->index_of[ds[j]]; -		for(i = 0; i < NROOTS; i++) +		for (i = 0; i < NROOTS; i++)  			s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)];  	} @@ -201,7 +198,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)  	 * but they are given by the design of the de/encoder circuit  	 * in the DoC ASIC's.  	 */ -	for(i = 0;i < nerr; i++) { +	for (i = 0; i < nerr; i++) {  		int index, bitpos, pos = 1015 - errpos[i];  		uint8_t val;  		if (pos >= NB_DATA && pos < 1019) @@ -213,8 +210,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)  			   can be modified since pos is even */  			index = (pos >> 3) ^ 1;  			bitpos = pos & 7; -			if ((index >= 0 && index < SECTOR_SIZE) || -			    index == (SECTOR_SIZE + 1)) { +			if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {  				val = (uint8_t) (errval[i] >> (2 + bitpos));  				parity ^= val;  				if (index < SECTOR_SIZE) @@ -224,9 +220,8 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)  			bitpos = (bitpos + 10) & 7;  			if (bitpos == 0)  				bitpos = 8; -			if ((index >= 0 && index < SECTOR_SIZE) || -			    index == (SECTOR_SIZE + 1)) { -				val = (uint8_t)(errval[i] << (8 - bitpos)); +			if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) { +				val = (uint8_t) (errval[i] << (8 - bitpos));  				parity ^= val;  				if (index < SECTOR_SIZE)  					data[index] ^= val; @@ -261,7 +256,8 @@ static int _DoC_WaitReady(struct doc_priv *doc)  	void __iomem *docptr = doc->virtadr;  	unsigned long timeo = jiffies + (HZ * 10); -	if(debug) printk("_DoC_WaitReady...\n"); +	if (debug) +		printk("_DoC_WaitReady...\n");  	/* Out-of-line routine to wait for chip response */  	if (DoC_is_MillenniumPlus(doc)) {  		while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) { @@ -306,7 +302,8 @@ static inline int DoC_WaitReady(struct doc_priv *doc)  		DoC_Delay(doc, 2);  	} -	if(debug) printk("DoC_WaitReady OK\n"); +	if (debug) +		printk("DoC_WaitReady OK\n");  	return ret;  } @@ -316,7 +313,8 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)  	struct doc_priv *doc = this->priv;  	void __iomem *docptr = doc->virtadr; -	if(debug)printk("write_byte %02x\n", datum); +	if (debug) +		printk("write_byte %02x\n", datum);  	WriteDOC(datum, docptr, CDSNSlowIO);  	WriteDOC(datum, docptr, 2k_CDSN_IO);  } @@ -331,37 +329,39 @@ static u_char doc2000_read_byte(struct mtd_info *mtd)  	ReadDOC(docptr, CDSNSlowIO);  	DoC_Delay(doc, 2);  	ret = ReadDOC(docptr, 2k_CDSN_IO); -	if (debug) printk("read_byte returns %02x\n", ret); +	if (debug) +		printk("read_byte returns %02x\n", ret);  	return ret;  } -static void doc2000_writebuf(struct mtd_info *mtd, -			     const u_char *buf, int len) +static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv;  	void __iomem *docptr = doc->virtadr;  	int i; -	if (debug)printk("writebuf of %d bytes: ", len); -	for (i=0; i < len; i++) { +	if (debug) +		printk("writebuf of %d bytes: ", len); +	for (i = 0; i < len; i++) {  		WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i);  		if (debug && i < 16)  			printk("%02x ", buf[i]);  	} -	if (debug) printk("\n"); +	if (debug) +		printk("\n");  } -static void doc2000_readbuf(struct mtd_info *mtd, -			    u_char *buf, int len) +static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv;  	void __iomem *docptr = doc->virtadr;  	int i; -	if (debug)printk("readbuf of %d bytes: ", len); +	if (debug) +		printk("readbuf of %d bytes: ", len); -	for (i=0; i < len; i++) { +	for (i = 0; i < len; i++) {  		buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);  	}  } @@ -374,28 +374,28 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd,  	void __iomem *docptr = doc->virtadr;  	int i; -	if (debug) printk("readbuf_dword of %d bytes: ", len); +	if (debug) +		printk("readbuf_dword of %d bytes: ", len); -	if (unlikely((((unsigned long)buf)|len) & 3)) { -		for (i=0; i < len; i++) { -			*(uint8_t *)(&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i); +	if (unlikely((((unsigned long)buf) | len) & 3)) { +		for (i = 0; i < len; i++) { +			*(uint8_t *) (&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i);  		}  	} else { -		for (i=0; i < len; i+=4) { -			*(uint32_t*)(&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i); +		for (i = 0; i < len; i += 4) { +			*(uint32_t*) (&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i);  		}  	}  } -static int doc2000_verifybuf(struct mtd_info *mtd, -			      const u_char *buf, int len) +static int doc2000_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv;  	void __iomem *docptr = doc->virtadr;  	int i; -	for (i=0; i < len; i++) +	for (i = 0; i < len; i++)  		if (buf[i] != ReadDOC(docptr, 2k_CDSN_IO))  			return -EFAULT;  	return 0; @@ -408,12 +408,15 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)  	uint16_t ret;  	doc200x_select_chip(mtd, nr); -	doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); -	this->write_byte(mtd, NAND_CMD_READID); -	doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); -	doc200x_hwcontrol(mtd, NAND_CTL_SETALE); -	this->write_byte(mtd, 0); -	doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); +	doc200x_hwcontrol(mtd, NAND_CMD_READID, +			  NAND_CTRL_CLE | NAND_CTRL_CHANGE); +	doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); +	doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + +	/* We cant' use dev_ready here, but at least we wait for the +	 * command to complete +	 */ +	udelay(50);  	ret = this->read_byte(mtd) << 8;  	ret |= this->read_byte(mtd); @@ -426,12 +429,13 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)  		} ident;  		void __iomem *docptr = doc->virtadr; -		doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); -		doc2000_write_byte(mtd, NAND_CMD_READID); -		doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); -		doc200x_hwcontrol(mtd, NAND_CTL_SETALE); -		doc2000_write_byte(mtd, 0); -		doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); +		doc200x_hwcontrol(mtd, NAND_CMD_READID, +				  NAND_CTRL_CLE | NAND_CTRL_CHANGE); +		doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); +		doc200x_hwcontrol(mtd, NAND_CMD_NONE, +				  NAND_NCE | NAND_CTRL_CHANGE); + +		udelay(50);  		ident.dword = readl(docptr + DoC_2k_CDSN_IO);  		if (((ident.byte[0] << 8) | ident.byte[1]) == ret) { @@ -465,7 +469,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd)  	printk(KERN_DEBUG "Detected %d chips per floor.\n", i);  } -static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state) +static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)  {  	struct doc_priv *doc = this->priv; @@ -496,30 +500,28 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)  	struct doc_priv *doc = this->priv;  	void __iomem *docptr = doc->virtadr; -	/*ReadDOC(docptr, CDSNSlowIO); */ +	//ReadDOC(docptr, CDSNSlowIO);  	/* 11.4.5 -- delay twice to allow extended length cycle */  	DoC_Delay(doc, 2);  	ReadDOC(docptr, ReadPipeInit); -	/*return ReadDOC(docptr, Mil_CDSN_IO); */ +	//return ReadDOC(docptr, Mil_CDSN_IO);  	return ReadDOC(docptr, LastDataRead);  } -static void doc2001_writebuf(struct mtd_info *mtd, -			     const u_char *buf, int len) +static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv;  	void __iomem *docptr = doc->virtadr;  	int i; -	for (i=0; i < len; i++) +	for (i = 0; i < len; i++)  		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);  	/* Terminate write pipeline */  	WriteDOC(0x00, docptr, WritePipeTerm);  } -static void doc2001_readbuf(struct mtd_info *mtd, -			    u_char *buf, int len) +static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv; @@ -529,15 +531,14 @@ static void doc2001_readbuf(struct mtd_info *mtd,  	/* Start read pipeline */  	ReadDOC(docptr, ReadPipeInit); -	for (i=0; i < len-1; i++) +	for (i = 0; i < len - 1; i++)  		buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));  	/* Terminate read pipeline */  	buf[i] = ReadDOC(docptr, LastDataRead);  } -static int doc2001_verifybuf(struct mtd_info *mtd, -			     const u_char *buf, int len) +static int doc2001_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv; @@ -547,7 +548,7 @@ static int doc2001_verifybuf(struct mtd_info *mtd,  	/* Start read pipeline */  	ReadDOC(docptr, ReadPipeInit); -	for (i=0; i < len-1; i++) +	for (i = 0; i < len - 1; i++)  		if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) {  			ReadDOC(docptr, LastDataRead);  			return i; @@ -567,81 +568,84 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd)  	ReadDOC(docptr, Mplus_ReadPipeInit);  	ReadDOC(docptr, Mplus_ReadPipeInit);  	ret = ReadDOC(docptr, Mplus_LastDataRead); -	if (debug) printk("read_byte returns %02x\n", ret); +	if (debug) +		printk("read_byte returns %02x\n", ret);  	return ret;  } -static void doc2001plus_writebuf(struct mtd_info *mtd, -			     const u_char *buf, int len) +static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv;  	void __iomem *docptr = doc->virtadr;  	int i; -	if (debug)printk("writebuf of %d bytes: ", len); -	for (i=0; i < len; i++) { +	if (debug) +		printk("writebuf of %d bytes: ", len); +	for (i = 0; i < len; i++) {  		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);  		if (debug && i < 16)  			printk("%02x ", buf[i]);  	} -	if (debug) printk("\n"); +	if (debug) +		printk("\n");  } -static void doc2001plus_readbuf(struct mtd_info *mtd, -			    u_char *buf, int len) +static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv;  	void __iomem *docptr = doc->virtadr;  	int i; -	if (debug)printk("readbuf of %d bytes: ", len); +	if (debug) +		printk("readbuf of %d bytes: ", len);  	/* Start read pipeline */  	ReadDOC(docptr, Mplus_ReadPipeInit);  	ReadDOC(docptr, Mplus_ReadPipeInit); -	for (i=0; i < len-2; i++) { +	for (i = 0; i < len - 2; i++) {  		buf[i] = ReadDOC(docptr, Mil_CDSN_IO);  		if (debug && i < 16)  			printk("%02x ", buf[i]);  	}  	/* Terminate read pipeline */ -	buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead); +	buf[len - 2] = ReadDOC(docptr, Mplus_LastDataRead);  	if (debug && i < 16) -		printk("%02x ", buf[len-2]); -	buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead); +		printk("%02x ", buf[len - 2]); +	buf[len - 1] = ReadDOC(docptr, Mplus_LastDataRead);  	if (debug && i < 16) -		printk("%02x ", buf[len-1]); -	if (debug) printk("\n"); +		printk("%02x ", buf[len - 1]); +	if (debug) +		printk("\n");  } -static int doc2001plus_verifybuf(struct mtd_info *mtd, -			     const u_char *buf, int len) +static int doc2001plus_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv;  	void __iomem *docptr = doc->virtadr;  	int i; -	if (debug)printk("verifybuf of %d bytes: ", len); +	if (debug) +		printk("verifybuf of %d bytes: ", len);  	/* Start read pipeline */  	ReadDOC(docptr, Mplus_ReadPipeInit);  	ReadDOC(docptr, Mplus_ReadPipeInit); -	for (i=0; i < len-2; i++) +	for (i = 0; i < len - 2; i++)  		if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) {  			ReadDOC(docptr, Mplus_LastDataRead);  			ReadDOC(docptr, Mplus_LastDataRead);  			return i;  		} -	if (buf[len-2] != ReadDOC(docptr, Mplus_LastDataRead)) -		return len-2; -	if (buf[len-1] != ReadDOC(docptr, Mplus_LastDataRead)) -		return len-1; +	if (buf[len - 2] != ReadDOC(docptr, Mplus_LastDataRead)) +		return len - 2; +	if (buf[len - 1] != ReadDOC(docptr, Mplus_LastDataRead)) +		return len - 1;  	return 0;  } @@ -652,7 +656,8 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)  	void __iomem *docptr = doc->virtadr;  	int floor = 0; -	if(debug)printk("select chip (%d)\n", chip); +	if (debug) +		printk("select chip (%d)\n", chip);  	if (chip == -1) {  		/* Disable flash internally */ @@ -661,7 +666,7 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)  	}  	floor = chip / doc->chips_per_floor; -	chip -= (floor *  doc->chips_per_floor); +	chip -= (floor * doc->chips_per_floor);  	/* Assert ChipEnable and deassert WriteProtect */  	WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect); @@ -678,65 +683,54 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)  	void __iomem *docptr = doc->virtadr;  	int floor = 0; -	if(debug)printk("select chip (%d)\n", chip); +	if (debug) +		printk("select chip (%d)\n", chip);  	if (chip == -1)  		return;  	floor = chip / doc->chips_per_floor; -	chip -= (floor *  doc->chips_per_floor); +	chip -= (floor * doc->chips_per_floor);  	/* 11.4.4 -- deassert CE before changing chip */ -	doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE); +	doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);  	WriteDOC(floor, docptr, FloorSelect);  	WriteDOC(chip, docptr, CDSNDeviceSelect); -	doc200x_hwcontrol(mtd, NAND_CTL_SETNCE); +	doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);  	doc->curchip = chip;  	doc->curfloor = floor;  } -static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd) +#define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE) + +static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd, +			      unsigned int ctrl)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv;  	void __iomem *docptr = doc->virtadr; -	switch(cmd) { -	case NAND_CTL_SETNCE: -		doc->CDSNControl |= CDSN_CTRL_CE; -		break; -	case NAND_CTL_CLRNCE: -		doc->CDSNControl &= ~CDSN_CTRL_CE; -		break; -	case NAND_CTL_SETCLE: -		doc->CDSNControl |= CDSN_CTRL_CLE; -		break; -	case NAND_CTL_CLRCLE: -		doc->CDSNControl &= ~CDSN_CTRL_CLE; -		break; -	case NAND_CTL_SETALE: -		doc->CDSNControl |= CDSN_CTRL_ALE; -		break; -	case NAND_CTL_CLRALE: -		doc->CDSNControl &= ~CDSN_CTRL_ALE; -		break; -	case NAND_CTL_SETWP: -		doc->CDSNControl |= CDSN_CTRL_WP; -		break; -	case NAND_CTL_CLRWP: -		doc->CDSNControl &= ~CDSN_CTRL_WP; -		break; +	if (ctrl & NAND_CTRL_CHANGE) { +		doc->CDSNControl &= ~CDSN_CTRL_MSK; +		doc->CDSNControl |= ctrl & CDSN_CTRL_MSK; +		if (debug) +			printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl); +		WriteDOC(doc->CDSNControl, docptr, CDSNControl); +		/* 11.4.3 -- 4 NOPs after CSDNControl write */ +		DoC_Delay(doc, 4); +	} +	if (cmd != NAND_CMD_NONE) { +		if (DoC_is_2000(doc)) +			doc2000_write_byte(mtd, cmd); +		else +			doc2001_write_byte(mtd, cmd);  	} -	if (debug)printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl); -	WriteDOC(doc->CDSNControl, docptr, CDSNControl); -	/* 11.4.3 -- 4 NOPs after CSDNControl write */ -	DoC_Delay(doc, 4);  } -static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) +static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv; @@ -757,9 +751,9 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col  	if (command == NAND_CMD_SEQIN) {  		int readcmd; -		if (column >= mtd->oobblock) { +		if (column >= mtd->writesize) {  			/* OOB area */ -			column -= mtd->oobblock; +			column -= mtd->writesize;  			readcmd = NAND_CMD_READOOB;  		} else if (column < 256) {  			/* First 256 bytes --> READ0 */ @@ -783,25 +777,26 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col  			WriteDOC(column, docptr, Mplus_FlashAddress);  		}  		if (page_addr != -1) { -			WriteDOC((unsigned char) (page_addr & 0xff), docptr, Mplus_FlashAddress); -			WriteDOC((unsigned char) ((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress); +			WriteDOC((unsigned char)(page_addr & 0xff), docptr, Mplus_FlashAddress); +			WriteDOC((unsigned char)((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress);  			/* One more address cycle for higher density devices */  			if (this->chipsize & 0x0c000000) { -				WriteDOC((unsigned char) ((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress); +				WriteDOC((unsigned char)((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress);  				printk("high density\n");  			}  		}  		WriteDOC(0, docptr, Mplus_WritePipeTerm);  		WriteDOC(0, docptr, Mplus_WritePipeTerm);  		/* deassert ALE */ -		if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || command == NAND_CMD_READOOB || command == NAND_CMD_READID) +		if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || +		    command == NAND_CMD_READOOB || command == NAND_CMD_READID)  			WriteDOC(0, docptr, Mplus_FlashControl);  	}  	/*  	 * program and erase have their own busy handlers  	 * status and sequential in needs no delay -	*/ +	 */  	switch (command) {  	case NAND_CMD_PAGEPROG: @@ -818,26 +813,26 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col  		WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd);  		WriteDOC(0, docptr, Mplus_WritePipeTerm);  		WriteDOC(0, docptr, Mplus_WritePipeTerm); -		while ( !(this->read_byte(mtd) & 0x40)); +		while (!(this->read_byte(mtd) & 0x40)) ;  		return; -	/* This applies to read commands */ +		/* This applies to read commands */  	default:  		/*  		 * If we don't have access to the busy pin, we apply the given  		 * command delay -		*/ +		 */  		if (!this->dev_ready) { -			udelay (this->chip_delay); +			udelay(this->chip_delay);  			return;  		}  	}  	/* Apply this short delay always to ensure that we do wait tWB in  	 * any case on any machine. */ -	ndelay (100); +	ndelay(100);  	/* wait until command is processed */ -	while (!this->dev_ready(mtd)); +	while (!this->dev_ready(mtd)) ;  }  static int doc200x_dev_ready(struct mtd_info *mtd) @@ -850,23 +845,25 @@ static int doc200x_dev_ready(struct mtd_info *mtd)  		/* 11.4.2 -- must NOP four times before checking FR/B# */  		DoC_Delay(doc, 4);  		if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) { -			if(debug) +			if (debug)  				printk("not ready\n");  			return 0;  		} -		if (debug)printk("was ready\n"); +		if (debug) +			printk("was ready\n");  		return 1;  	} else {  		/* 11.4.2 -- must NOP four times before checking FR/B# */  		DoC_Delay(doc, 4);  		if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { -			if(debug) +			if (debug)  				printk("not ready\n");  			return 0;  		}  		/* 11.4.2 -- Must NOP twice if it's ready */  		DoC_Delay(doc, 2); -		if (debug)printk("was ready\n"); +		if (debug) +			printk("was ready\n");  		return 1;  	}  } @@ -885,7 +882,7 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)  	void __iomem *docptr = doc->virtadr;  	/* Prime the ECC engine */ -	switch(mode) { +	switch (mode) {  	case NAND_ECC_READ:  		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);  		WriteDOC(DOC_ECC_EN, docptr, ECCConf); @@ -904,7 +901,7 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)  	void __iomem *docptr = doc->virtadr;  	/* Prime the ECC engine */ -	switch(mode) { +	switch (mode) {  	case NAND_ECC_READ:  		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);  		WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf); @@ -917,8 +914,7 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)  }  /* This code is only called on write */ -static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, -				 unsigned char *ecc_code) +static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv; @@ -962,7 +958,8 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,  		   often.  It could be optimized away by examining the data in  		   the writebuf routine, and remembering the result. */  		for (i = 0; i < 512; i++) { -			if (dat[i] == 0xff) continue; +			if (dat[i] == 0xff) +				continue;  			emptymatch = 0;  			break;  		} @@ -970,17 +967,20 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,  	/* If emptymatch still =1, we do have an all-0xff data buffer.  	   Return all-0xff ecc value instead of the computed one, so  	   it'll look just like a freshly-erased page. */ -	if (emptymatch) memset(ecc_code, 0xff, 6); +	if (emptymatch) +		memset(ecc_code, 0xff, 6);  #endif  	return 0;  } -static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) +static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, +				u_char *read_ecc, u_char *isnull)  {  	int i, ret = 0;  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv;  	void __iomem *docptr = doc->virtadr; +	uint8_t calc_ecc[6];  	volatile u_char dummy;  	int emptymatch = 1; @@ -1013,18 +1013,20 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_  		   all-0xff data and stored ecc block.  Check the stored ecc. */  		if (emptymatch) {  			for (i = 0; i < 6; i++) { -				if (read_ecc[i] == 0xff) continue; +				if (read_ecc[i] == 0xff) +					continue;  				emptymatch = 0;  				break;  			}  		}  		/* If emptymatch still =1, check the data block. */  		if (emptymatch) { -		/* Note: this somewhat expensive test should not be triggered -		   often.  It could be optimized away by examining the data in -		   the readbuf routine, and remembering the result. */ +			/* Note: this somewhat expensive test should not be triggered +			   often.  It could be optimized away by examining the data in +			   the readbuf routine, and remembering the result. */  			for (i = 0; i < 512; i++) { -				if (dat[i] == 0xff) continue; +				if (dat[i] == 0xff) +					continue;  				emptymatch = 0;  				break;  			} @@ -1033,7 +1035,8 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_  		   erased block, in which case the ECC will not come out right.  		   We'll suppress the error and tell the caller everything's  		   OK.  Because it is. */ -		if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc); +		if (!emptymatch) +			ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);  		if (ret > 0)  			printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);  	} @@ -1048,13 +1051,22 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_  	return ret;  } -/*u_char mydatabuf[528]; */ +//u_char mydatabuf[528]; -static struct nand_oobinfo doc200x_oobinfo = { -	.useecc = MTD_NANDECC_AUTOPLACE, +/* The strange out-of-order .oobfree list below is a (possibly unneeded) + * attempt to retain compatibility.  It used to read: + * 	.oobfree = { {8, 8} } + * Since that leaves two bytes unusable, it was changed.  But the following + * scheme might affect existing jffs2 installs by moving the cleanmarker: + * 	.oobfree = { {6, 10} } + * jffs2 seems to handle the above gracefully, but the current scheme seems + * safer.  The only problem with it is that any code that parses oobfree must + * be able to handle out-of-order segments. + */ +static struct nand_ecclayout doc200x_oobinfo = {  	.eccbytes = 6,  	.eccpos = {0, 1, 2, 3, 4, 5}, -	.oobfree = { {8, 8} } +	.oobfree = {{8, 8}, {6, 2}}  };  /* Find the (I)NFTL Media Header, and optionally also the mirror media header. @@ -1063,28 +1075,28 @@ static struct nand_oobinfo doc200x_oobinfo = {     either "ANAND" or "BNAND".  If findmirror=1, also look for the mirror media     header.  The page #s of the found media headers are placed in mh0_page and     mh1_page in the DOC private structure. */ -static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, -				     const char *id, int findmirror) +static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv; -	unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift); +	unsigned offs;  	int ret;  	size_t retlen; -	end = min(end, mtd->size); /* paranoia */ -	for (offs = 0; offs < end; offs += mtd->erasesize) { -		ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf); -		if (retlen != mtd->oobblock) continue; +	for (offs = 0; offs < mtd->size; offs += mtd->erasesize) { +		ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf); +		if (retlen != mtd->writesize) +			continue;  		if (ret) { -			printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", -				offs); +			printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", offs);  		} -		if (memcmp(buf, id, 6)) continue; +		if (memcmp(buf, id, 6)) +			continue;  		printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs);  		if (doc->mh0_page == -1) {  			doc->mh0_page = offs >> this->page_shift; -			if (!findmirror) return 1; +			if (!findmirror) +				return 1;  			continue;  		}  		doc->mh1_page = offs >> this->page_shift; @@ -1097,8 +1109,8 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,  	/* Only one mediaheader was found.  We want buf to contain a  	   mediaheader on return, so we'll have to re-read the one we found. */  	offs = doc->mh0_page << this->page_shift; -	ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf); -	if (retlen != mtd->oobblock) { +	ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf); +	if (retlen != mtd->writesize) {  		/* Insanity.  Give up. */  		printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");  		return 0; @@ -1106,8 +1118,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,  	return 1;  } -static inline int __init nftl_partscan(struct mtd_info *mtd, -				struct mtd_partition *parts) +static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv; @@ -1115,19 +1126,23 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,  	u_char *buf;  	struct NFTLMediaHeader *mh;  	const unsigned psize = 1 << this->page_shift; +	int numparts = 0;  	unsigned blocks, maxblocks;  	int offs, numheaders; -	buf = kmalloc(mtd->oobblock, GFP_KERNEL); +	buf = kmalloc(mtd->writesize, GFP_KERNEL);  	if (!buf) {  		printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");  		return 0;  	} -	if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out; -	mh = (struct NFTLMediaHeader *) buf; +	if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1))) +		goto out; +	mh = (struct NFTLMediaHeader *)buf; + +	mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits); +	mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN); +	mh->FormattedSize = le32_to_cpu(mh->FormattedSize); -/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */ -/*	if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */  	printk(KERN_INFO "    DataOrgID        = %s\n"  			 "    NumEraseUnits    = %d\n"  			 "    FirstPhysicalEUN = %d\n" @@ -1136,7 +1151,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,  		mh->DataOrgID, mh->NumEraseUnits,  		mh->FirstPhysicalEUN, mh->FormattedSize,  		mh->UnitSizeFactor); -/*#endif */  	blocks = mtd->size >> this->phys_erase_shift;  	maxblocks = min(32768U, mtd->erasesize - psize); @@ -1145,8 +1159,8 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,  		/* Auto-determine UnitSizeFactor.  The constraints are:  		   - There can be at most 32768 virtual blocks.  		   - There can be at most (virtual block size - page size) -		     virtual blocks (because MediaHeader+BBT must fit in 1). -		*/ +		   virtual blocks (because MediaHeader+BBT must fit in 1). +		 */  		mh->UnitSizeFactor = 0xff;  		while (blocks > maxblocks) {  			blocks >>= 1; @@ -1179,31 +1193,35 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,  	offs <<= this->page_shift;  	offs += mtd->erasesize; -	/*parts[0].name = " DiskOnChip Boot / Media Header partition"; */ -	/*parts[0].offset = 0; */ -	/*parts[0].size = offs; */ +	if (show_firmware_partition == 1) { +		parts[0].name = " DiskOnChip Firmware / Media Header partition"; +		parts[0].offset = 0; +		parts[0].size = offs; +		numparts = 1; +	} + +	parts[numparts].name = " DiskOnChip BDTL partition"; +	parts[numparts].offset = offs; +	parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift; -	parts[0].name = " DiskOnChip BDTL partition"; -	parts[0].offset = offs; -	parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift; +	offs += parts[numparts].size; +	numparts++; -	offs += parts[0].size;  	if (offs < mtd->size) { -		parts[1].name = " DiskOnChip Remainder partition"; -		parts[1].offset = offs; -		parts[1].size = mtd->size - offs; -		ret = 2; -		goto out; +		parts[numparts].name = " DiskOnChip Remainder partition"; +		parts[numparts].offset = offs; +		parts[numparts].size = mtd->size - offs; +		numparts++;  	} -	ret = 1; -out: + +	ret = numparts; + out:  	kfree(buf);  	return ret;  }  /* This is a stripped-down copy of the code in inftlmount.c */ -static inline int __init inftl_partscan(struct mtd_info *mtd, -				 struct mtd_partition *parts) +static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)  {  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv; @@ -1220,15 +1238,16 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,  	if (inftl_bbt_write)  		end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift); -	buf = kmalloc(mtd->oobblock, GFP_KERNEL); +	buf = kmalloc(mtd->writesize, GFP_KERNEL);  	if (!buf) {  		printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");  		return 0;  	} -	if (!find_media_headers(mtd, buf, "BNAND", 0)) goto out; +	if (!find_media_headers(mtd, buf, "BNAND", 0)) +		goto out;  	doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift); -	mh = (struct INFTLMediaHeader *) buf; +	mh = (struct INFTLMediaHeader *)buf;  	mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);  	mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions); @@ -1237,8 +1256,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,  	mh->FormatFlags = le32_to_cpu(mh->FormatFlags);  	mh->PercentUsed = le32_to_cpu(mh->PercentUsed); -/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */ -/*	if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */  	printk(KERN_INFO "    bootRecordID          = %s\n"  			 "    NoOfBootImageBlocks   = %d\n"  			 "    NoOfBinaryPartitions  = %d\n" @@ -1256,7 +1273,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,  		((unsigned char *) &mh->OsakVersion)[2] & 0xf,  		((unsigned char *) &mh->OsakVersion)[3] & 0xf,  		mh->PercentUsed); -/*#endif */  	vshift = this->phys_erase_shift + mh->BlockMultiplierBits; @@ -1282,8 +1298,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,  		ip->spareUnits = le32_to_cpu(ip->spareUnits);  		ip->Reserved0 = le32_to_cpu(ip->Reserved0); -/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */ -/*		if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */  		printk(KERN_INFO	"    PARTITION[%d] ->\n"  			"        virtualUnits    = %d\n"  			"        firstUnit       = %d\n" @@ -1293,16 +1307,14 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,  			i, ip->virtualUnits, ip->firstUnit,  			ip->lastUnit, ip->flags,  			ip->spareUnits); -/*#endif */ -/* -		if ((i == 0) && (ip->firstUnit > 0)) { +		if ((show_firmware_partition == 1) && +		    (i == 0) && (ip->firstUnit > 0)) {  			parts[0].name = " DiskOnChip IPL / Media Header partition";  			parts[0].offset = 0;  			parts[0].size = mtd->erasesize * ip->firstUnit;  			numparts = 1;  		} -*/  		if (ip->flags & INFTL_BINARY)  			parts[numparts].name = " DiskOnChip BDK partition"; @@ -1311,8 +1323,10 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,  		parts[numparts].offset = ip->firstUnit << vshift;  		parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;  		numparts++; -		if (ip->lastUnit > lastvunit) lastvunit = ip->lastUnit; -		if (ip->flags & INFTL_LAST) break; +		if (ip->lastUnit > lastvunit) +			lastvunit = ip->lastUnit; +		if (ip->flags & INFTL_LAST) +			break;  	}  	lastvunit++;  	if ((lastvunit << vshift) < end) { @@ -1322,7 +1336,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,  		numparts++;  	}  	ret = numparts; -out: + out:  	kfree(buf);  	return ret;  } @@ -1334,11 +1348,12 @@ static int __init nftl_scan_bbt(struct mtd_info *mtd)  	struct doc_priv *doc = this->priv;  	struct mtd_partition parts[2]; -	memset((char *) parts, 0, sizeof(parts)); +	memset((char *)parts, 0, sizeof(parts));  	/* On NFTL, we have to find the media headers before we can read the  	   BBTs, since they're stored in the media header eraseblocks. */  	numparts = nftl_partscan(mtd, parts); -	if (!numparts) return -EIO; +	if (!numparts) +		return -EIO;  	this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |  				NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |  				NAND_BBT_VERSION; @@ -1385,8 +1400,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)  		this->bbt_td->pages[0] = 2;  		this->bbt_md = NULL;  	} else { -		this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | -					NAND_BBT_VERSION; +		this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;  		if (inftl_bbt_write)  			this->bbt_td->options |= NAND_BBT_WRITE;  		this->bbt_td->offs = 8; @@ -1396,8 +1410,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)  		this->bbt_td->reserved_block_code = 0x01;  		this->bbt_td->pattern = "MSYS_BBT"; -		this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | -					NAND_BBT_VERSION; +		this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;  		if (inftl_bbt_write)  			this->bbt_md->options |= NAND_BBT_WRITE;  		this->bbt_md->offs = 8; @@ -1412,12 +1425,13 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)  	   At least as nand_bbt.c is currently written. */  	if ((ret = nand_scan_bbt(mtd, NULL)))  		return ret; -	memset((char *) parts, 0, sizeof(parts)); +	memset((char *)parts, 0, sizeof(parts));  	numparts = inftl_partscan(mtd, parts);  	/* At least for now, require the INFTL Media Header.  We could probably  	   do without it for non-INFTL use, since all it gives us is  	   autopartitioning, but I want to give it more thought. */ -	if (!numparts) return -EIO; +	if (!numparts) +		return -EIO;  	add_mtd_device(mtd);  #ifdef CONFIG_MTD_PARTITIONS  	if (!no_autopart) @@ -1431,7 +1445,6 @@ static inline int __init doc2000_init(struct mtd_info *mtd)  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv; -	this->write_byte = doc2000_write_byte;  	this->read_byte = doc2000_read_byte;  	this->write_buf = doc2000_writebuf;  	this->read_buf = doc2000_readbuf; @@ -1449,7 +1462,6 @@ static inline int __init doc2001_init(struct mtd_info *mtd)  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv; -	this->write_byte = doc2001_write_byte;  	this->read_byte = doc2001_read_byte;  	this->write_buf = doc2001_writebuf;  	this->read_buf = doc2001_readbuf; @@ -1481,16 +1493,15 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)  	struct nand_chip *this = mtd->priv;  	struct doc_priv *doc = this->priv; -	this->write_byte = NULL;  	this->read_byte = doc2001plus_read_byte;  	this->write_buf = doc2001plus_writebuf;  	this->read_buf = doc2001plus_readbuf;  	this->verify_buf = doc2001plus_verifybuf;  	this->scan_bbt = inftl_scan_bbt; -	this->hwcontrol = NULL; +	this->cmd_ctrl = NULL;  	this->select_chip = doc2001plus_select_chip;  	this->cmdfunc = doc2001plus_command; -	this->enable_hwecc = doc2001plus_enable_hwecc; +	this->ecc.hwctl = doc2001plus_enable_hwecc;  	doc->chips_per_floor = 1;  	mtd->name = "DiskOnChip Millennium Plus"; @@ -1498,7 +1509,7 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)  	return 1;  } -static inline int __init doc_probe(unsigned long physadr) +static int __init doc_probe(unsigned long physadr)  {  	unsigned char ChipID;  	struct mtd_info *mtd; @@ -1527,20 +1538,16 @@ static inline int __init doc_probe(unsigned long physadr)  	save_control = ReadDOC(virtadr, DOCControl);  	/* Reset the DiskOnChip ASIC */ -	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, -		 virtadr, DOCControl); -	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, -		 virtadr, DOCControl); +	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl); +	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);  	/* Enable the DiskOnChip ASIC */ -	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, -		 virtadr, DOCControl); -	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, -		 virtadr, DOCControl); +	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl); +	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);  	ChipID = ReadDOC(virtadr, ChipID); -	switch(ChipID) { +	switch (ChipID) {  	case DOC_ChipID_Doc2k:  		reg = DoC_2k_ECCStatus;  		break; @@ -1556,15 +1563,13 @@ static inline int __init doc_probe(unsigned long physadr)  			ReadDOC(virtadr, Mplus_Power);  		/* Reset the Millennium Plus ASIC */ -		tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | -			DOC_MODE_BDECT; +		tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;  		WriteDOC(tmp, virtadr, Mplus_DOCControl);  		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);  		mdelay(1);  		/* Enable the Millennium Plus ASIC */ -		tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | -			DOC_MODE_BDECT; +		tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;  		WriteDOC(tmp, virtadr, Mplus_DOCControl);  		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);  		mdelay(1); @@ -1588,7 +1593,7 @@ static inline int __init doc_probe(unsigned long physadr)  		goto notfound;  	}  	/* Check the TOGGLE bit in the ECC register */ -	tmp  = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; +	tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;  	tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;  	tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;  	if ((tmp == tmpb) || (tmp != tmpc)) { @@ -1618,11 +1623,11 @@ static inline int __init doc_probe(unsigned long physadr)  		if (ChipID == DOC_ChipID_DocMilPlus16) {  			WriteDOC(~newval, virtadr, Mplus_AliasResolution);  			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution); -			WriteDOC(newval, virtadr, Mplus_AliasResolution); /* restore it */ +			WriteDOC(newval, virtadr, Mplus_AliasResolution);	// restore it  		} else {  			WriteDOC(~newval, virtadr, AliasResolution);  			oldval = ReadDOC(doc->virtadr, AliasResolution); -			WriteDOC(newval, virtadr, AliasResolution); /* restore it */ +			WriteDOC(newval, virtadr, AliasResolution);	// restore it  		}  		newval = ~newval;  		if (oldval == newval) { @@ -1634,16 +1639,13 @@ static inline int __init doc_probe(unsigned long physadr)  	printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);  	len = sizeof(struct mtd_info) + -	      sizeof(struct nand_chip) + -	      sizeof(struct doc_priv) + -	      (2 * sizeof(struct nand_bbt_descr)); -	mtd =  kmalloc(len, GFP_KERNEL); +	    sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr)); +	mtd = kzalloc(len, GFP_KERNEL);  	if (!mtd) {  		printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);  		ret = -ENOMEM;  		goto fail;  	} -	memset(mtd, 0, len);  	nand			= (struct nand_chip *) (mtd + 1);  	doc			= (struct doc_priv *) (nand + 1); @@ -1655,17 +1657,19 @@ static inline int __init doc_probe(unsigned long physadr)  	nand->priv		= doc;  	nand->select_chip	= doc200x_select_chip; -	nand->hwcontrol		= doc200x_hwcontrol; +	nand->cmd_ctrl		= doc200x_hwcontrol;  	nand->dev_ready		= doc200x_dev_ready;  	nand->waitfunc		= doc200x_wait;  	nand->block_bad		= doc200x_block_bad; -	nand->enable_hwecc	= doc200x_enable_hwecc; -	nand->calculate_ecc	= doc200x_calculate_ecc; -	nand->correct_data	= doc200x_correct_data; +	nand->ecc.hwctl		= doc200x_enable_hwecc; +	nand->ecc.calculate	= doc200x_calculate_ecc; +	nand->ecc.correct	= doc200x_correct_data; -	nand->autooob		= &doc200x_oobinfo; -	nand->eccmode		= NAND_ECC_HW6_512; -	nand->options		= NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME; +	nand->ecc.layout	= &doc200x_oobinfo; +	nand->ecc.mode		= NAND_ECC_HW_SYNDROME; +	nand->ecc.size		= 512; +	nand->ecc.bytes		= 6; +	nand->options		= NAND_USE_FLASH_BBT;  	doc->physadr		= physadr;  	doc->virtadr		= virtadr; @@ -1699,11 +1703,11 @@ static inline int __init doc_probe(unsigned long physadr)  	doclist = mtd;  	return 0; -notfound: + notfound:  	/* Put back the contents of the DOCControl register, in case it's not  	   actually a DiskOnChip.  */  	WriteDOC(save_control, virtadr, DOCControl); -fail: + fail:  	iounmap(virtadr);  	return ret;  } @@ -1740,7 +1744,7 @@ static int __init init_nanddoc(void)  	 */  	rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);  	if (!rs_decoder) { -		printk (KERN_ERR "DiskOnChip: Could not create a RS decoder\n"); +		printk(KERN_ERR "DiskOnChip: Could not create a RS decoder\n");  		return -ENOMEM;  	} @@ -1750,7 +1754,7 @@ static int __init init_nanddoc(void)  		if (ret < 0)  			goto outerr;  	} else { -		for (i=0; (doc_locations[i] != 0xffffffff); i++) { +		for (i = 0; (doc_locations[i] != 0xffffffff); i++) {  			doc_probe(doc_locations[i]);  		}  	} @@ -1762,7 +1766,7 @@ static int __init init_nanddoc(void)  		goto outerr;  	}  	return 0; -outerr: + outerr:  	free_rs(rs_decoder);  	return ret;  } diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 6416d1529..aeb179731 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -10,39 +10,21 @@   *	http://www.linux-mtd.infradead.org/tech/nand.html   *   *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - *		  2002 Thomas Gleixner (tglx@linutronix.de) + *		  2002-2006 Thomas Gleixner (tglx@linutronix.de)   * - *  02-08-2004  tglx: support for strange chips, which cannot auto increment - *		pages on read / read_oob - * - *  03-17-2004  tglx: Check ready before auto increment check. Simon Bayes - *		pointed this out, as he marked an auto increment capable chip - *		as NOAUTOINCR in the board driver. - *		Make reads over block boundaries work too - * - *  04-14-2004	tglx: first working version for 2k page size chips - * - *  05-19-2004  tglx: Basic support for Renesas AG-AND chips - * - *  09-24-2004  tglx: add support for hardware controllers (e.g. ECC) shared - *		among multiple independend devices. Suggestions and initial patch - *		from Ben Dooks <ben-mtd@fluff.org> - * - * Credits: + *  Credits:   *	David Woodhouse for adding multichip support   *   *	Aleph One Ltd. and Toby Churchill Ltd. for supporting the   *	rework for 2K page size chips   * - * TODO: + *  TODO:   *	Enable cached programming for 2k page size chips   *	Check, if mtd->ecctype should be set to MTD_ECC_HW   *	if we have HW ecc support.   *	The AG-AND chips have nice features for speed improvement,   *	which are not supported yet. Read / program 4 pages in one go.   * - * $Id: nand_base.c,v 1.126 2004/12/13 11:22:25 lavinen 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   * published by the Free Software Foundation. @@ -51,8 +33,10 @@  /* XXX U-BOOT XXX */  #if 0 +#include <linux/module.h>  #include <linux/delay.h>  #include <linux/errno.h> +#include <linux/err.h>  #include <linux/sched.h>  #include <linux/slab.h>  #include <linux/types.h> @@ -62,6 +46,7 @@  #include <linux/mtd/compatmac.h>  #include <linux/interrupt.h>  #include <linux/bitops.h> +#include <linux/leds.h>  #include <asm/io.h>  #ifdef CONFIG_MTD_PARTITIONS @@ -72,10 +57,13 @@  #include <common.h> +#define ENOTSUPP	524	/* Operation is not supported */ +  #if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY)  #include <malloc.h>  #include <watchdog.h> +#include <linux/err.h>  #include <linux/mtd/compat.h>  #include <linux/mtd/mtd.h>  #include <linux/mtd/nand.h> @@ -89,83 +77,67 @@  #endif  /* Define default oob placement schemes for large and small page devices */ -static struct nand_oobinfo nand_oob_8 = { -	.useecc = MTD_NANDECC_AUTOPLACE, +static struct nand_ecclayout nand_oob_8 = {  	.eccbytes = 3,  	.eccpos = {0, 1, 2}, -	.oobfree = { {3, 2}, {6, 2} } +	.oobfree = { +		{.offset = 3, +		 .length = 2}, +		{.offset = 6, +		 .length = 2}}  }; -static struct nand_oobinfo nand_oob_16 = { -	.useecc = MTD_NANDECC_AUTOPLACE, +static struct nand_ecclayout nand_oob_16 = {  	.eccbytes = 6,  	.eccpos = {0, 1, 2, 3, 6, 7}, -	.oobfree = { {8, 8} } +	.oobfree = { +		{.offset = 8, +		 . length = 8}}  }; -static struct nand_oobinfo nand_oob_64 = { -	.useecc = MTD_NANDECC_AUTOPLACE, +static struct nand_ecclayout nand_oob_64 = {  	.eccbytes = 24,  	.eccpos = { -		40, 41, 42, 43, 44, 45, 46, 47, -		48, 49, 50, 51, 52, 53, 54, 55, -		56, 57, 58, 59, 60, 61, 62, 63}, -	.oobfree = { {2, 38} } +		   40, 41, 42, 43, 44, 45, 46, 47, +		   48, 49, 50, 51, 52, 53, 54, 55, +		   56, 57, 58, 59, 60, 61, 62, 63}, +	.oobfree = { +		{.offset = 2, +		 .length = 38}}  }; -static struct nand_oobinfo nand_oob_128 = { -	.useecc = MTD_NANDECC_AUTOPLACE, +static struct nand_ecclayout nand_oob_128 = {  	.eccbytes = 48,  	.eccpos = { -		80,  81,  82,  83,  84,  85,  86,  87, -		88,  89,  90,  91,  92,  93,  94,  95, -		96,  97,  98,  99, 100, 101, 102, 103, -		104, 105, 106, 107, 108, 109, 110, 111, -		112, 113, 114, 115, 116, 117, 118, 119, -		120, 121, 122, 123, 124, 125, 126, 127}, -	.oobfree = { {2, 78} } +		    80,  81,  82,  83,  84,  85,  86,  87, +		    88,  89,  90,  91,  92,  93,  94,  95, +		    96,  97,  98,  99, 100, 101, 102, 103, +		   104, 105, 106, 107, 108, 109, 110, 111, +		   112, 113, 114, 115, 116, 117, 118, 119, +		   120, 121, 122, 123, 124, 125, 126, 127}, +	.oobfree = { +		{.offset = 2, +		 .length = 78}}  }; -/* This is used for padding purposes in nand_write_oob */ -static u_char *ffchars; + +static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, +			   int new_state); + +static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, +			     struct mtd_oob_ops *ops); + +static int nand_wait(struct mtd_info *mtd, struct nand_chip *this);  /* - * NAND low-level MTD interface functions + * For devices which display every fart in the system on a seperate LED. Is + * compiled away when LED support is disabled.   */ -static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len); -static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len); -static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len); - -static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); -static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, -			  size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); -static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); -static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf); -static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, -			   size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); -static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf);  /* XXX U-BOOT XXX */  #if 0 -static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, -			unsigned long count, loff_t to, size_t * retlen); -static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, -			unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); -#endif -static int nand_erase (struct mtd_info *mtd, struct erase_info *instr); -static void nand_sync (struct mtd_info *mtd); - -/* Some internal functions */ -static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, -		struct nand_oobinfo *oobsel, int mode); -#ifdef CONFIG_MTD_NAND_VERIFY_WRITE -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, -	u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode); -#else -#define nand_verify_pages(...) (0) +DEFINE_LED_TRIGGER(nand_led_trigger);  #endif -static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); -  /**   * nand_release_device - [GENERIC] release chip   * @mtd:	MTD device structure @@ -174,33 +146,25 @@ static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int n   */  /* XXX U-BOOT XXX */  #if 0 -static void nand_release_device (struct mtd_info *mtd) +static void nand_release_device(struct mtd_info *mtd)  { -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv;  	/* De-select the NAND device */ -	this->select_chip(mtd, -1); -	/* Do we have a hardware controller ? */ -	if (this->controller) { -		spin_lock(&this->controller->lock); -		this->controller->active = NULL; -		spin_unlock(&this->controller->lock); -	} -	/* Release the chip */ -	spin_lock (&this->chip_lock); -	this->state = FL_READY; -	wake_up (&this->wq); -	spin_unlock (&this->chip_lock); +	chip->select_chip(mtd, -1); + +	/* Release the controller and the chip */ +	spin_lock(&chip->controller->lock); +	chip->controller->active = NULL; +	chip->state = FL_READY; +	wake_up(&chip->controller->wq); +	spin_unlock(&chip->controller->lock);  }  #else  static void nand_release_device (struct mtd_info *mtd)  {  	struct nand_chip *this = mtd->priv;  	this->select_chip(mtd, -1);	/* De-select the NAND device */ -	if (ffchars) { -		kfree(ffchars); -		ffchars = NULL; -	}  }  #endif @@ -210,23 +174,10 @@ static void nand_release_device (struct mtd_info *mtd)   *   * Default read function for 8bit buswith   */ -static u_char nand_read_byte(struct mtd_info *mtd) +static uint8_t nand_read_byte(struct mtd_info *mtd)  { -	struct nand_chip *this = mtd->priv; -	return readb(this->IO_ADDR_R); -} - -/** - * nand_write_byte - [DEFAULT] write one byte to the chip - * @mtd:	MTD device structure - * @byte:	pointer to data byte to write - * - * Default write function for 8it buswith - */ -static void nand_write_byte(struct mtd_info *mtd, u_char byte) -{ -	struct nand_chip *this = mtd->priv; -	writeb(byte, this->IO_ADDR_W); +	struct nand_chip *chip = mtd->priv; +	return readb(chip->IO_ADDR_R);  }  /** @@ -236,24 +187,10 @@ static void nand_write_byte(struct mtd_info *mtd, u_char byte)   * Default read function for 16bit buswith with   * endianess conversion   */ -static u_char nand_read_byte16(struct mtd_info *mtd) +static uint8_t nand_read_byte16(struct mtd_info *mtd)  { -	struct nand_chip *this = mtd->priv; -	return (u_char) cpu_to_le16(readw(this->IO_ADDR_R)); -} - -/** - * nand_write_byte16 - [DEFAULT] write one byte endianess aware to the chip - * @mtd:	MTD device structure - * @byte:	pointer to data byte to write - * - * Default write function for 16bit buswith with - * endianess conversion - */ -static void nand_write_byte16(struct mtd_info *mtd, u_char byte) -{ -	struct nand_chip *this = mtd->priv; -	writew(le16_to_cpu((u16) byte), this->IO_ADDR_W); +	struct nand_chip *chip = mtd->priv; +	return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));  }  /** @@ -265,40 +202,26 @@ static void nand_write_byte16(struct mtd_info *mtd, u_char byte)   */  static u16 nand_read_word(struct mtd_info *mtd)  { -	struct nand_chip *this = mtd->priv; -	return readw(this->IO_ADDR_R); -} - -/** - * nand_write_word - [DEFAULT] write one word to the chip - * @mtd:	MTD device structure - * @word:	data word to write - * - * Default write function for 16bit buswith without - * endianess conversion - */ -static void nand_write_word(struct mtd_info *mtd, u16 word) -{ -	struct nand_chip *this = mtd->priv; -	writew(word, this->IO_ADDR_W); +	struct nand_chip *chip = mtd->priv; +	return readw(chip->IO_ADDR_R);  }  /**   * nand_select_chip - [DEFAULT] control CE line   * @mtd:	MTD device structure - * @chip:	chipnumber to select, -1 for deselect + * @chipnr:	chipnumber to select, -1 for deselect   *   * Default select function for 1 chip devices.   */ -static void nand_select_chip(struct mtd_info *mtd, int chip) +static void nand_select_chip(struct mtd_info *mtd, int chipnr)  { -	struct nand_chip *this = mtd->priv; -	switch(chip) { +	struct nand_chip *chip = mtd->priv; + +	switch (chipnr) {  	case -1: -		this->hwcontrol(mtd, NAND_CTL_CLRNCE); +		chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);  		break;  	case 0: -		this->hwcontrol(mtd, NAND_CTL_SETNCE);  		break;  	default: @@ -314,13 +237,13 @@ static void nand_select_chip(struct mtd_info *mtd, int chip)   *   * Default write function for 8bit buswith   */ -static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)  {  	int i; -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv; -	for (i=0; i<len; i++) -		writeb(buf[i], this->IO_ADDR_W); +	for (i = 0; i < len; i++) +		writeb(buf[i], chip->IO_ADDR_W);  }  /** @@ -331,13 +254,13 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)   *   * Default read function for 8bit buswith   */ -static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)  {  	int i; -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv; -	for (i=0; i<len; i++) -		buf[i] = readb(this->IO_ADDR_R); +	for (i = 0; i < len; i++) +		buf[i] = readb(chip->IO_ADDR_R);  }  /** @@ -348,15 +271,14 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)   *   * Default verify function for 8bit buswith   */ -static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) +static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)  {  	int i; -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv; -	for (i=0; i<len; i++) -		if (buf[i] != readb(this->IO_ADDR_R)) +	for (i = 0; i < len; i++) +		if (buf[i] != readb(chip->IO_ADDR_R))  			return -EFAULT; -  	return 0;  } @@ -368,15 +290,15 @@ static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)   *   * Default write function for 16bit buswith   */ -static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) +static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)  {  	int i; -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv;  	u16 *p = (u16 *) buf;  	len >>= 1; -	for (i=0; i<len; i++) -		writew(p[i], this->IO_ADDR_W); +	for (i = 0; i < len; i++) +		writew(p[i], chip->IO_ADDR_W);  } @@ -388,15 +310,15 @@ static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)   *   * Default read function for 16bit buswith   */ -static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len) +static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)  {  	int i; -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv;  	u16 *p = (u16 *) buf;  	len >>= 1; -	for (i=0; i<len; i++) -		p[i] = readw(this->IO_ADDR_R); +	for (i = 0; i < len; i++) +		p[i] = readw(chip->IO_ADDR_R);  }  /** @@ -407,15 +329,15 @@ static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len)   *   * Default verify function for 16bit buswith   */ -static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) +static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)  {  	int i; -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv;  	u16 *p = (u16 *) buf;  	len >>= 1; -	for (i=0; i<len; i++) -		if (p[i] != readw(this->IO_ADDR_R)) +	for (i = 0; i < len; i++) +		if (p[i] != readw(chip->IO_ADDR_R))  			return -EFAULT;  	return 0; @@ -432,38 +354,36 @@ static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)  static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)  {  	int page, chipnr, res = 0; -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv;  	u16 bad; -	page = (int)(ofs >> this->page_shift) & this->pagemask; +	page = (int)(ofs >> chip->page_shift) & chip->pagemask;  	if (getchip) { -		chipnr = (int)(ofs >> this->chip_shift); +		chipnr = (int)(ofs >> chip->chip_shift); -		/* Grab the lock and see if the device is available */ -		nand_get_device (this, mtd, FL_READING); +		nand_get_device(chip, mtd, FL_READING);  		/* Select the NAND device */ -		this->select_chip(mtd, chipnr); +		chip->select_chip(mtd, chipnr);  	} -	if (this->options & NAND_BUSWIDTH_16) { -		this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page); -		bad = cpu_to_le16(this->read_word(mtd)); -		if (this->badblockpos & 0x1) -			bad >>= 1; +	if (chip->options & NAND_BUSWIDTH_16) { +		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE, +			      page); +		bad = cpu_to_le16(chip->read_word(mtd)); +		if (chip->badblockpos & 0x1) +			bad >>= 8;  		if ((bad & 0xFF) != 0xff)  			res = 1;  	} else { -		this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos, page); -		if (this->read_byte(mtd) != 0xff) +		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page); +		if (chip->read_byte(mtd) != 0xff)  			res = 1;  	} -	if (getchip) { -		/* Deselect and wake up anyone waiting on the device */ +	if (getchip)  		nand_release_device(mtd); -	}  	return res;  } @@ -478,22 +398,33 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)  */  static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)  { -	struct nand_chip *this = mtd->priv; -	u_char buf[2] = {0, 0}; -	size_t	retlen; -	int block; +	struct nand_chip *chip = mtd->priv; +	uint8_t buf[2] = { 0, 0 }; +	int block, ret;  	/* Get block number */ -	block = ((int) ofs) >> this->bbt_erase_shift; -	this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); +	block = (int)(ofs >> chip->bbt_erase_shift); +	if (chip->bbt) +		chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);  	/* Do we have a flash based bad block table ? */ -	if (this->options & NAND_USE_FLASH_BBT) -		return nand_update_bbt (mtd, ofs); +	if (chip->options & NAND_USE_FLASH_BBT) +		ret = nand_update_bbt(mtd, ofs); +	else { +		/* We write two bytes, so we dont have to mess with 16 bit +		 * access +		 */ +		ofs += mtd->oobsize; +		chip->ops.len = chip->ops.ooblen = 2; +		chip->ops.datbuf = NULL; +		chip->ops.oobbuf = buf; +		chip->ops.ooboffs = chip->badblockpos & ~0x01; -	/* We write two bytes, so we dont have to mess with 16 bit access */ -	ofs += mtd->oobsize + (this->badblockpos & ~0x01); -	return nand_write_oob (mtd, ofs , 2, &retlen, buf); +		ret = nand_do_write_oob(mtd, ofs, &chip->ops); +	} +	if (!ret) +		mtd->ecc_stats.badblocks++; +	return ret;  }  /** @@ -503,12 +434,12 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)   *   * The function expects, that the device is already selected   */ -static int nand_check_wp (struct mtd_info *mtd) +static int nand_check_wp(struct mtd_info *mtd)  { -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv;  	/* Check the WP bit */ -	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); -	return (this->read_byte(mtd) & 0x80) ? 0 : 1; +	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); +	return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;  }  /** @@ -521,17 +452,47 @@ static int nand_check_wp (struct mtd_info *mtd)   * Check, if the block is bad. Either by reading the bad block table or   * calling of the scan function.   */ -static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) +static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, +			       int allowbbt)  { -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv; -	if (!this->bbt) -		return this->block_bad(mtd, ofs, getchip); +	if (!chip->bbt) +		return chip->block_bad(mtd, ofs, getchip);  	/* Return info from the table */ -	return nand_isbad_bbt (mtd, ofs, allowbbt); +	return nand_isbad_bbt(mtd, ofs, allowbbt);  } +/* + * Wait for the ready pin, after a command + * The timeout is catched later. + */ +/* XXX U-BOOT XXX */ +#if 0 +void nand_wait_ready(struct mtd_info *mtd) +{ +	struct nand_chip *chip = mtd->priv; +	unsigned long timeo = jiffies + 2; + +	led_trigger_event(nand_led_trigger, LED_FULL); +	/* wait until command is processed or timeout occures */ +	do { +		if (chip->dev_ready(mtd)) +			break; +		touch_softlockup_watchdog(); +	} while (time_before(jiffies, timeo)); +	led_trigger_event(nand_led_trigger, LED_OFF); +} +EXPORT_SYMBOL_GPL(nand_wait_ready); +#else +void nand_wait_ready(struct mtd_info *mtd) +{ +	struct nand_chip *chip = mtd->priv; +	nand_wait(mtd, chip); +} +#endif +  /**   * nand_command - [DEFAULT] Send command to NAND device   * @mtd:	MTD device structure @@ -542,21 +503,21 @@ static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, i   * Send command to NAND device. This function is used for small page   * devices (256/512 Bytes per page)   */ -static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) +static void nand_command(struct mtd_info *mtd, unsigned int command, +			 int column, int page_addr)  { -	register struct nand_chip *this = mtd->priv; +	register struct nand_chip *chip = mtd->priv; +	int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; -	/* Begin command latch cycle */ -	this->hwcontrol(mtd, NAND_CTL_SETCLE);  	/*  	 * Write out the command to the device.  	 */  	if (command == NAND_CMD_SEQIN) {  		int readcmd; -		if (column >= mtd->oobblock) { +		if (column >= mtd->writesize) {  			/* OOB area */ -			column -= mtd->oobblock; +			column -= mtd->writesize;  			readcmd = NAND_CMD_READOOB;  		} else if (column < 256) {  			/* First 256 bytes --> READ0 */ @@ -565,38 +526,37 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in  			column -= 256;  			readcmd = NAND_CMD_READ1;  		} -		this->write_byte(mtd, readcmd); +		chip->cmd_ctrl(mtd, readcmd, ctrl); +		ctrl &= ~NAND_CTRL_CHANGE;  	} -	this->write_byte(mtd, command); - -	/* Set ALE and clear CLE to start address cycle */ -	this->hwcontrol(mtd, NAND_CTL_CLRCLE); +	chip->cmd_ctrl(mtd, command, ctrl); -	if (column != -1 || page_addr != -1) { -		this->hwcontrol(mtd, NAND_CTL_SETALE); - -		/* Serially input address */ -		if (column != -1) { -			/* Adjust columns for 16 bit buswidth */ -			if (this->options & NAND_BUSWIDTH_16) -				column >>= 1; -			this->write_byte(mtd, column); -		} -		if (page_addr != -1) { -			this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); -			this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); -			/* One more address cycle for devices > 32MiB */ -			if (this->chipsize > (32 << 20)) -				this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f)); -		} -		/* Latch in address */ -		this->hwcontrol(mtd, NAND_CTL_CLRALE); +	/* +	 * Address cycle, when necessary +	 */ +	ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; +	/* Serially input address */ +	if (column != -1) { +		/* Adjust columns for 16 bit buswidth */ +		if (chip->options & NAND_BUSWIDTH_16) +			column >>= 1; +		chip->cmd_ctrl(mtd, column, ctrl); +		ctrl &= ~NAND_CTRL_CHANGE; +	} +	if (page_addr != -1) { +		chip->cmd_ctrl(mtd, page_addr, ctrl); +		ctrl &= ~NAND_CTRL_CHANGE; +		chip->cmd_ctrl(mtd, page_addr >> 8, ctrl); +		/* One more address cycle for devices > 32MiB */ +		if (chip->chipsize > (32 << 20)) +			chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);  	} +	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);  	/*  	 * program and erase have their own busy handlers  	 * status and sequential in needs no delay -	*/ +	 */  	switch (command) {  	case NAND_CMD_PAGEPROG: @@ -607,32 +567,32 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in  		return;  	case NAND_CMD_RESET: -		if (this->dev_ready) +		if (chip->dev_ready)  			break; -		udelay(this->chip_delay); -		this->hwcontrol(mtd, NAND_CTL_SETCLE); -		this->write_byte(mtd, NAND_CMD_STATUS); -		this->hwcontrol(mtd, NAND_CTL_CLRCLE); -		while ( !(this->read_byte(mtd) & 0x40)); +		udelay(chip->chip_delay); +		chip->cmd_ctrl(mtd, NAND_CMD_STATUS, +			       NAND_CTRL_CLE | NAND_CTRL_CHANGE); +		chip->cmd_ctrl(mtd, +			       NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); +		while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;  		return; -	/* This applies to read commands */ +		/* This applies to read commands */  	default:  		/*  		 * If we don't have access to the busy pin, we apply the given  		 * command delay -		*/ -		if (!this->dev_ready) { -			udelay (this->chip_delay); +		 */ +		if (!chip->dev_ready) { +			udelay(chip->chip_delay);  			return;  		}  	} -  	/* Apply this short delay always to ensure that we do wait tWB in  	 * any case on any machine. */ -	ndelay (100); -	/* wait until command is processed */ -	while (!this->dev_ready(mtd)); +	ndelay(100); + +	nand_wait_ready(mtd);  }  /** @@ -642,55 +602,53 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in   * @column:	the column address for this command, -1 if none   * @page_addr:	the page address for this command, -1 if none   * - * Send command to NAND device. This is the version for the new large page devices - * We dont have the seperate regions as we have in the small page devices. - * We must emulate NAND_CMD_READOOB to keep the code compatible. - * + * Send command to NAND device. This is the version for the new large page + * devices We dont have the separate regions as we have in the small page + * devices.  We must emulate NAND_CMD_READOOB to keep the code compatible.   */ -static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, int page_addr) +static void nand_command_lp(struct mtd_info *mtd, unsigned int command, +			    int column, int page_addr)  { -	register struct nand_chip *this = mtd->priv; +	register struct nand_chip *chip = mtd->priv;  	/* Emulate NAND_CMD_READOOB */  	if (command == NAND_CMD_READOOB) { -		column += mtd->oobblock; +		column += mtd->writesize;  		command = NAND_CMD_READ0;  	} - -	/* Begin command latch cycle */ -	this->hwcontrol(mtd, NAND_CTL_SETCLE); -	/* Write out the command to the device. */ -	this->write_byte(mtd, command); -	/* End command latch cycle */ -	this->hwcontrol(mtd, NAND_CTL_CLRCLE); +	/* Command latch cycle */ +	chip->cmd_ctrl(mtd, command & 0xff, +		       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);  	if (column != -1 || page_addr != -1) { -		this->hwcontrol(mtd, NAND_CTL_SETALE); +		int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;  		/* Serially input address */  		if (column != -1) {  			/* Adjust columns for 16 bit buswidth */ -			if (this->options & NAND_BUSWIDTH_16) +			if (chip->options & NAND_BUSWIDTH_16)  				column >>= 1; -			this->write_byte(mtd, column & 0xff); -			this->write_byte(mtd, column >> 8); +			chip->cmd_ctrl(mtd, column, ctrl); +			ctrl &= ~NAND_CTRL_CHANGE; +			chip->cmd_ctrl(mtd, column >> 8, ctrl);  		}  		if (page_addr != -1) { -			this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); -			this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); +			chip->cmd_ctrl(mtd, page_addr, ctrl); +			chip->cmd_ctrl(mtd, page_addr >> 8, +				       NAND_NCE | NAND_ALE);  			/* One more address cycle for devices > 128MiB */ -			if (this->chipsize > (128 << 20)) -				this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0xff)); +			if (chip->chipsize > (128 << 20)) +				chip->cmd_ctrl(mtd, page_addr >> 16, +					       NAND_NCE | NAND_ALE);  		} -		/* Latch in address */ -		this->hwcontrol(mtd, NAND_CTL_CLRALE);  	} +	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);  	/*  	 * program and erase have their own busy handlers -	 * status and sequential in needs no delay -	*/ +	 * status, sequential in, and deplete1 need no delay +	 */  	switch (command) {  	case NAND_CMD_CACHEDPROG: @@ -698,51 +656,69 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,  	case NAND_CMD_ERASE1:  	case NAND_CMD_ERASE2:  	case NAND_CMD_SEQIN: +	case NAND_CMD_RNDIN:  	case NAND_CMD_STATUS: +	case NAND_CMD_DEPLETE1:  		return; +		/* +		 * read error status commands require only a short delay +		 */ +	case NAND_CMD_STATUS_ERROR: +	case NAND_CMD_STATUS_ERROR0: +	case NAND_CMD_STATUS_ERROR1: +	case NAND_CMD_STATUS_ERROR2: +	case NAND_CMD_STATUS_ERROR3: +		udelay(chip->chip_delay); +		return;  	case NAND_CMD_RESET: -		if (this->dev_ready) +		if (chip->dev_ready)  			break; -		udelay(this->chip_delay); -		this->hwcontrol(mtd, NAND_CTL_SETCLE); -		this->write_byte(mtd, NAND_CMD_STATUS); -		this->hwcontrol(mtd, NAND_CTL_CLRCLE); -		while ( !(this->read_byte(mtd) & 0x40)); +		udelay(chip->chip_delay); +		chip->cmd_ctrl(mtd, NAND_CMD_STATUS, +			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); +		chip->cmd_ctrl(mtd, NAND_CMD_NONE, +			       NAND_NCE | NAND_CTRL_CHANGE); +		while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; +		return; + +	case NAND_CMD_RNDOUT: +		/* No ready / busy check necessary */ +		chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART, +			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); +		chip->cmd_ctrl(mtd, NAND_CMD_NONE, +			       NAND_NCE | NAND_CTRL_CHANGE);  		return;  	case NAND_CMD_READ0: -		/* Begin command latch cycle */ -		this->hwcontrol(mtd, NAND_CTL_SETCLE); -		/* Write out the start read command */ -		this->write_byte(mtd, NAND_CMD_READSTART); -		/* End command latch cycle */ -		this->hwcontrol(mtd, NAND_CTL_CLRCLE); -		/* Fall through into ready check */ +		chip->cmd_ctrl(mtd, NAND_CMD_READSTART, +			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); +		chip->cmd_ctrl(mtd, NAND_CMD_NONE, +			       NAND_NCE | NAND_CTRL_CHANGE); -	/* This applies to read commands */ +		/* This applies to read commands */  	default:  		/*  		 * If we don't have access to the busy pin, we apply the given  		 * command delay -		*/ -		if (!this->dev_ready) { -			udelay (this->chip_delay); +		 */ +		if (!chip->dev_ready) { +			udelay(chip->chip_delay);  			return;  		}  	}  	/* Apply this short delay always to ensure that we do wait tWB in  	 * any case on any machine. */ -	ndelay (100); -	/* wait until command is processed */ -	while (!this->dev_ready(mtd)); +	ndelay(100); + +	nand_wait_ready(mtd);  }  /**   * nand_get_device - [GENERIC] Get chip for selected access - * @this:	the nand chip descriptor + * @chip:	the nand chip descriptor   * @mtd:	MTD device structure   * @new_state:	the state which is requested   * @@ -750,100 +726,96 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,   */  /* XXX U-BOOT XXX */  #if 0 -static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) +static int +nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)  { -	struct nand_chip *active = this; - -	DECLARE_WAITQUEUE (wait, current); +	spinlock_t *lock = &chip->controller->lock; +	wait_queue_head_t *wq = &chip->controller->wq; +	DECLARE_WAITQUEUE(wait, current); + retry: +	spin_lock(lock); -	/* -	 * Grab the lock and see if the device is available -	*/ -retry:  	/* Hardware controller shared among independend devices */ -	if (this->controller) { -		spin_lock (&this->controller->lock); -		if (this->controller->active) -			active = this->controller->active; -		else -			this->controller->active = this; -		spin_unlock (&this->controller->lock); -	} +	/* Hardware controller shared among independend devices */ +	if (!chip->controller->active) +		chip->controller->active = chip; -	if (active == this) { -		spin_lock (&this->chip_lock); -		if (this->state == FL_READY) { -			this->state = new_state; -			spin_unlock (&this->chip_lock); -			return; -		} +	if (chip->controller->active == chip && chip->state == FL_READY) { +		chip->state = new_state; +		spin_unlock(lock); +		return 0;  	} -	set_current_state (TASK_UNINTERRUPTIBLE); -	add_wait_queue (&active->wq, &wait); -	spin_unlock (&active->chip_lock); -	schedule (); -	remove_wait_queue (&active->wq, &wait); +	if (new_state == FL_PM_SUSPENDED) { +		spin_unlock(lock); +		return (chip->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN; +	} +	set_current_state(TASK_UNINTERRUPTIBLE); +	add_wait_queue(wq, &wait); +	spin_unlock(lock); +	schedule(); +	remove_wait_queue(wq, &wait);  	goto retry;  }  #else -static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) {} +static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) +{ +	return 0; +}  #endif  /**   * nand_wait - [DEFAULT]  wait until the command is done   * @mtd:	MTD device structure - * @this:	NAND chip structure - * @state:	state to select the max. timeout value + * @chip:	NAND chip structure   *   * Wait for command done. This applies to erase and program only   * Erase can take up to 400ms and program up to 20ms according to   * general NAND and SmartMedia specs - * -*/ + */  /* XXX U-BOOT XXX */  #if 0 -static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) +static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)  { -	unsigned long	timeo = jiffies; -	int	status; + +	unsigned long timeo = jiffies; +	int status, state = chip->state;  	if (state == FL_ERASING) -		 timeo += (HZ * 400) / 1000; +		timeo += (HZ * 400) / 1000;  	else -		 timeo += (HZ * 20) / 1000; +		timeo += (HZ * 20) / 1000; + +	led_trigger_event(nand_led_trigger, LED_FULL);  	/* Apply this short delay always to ensure that we do wait tWB in  	 * any case on any machine. */ -	ndelay (100); +	ndelay(100); -	if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) -		this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1); +	if ((state == FL_ERASING) && (chip->options & NAND_IS_AND)) +		chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);  	else -		this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); +		chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);  	while (time_before(jiffies, timeo)) { -		/* Check, if we were interrupted */ -		if (this->state != state) -			return 0; - -		if (this->dev_ready) { -			if (this->dev_ready(mtd)) +		if (chip->dev_ready) { +			if (chip->dev_ready(mtd))  				break;  		} else { -			if (this->read_byte(mtd) & NAND_STATUS_READY) +			if (chip->read_byte(mtd) & NAND_STATUS_READY)  				break;  		} -		yield (); +		cond_resched();  	} -	status = (int) this->read_byte(mtd); -	return status; +	led_trigger_event(nand_led_trigger, LED_OFF); -	return 0; +	status = (int)chip->read_byte(mtd); +	return status;  }  #else -static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) +static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)  {  	unsigned long	timeo; +	int state = this->state;  	if (state == FL_ERASING)  		timeo = (CFG_HZ * 400) / 1000; @@ -881,478 +853,305 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)  #endif  /** - * nand_write_page - [GENERIC] write one page - * @mtd:	MTD device structure - * @this:	NAND chip structure - * @page:	startpage inside the chip, must be called with (page & this->pagemask) - * @oob_buf:	out of band data buffer - * @oobsel:	out of band selecttion structre - * @cached:	1 = enable cached programming if supported by chip - * - * Nand_page_program function is used for write and writev ! - * This function will always program a full page of data - * If you call it with a non page aligned buffer, you're lost :) - * - * Cached programming is not supported yet. + * nand_read_page_raw - [Intern] read raw page data without ecc + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @buf:	buffer to store read data   */ -static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, -	u_char *oob_buf,  struct nand_oobinfo *oobsel, int cached) +static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, +			      uint8_t *buf)  { -	int	i, status; -	u_char	ecc_code[NAND_MAX_OOBSIZE]; -	int	eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; -	uint	*oob_config = oobsel->eccpos; -	int	datidx = 0, eccidx = 0, eccsteps = this->eccsteps; -	int	eccbytes = 0; +	chip->read_buf(mtd, buf, mtd->writesize); +	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); +	return 0; +} -	/* FIXME: Enable cached programming */ -	cached = 0; +/** + * nand_read_page_swecc - [REPLACABLE] software ecc based page read function + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @buf:	buffer to store read data + */ +static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, +				uint8_t *buf) +{ +	int i, eccsize = chip->ecc.size; +	int eccbytes = chip->ecc.bytes; +	int eccsteps = chip->ecc.steps; +	uint8_t *p = buf; +	uint8_t *ecc_calc = chip->buffers->ecccalc; +	uint8_t *ecc_code = chip->buffers->ecccode; +	uint32_t *eccpos = chip->ecc.layout->eccpos; -	/* Send command to begin auto page programming */ -	this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); +	chip->ecc.read_page_raw(mtd, chip, buf); -	/* Write out complete page of data, take care of eccmode */ -	switch (eccmode) { -	/* No ecc, write all */ -	case NAND_ECC_NONE: -		printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); -		this->write_buf(mtd, this->data_poi, mtd->oobblock); -		break; +	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) +		chip->ecc.calculate(mtd, p, &ecc_calc[i]); -	/* Software ecc 3/256, write all */ -	case NAND_ECC_SOFT: -		for (; eccsteps; eccsteps--) { -			this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code); -			for (i = 0; i < 3; i++, eccidx++) -				oob_buf[oob_config[eccidx]] = ecc_code[i]; -			datidx += this->eccsize; -		} -		this->write_buf(mtd, this->data_poi, mtd->oobblock); -		break; -	default: -		eccbytes = this->eccbytes; -		for (; eccsteps; eccsteps--) { -			/* enable hardware ecc logic for write */ -			this->enable_hwecc(mtd, NAND_ECC_WRITE); -			this->write_buf(mtd, &this->data_poi[datidx], this->eccsize); -			this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code); -			for (i = 0; i < eccbytes; i++, eccidx++) -				oob_buf[oob_config[eccidx]] = ecc_code[i]; -			/* If the hardware ecc provides syndromes then -			 * the ecc code must be written immediately after -			 * the data bytes (words) */ -			if (this->options & NAND_HWECC_SYNDROME) -				this->write_buf(mtd, ecc_code, eccbytes); -			datidx += this->eccsize; -		} -		break; -	} +	for (i = 0; i < chip->ecc.total; i++) +		ecc_code[i] = chip->oob_poi[eccpos[i]]; -	/* Write out OOB data */ -	if (this->options & NAND_HWECC_SYNDROME) -		this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes); -	else -		this->write_buf(mtd, oob_buf, mtd->oobsize); +	eccsteps = chip->ecc.steps; +	p = buf; -	/* Send command to actually program the data */ -	this->cmdfunc (mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1); +	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { +		int stat; -	if (!cached) { -		/* call wait ready function */ -		status = this->waitfunc (mtd, this, FL_WRITING); -		/* See if device thinks it succeeded */ -		if (status & 0x01) { -			MTDDEBUG (MTD_DEBUG_LEVEL0, -			          "%s: Failed write, page 0x%08x, ", -			          __FUNCTION__, page); -			return -EIO; -		} -	} else { -		/* FIXME: Implement cached programming ! */ -		/* wait until cache is ready*/ -		/* status = this->waitfunc (mtd, this, FL_CACHEDRPG); */ +		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); +		if (stat == -1) +			mtd->ecc_stats.failed++; +		else +			mtd->ecc_stats.corrected += stat;  	}  	return 0;  } -#ifdef CONFIG_MTD_NAND_VERIFY_WRITE  /** - * nand_verify_pages - [GENERIC] verify the chip contents after a write - * @mtd:	MTD device structure - * @this:	NAND chip structure - * @page:	startpage inside the chip, must be called with (page & this->pagemask) - * @numpages:	number of pages to verify - * @oob_buf:	out of band data buffer - * @oobsel:	out of band selecttion structre - * @chipnr:	number of the current chip - * @oobmode:	1 = full buffer verify, 0 = ecc only + * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @buf:	buffer to store read data   * - * The NAND device assumes that it is always writing to a cleanly erased page. - * Hence, it performs its internal write verification only on bits that - * transitioned from 1 to 0. The device does NOT verify the whole page on a - * byte by byte basis. It is possible that the page was not completely erased - * or the page is becoming unusable due to wear. The read with ECC would catch - * the error later when the ECC page check fails, but we would rather catch - * it early in the page write stage. Better to write no data than invalid data. + * Not for syndrome calculating ecc controllers which need a special oob layout   */ -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, -	u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode) +static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, +				uint8_t *buf)  { -	int	i, j, datidx = 0, oobofs = 0, res = -EIO; -	int	eccsteps = this->eccsteps; -	int	hweccbytes; -	u_char	oobdata[64]; +	int i, eccsize = chip->ecc.size; +	int eccbytes = chip->ecc.bytes; +	int eccsteps = chip->ecc.steps; +	uint8_t *p = buf; +	uint8_t *ecc_calc = chip->buffers->ecccalc; +	uint8_t *ecc_code = chip->buffers->ecccode; +	uint32_t *eccpos = chip->ecc.layout->eccpos; -	hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; - -	/* Send command to read back the first page */ -	this->cmdfunc (mtd, NAND_CMD_READ0, 0, page); - -	for(;;) { -		for (j = 0; j < eccsteps; j++) { -			/* Loop through and verify the data */ -			if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) { -				MTDDEBUG (MTD_DEBUG_LEVEL0, "%s: " -				          "Failed write verify, page 0x%08x ", -				          __FUNCTION__, page); -				goto out; -			} -			datidx += mtd->eccsize; -			/* Have we a hw generator layout ? */ -			if (!hweccbytes) -				continue; -			if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) { -				MTDDEBUG (MTD_DEBUG_LEVEL0, "%s: " -				          "Failed write verify, page 0x%08x ", -				          __FUNCTION__, page); -				goto out; -			} -			oobofs += hweccbytes; -		} +	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { +		chip->ecc.hwctl(mtd, NAND_ECC_READ); +		chip->read_buf(mtd, p, eccsize); +		chip->ecc.calculate(mtd, p, &ecc_calc[i]); +	} +	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -		/* check, if we must compare all data or if we just have to -		 * compare the ecc bytes -		 */ -		if (oobmode) { -			if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) { -				MTDDEBUG (MTD_DEBUG_LEVEL0, "%s: " -				          "Failed write verify, page 0x%08x ", -				          __FUNCTION__, page); -				goto out; -			} -		} else { -			/* Read always, else autoincrement fails */ -			this->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps); +	for (i = 0; i < chip->ecc.total; i++) +		ecc_code[i] = chip->oob_poi[eccpos[i]]; -			if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) { -				int ecccnt = oobsel->eccbytes; +	eccsteps = chip->ecc.steps; +	p = buf; -				for (i = 0; i < ecccnt; i++) { -					int idx = oobsel->eccpos[i]; -					if (oobdata[idx] != oob_buf[oobofs + idx] ) { -						MTDDEBUG (MTD_DEBUG_LEVEL0, -						"%s: Failed ECC write " -						"verify, page 0x%08x, " -						"%6i bytes were succesful\n", -						__FUNCTION__, page, i); -						goto out; -					} -				} -			} -		} -		oobofs += mtd->oobsize - hweccbytes * eccsteps; -		page++; -		numpages--; +	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { +		int stat; -		/* Apply delay or wait for ready/busy pin -		 * Do this before the AUTOINCR check, so no problems -		 * arise if a chip which does auto increment -		 * is marked as NOAUTOINCR by the board driver. -		 * Do this also before returning, so the chip is -		 * ready for the next command. -		*/ -		if (!this->dev_ready) -			udelay (this->chip_delay); +		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); +		if (stat == -1) +			mtd->ecc_stats.failed++;  		else -			while (!this->dev_ready(mtd)); - -		/* All done, return happy */ -		if (!numpages) -			return 0; - - -		/* Check, if the chip supports auto page increment */ -		if (!NAND_CANAUTOINCR(this)) -			this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); +			mtd->ecc_stats.corrected += stat;  	} -	/* -	 * Terminate the read command. We come here in case of an error -	 * So we must issue a reset command. -	 */ -out: -	this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1); -	return res; -} -#endif - -/** - * nand_read - [MTD Interface] MTD compability function for nand_read_ecc - * @mtd:	MTD device structure - * @from:	offset to read from - * @len:	number of bytes to read - * @retlen:	pointer to variable to store the number of read bytes - * @buf:	the databuffer to put data - * - * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL -*/ -static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) -{ -	return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); +	return 0;  } -  /** - * nand_read_ecc - [MTD Interface] Read data with ECC - * @mtd:	MTD device structure - * @from:	offset to read from - * @len:	number of bytes to read - * @retlen:	pointer to variable to store the number of read bytes - * @buf:	the databuffer to put data - * @oob_buf:	filesystem supplied oob data buffer - * @oobsel:	oob selection structure + * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @buf:	buffer to store read data   * - * NAND read with ECC + * The hw generator calculates the error syndrome automatically. Therefor + * we need a special oob layout and handling.   */ -static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, -			  size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) +static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, +				   uint8_t *buf)  { -	int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; -	int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; -	struct nand_chip *this = mtd->priv; -	u_char *data_poi, *oob_data = oob_buf; -	u_char ecc_calc[NAND_MAX_OOBSIZE]; -	u_char ecc_code[NAND_MAX_OOBSIZE]; -	int eccmode, eccsteps; -	unsigned *oob_config; -	int	datidx; -	int	blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; -	int	eccbytes; -	int	compareecc = 1; -	int	oobreadlen; - - -	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", -	          (unsigned int) from, (int) len); - -	/* Do not allow reads past end of device */ -	if ((from + len) > mtd->size) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, -		          "nand_read_ecc: Attempt read beyond end of device\n"); -		*retlen = 0; -		return -EINVAL; -	} +	int i, eccsize = chip->ecc.size; +	int eccbytes = chip->ecc.bytes; +	int eccsteps = chip->ecc.steps; +	uint8_t *p = buf; +	uint8_t *oob = chip->oob_poi; -	/* Grab the lock and see if the device is available */ -	nand_get_device (this, mtd ,FL_READING); +	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { +		int stat; -	/* use userspace supplied oobinfo, if zero */ -	if (oobsel == NULL) -		oobsel = &mtd->oobinfo; +		chip->ecc.hwctl(mtd, NAND_ECC_READ); +		chip->read_buf(mtd, p, eccsize); -	/* Autoplace of oob data ? Use the default placement scheme */ -	if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) -		oobsel = this->autooob; - -	eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; -	oob_config = oobsel->eccpos; +		if (chip->ecc.prepad) { +			chip->read_buf(mtd, oob, chip->ecc.prepad); +			oob += chip->ecc.prepad; +		} -	/* Select the NAND device */ -	chipnr = (int)(from >> this->chip_shift); -	this->select_chip(mtd, chipnr); +		chip->ecc.hwctl(mtd, NAND_ECC_READSYN); +		chip->read_buf(mtd, oob, eccbytes); +		stat = chip->ecc.correct(mtd, p, oob, NULL); -	/* First we calculate the starting page */ -	realpage = (int) (from >> this->page_shift); -	page = realpage & this->pagemask; +		if (stat == -1) +			mtd->ecc_stats.failed++; +		else +			mtd->ecc_stats.corrected += stat; -	/* Get raw starting column */ -	col = from & (mtd->oobblock - 1); +		oob += eccbytes; -	end = mtd->oobblock; -	ecc = this->eccsize; -	eccbytes = this->eccbytes; +		if (chip->ecc.postpad) { +			chip->read_buf(mtd, oob, chip->ecc.postpad); +			oob += chip->ecc.postpad; +		} +	} -	if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME)) -		compareecc = 0; +	/* Calculate remaining oob bytes */ +	i = mtd->oobsize - (oob - chip->oob_poi); +	if (i) +		chip->read_buf(mtd, oob, i); -	oobreadlen = mtd->oobsize; -	if (this->options & NAND_HWECC_SYNDROME) -		oobreadlen -= oobsel->eccbytes; +	return 0; +} -	/* Loop until all data read */ -	while (read < len) { +/** + * nand_transfer_oob - [Internal] Transfer oob to client buffer + * @chip:	nand chip structure + * @oob:	oob destination address + * @ops:	oob ops structure + * @len:	size of oob to transfer + */ +static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, +				  struct mtd_oob_ops *ops, size_t len) +{ +	switch(ops->mode) { -		int aligned = (!col && (len - read) >= end); -		/* -		 * If the read is not page aligned, we have to read into data buffer -		 * due to ecc, else we read into return buffer direct -		 */ -		if (aligned) -			data_poi = &buf[read]; -		else -			data_poi = this->data_buf; +	case MTD_OOB_PLACE: +	case MTD_OOB_RAW: +		memcpy(oob, chip->oob_poi + ops->ooboffs, len); +		return oob + len; -		/* Check, if we have this page in the buffer -		 * -		 * FIXME: Make it work when we must provide oob data too, -		 * check the usage of data_buf oob field -		 */ -		if (realpage == this->pagebuf && !oob_buf) { -			/* aligned read ? */ -			if (aligned) -				memcpy (data_poi, this->data_buf, end); -			goto readdata; -		} +	case MTD_OOB_AUTO: { +		struct nand_oobfree *free = chip->ecc.layout->oobfree; +		uint32_t boffs = 0, roffs = ops->ooboffs; +		size_t bytes = 0; -		/* Check, if we must send the read command */ -		if (sndcmd) { -			this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); -			sndcmd = 0; +		for(; free->length && len; free++, len -= bytes) { +			/* Read request not from offset 0 ? */ +			if (unlikely(roffs)) { +				if (roffs >= free->length) { +					roffs -= free->length; +					continue; +				} +				boffs = free->offset + roffs; +				bytes = min_t(size_t, len, +					      (free->length - roffs)); +				roffs = 0; +			} else { +				bytes = min_t(size_t, len, free->length); +				boffs = free->offset; +			} +			memcpy(oob, chip->oob_poi + boffs, bytes); +			oob += bytes;  		} +		return oob; +	} +	default: +		BUG(); +	} +	return NULL; +} -		/* get oob area, if we have no oob buffer from fs-driver */ -		if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE || -			oobsel->useecc == MTD_NANDECC_AUTOPL_USR) -			oob_data = &this->data_buf[end]; - -		eccsteps = this->eccsteps; +/** + * nand_do_read_ops - [Internal] Read data with ECC + * + * @mtd:	MTD device structure + * @from:	offset to read from + * @ops:	oob ops structure + * + * Internal function. Called with chip held. + */ +static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, +			    struct mtd_oob_ops *ops) +{ +	int chipnr, page, realpage, col, bytes, aligned; +	struct nand_chip *chip = mtd->priv; +	struct mtd_ecc_stats stats; +	int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; +	int sndcmd = 1; +	int ret = 0; +	uint32_t readlen = ops->len; +	uint32_t oobreadlen = ops->ooblen; +	uint8_t *bufpoi, *oob, *buf; -		switch (eccmode) { -		case NAND_ECC_NONE: {	/* No ECC, Read in a page */ -/* XXX U-BOOT XXX */ -#if 0 -			static unsigned long lastwhinge = 0; -			if ((lastwhinge / HZ) != (jiffies / HZ)) { -				printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n"); -				lastwhinge = jiffies; -			} -#else -			puts("Reading data from NAND FLASH without ECC is not recommended\n"); -#endif -			this->read_buf(mtd, data_poi, end); -			break; -		} +	stats = mtd->ecc_stats; -		case NAND_ECC_SOFT:	/* Software ECC 3/256: Read in a page + oob data */ -			this->read_buf(mtd, data_poi, end); -			for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) -				this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); -			break; +	chipnr = (int)(from >> chip->chip_shift); +	chip->select_chip(mtd, chipnr); -		default: -			for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) { -				this->enable_hwecc(mtd, NAND_ECC_READ); -				this->read_buf(mtd, &data_poi[datidx], ecc); +	realpage = (int)(from >> chip->page_shift); +	page = realpage & chip->pagemask; -				/* HW ecc with syndrome calculation must read the -				 * syndrome from flash immidiately after the data */ -				if (!compareecc) { -					/* Some hw ecc generators need to know when the -					 * syndrome is read from flash */ -					this->enable_hwecc(mtd, NAND_ECC_READSYN); -					this->read_buf(mtd, &oob_data[i], eccbytes); -					/* We calc error correction directly, it checks the hw -					 * generator for an error, reads back the syndrome and -					 * does the error correction on the fly */ -					if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { -						MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " -							"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); -						ecc_failed++; -					} -				} else { -					this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); -				} -			} -			break; -		} +	col = (int)(from & (mtd->writesize - 1)); -		/* read oobdata */ -		this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen); +	buf = ops->datbuf; +	oob = ops->oobbuf; -		/* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */ -		if (!compareecc) -			goto readoob; +	while(1) { +		bytes = min(mtd->writesize - col, readlen); +		aligned = (bytes == mtd->writesize); -		/* Pick the ECC bytes out of the oob data */ -		for (j = 0; j < oobsel->eccbytes; j++) -			ecc_code[j] = oob_data[oob_config[j]]; +		/* Is the current page in the buffer ? */ +		if (realpage != chip->pagebuf || oob) { +			bufpoi = aligned ? buf : chip->buffers->databuf; -		/* correct data, if neccecary */ -		for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) { -			ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); +			if (likely(sndcmd)) { +				chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); +				sndcmd = 0; +			} -			/* Get next chunk of ecc bytes */ -			j += eccbytes; +			/* Now read the page into the buffer */ +			if (unlikely(ops->mode == MTD_OOB_RAW)) +				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); +			else +				ret = chip->ecc.read_page(mtd, chip, bufpoi); +			if (ret < 0) +				break; -			/* Check, if we have a fs supplied oob-buffer, -			 * This is the legacy mode. Used by YAFFS1 -			 * Should go away some day -			 */ -			if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { -				int *p = (int *)(&oob_data[mtd->oobsize]); -				p[i] = ecc_status; +			/* Transfer not aligned data */ +			if (!aligned) { +				chip->pagebuf = realpage; +				memcpy(buf, chip->buffers->databuf + col, bytes);  			} -			if (ecc_status == -1) { -				MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " -				          "Failed ECC read, page 0x%08x\n", -				          page); -				ecc_failed++; +			buf += bytes; + +			if (unlikely(oob)) { +				/* Raw mode does data:oob:data:oob */ +				if (ops->mode != MTD_OOB_RAW) { +					int toread = min(oobreadlen, +						chip->ecc.layout->oobavail); +					if (toread) { +						oob = nand_transfer_oob(chip, +							oob, ops, toread); +						oobreadlen -= toread; +					} +				} else +					buf = nand_transfer_oob(chip, +						buf, ops, mtd->oobsize);  			} -		} -	readoob: -		/* check, if we have a fs supplied oob-buffer */ -		if (oob_buf) { -			/* without autoplace. Legacy mode used by YAFFS1 */ -			switch(oobsel->useecc) { -			case MTD_NANDECC_AUTOPLACE: -			case MTD_NANDECC_AUTOPL_USR: -				/* Walk through the autoplace chunks */ -				for (i = 0, j = 0; j < mtd->oobavail; i++) { -					int from = oobsel->oobfree[i][0]; -					int num = oobsel->oobfree[i][1]; -					memcpy(&oob_buf[oob+j], &oob_data[from], num); -					j+= num; -				} -				oob += mtd->oobavail; -				break; -			case MTD_NANDECC_PLACE: -				/* YAFFS1 legacy mode */ -				oob_data += this->eccsteps * sizeof (int); -			default: -				oob_data += mtd->oobsize; +			if (!(chip->options & NAND_NO_READRDY)) { +				/* +				 * Apply delay or wait for ready/busy pin. Do +				 * this before the AUTOINCR check, so no +				 * problems arise if a chip which does auto +				 * increment is marked as NOAUTOINCR by the +				 * board driver. +				 */ +				if (!chip->dev_ready) +					udelay(chip->chip_delay); +				else +					nand_wait_ready(mtd);  			} +		} else { +			memcpy(buf, chip->buffers->databuf + col, bytes); +			buf += bytes;  		} -	readdata: -		/* Partial page read, transfer data into fs buffer */ -		if (!aligned) { -			for (j = col; j < end && read < len; j++) -				buf[read++] = data_poi[j]; -			this->pagebuf = realpage; -		} else -			read += mtd->oobblock; -		/* Apply delay or wait for ready/busy pin -		 * Do this before the AUTOINCR check, so no problems -		 * arise if a chip which does auto increment -		 * is marked as NOAUTOINCR by the board driver. -		*/ -		if (!this->dev_ready) -			udelay (this->chip_delay); -		else -			while (!this->dev_ready(mtd)); +		readlen -= bytes; -		if (read == len) +		if (!readlen)  			break;  		/* For subsequent reads align to page boundary. */ @@ -1360,732 +1159,829 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,  		/* Increment page address */  		realpage++; -		page = realpage & this->pagemask; +		page = realpage & chip->pagemask;  		/* Check, if we cross a chip boundary */  		if (!page) {  			chipnr++; -			this->select_chip(mtd, -1); -			this->select_chip(mtd, chipnr); +			chip->select_chip(mtd, -1); +			chip->select_chip(mtd, chipnr);  		} +  		/* Check, if the chip supports auto page increment  		 * or if we have hit a block boundary. -		*/ -		if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) +		 */ +		if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))  			sndcmd = 1;  	} -	/* Deselect and wake up anyone waiting on the device */ -	nand_release_device(mtd); +	ops->retlen = ops->len - (size_t) readlen; +	if (oob) +		ops->oobretlen = ops->ooblen - oobreadlen; -	/* -	 * Return success, if no ECC failures, else -EBADMSG -	 * fs driver will take care of that, because -	 * retlen == desired len and result == -EBADMSG -	 */ -	*retlen = read; -	return ecc_failed ? -EBADMSG : 0; +	if (ret) +		return ret; + +	if (mtd->ecc_stats.failed - stats.failed) +		return -EBADMSG; + +	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;  }  /** - * nand_read_oob - [MTD Interface] NAND read out-of-band + * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc   * @mtd:	MTD device structure   * @from:	offset to read from   * @len:	number of bytes to read   * @retlen:	pointer to variable to store the number of read bytes   * @buf:	the databuffer to put data   * - * NAND read out-of-band data from the spare area + * Get hold of the chip and call nand_do_read   */ -static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) +static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, +		     size_t *retlen, uint8_t *buf)  { -	int i, col, page, chipnr; -	struct nand_chip *this = mtd->priv; -	int	blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; +	struct nand_chip *chip = mtd->priv; +	int ret; -	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", -	          (unsigned int) from, (int) len); +	/* Do not allow reads past end of device */ +	if ((from + len) > mtd->size) +		return -EINVAL; +	if (!len) +		return 0; -	/* Shift to get page */ -	page = (int)(from >> this->page_shift); -	chipnr = (int)(from >> this->chip_shift); +	nand_get_device(chip, mtd, FL_READING); -	/* Mask to get column */ -	col = from & (mtd->oobsize - 1); +	chip->ops.len = len; +	chip->ops.datbuf = buf; +	chip->ops.oobbuf = NULL; -	/* Initialize return length value */ -	*retlen = 0; +	ret = nand_do_read_ops(mtd, from, &chip->ops); -	/* Do not allow reads past end of device */ -	if ((from + len) > mtd->size) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, -		          "nand_read_oob: Attempt read beyond end of device\n"); -		*retlen = 0; -		return -EINVAL; +	*retlen = chip->ops.retlen; + +	nand_release_device(mtd); + +	return ret; +} + +/** + * nand_read_oob_std - [REPLACABLE] the most common OOB data read function + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @page:	page number to read + * @sndcmd:	flag whether to issue read command or not + */ +static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, +			     int page, int sndcmd) +{ +	if (sndcmd) { +		chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); +		sndcmd = 0;  	} +	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); +	return sndcmd; +} -	/* Grab the lock and see if the device is available */ -	nand_get_device (this, mtd , FL_READING); +/** + * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC + *			    with syndromes + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @page:	page number to read + * @sndcmd:	flag whether to issue read command or not + */ +static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, +				  int page, int sndcmd) +{ +	uint8_t *buf = chip->oob_poi; +	int length = mtd->oobsize; +	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; +	int eccsize = chip->ecc.size; +	uint8_t *bufpoi = buf; +	int i, toread, sndrnd = 0, pos; -	/* Select the NAND device */ -	this->select_chip(mtd, chipnr); +	chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page); +	for (i = 0; i < chip->ecc.steps; i++) { +		if (sndrnd) { +			pos = eccsize + i * (eccsize + chunk); +			if (mtd->writesize > 512) +				chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1); +			else +				chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page); +		} else +			sndrnd = 1; +		toread = min_t(int, length, chunk); +		chip->read_buf(mtd, bufpoi, toread); +		bufpoi += toread; +		length -= toread; +	} +	if (length > 0) +		chip->read_buf(mtd, bufpoi, length); -	/* Send the read command */ -	this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask); -	/* -	 * Read the data, if we read more than one page -	 * oob data, let the device transfer the data ! -	 */ -	i = 0; -	while (i < len) { -		int thislen = mtd->oobsize - col; -		thislen = min_t(int, thislen, len); -		this->read_buf(mtd, &buf[i], thislen); -		i += thislen; +	return 1; +} -		/* Apply delay or wait for ready/busy pin -		 * Do this before the AUTOINCR check, so no problems -		 * arise if a chip which does auto increment -		 * is marked as NOAUTOINCR by the board driver. -		*/ -		if (!this->dev_ready) -			udelay (this->chip_delay); -		else -			while (!this->dev_ready(mtd)); +/** + * nand_write_oob_std - [REPLACABLE] the most common OOB data write function + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @page:	page number to write + */ +static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, +			      int page) +{ +	int status = 0; +	const uint8_t *buf = chip->oob_poi; +	int length = mtd->oobsize; -		/* Read more ? */ -		if (i < len) { -			page++; -			col = 0; +	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); +	chip->write_buf(mtd, buf, length); +	/* Send command to program the OOB data */ +	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); -			/* Check, if we cross a chip boundary */ -			if (!(page & this->pagemask)) { -				chipnr++; -				this->select_chip(mtd, -1); -				this->select_chip(mtd, chipnr); -			} +	status = chip->waitfunc(mtd, chip); + +	return status & NAND_STATUS_FAIL ? -EIO : 0; +} + +/** + * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC + *			     with syndrome - only for large page flash ! + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @page:	page number to write + */ +static int nand_write_oob_syndrome(struct mtd_info *mtd, +				   struct nand_chip *chip, int page) +{ +	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; +	int eccsize = chip->ecc.size, length = mtd->oobsize; +	int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps; +	const uint8_t *bufpoi = chip->oob_poi; + +	/* +	 * data-ecc-data-ecc ... ecc-oob +	 * or +	 * data-pad-ecc-pad-data-pad .... ecc-pad-oob +	 */ +	if (!chip->ecc.prepad && !chip->ecc.postpad) { +		pos = steps * (eccsize + chunk); +		steps = 0; +	} else +		pos = eccsize; + +	chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); +	for (i = 0; i < steps; i++) { +		if (sndcmd) { +			if (mtd->writesize <= 512) { +				uint32_t fill = 0xFFFFFFFF; -			/* Check, if the chip supports auto page increment -			 * or if we have hit a block boundary. -			*/ -			if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) { -				/* For subsequent page reads set offset to 0 */ -				this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); +				len = eccsize; +				while (len > 0) { +					int num = min_t(int, len, 4); +					chip->write_buf(mtd, (uint8_t *)&fill, +							num); +					len -= num; +				} +			} else { +				pos = eccsize + i * (eccsize + chunk); +				chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1);  			} -		} +		} else +			sndcmd = 1; +		len = min_t(int, length, chunk); +		chip->write_buf(mtd, bufpoi, len); +		bufpoi += len; +		length -= len;  	} +	if (length > 0) +		chip->write_buf(mtd, bufpoi, length); -	/* Deselect and wake up anyone waiting on the device */ -	nand_release_device(mtd); +	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); +	status = chip->waitfunc(mtd, chip); -	/* Return happy */ -	*retlen = len; -	return 0; +	return status & NAND_STATUS_FAIL ? -EIO : 0;  }  /** - * nand_read_raw - [GENERIC] Read raw data including oob into buffer + * nand_do_read_oob - [Intern] NAND read out-of-band   * @mtd:	MTD device structure - * @buf:	temporary buffer   * @from:	offset to read from - * @len:	number of bytes to read - * @ooblen:	number of oob data bytes to read + * @ops:	oob operations description structure   * - * Read raw data including oob into buffer + * NAND read out-of-band data from the spare area   */ -int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen) +static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, +			    struct mtd_oob_ops *ops)  { -	struct nand_chip *this = mtd->priv; -	int page = (int) (from >> this->page_shift); -	int chip = (int) (from >> this->chip_shift); -	int sndcmd = 1; -	int cnt = 0; -	int pagesize = mtd->oobblock + mtd->oobsize; -	int	blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; +	int page, realpage, chipnr, sndcmd = 1; +	struct nand_chip *chip = mtd->priv; +	int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; +	int readlen = ops->ooblen; +	int len; +	uint8_t *buf = ops->oobbuf; + +	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n", +	          (unsigned long long)from, readlen); + +	if (ops->mode == MTD_OOB_AUTO) +		len = chip->ecc.layout->oobavail; +	else +		len = mtd->oobsize; + +	if (unlikely(ops->ooboffs >= len)) { +		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: " +		          "Attempt to start read outside oob\n"); +		return -EINVAL; +	}  	/* Do not allow reads past end of device */ -	if ((from + len) > mtd->size) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, -		          "nand_read_raw: Attempt read beyond end of device\n"); +	if (unlikely(from >= mtd->size || +		     ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - +					(from >> chip->page_shift)) * len)) { +		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: " +		          "Attempt read beyond end of device\n");  		return -EINVAL;  	} -	/* Grab the lock and see if the device is available */ -	nand_get_device (this, mtd , FL_READING); +	chipnr = (int)(from >> chip->chip_shift); +	chip->select_chip(mtd, chipnr); -	this->select_chip (mtd, chip); +	/* Shift to get page */ +	realpage = (int)(from >> chip->page_shift); +	page = realpage & chip->pagemask; -	/* Add requested oob length */ -	len += ooblen; +	while(1) { +		sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); -	while (len) { -		if (sndcmd) -			this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask); -		sndcmd = 0; +		len = min(len, readlen); +		buf = nand_transfer_oob(chip, buf, ops, len); -		this->read_buf (mtd, &buf[cnt], pagesize); +		if (!(chip->options & NAND_NO_READRDY)) { +			/* +			 * Apply delay or wait for ready/busy pin. Do this +			 * before the AUTOINCR check, so no problems arise if a +			 * chip which does auto increment is marked as +			 * NOAUTOINCR by the board driver. +			 */ +			if (!chip->dev_ready) +				udelay(chip->chip_delay); +			else +				nand_wait_ready(mtd); +		} -		len -= pagesize; -		cnt += pagesize; -		page++; +		readlen -= len; +		if (!readlen) +			break; -		if (!this->dev_ready) -			udelay (this->chip_delay); -		else -			while (!this->dev_ready(mtd)); +		/* Increment page address */ +		realpage++; -		/* Check, if the chip supports auto page increment */ -		if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) +		page = realpage & chip->pagemask; +		/* Check, if we cross a chip boundary */ +		if (!page) { +			chipnr++; +			chip->select_chip(mtd, -1); +			chip->select_chip(mtd, chipnr); +		} + +		/* Check, if the chip supports auto page increment +		 * or if we have hit a block boundary. +		 */ +		if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))  			sndcmd = 1;  	} -	/* Deselect and wake up anyone waiting on the device */ -	nand_release_device(mtd); +	ops->oobretlen = ops->ooblen;  	return 0;  } -  /** - * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer + * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band   * @mtd:	MTD device structure - * @fsbuf:	buffer given by fs driver - * @oobsel:	out of band selection structre - * @autoplace:	1 = place given buffer into the oob bytes - * @numpages:	number of pages to prepare - * - * Return: - * 1. Filesystem buffer available and autoplacement is off, - *    return filesystem buffer - * 2. No filesystem buffer or autoplace is off, return internal - *    buffer - * 3. Filesystem buffer is given and autoplace selected - *    put data from fs buffer into internal buffer and - *    retrun internal buffer - * - * Note: The internal buffer is filled with 0xff. This must - * be done only once, when no autoplacement happens - * Autoplacement sets the buffer dirty flag, which - * forces the 0xff fill before using the buffer again. + * @from:	offset to read from + * @ops:	oob operation description structure   * -*/ -static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct nand_oobinfo *oobsel, -		int autoplace, int numpages) + * NAND read data and/or out-of-band data + */ +static int nand_read_oob(struct mtd_info *mtd, loff_t from, +			 struct mtd_oob_ops *ops)  { -	struct nand_chip *this = mtd->priv; -	int i, len, ofs; +	struct nand_chip *chip = mtd->priv; +	int ret = -ENOTSUPP; -	/* Zero copy fs supplied buffer */ -	if (fsbuf && !autoplace) -		return fsbuf; +	ops->retlen = 0; -	/* Check, if the buffer must be filled with ff again */ -	if (this->oobdirty) { -		memset (this->oob_buf, 0xff, -			mtd->oobsize << (this->phys_erase_shift - this->page_shift)); -		this->oobdirty = 0; +	/* Do not allow reads past end of device */ +	if (ops->datbuf && (from + ops->len) > mtd->size) { +		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: " +		          "Attempt read beyond end of device\n"); +		return -EINVAL;  	} -	/* If we have no autoplacement or no fs buffer use the internal one */ -	if (!autoplace || !fsbuf) -		return this->oob_buf; +	nand_get_device(chip, mtd, FL_READING); -	/* Walk through the pages and place the data */ -	this->oobdirty = 1; -	ofs = 0; -	while (numpages--) { -		for (i = 0, len = 0; len < mtd->oobavail; i++) { -			int to = ofs + oobsel->oobfree[i][0]; -			int num = oobsel->oobfree[i][1]; -			memcpy (&this->oob_buf[to], fsbuf, num); -			len += num; -			fsbuf += num; -		} -		ofs += mtd->oobavail; +	switch(ops->mode) { +	case MTD_OOB_PLACE: +	case MTD_OOB_AUTO: +	case MTD_OOB_RAW: +		break; + +	default: +		goto out;  	} -	return this->oob_buf; + +	if (!ops->datbuf) +		ret = nand_do_read_oob(mtd, from, ops); +	else +		ret = nand_do_read_ops(mtd, from, ops); + + out: +	nand_release_device(mtd); +	return ret;  } -#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0  /** - * nand_write - [MTD Interface] compability function for nand_write_ecc - * @mtd:	MTD device structure - * @to:		offset to write to - * @len:	number of bytes to write - * @retlen:	pointer to variable to store the number of written bytes - * @buf:	the data to write - * - * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL - * -*/ -static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) + * nand_write_page_raw - [Intern] raw page write function + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @buf:	data buffer + */ +static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, +				const uint8_t *buf)  { -	return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); +	chip->write_buf(mtd, buf, mtd->writesize); +	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);  }  /** - * nand_write_ecc - [MTD Interface] NAND write with ECC - * @mtd:	MTD device structure - * @to:		offset to write to - * @len:	number of bytes to write - * @retlen:	pointer to variable to store the number of written bytes - * @buf:	the data to write - * @eccbuf:	filesystem supplied oob data buffer - * @oobsel:	oob selection structure - * - * NAND write with ECC + * nand_write_page_swecc - [REPLACABLE] software ecc based page write function + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @buf:	data buffer   */ -static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, -			   size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel) +static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, +				  const uint8_t *buf)  { -	int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr; -	int autoplace = 0, numpages, totalpages; -	struct nand_chip *this = mtd->priv; -	u_char *oobbuf, *bufstart; -	int	ppblock = (1 << (this->phys_erase_shift - this->page_shift)); +	int i, eccsize = chip->ecc.size; +	int eccbytes = chip->ecc.bytes; +	int eccsteps = chip->ecc.steps; +	uint8_t *ecc_calc = chip->buffers->ecccalc; +	const uint8_t *p = buf; +	uint32_t *eccpos = chip->ecc.layout->eccpos; -	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", -	          (unsigned int) to, (int) len); +	/* Software ecc calculation */ +	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) +		chip->ecc.calculate(mtd, p, &ecc_calc[i]); -	/* Initialize retlen, in case of early exit */ -	*retlen = 0; +	for (i = 0; i < chip->ecc.total; i++) +		chip->oob_poi[eccpos[i]] = ecc_calc[i]; -	/* Do not allow write past end of device */ -	if ((to + len) > mtd->size) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, -		          "nand_write_ecc: Attempt to write past end of page\n"); -		return -EINVAL; -	} +	chip->ecc.write_page_raw(mtd, chip, buf); +} -	/* reject writes, which are not page aligned */ -	if (NOTALIGNED (to) || NOTALIGNED(len)) { -		printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); -		return -EINVAL; +/** + * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @buf:	data buffer + */ +static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, +				  const uint8_t *buf) +{ +	int i, eccsize = chip->ecc.size; +	int eccbytes = chip->ecc.bytes; +	int eccsteps = chip->ecc.steps; +	uint8_t *ecc_calc = chip->buffers->ecccalc; +	const uint8_t *p = buf; +	uint32_t *eccpos = chip->ecc.layout->eccpos; + +	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { +		chip->ecc.hwctl(mtd, NAND_ECC_WRITE); +		chip->write_buf(mtd, p, eccsize); +		chip->ecc.calculate(mtd, p, &ecc_calc[i]);  	} -	/* Grab the lock and see if the device is available */ -	nand_get_device (this, mtd, FL_WRITING); +	for (i = 0; i < chip->ecc.total; i++) +		chip->oob_poi[eccpos[i]] = ecc_calc[i]; -	/* Calculate chipnr */ -	chipnr = (int)(to >> this->chip_shift); -	/* Select the NAND device */ -	this->select_chip(mtd, chipnr); +	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); +} -	/* Check, if it is write protected */ -	if (nand_check_wp(mtd)) { -		printk (KERN_NOTICE "nand_write_ecc: Device is write protected\n"); -		goto out; -	} +/** + * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write + * @mtd:	mtd info structure + * @chip:	nand chip info structure + * @buf:	data buffer + * + * The hw generator calculates the error syndrome automatically. Therefor + * we need a special oob layout and handling. + */ +static void nand_write_page_syndrome(struct mtd_info *mtd, +				    struct nand_chip *chip, const uint8_t *buf) +{ +	int i, eccsize = chip->ecc.size; +	int eccbytes = chip->ecc.bytes; +	int eccsteps = chip->ecc.steps; +	const uint8_t *p = buf; +	uint8_t *oob = chip->oob_poi; + +	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { -	/* if oobsel is NULL, use chip defaults */ -	if (oobsel == NULL) -		oobsel = &mtd->oobinfo; +		chip->ecc.hwctl(mtd, NAND_ECC_WRITE); +		chip->write_buf(mtd, p, eccsize); + +		if (chip->ecc.prepad) { +			chip->write_buf(mtd, oob, chip->ecc.prepad); +			oob += chip->ecc.prepad; +		} -	/* Autoplace of oob data ? Use the default placement scheme */ -	if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { -		oobsel = this->autooob; -		autoplace = 1; +		chip->ecc.calculate(mtd, p, oob); +		chip->write_buf(mtd, oob, eccbytes); +		oob += eccbytes; + +		if (chip->ecc.postpad) { +			chip->write_buf(mtd, oob, chip->ecc.postpad); +			oob += chip->ecc.postpad; +		}  	} -	if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) -		autoplace = 1; -	/* Setup variables and oob buffer */ -	totalpages = len >> this->page_shift; -	page = (int) (to >> this->page_shift); -	/* Invalidate the page cache, if we write to the cached page */ -	if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) -		this->pagebuf = -1; +	/* Calculate remaining oob bytes */ +	i = mtd->oobsize - (oob - chip->oob_poi); +	if (i) +		chip->write_buf(mtd, oob, i); +} -	/* Set it relative to chip */ -	page &= this->pagemask; -	startpage = page; -	/* Calc number of pages we can write in one go */ -	numpages = min (ppblock - (startpage  & (ppblock - 1)), totalpages); -	oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, autoplace, numpages); -	bufstart = (u_char *)buf; +/** + * nand_write_page - [REPLACEABLE] write one page + * @mtd:	MTD device structure + * @chip:	NAND chip descriptor + * @buf:	the data to write + * @page:	page number to write + * @cached:	cached programming + * @raw:	use _raw version of write_page + */ +static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, +			   const uint8_t *buf, int page, int cached, int raw) +{ +	int status; -	/* Loop until all data is written */ -	while (written < len) { +	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); -		this->data_poi = (u_char*) &buf[written]; -		/* Write one page. If this is the last page to write -		 * or the last page in this block, then use the -		 * real pageprogram command, else select cached programming -		 * if supported by the chip. +	if (unlikely(raw)) +		chip->ecc.write_page_raw(mtd, chip, buf); +	else +		chip->ecc.write_page(mtd, chip, buf); + +	/* +	 * Cached progamming disabled for now, Not sure if its worth the +	 * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s) +	 */ +	cached = 0; + +	if (!cached || !(chip->options & NAND_CACHEPRG)) { + +		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); +		status = chip->waitfunc(mtd, chip); +		/* +		 * See if operation failed and additional status checks are +		 * available  		 */ -		ret = nand_write_page (mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0)); -		if (ret) { -			MTDDEBUG (MTD_DEBUG_LEVEL0, -			          "nand_write_ecc: write_page failed %d\n", ret); -			goto out; -		} -		/* Next oob page */ -		oob += mtd->oobsize; -		/* Update written bytes count */ -		written += mtd->oobblock; -		if (written == len) -			goto cmp; +		if ((status & NAND_STATUS_FAIL) && (chip->errstat)) +			status = chip->errstat(mtd, chip, FL_WRITING, status, +					       page); -		/* Increment page address */ -		page++; +		if (status & NAND_STATUS_FAIL) +			return -EIO; +	} else { +		chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1); +		status = chip->waitfunc(mtd, chip); +	} -		/* Have we hit a block boundary ? Then we have to verify and -		 * if verify is ok, we have to setup the oob buffer for -		 * the next pages. -		*/ -		if (!(page & (ppblock - 1))){ -			int ofs; -			this->data_poi = bufstart; -			ret = nand_verify_pages (mtd, this, startpage, -				page - startpage, -				oobbuf, oobsel, chipnr, (eccbuf != NULL)); -			if (ret) { -				MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: " -				          "verify_pages failed %d\n", ret); -				goto out; -			} -			*retlen = written; -			bufstart = (u_char*) &buf[written]; +#ifdef CONFIG_MTD_NAND_VERIFY_WRITE +	/* Send command to read back the data */ +	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + +	if (chip->verify_buf(mtd, buf, mtd->writesize)) +		return -EIO; +#endif +	return 0; +} + +/** + * nand_fill_oob - [Internal] Transfer client buffer to oob + * @chip:	nand chip structure + * @oob:	oob data buffer + * @ops:	oob ops structure + */ +static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, +				  struct mtd_oob_ops *ops) +{ +	size_t len = ops->ooblen; + +	switch(ops->mode) { -			ofs = autoplace ? mtd->oobavail : mtd->oobsize; -			if (eccbuf) -				eccbuf += (page - startpage) * ofs; -			totalpages -= page - startpage; -			numpages = min (totalpages, ppblock); -			page &= this->pagemask; -			startpage = page; -			oob = 0; -			this->oobdirty = 1; -			oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, -					autoplace, numpages); -			/* Check, if we cross a chip boundary */ -			if (!page) { -				chipnr++; -				this->select_chip(mtd, -1); -				this->select_chip(mtd, chipnr); +	case MTD_OOB_PLACE: +	case MTD_OOB_RAW: +		memcpy(chip->oob_poi + ops->ooboffs, oob, len); +		return oob + len; + +	case MTD_OOB_AUTO: { +		struct nand_oobfree *free = chip->ecc.layout->oobfree; +		uint32_t boffs = 0, woffs = ops->ooboffs; +		size_t bytes = 0; + +		for(; free->length && len; free++, len -= bytes) { +			/* Write request not from offset 0 ? */ +			if (unlikely(woffs)) { +				if (woffs >= free->length) { +					woffs -= free->length; +					continue; +				} +				boffs = free->offset + woffs; +				bytes = min_t(size_t, len, +					      (free->length - woffs)); +				woffs = 0; +			} else { +				bytes = min_t(size_t, len, free->length); +				boffs = free->offset;  			} +			memcpy(chip->oob_poi + boffs, oob, bytes); +			oob += bytes;  		} +		return oob;  	} -	/* Verify the remaining pages */ -cmp: -	this->data_poi = bufstart; -	ret = nand_verify_pages (mtd, this, startpage, totalpages, -		oobbuf, oobsel, chipnr, (eccbuf != NULL)); -	if (!ret) -		*retlen = written; -	else -		MTDDEBUG (MTD_DEBUG_LEVEL0, -		          "nand_write_ecc: verify_pages failed %d\n", ret); - -out: -	/* Deselect and wake up anyone waiting on the device */ -	nand_release_device(mtd); - -	return ret; +	default: +		BUG(); +	} +	return NULL;  } +#define NOTALIGNED(x)	(x & (chip->subpagesize - 1)) != 0  /** - * nand_write_oob - [MTD Interface] NAND write out-of-band + * nand_do_write_ops - [Internal] NAND write with ECC   * @mtd:	MTD device structure   * @to:		offset to write to - * @len:	number of bytes to write - * @retlen:	pointer to variable to store the number of written bytes - * @buf:	the data to write + * @ops:	oob operations description structure   * - * NAND write out-of-band + * NAND write with ECC   */ -static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) +static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, +			     struct mtd_oob_ops *ops)  { -	int column, page, status, ret = -EIO, chipnr; -	struct nand_chip *this = mtd->priv; +	int chipnr, realpage, page, blockmask, column; +	struct nand_chip *chip = mtd->priv; +	uint32_t writelen = ops->len; +	uint8_t *oob = ops->oobbuf; +	uint8_t *buf = ops->datbuf; +	int ret, subpage; -	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", -	          (unsigned int) to, (int) len); - -	/* Shift to get page */ -	page = (int) (to >> this->page_shift); -	chipnr = (int) (to >> this->chip_shift); +	ops->retlen = 0; +	if (!writelen) +		return 0; -	/* Mask to get column */ -	column = to & (mtd->oobsize - 1); - -	/* Initialize return length value */ -	*retlen = 0; - -	/* Do not allow write past end of page */ -	if ((column + len) > mtd->oobsize) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " -		          "Attempt to write past end of page\n"); +	/* reject writes, which are not page aligned */ +	if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { +		printk(KERN_NOTICE "nand_write: " +		       "Attempt to write not page aligned data\n");  		return -EINVAL;  	} -	/* Grab the lock and see if the device is available */ -	nand_get_device (this, mtd, FL_WRITING); +	column = to & (mtd->writesize - 1); +	subpage = column || (writelen & (mtd->writesize - 1)); -	/* Select the NAND device */ -	this->select_chip(mtd, chipnr); +	if (subpage && oob) +		return -EINVAL; -	/* Reset the chip. Some chips (like the Toshiba TC5832DC found -	   in one of my DiskOnChip 2000 test units) will clear the whole -	   data page too if we don't do this. I have no clue why, but -	   I seem to have 'fixed' it in the doc2000 driver in -	   August 1999.  dwmw2. */ -	this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); +	chipnr = (int)(to >> chip->chip_shift); +	chip->select_chip(mtd, chipnr);  	/* Check, if it is write protected */ -	if (nand_check_wp(mtd)) -		goto out; +	if (nand_check_wp(mtd)) { +		printk (KERN_NOTICE "nand_do_write_ops: Device is write protected\n"); +		return -EIO; +	} -	/* Invalidate the page cache, if we write to the cached page */ -	if (page == this->pagebuf) -		this->pagebuf = -1; +	realpage = (int)(to >> chip->page_shift); +	page = realpage & chip->pagemask; +	blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; -	if (NAND_MUST_PAD(this)) { -		/* Write out desired data */ -		this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask); -		if (!ffchars) { -			if (!(ffchars = kmalloc (mtd->oobsize, GFP_KERNEL))) { -				MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " -				          "No memory for padding array, " -				          "need %d bytes", mtd->oobsize); -				ret = -ENOMEM; -				goto out; -			} -			memset(ffchars, 0xff, mtd->oobsize); +	/* Invalidate the page cache, when we write to the cached page */ +	if (to <= (chip->pagebuf << chip->page_shift) && +	    (chip->pagebuf << chip->page_shift) < (to + ops->len)) +		chip->pagebuf = -1; + +	/* If we're not given explicit OOB data, let it be 0xFF */ +	if (likely(!oob)) +		memset(chip->oob_poi, 0xff, mtd->oobsize); + +	while(1) { +		int bytes = mtd->writesize; +		int cached = writelen > bytes && page != blockmask; +		uint8_t *wbuf = buf; + +		/* Partial page write ? */ +		if (unlikely(column || writelen < (mtd->writesize - 1))) { +			cached = 0; +			bytes = min_t(int, bytes - column, (int) writelen); +			chip->pagebuf = -1; +			memset(chip->buffers->databuf, 0xff, mtd->writesize); +			memcpy(&chip->buffers->databuf[column], buf, bytes); +			wbuf = chip->buffers->databuf;  		} -		/* prepad 0xff for partial programming */ -		this->write_buf(mtd, ffchars, column); -		/* write data */ -		this->write_buf(mtd, buf, len); -		/* postpad 0xff for partial programming */ -		this->write_buf(mtd, ffchars, mtd->oobsize - (len+column)); -	} else { -		/* Write out desired data */ -		this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock + column, page & this->pagemask); -		/* write data */ -		this->write_buf(mtd, buf, len); -	} -	/* Send command to program the OOB data */ -	this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1); -	status = this->waitfunc (mtd, this, FL_WRITING); +		if (unlikely(oob)) +			oob = nand_fill_oob(chip, oob, ops); -	/* See if device thinks it succeeded */ -	if (status & 0x01) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " -		          "Failed write, page 0x%08x\n", page); -		ret = -EIO; -		goto out; -	} -	/* Return happy */ -	*retlen = len; +		ret = chip->write_page(mtd, chip, wbuf, page, cached, +				       (ops->mode == MTD_OOB_RAW)); +		if (ret) +			break; -#ifdef CONFIG_MTD_NAND_VERIFY_WRITE -	/* Send command to read back the data */ -	this->cmdfunc (mtd, NAND_CMD_READOOB, column, page & this->pagemask); +		writelen -= bytes; +		if (!writelen) +			break; -	if (this->verify_buf(mtd, buf, len)) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " -		          "Failed write verify, page 0x%08x\n", page); -		ret = -EIO; -		goto out; +		column = 0; +		buf += bytes; +		realpage++; + +		page = realpage & chip->pagemask; +		/* Check, if we cross a chip boundary */ +		if (!page) { +			chipnr++; +			chip->select_chip(mtd, -1); +			chip->select_chip(mtd, chipnr); +		}  	} -#endif -	ret = 0; -out: -	/* Deselect and wake up anyone waiting on the device */ -	nand_release_device(mtd); +	ops->retlen = ops->len - writelen; +	if (unlikely(oob)) +		ops->oobretlen = ops->ooblen;  	return ret;  } -/* XXX U-BOOT XXX */ -#if 0  /** - * nand_writev - [MTD Interface] compabilty function for nand_writev_ecc + * nand_write - [MTD Interface] NAND write with ECC   * @mtd:	MTD device structure - * @vecs:	the iovectors to write - * @count:	number of vectors   * @to:		offset to write to + * @len:	number of bytes to write   * @retlen:	pointer to variable to store the number of written bytes + * @buf:	the data to write   * - * NAND write with kvec. This just calls the ecc function + * NAND write with ECC   */ -static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, -		loff_t to, size_t * retlen) +static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, +			  size_t *retlen, const uint8_t *buf)  { -	return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL)); +	struct nand_chip *chip = mtd->priv; +	int ret; + +	/* Do not allow reads past end of device */ +	if ((to + len) > mtd->size) +		return -EINVAL; +	if (!len) +		return 0; + +	nand_get_device(chip, mtd, FL_WRITING); + +	chip->ops.len = len; +	chip->ops.datbuf = (uint8_t *)buf; +	chip->ops.oobbuf = NULL; + +	ret = nand_do_write_ops(mtd, to, &chip->ops); + +	*retlen = chip->ops.retlen; + +	nand_release_device(mtd); + +	return ret;  }  /** - * nand_writev_ecc - [MTD Interface] write with iovec with ecc + * nand_do_write_oob - [MTD Interface] NAND write out-of-band   * @mtd:	MTD device structure - * @vecs:	the iovectors to write - * @count:	number of vectors   * @to:		offset to write to - * @retlen:	pointer to variable to store the number of written bytes - * @eccbuf:	filesystem supplied oob data buffer - * @oobsel:	oob selection structure + * @ops:	oob operation description structure   * - * NAND write with iovec with ecc + * NAND write out-of-band   */ -static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, -		loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) +static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, +			     struct mtd_oob_ops *ops)  { -	int i, page, len, total_len, ret = -EIO, written = 0, chipnr; -	int oob, numpages, autoplace = 0, startpage; -	struct nand_chip *this = mtd->priv; -	int	ppblock = (1 << (this->phys_erase_shift - this->page_shift)); -	u_char *oobbuf, *bufstart; - -	/* Preset written len for early exit */ -	*retlen = 0; +	int chipnr, page, status, len; +	struct nand_chip *chip = mtd->priv; -	/* Calculate total length of data */ -	total_len = 0; -	for (i = 0; i < count; i++) -		total_len += (int) vecs[i].iov_len; +	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", +	          (unsigned int)to, (int)ops->ooblen); -	MTDDEBUG (MTD_DEBUG_LEVEL3, -	          "nand_writev: to = 0x%08x, len = %i, count = %ld\n", -	          (unsigned int) to, (unsigned int) total_len, count); +	if (ops->mode == MTD_OOB_AUTO) +		len = chip->ecc.layout->oobavail; +	else +		len = mtd->oobsize;  	/* Do not allow write past end of page */ -	if ((to + total_len) > mtd->size) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, -		          "nand_writev: Attempted write past end of device\n"); +	if ((ops->ooboffs + ops->ooblen) > len) { +		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " +		          "Attempt to write past end of page\n");  		return -EINVAL;  	} -	/* reject writes, which are not page aligned */ -	if (NOTALIGNED (to) || NOTALIGNED(total_len)) { -		printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); +	if (unlikely(ops->ooboffs >= len)) { +		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: " +		          "Attempt to start write outside oob\n");  		return -EINVAL;  	} -	/* Grab the lock and see if the device is available */ -	nand_get_device (this, mtd, FL_WRITING); +	/* Do not allow reads past end of device */ +	if (unlikely(to >= mtd->size || +		     ops->ooboffs + ops->ooblen > +			((mtd->size >> chip->page_shift) - +			 (to >> chip->page_shift)) * len)) { +		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: " +		          "Attempt write beyond end of device\n"); +		return -EINVAL; +	} -	/* Get the current chip-nr */ -	chipnr = (int) (to >> this->chip_shift); -	/* Select the NAND device */ -	this->select_chip(mtd, chipnr); +	chipnr = (int)(to >> chip->chip_shift); +	chip->select_chip(mtd, chipnr); + +	/* Shift to get page */ +	page = (int)(to >> chip->page_shift); + +	/* +	 * Reset the chip. Some chips (like the Toshiba TC5832DC found in one +	 * of my DiskOnChip 2000 test units) will clear the whole data page too +	 * if we don't do this. I have no clue why, but I seem to have 'fixed' +	 * it in the doc2000 driver in August 1999.  dwmw2. +	 */ +	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);  	/* Check, if it is write protected */  	if (nand_check_wp(mtd)) -		goto out; +		return -EROFS; + +	/* Invalidate the page cache, if we write to the cached page */ +	if (page == chip->pagebuf) +		chip->pagebuf = -1; -	/* if oobsel is NULL, use chip defaults */ -	if (oobsel == NULL) -		oobsel = &mtd->oobinfo; +	memset(chip->oob_poi, 0xff, mtd->oobsize); +	nand_fill_oob(chip, ops->oobbuf, ops); +	status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); +	memset(chip->oob_poi, 0xff, mtd->oobsize); -	/* Autoplace of oob data ? Use the default placement scheme */ -	if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { -		oobsel = this->autooob; -		autoplace = 1; -	} -	if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) -		autoplace = 1; +	if (status) +		return status; -	/* Setup start page */ -	page = (int) (to >> this->page_shift); -	/* Invalidate the page cache, if we write to the cached page */ -	if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) -		this->pagebuf = -1; +	ops->oobretlen = ops->ooblen; -	startpage = page & this->pagemask; +	return 0; +} -	/* Loop until all kvec' data has been written */ -	len = 0; -	while (count) { -		/* If the given tuple is >= pagesize then -		 * write it out from the iov -		 */ -		if ((vecs->iov_len - len) >= mtd->oobblock) { -			/* Calc number of pages we can write -			 * out of this iov in one go */ -			numpages = (vecs->iov_len - len) >> this->page_shift; -			/* Do not cross block boundaries */ -			numpages = min (ppblock - (startpage & (ppblock - 1)), numpages); -			oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages); -			bufstart = (u_char *)vecs->iov_base; -			bufstart += len; -			this->data_poi = bufstart; -			oob = 0; -			for (i = 1; i <= numpages; i++) { -				/* Write one page. If this is the last page to write -				 * then use the real pageprogram command, else select -				 * cached programming if supported by the chip. -				 */ -				ret = nand_write_page (mtd, this, page & this->pagemask, -					&oobbuf[oob], oobsel, i != numpages); -				if (ret) -					goto out; -				this->data_poi += mtd->oobblock; -				len += mtd->oobblock; -				oob += mtd->oobsize; -				page++; -			} -			/* Check, if we have to switch to the next tuple */ -			if (len >= (int) vecs->iov_len) { -				vecs++; -				len = 0; -				count--; -			} -		} else { -			/* We must use the internal buffer, read data out of each -			 * tuple until we have a full page to write -			 */ -			int cnt = 0; -			while (cnt < mtd->oobblock) { -				if (vecs->iov_base != NULL && vecs->iov_len) -					this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; -				/* Check, if we have to switch to the next tuple */ -				if (len >= (int) vecs->iov_len) { -					vecs++; -					len = 0; -					count--; -				} -			} -			this->pagebuf = page; -			this->data_poi = this->data_buf; -			bufstart = this->data_poi; -			numpages = 1; -			oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages); -			ret = nand_write_page (mtd, this, page & this->pagemask, -				oobbuf, oobsel, 0); -			if (ret) -				goto out; -			page++; -		} +/** + * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band + * @mtd:	MTD device structure + * @to:		offset to write to + * @ops:	oob operation description structure + */ +static int nand_write_oob(struct mtd_info *mtd, loff_t to, +			  struct mtd_oob_ops *ops) +{ +	struct nand_chip *chip = mtd->priv; +	int ret = -ENOTSUPP; -		this->data_poi = bufstart; -		ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0); -		if (ret) -			goto out; +	ops->retlen = 0; -		written += mtd->oobblock * numpages; -		/* All done ? */ -		if (!count) -			break; +	/* Do not allow writes past end of device */ +	if (ops->datbuf && (to + ops->len) > mtd->size) { +		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: " +		          "Attempt read beyond end of device\n"); +		return -EINVAL; +	} -		startpage = page & this->pagemask; -		/* Check, if we cross a chip boundary */ -		if (!startpage) { -			chipnr++; -			this->select_chip(mtd, -1); -			this->select_chip(mtd, chipnr); -		} +	nand_get_device(chip, mtd, FL_WRITING); + +	switch(ops->mode) { +	case MTD_OOB_PLACE: +	case MTD_OOB_AUTO: +	case MTD_OOB_RAW: +		break; + +	default: +		goto out;  	} -	ret = 0; -out: -	/* Deselect and wake up anyone waiting on the device */ -	nand_release_device(mtd); -	*retlen = written; +	if (!ops->datbuf) +		ret = nand_do_write_oob(mtd, to, ops); +	else +		ret = nand_do_write_ops(mtd, to, ops); + + out: +	nand_release_device(mtd);  	return ret;  } -#endif  /**   * single_erease_cmd - [GENERIC] NAND standard block erase command function @@ -2094,12 +1990,12 @@ out:   *   * Standard erase command for NAND chips   */ -static void single_erase_cmd (struct mtd_info *mtd, int page) +static void single_erase_cmd(struct mtd_info *mtd, int page)  { -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv;  	/* Send commands to erase a block */ -	this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page); -	this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1); +	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); +	chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);  }  /** @@ -2110,15 +2006,15 @@ static void single_erase_cmd (struct mtd_info *mtd, int page)   * AND multi block erase command function   * Erase 4 consecutive blocks   */ -static void multi_erase_cmd (struct mtd_info *mtd, int page) +static void multi_erase_cmd(struct mtd_info *mtd, int page)  { -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv;  	/* Send commands to erase a block */ -	this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++); -	this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++); -	this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++); -	this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page); -	this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1); +	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++); +	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++); +	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++); +	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); +	chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);  }  /** @@ -2128,35 +2024,39 @@ static void multi_erase_cmd (struct mtd_info *mtd, int page)   *   * Erase one ore more blocks   */ -static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) +static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)  { -	return nand_erase_nand (mtd, instr, 0); +	return nand_erase_nand(mtd, instr, 0);  } +#define BBT_PAGE_MASK	0xffffff3f  /** - * nand_erase_intern - [NAND Interface] erase block(s) + * nand_erase_nand - [Internal] erase block(s)   * @mtd:	MTD device structure   * @instr:	erase instruction   * @allowbbt:	allow erasing the bbt area   *   * Erase one ore more blocks   */ -int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt) +int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, +		    int allowbbt)  {  	int page, len, status, pages_per_block, ret, chipnr; -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv; +	int rewrite_bbt[NAND_MAX_CHIPS]={0}; +	unsigned int bbt_masked_page = 0xffffffff;  	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",  	          (unsigned int) instr->addr, (unsigned int) instr->len);  	/* Start address must align on block boundary */ -	if (instr->addr & ((1 << this->phys_erase_shift) - 1)) { +	if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {  		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");  		return -EINVAL;  	}  	/* Length must align on block boundary */ -	if (instr->len & ((1 << this->phys_erase_shift) - 1)) { +	if (instr->len & ((1 << chip->phys_erase_shift) - 1)) {  		MTDDEBUG (MTD_DEBUG_LEVEL0,  		          "nand_erase: Length not block aligned\n");  		return -EINVAL; @@ -2172,19 +2072,18 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb  	instr->fail_addr = 0xffffffff;  	/* Grab the lock and see if the device is available */ -	nand_get_device (this, mtd, FL_ERASING); +	nand_get_device(chip, mtd, FL_ERASING);  	/* Shift to get first page */ -	page = (int) (instr->addr >> this->page_shift); -	chipnr = (int) (instr->addr >> this->chip_shift); +	page = (int)(instr->addr >> chip->page_shift); +	chipnr = (int)(instr->addr >> chip->chip_shift);  	/* Calculate pages in each block */ -	pages_per_block = 1 << (this->phys_erase_shift - this->page_shift); - +	pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); +	  	/* Select the NAND device */ -	this->select_chip(mtd, chipnr); +	chip->select_chip(mtd, chipnr); -	/* Check the WP bit */  	/* Check, if it is write protected */  	if (nand_check_wp(mtd)) {  		MTDDEBUG (MTD_DEBUG_LEVEL0, @@ -2193,52 +2092,92 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb  		goto erase_exit;  	} +	/* +	 * If BBT requires refresh, set the BBT page mask to see if the BBT +	 * should be rewritten. Otherwise the mask is set to 0xffffffff which +	 * can not be matched. This is also done when the bbt is actually +	 * erased to avoid recusrsive updates +	 */ +	if (chip->options & BBT_AUTO_REFRESH && !allowbbt) +		bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK; +  	/* Loop through the pages */  	len = instr->len;  	instr->state = MTD_ERASING;  	while (len) { -#ifndef NAND_ALLOW_ERASE_ALL -		/* Check if we have a bad block, we do not erase bad blocks ! */ -		if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) { -			printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page); +		/* +		 * heck if we have a bad block, we do not erase bad blocks ! +		 */ +		if (nand_block_checkbad(mtd, ((loff_t) page) << +					chip->page_shift, 0, allowbbt)) { +			printk(KERN_WARNING "nand_erase: attempt to erase a " +			       "bad block at page 0x%08x\n", page);  			instr->state = MTD_ERASE_FAILED;  			goto erase_exit;  		} -#endif -		/* Invalidate the page cache, if we erase the block which contains -		   the current cached page */ -		if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block)) -			this->pagebuf = -1; -		this->erase_cmd (mtd, page & this->pagemask); +		/* +		 * Invalidate the page cache, if we erase the block which +		 * contains the current cached page +		 */ +		if (page <= chip->pagebuf && chip->pagebuf < +		    (page + pages_per_block)) +			chip->pagebuf = -1; + +		chip->erase_cmd(mtd, page & chip->pagemask); -		status = this->waitfunc (mtd, this, FL_ERASING); +		status = chip->waitfunc(mtd, chip); + +		/* +		 * See if operation failed and additional status checks are +		 * available +		 */ +		if ((status & NAND_STATUS_FAIL) && (chip->errstat)) +			status = chip->errstat(mtd, chip, FL_ERASING, +					       status, page);  		/* See if block erase succeeded */ -		if (status & 0x01) { +		if (status & NAND_STATUS_FAIL) {  			MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: "  			          "Failed erase, page 0x%08x\n", page);  			instr->state = MTD_ERASE_FAILED; -			instr->fail_addr = (page << this->page_shift); +			instr->fail_addr = (page << chip->page_shift);  			goto erase_exit;  		} +		/* +		 * If BBT requires refresh, set the BBT rewrite flag to the +		 * page being erased +		 */ +		if (bbt_masked_page != 0xffffffff && +		    (page & BBT_PAGE_MASK) == bbt_masked_page) +			    rewrite_bbt[chipnr] = (page << chip->page_shift); +  		/* Increment page address and decrement length */ -		len -= (1 << this->phys_erase_shift); +		len -= (1 << chip->phys_erase_shift);  		page += pages_per_block;  		/* Check, if we cross a chip boundary */ -		if (len && !(page & this->pagemask)) { +		if (len && !(page & chip->pagemask)) {  			chipnr++; -			this->select_chip(mtd, -1); -			this->select_chip(mtd, chipnr); +			chip->select_chip(mtd, -1); +			chip->select_chip(mtd, chipnr); + +			/* +			 * If BBT requires refresh and BBT-PERCHIP, set the BBT +			 * page mask to see if this BBT should be rewritten +			 */ +			if (bbt_masked_page != 0xffffffff && +			    (chip->bbt_td->options & NAND_BBT_PERCHIP)) +				bbt_masked_page = chip->bbt_td->pages[chipnr] & +					BBT_PAGE_MASK;  		}  	}  	instr->state = MTD_ERASE_DONE; -erase_exit: + erase_exit:  	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;  	/* Do call back function */ @@ -2248,6 +2187,23 @@ erase_exit:  	/* Deselect and wake up anyone waiting on the device */  	nand_release_device(mtd); +	/* +	 * If BBT requires refresh and erase was successful, rewrite any +	 * selected bad block tables +	 */ +	if (bbt_masked_page == 0xffffffff || ret) +		return ret; + +	for (chipnr = 0; chipnr < chip->numchips; chipnr++) { +		if (!rewrite_bbt[chipnr]) +			continue; +		/* update the BBT for chip */ +		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt " +		          "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr], +		          chip->bbt_td->pages[chipnr]); +		nand_update_bbt(mtd, rewrite_bbt[chipnr]); +	} +  	/* Return more or less happy */  	return ret;  } @@ -2258,41 +2214,40 @@ erase_exit:   *   * Sync is actually a wait for chip ready function   */ -static void nand_sync (struct mtd_info *mtd) +static void nand_sync(struct mtd_info *mtd)  { -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv;  	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");  	/* Grab the lock and see if the device is available */ -	nand_get_device (this, mtd, FL_SYNCING); +	nand_get_device(chip, mtd, FL_SYNCING);  	/* Release it and go back */ -	nand_release_device (mtd); +	nand_release_device(mtd);  } -  /** - * nand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad + * nand_block_isbad - [MTD Interface] Check if block at offset is bad   * @mtd:	MTD device structure - * @ofs:	offset relative to mtd start + * @offs:	offset relative to mtd start   */ -static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs) +static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)  {  	/* Check for invalid offset */ -	if (ofs > mtd->size) +	if (offs > mtd->size)  		return -EINVAL; -	return nand_block_checkbad (mtd, ofs, 1, 0); +	return nand_block_checkbad(mtd, offs, 1, 0);  }  /** - * nand_block_markbad - [MTD Interface] Mark the block at the given offset as bad + * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad   * @mtd:	MTD device structure   * @ofs:	offset relative to mtd start   */ -static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs) +static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)  { -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv;  	int ret;  	if ((ret = nand_block_isbad(mtd, ofs))) { @@ -2302,419 +2257,553 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs)  		return ret;  	} -	return this->block_markbad(mtd, ofs); +	return chip->block_markbad(mtd, ofs);  }  /** - * nand_scan - [NAND Interface] Scan for the NAND device + * nand_suspend - [MTD Interface] Suspend the NAND flash   * @mtd:	MTD device structure - * @maxchips:	Number of chips to scan for - * - * This fills out all the not initialized function pointers - * with the defaults. - * The flash ID is read and the mtd/chip structures are - * filled with the appropriate values. Buffers are allocated if - * they are not provided by the board driver - *   */ -int nand_scan (struct mtd_info *mtd, int maxchips) +static int nand_suspend(struct mtd_info *mtd)  { -	int i, j, nand_maf_id, nand_dev_id, busw; -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv; + +	return nand_get_device(chip, mtd, FL_PM_SUSPENDED); +} -	/* Get buswidth to select the correct functions*/ -	busw = this->options & NAND_BUSWIDTH_16; +/** + * nand_resume - [MTD Interface] Resume the NAND flash + * @mtd:	MTD device structure + */ +static void nand_resume(struct mtd_info *mtd) +{ +	struct nand_chip *chip = mtd->priv; +	if (chip->state == FL_PM_SUSPENDED) +		nand_release_device(mtd); +	else +		printk(KERN_ERR "nand_resume() called for a chip which is not " +		       "in suspended state\n"); +} + +/* + * Set default functions + */ +static void nand_set_defaults(struct nand_chip *chip, int busw) +{  	/* check for proper chip_delay setup, set 20us if not */ -	if (!this->chip_delay) -		this->chip_delay = 20; +	if (!chip->chip_delay) +		chip->chip_delay = 20;  	/* check, if a user supplied command function given */ -	if (this->cmdfunc == NULL) -		this->cmdfunc = nand_command; +	if (chip->cmdfunc == NULL) +		chip->cmdfunc = nand_command;  	/* check, if a user supplied wait function given */ -	if (this->waitfunc == NULL) -		this->waitfunc = nand_wait; +	if (chip->waitfunc == NULL) +		chip->waitfunc = nand_wait; + +	if (!chip->select_chip) +		chip->select_chip = nand_select_chip; +	if (!chip->read_byte) +		chip->read_byte = busw ? nand_read_byte16 : nand_read_byte; +	if (!chip->read_word) +		chip->read_word = nand_read_word; +	if (!chip->block_bad) +		chip->block_bad = nand_block_bad; +	if (!chip->block_markbad) +		chip->block_markbad = nand_default_block_markbad; +	if (!chip->write_buf) +		chip->write_buf = busw ? nand_write_buf16 : nand_write_buf; +	if (!chip->read_buf) +		chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; +	if (!chip->verify_buf) +		chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf; +	if (!chip->scan_bbt) +		chip->scan_bbt = nand_default_bbt; + +	if (!chip->controller) { +		chip->controller = &chip->hwcontrol; + +		/* XXX U-BOOT XXX */ +#if 0 +		spin_lock_init(&chip->controller->lock); +		init_waitqueue_head(&chip->controller->wq); +#endif +	} + +} -	if (!this->select_chip) -		this->select_chip = nand_select_chip; -	if (!this->write_byte) -		this->write_byte = busw ? nand_write_byte16 : nand_write_byte; -	if (!this->read_byte) -		this->read_byte = busw ? nand_read_byte16 : nand_read_byte; -	if (!this->write_word) -		this->write_word = nand_write_word; -	if (!this->read_word) -		this->read_word = nand_read_word; -	if (!this->block_bad) -		this->block_bad = nand_block_bad; -	if (!this->block_markbad) -		this->block_markbad = nand_default_block_markbad; -	if (!this->write_buf) -		this->write_buf = busw ? nand_write_buf16 : nand_write_buf; -	if (!this->read_buf) -		this->read_buf = busw ? nand_read_buf16 : nand_read_buf; -	if (!this->verify_buf) -		this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf; -	if (!this->scan_bbt) -		this->scan_bbt = nand_default_bbt; +/* + * Get the flash and manufacturer id and lookup if the type is supported + */ +static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, +						  struct nand_chip *chip, +						  int busw, int *maf_id) +{ +	struct nand_flash_dev *type = NULL; +	int i, dev_id, maf_idx;  	/* Select the device */ -	this->select_chip(mtd, 0); +	chip->select_chip(mtd, 0);  	/* Send the command for reading device ID */ -	this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1); +	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);  	/* Read manufacturer and device IDs */ -	nand_maf_id = this->read_byte(mtd); -	nand_dev_id = this->read_byte(mtd); +	*maf_id = chip->read_byte(mtd); +	dev_id = chip->read_byte(mtd); -	/* Print and store flash device information */ +	/* Lookup the flash id */  	for (i = 0; nand_flash_ids[i].name != NULL; i++) { +		if (dev_id == nand_flash_ids[i].id) { +			type =  &nand_flash_ids[i]; +			break; +		} +	} -		if (nand_dev_id != nand_flash_ids[i].id) -			continue; +	if (!type) +		return ERR_PTR(-ENODEV); -		if (!mtd->name) mtd->name = nand_flash_ids[i].name; -		this->chipsize = nand_flash_ids[i].chipsize << 20; +	if (!mtd->name) +		mtd->name = type->name; -		/* New devices have all the information in additional id bytes */ -		if (!nand_flash_ids[i].pagesize) { -			int extid; -			/* The 3rd id byte contains non relevant data ATM */ -			extid = this->read_byte(mtd); -			/* The 4th id byte is the important one */ -			extid = this->read_byte(mtd); -			/* Calc pagesize */ -			mtd->oobblock = 1024 << (extid & 0x3); -			extid >>= 2; -			/* Calc oobsize */ -			mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock / 512); -			extid >>= 2; -			/* Calc blocksize. Blocksize is multiples of 64KiB */ -			mtd->erasesize = (64 * 1024)  << (extid & 0x03); -			extid >>= 2; -			/* Get buswidth information */ -			busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; +	chip->chipsize = type->chipsize << 20; -		} else { -			/* Old devices have this data hardcoded in the -			 * device id table */ -			mtd->erasesize = nand_flash_ids[i].erasesize; -			mtd->oobblock = nand_flash_ids[i].pagesize; -			mtd->oobsize = mtd->oobblock / 32; -			busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16; -		} +	/* Newer devices have all the information in additional id bytes */ +	if (!type->pagesize) { +		int extid; +		/* The 3rd id byte holds MLC / multichip data */ +		chip->cellinfo = chip->read_byte(mtd); +		/* The 4th id byte is the important one */ +		extid = chip->read_byte(mtd); +		/* Calc pagesize */ +		mtd->writesize = 1024 << (extid & 0x3); +		extid >>= 2; +		/* Calc oobsize */ +		mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9); +		extid >>= 2; +		/* Calc blocksize. Blocksize is multiples of 64KiB */ +		mtd->erasesize = (64 * 1024) << (extid & 0x03); +		extid >>= 2; +		/* Get buswidth information */ +		busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; -		/* Check, if buswidth is correct. Hardware drivers should set -		 * this correct ! */ -		if (busw != (this->options & NAND_BUSWIDTH_16)) { -			printk (KERN_INFO "NAND device: Manufacturer ID:" -				" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, -				nand_manuf_ids[i].name , mtd->name); -			printk (KERN_WARNING -				"NAND bus width %d instead %d bit\n", -					(this->options & NAND_BUSWIDTH_16) ? 16 : 8, -					busw ? 16 : 8); -			this->select_chip(mtd, -1); -			return 1; -		} +	} else { +		/* +		 * Old devices have chip data hardcoded in the device id table +		 */ +		mtd->erasesize = type->erasesize; +		mtd->writesize = type->pagesize; +		mtd->oobsize = mtd->writesize / 32; +		busw = type->options & NAND_BUSWIDTH_16; +	} -		/* Calculate the address shift from the page size */ -		this->page_shift = ffs(mtd->oobblock) - 1; -		this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1; -		this->chip_shift = ffs(this->chipsize) - 1; +	/* Try to identify manufacturer */ +	for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { +		if (nand_manuf_ids[maf_idx].id == *maf_id) +			break; +	} -		/* Set the bad block position */ -		this->badblockpos = mtd->oobblock > 512 ? -			NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; +	/* +	 * Check, if buswidth is correct. Hardware drivers should set +	 * chip correct ! +	 */ +	if (busw != (chip->options & NAND_BUSWIDTH_16)) { +		printk(KERN_INFO "NAND device: Manufacturer ID:" +		       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, +		       dev_id, nand_manuf_ids[maf_idx].name, mtd->name); +		printk(KERN_WARNING "NAND bus width %d instead %d bit\n", +		       (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, +		       busw ? 16 : 8); +		return ERR_PTR(-EINVAL); +	} -		/* Get chip options, preserve non chip based options */ -		this->options &= ~NAND_CHIPOPTIONS_MSK; -		this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK; -		/* Set this as a default. Board drivers can override it, if neccecary */ -		this->options |= NAND_NO_AUTOINCR; -		/* Check if this is a not a samsung device. Do not clear the options -		 * for chips which are not having an extended id. -		 */ -		if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize) -			this->options &= ~NAND_SAMSUNG_LP_OPTIONS; +	/* Calculate the address shift from the page size */ +	chip->page_shift = ffs(mtd->writesize) - 1; +	/* Convert chipsize to number of pages per chip -1. */ +	chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; -		/* Check for AND chips with 4 page planes */ -		if (this->options & NAND_4PAGE_ARRAY) -			this->erase_cmd = multi_erase_cmd; -		else -			this->erase_cmd = single_erase_cmd; +	chip->bbt_erase_shift = chip->phys_erase_shift = +		ffs(mtd->erasesize) - 1; +	chip->chip_shift = ffs(chip->chipsize) - 1; -		/* Do not replace user supplied command function ! */ -		if (mtd->oobblock > 512 && this->cmdfunc == nand_command) -			this->cmdfunc = nand_command_lp; +	/* Set the bad block position */ +	chip->badblockpos = mtd->writesize > 512 ? +		NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; -		/* Try to identify manufacturer */ -		for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { -			if (nand_manuf_ids[j].id == nand_maf_id) -				break; -		} -		break; -	} +	/* Get chip options, preserve non chip based options */ +	chip->options &= ~NAND_CHIPOPTIONS_MSK; +	chip->options |= type->options & NAND_CHIPOPTIONS_MSK; -	if (!nand_flash_ids[i].name) { -#ifndef CFG_NAND_QUIET_TEST -		printk (KERN_WARNING "No NAND device found!!!\n"); -#endif -		this->select_chip(mtd, -1); -		return 1; -	} +	/* +	 * Set chip as a default. Board drivers can override it, if necessary +	 */ +	chip->options |= NAND_NO_AUTOINCR; -	for (i=1; i < maxchips; i++) { -		this->select_chip(mtd, i); +	/* Check if chip is a not a samsung device. Do not clear the +	 * options for chips which are not having an extended id. +	 */ +	if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) +		chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; -		/* Send the command for reading device ID */ -		this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1); +	/* Check for AND chips with 4 page planes */ +	if (chip->options & NAND_4PAGE_ARRAY) +		chip->erase_cmd = multi_erase_cmd; +	else +		chip->erase_cmd = single_erase_cmd; +	/* Do not replace user supplied command function ! */ +	if (mtd->writesize > 512 && chip->cmdfunc == nand_command) +		chip->cmdfunc = nand_command_lp; + +	printk(KERN_INFO "NAND device: Manufacturer ID:" +	       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, +	       nand_manuf_ids[maf_idx].name, type->name); + +	return type; +} + +/** + * nand_scan_ident - [NAND Interface] Scan for the NAND device + * @mtd:	     MTD device structure + * @maxchips:	     Number of chips to scan for + * + * This is the first phase of the normal nand_scan() function. It + * reads the flash ID and sets up MTD fields accordingly. + * + * The mtd->owner field must be set to the module of the caller. + */ +int nand_scan_ident(struct mtd_info *mtd, int maxchips) +{ +	int i, busw, nand_maf_id; +	struct nand_chip *chip = mtd->priv; +	struct nand_flash_dev *type; + +	/* Get buswidth to select the correct functions */ +	busw = chip->options & NAND_BUSWIDTH_16; +	/* Set the default functions */ +	nand_set_defaults(chip, busw); + +	/* Read the flash type */ +	type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id); + +	if (IS_ERR(type)) { +		printk(KERN_WARNING "No NAND device found!!!\n"); +		chip->select_chip(mtd, -1); +		return PTR_ERR(type); +	} + +	/* Check for a chip array */ +	for (i = 1; i < maxchips; i++) { +		chip->select_chip(mtd, i); +		/* Send the command for reading device ID */ +		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);  		/* Read manufacturer and device IDs */ -		if (nand_maf_id != this->read_byte(mtd) || -		    nand_dev_id != this->read_byte(mtd)) +		if (nand_maf_id != chip->read_byte(mtd) || +		    type->id != chip->read_byte(mtd))  			break;  	}  	if (i > 1)  		printk(KERN_INFO "%d NAND chips detected\n", i); -	/* Allocate buffers, if neccecary */ -	if (!this->oob_buf) { -		size_t len; -		len = mtd->oobsize << (this->phys_erase_shift - this->page_shift); -		this->oob_buf = kmalloc (len, GFP_KERNEL); -		if (!this->oob_buf) { -			printk (KERN_ERR "nand_scan(): Cannot allocate oob_buf\n"); -			return -ENOMEM; -		} -		this->options |= NAND_OOBBUF_ALLOC; -	} +	/* Store the number of chips and calc total size for mtd */ +	chip->numchips = i; +	mtd->size = i * chip->chipsize; -	if (!this->data_buf) { -		size_t len; -		len = mtd->oobblock + mtd->oobsize; -		this->data_buf = kmalloc (len, GFP_KERNEL); -		if (!this->data_buf) { -			if (this->options & NAND_OOBBUF_ALLOC) -				kfree (this->oob_buf); -			printk (KERN_ERR "nand_scan(): Cannot allocate data_buf\n"); -			return -ENOMEM; -		} -		this->options |= NAND_DATABUF_ALLOC; -	} +	return 0; +} -	/* Store the number of chips and calc total size for mtd */ -	this->numchips = i; -	mtd->size = i * this->chipsize; -	/* Convert chipsize to number of pages per chip -1. */ -	this->pagemask = (this->chipsize >> this->page_shift) - 1; -	/* Preset the internal oob buffer */ -	memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift)); -	/* If no default placement scheme is given, select an -	 * appropriate one */ -	if (!this->autooob) { -		/* Select the appropriate default oob placement scheme for -		 * placement agnostic filesystems */ +/** + * nand_scan_tail - [NAND Interface] Scan for the NAND device + * @mtd:	    MTD device structure + * @maxchips:	    Number of chips to scan for + * + * This is the second phase of the normal nand_scan() function. It + * fills out all the uninitialized function pointers with the defaults + * and scans for a bad block table if appropriate. + */ +int nand_scan_tail(struct mtd_info *mtd) +{ +	int i; +	struct nand_chip *chip = mtd->priv; + +	if (!(chip->options & NAND_OWN_BUFFERS)) +		chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL); +	if (!chip->buffers) +		return -ENOMEM; + +	/* Set the internal oob buffer location, just after the page data */ +	chip->oob_poi = chip->buffers->databuf + mtd->writesize; + +	/* +	 * If no default placement scheme is given, select an appropriate one +	 */ +	if (!chip->ecc.layout) {  		switch (mtd->oobsize) {  		case 8: -			this->autooob = &nand_oob_8; +			chip->ecc.layout = &nand_oob_8;  			break;  		case 16: -			this->autooob = &nand_oob_16; +			chip->ecc.layout = &nand_oob_16;  			break;  		case 64: -			this->autooob = &nand_oob_64; +			chip->ecc.layout = &nand_oob_64;  			break;  		case 128: -			this->autooob = &nand_oob_128; +			chip->ecc.layout = &nand_oob_128;  			break;  		default: -			printk (KERN_WARNING "No oob scheme defined for oobsize %d\n", -				mtd->oobsize); -/*			BUG(); */ +			printk(KERN_WARNING "No oob scheme defined for " +			       "oobsize %d\n", mtd->oobsize); +//			BUG();  		}  	} -	/* The number of bytes available for the filesystem to place fs dependend -	 * oob data */ -	mtd->oobavail = 0; -	for (i=0; this->autooob->oobfree[i][1]; i++) -		mtd->oobavail += this->autooob->oobfree[i][1]; +	if (!chip->write_page) +		chip->write_page = nand_write_page;  	/* -	 * check ECC mode, default to software -	 * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize -	 * fallback to software ECC -	*/ -	this->eccsize = 256;	/* set default eccsize */ -	this->eccbytes = 3; +	 * check ECC mode, default to software if 3byte/512byte hardware ECC is +	 * selected and we have 256 byte pagesize fallback to software ECC +	 */ +	if (!chip->ecc.read_page_raw) +		chip->ecc.read_page_raw = nand_read_page_raw; +	if (!chip->ecc.write_page_raw) +		chip->ecc.write_page_raw = nand_write_page_raw; -	switch (this->eccmode) { -	case NAND_ECC_HW12_2048: -		if (mtd->oobblock < 2048) { -			printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n", -			       mtd->oobblock); -			this->eccmode = NAND_ECC_SOFT; -			this->calculate_ecc = nand_calculate_ecc; -			this->correct_data = nand_correct_data; -		} else -			this->eccsize = 2048; -		break; +	switch (chip->ecc.mode) { +	case NAND_ECC_HW: +		/* Use standard hwecc read page function ? */ +		if (!chip->ecc.read_page) +			chip->ecc.read_page = nand_read_page_hwecc; +		if (!chip->ecc.write_page) +			chip->ecc.write_page = nand_write_page_hwecc; +		if (!chip->ecc.read_oob) +			chip->ecc.read_oob = nand_read_oob_std; +		if (!chip->ecc.write_oob) +			chip->ecc.write_oob = nand_write_oob_std; -	case NAND_ECC_HW3_512: -	case NAND_ECC_HW6_512: -	case NAND_ECC_HW8_512: -		if (mtd->oobblock == 256) { -			printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); -			this->eccmode = NAND_ECC_SOFT; -			this->calculate_ecc = nand_calculate_ecc; -			this->correct_data = nand_correct_data; -		} else -			this->eccsize = 512; /* set eccsize to 512 */ -		break; +	case NAND_ECC_HW_SYNDROME: +		if (!chip->ecc.calculate || !chip->ecc.correct || +		    !chip->ecc.hwctl) { +			printk(KERN_WARNING "No ECC functions supplied, " +			       "Hardware ECC not possible\n"); +			BUG(); +		} +		/* Use standard syndrome read/write page function ? */ +		if (!chip->ecc.read_page) +			chip->ecc.read_page = nand_read_page_syndrome; +		if (!chip->ecc.write_page) +			chip->ecc.write_page = nand_write_page_syndrome; +		if (!chip->ecc.read_oob) +			chip->ecc.read_oob = nand_read_oob_syndrome; +		if (!chip->ecc.write_oob) +			chip->ecc.write_oob = nand_write_oob_syndrome; -	case NAND_ECC_HW3_256: -		break; +		if (mtd->writesize >= chip->ecc.size) +			break; +		printk(KERN_WARNING "%d byte HW ECC not possible on " +		       "%d byte page size, fallback to SW ECC\n", +		       chip->ecc.size, mtd->writesize); +		chip->ecc.mode = NAND_ECC_SOFT; -	case NAND_ECC_NONE: -		printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); -		this->eccmode = NAND_ECC_NONE; +	case NAND_ECC_SOFT: +		chip->ecc.calculate = nand_calculate_ecc; +		chip->ecc.correct = nand_correct_data; +		chip->ecc.read_page = nand_read_page_swecc; +		chip->ecc.write_page = nand_write_page_swecc; +		chip->ecc.read_oob = nand_read_oob_std; +		chip->ecc.write_oob = nand_write_oob_std; +		chip->ecc.size = 256; +		chip->ecc.bytes = 3;  		break; -	case NAND_ECC_SOFT: -		this->calculate_ecc = nand_calculate_ecc; -		this->correct_data = nand_correct_data; +	case NAND_ECC_NONE: +		printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " +		       "This is not recommended !!\n"); +		chip->ecc.read_page = nand_read_page_raw; +		chip->ecc.write_page = nand_write_page_raw; +		chip->ecc.read_oob = nand_read_oob_std; +		chip->ecc.write_oob = nand_write_oob_std; +		chip->ecc.size = mtd->writesize; +		chip->ecc.bytes = 0;  		break;  	default: -		printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); -/*		BUG(); */ -	} - -	/* Check hardware ecc function availability and adjust number of ecc bytes per -	 * calculation step -	*/ -	switch (this->eccmode) { -	case NAND_ECC_HW12_2048: -		this->eccbytes += 4; -	case NAND_ECC_HW8_512: -		this->eccbytes += 2; -	case NAND_ECC_HW6_512: -		this->eccbytes += 3; -	case NAND_ECC_HW3_512: -	case NAND_ECC_HW3_256: -		if (this->calculate_ecc && this->correct_data && this->enable_hwecc) -			break; -		printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n"); -/*		BUG();	*/ +		printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", +		       chip->ecc.mode); +		BUG();  	} -	mtd->eccsize = this->eccsize; +	/* +	 * The number of bytes available for a client to place data into +	 * the out of band area +	 */ +	chip->ecc.layout->oobavail = 0; +	for (i = 0; chip->ecc.layout->oobfree[i].length; i++) +		chip->ecc.layout->oobavail += +			chip->ecc.layout->oobfree[i].length; +	mtd->oobavail = chip->ecc.layout->oobavail; -	/* Set the number of read / write steps for one page to ensure ECC generation */ -	switch (this->eccmode) { -	case NAND_ECC_HW12_2048: -		this->eccsteps = mtd->oobblock / 2048; -		break; -	case NAND_ECC_HW3_512: -	case NAND_ECC_HW6_512: -	case NAND_ECC_HW8_512: -		this->eccsteps = mtd->oobblock / 512; -		break; -	case NAND_ECC_HW3_256: -	case NAND_ECC_SOFT: -		this->eccsteps = mtd->oobblock / 256; -		break; +	/* +	 * Set the number of read / write steps for one page depending on ECC +	 * mode +	 */ +	chip->ecc.steps = mtd->writesize / chip->ecc.size; +	if(chip->ecc.steps * chip->ecc.size != mtd->writesize) { +		printk(KERN_WARNING "Invalid ecc parameters\n"); +		BUG(); +	} +	chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; -	case NAND_ECC_NONE: -		this->eccsteps = 1; -		break; +	/* +	 * Allow subpage writes up to ecc.steps. Not possible for MLC +	 * FLASH. +	 */ +	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && +	    !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { +		switch(chip->ecc.steps) { +		case 2: +			mtd->subpage_sft = 1; +			break; +		case 4: +		case 8: +			mtd->subpage_sft = 2; +			break; +		}  	} +	chip->subpagesize = mtd->writesize >> mtd->subpage_sft; -/* XXX U-BOOT XXX */ -#if 0 -	/* Initialize state, waitqueue and spinlock */ -	this->state = FL_READY; -	init_waitqueue_head (&this->wq); -	spin_lock_init (&this->chip_lock); -#endif +	/* Initialize state */ +	chip->state = FL_READY;  	/* De-select the device */ -	this->select_chip(mtd, -1); +	chip->select_chip(mtd, -1);  	/* Invalidate the pagebuffer reference */ -	this->pagebuf = -1; +	chip->pagebuf = -1;  	/* Fill in remaining MTD driver data */  	mtd->type = MTD_NANDFLASH; -	mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; -	mtd->ecctype = MTD_ECC_SW; +	mtd->flags = MTD_CAP_NANDFLASH;  	mtd->erase = nand_erase;  	mtd->point = NULL;  	mtd->unpoint = NULL;  	mtd->read = nand_read;  	mtd->write = nand_write; -	mtd->read_ecc = nand_read_ecc; -	mtd->write_ecc = nand_write_ecc;  	mtd->read_oob = nand_read_oob;  	mtd->write_oob = nand_write_oob; -/* XXX U-BOOT XXX */ -#if 0 -	mtd->readv = NULL; -	mtd->writev = nand_writev; -	mtd->writev_ecc = nand_writev_ecc; -#endif  	mtd->sync = nand_sync; -/* XXX U-BOOT XXX */ -#if 0  	mtd->lock = NULL;  	mtd->unlock = NULL; -	mtd->suspend = NULL; -	mtd->resume = NULL; -#endif +	mtd->suspend = nand_suspend; +	mtd->resume = nand_resume;  	mtd->block_isbad = nand_block_isbad;  	mtd->block_markbad = nand_block_markbad; -	/* and make the autooob the default one */ -	memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); -/* XXX U-BOOT XXX */ +	/* propagate ecc.layout to mtd_info */ +	mtd->ecclayout = chip->ecc.layout; + +	/* Check, if we should skip the bad block table scan */ +	if (chip->options & NAND_SKIP_BBTSCAN) +		return 0; + +	/* Build bad block table */ +	return chip->scan_bbt(mtd); +} + +/* module_text_address() isn't exported, and it's mostly a pointless +   test if this is a module _anyway_ -- they'd have to try _really_ hard +   to call us from in-kernel code if the core NAND support is modular. */ +#ifdef MODULE +#define caller_is_module() (1) +#else +#define caller_is_module() \ +	module_text_address((unsigned long)__builtin_return_address(0)) +#endif + +/** + * nand_scan - [NAND Interface] Scan for the NAND device + * @mtd:	MTD device structure + * @maxchips:	Number of chips to scan for + * + * This fills out all the uninitialized function pointers + * with the defaults. + * The flash ID is read and the mtd/chip structures are + * filled with the appropriate values. + * The mtd->owner field must be set to the module of the caller + * + */ +int nand_scan(struct mtd_info *mtd, int maxchips) +{ +	int ret; + +	/* Many callers got this wrong, so check for it for a while... */ +	/* XXX U-BOOT XXX */  #if 0 -	mtd->owner = THIS_MODULE; +	if (!mtd->owner && caller_is_module()) { +		printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n"); +		BUG(); +	}  #endif -	/* Build bad block table */ -	return this->scan_bbt (mtd); +	 +	ret = nand_scan_ident(mtd, maxchips); +	if (!ret) +		ret = nand_scan_tail(mtd); +	return ret;  }  /**   * nand_release - [NAND Interface] Free resources held by the NAND device   * @mtd:	MTD device structure - */ -void nand_release (struct mtd_info *mtd) +*/ +void nand_release(struct mtd_info *mtd)  { -	struct nand_chip *this = mtd->priv; +	struct nand_chip *chip = mtd->priv;  #ifdef CONFIG_MTD_PARTITIONS  	/* Deregister partitions */ -	del_mtd_partitions (mtd); +	del_mtd_partitions(mtd);  #endif  	/* Deregister the device */ -/* XXX U-BOOT XXX */ +	/* XXX U-BOOT XXX */  #if 0 -	del_mtd_device (mtd); +	del_mtd_device(mtd);  #endif -	/* Free bad block table memory, if allocated */ -	if (this->bbt) -		kfree (this->bbt); -	/* Buffer allocated by nand_scan ? */ -	if (this->options & NAND_OOBBUF_ALLOC) -		kfree (this->oob_buf); -	/* Buffer allocated by nand_scan ? */ -	if (this->options & NAND_DATABUF_ALLOC) -		kfree (this->data_buf); + +	/* Free bad block table memory */ +	kfree(chip->bbt); +	if (!(chip->options & NAND_OWN_BUFFERS)) +		kfree(chip->buffers);  } +/* XXX U-BOOT XXX */ +#if 0 +EXPORT_SYMBOL_GPL(nand_scan); +EXPORT_SYMBOL_GPL(nand_scan_ident); +EXPORT_SYMBOL_GPL(nand_scan_tail); +EXPORT_SYMBOL_GPL(nand_release); + +static int __init nand_base_init(void) +{ +	led_trigger_register_simple("nand-disk", &nand_led_trigger); +	return 0; +} + +static void __exit nand_base_exit(void) +{ +	led_trigger_unregister_simple(nand_led_trigger); +} + +module_init(nand_base_init); +module_exit(nand_base_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>"); +MODULE_DESCRIPTION("Generic NAND flash driver code");  #endif + +#endif + diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index a97743b45..acf1cf543 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -6,7 +6,7 @@   *   *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)   * - * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $ + * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License version 2 as @@ -48,7 +48,7 @@   *   * Following assumptions are made:   * - bbts start at a page boundary, if autolocated on a block boundary - * - the space neccecary for a bbt in FLASH does not exceed a block boundary + * - the space necessary for a bbt in FLASH does not exceed a block boundary   *   */ @@ -63,6 +63,19 @@  #include <asm/errno.h> +/* XXX U-BOOT XXX */ +#if 0 +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/compatmac.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/vmalloc.h> +#endif +  /**   * check_pattern - [GENERIC] check if a pattern is in the buffer   * @buf:	the buffer to search @@ -76,9 +89,9 @@   * pattern area contain 0xff   *  */ -static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) +static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)  { -	int i, end; +	int i, end = 0;  	uint8_t *p = buf;  	end = paglen + td->offs; @@ -96,9 +109,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des  			return -1;  	} -	p += td->len; -	end += td->len;  	if (td->options & NAND_BBT_SCANEMPTY) { +		p += td->len; +		end += td->len;  		for (i = end; i < len; i++) {  			if (*p++ != 0xff)  				return -1; @@ -108,6 +121,29 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des  }  /** + * check_short_pattern - [GENERIC] check if a pattern is in the buffer + * @buf:	the buffer to search + * @td:		search pattern descriptor + * + * Check for a pattern at the given place. Used to search bad block + * tables and good / bad block identifiers. Same as check_pattern, but + * no optional empty check + * +*/ +static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) +{ +	int i; +	uint8_t *p = buf; + +	/* Compare the pattern */ +	for (i = 0; i < td->len; i++) { +		if (p[td->offs + i] != td->pattern[i]) +			return -1; +	} +	return 0; +} + +/**   * read_bbt - [GENERIC] Read the bad block table starting from page   * @mtd:	MTD device structure   * @buf:	temporary buffer @@ -120,8 +156,8 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des   * Read the bad block table starting from page.   *   */ -static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, -	int bits, int offs, int reserved_block_code) +static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, +		    int bits, int offs, int reserved_block_code)  {  	int res, i, j, act = 0;  	struct nand_chip *this = mtd->priv; @@ -130,17 +166,17 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,  	uint8_t msk = (uint8_t) ((1 << bits) - 1);  	totlen = (num * bits) >> 3; -	from = ((loff_t)page) << this->page_shift; +	from = ((loff_t) page) << this->page_shift;  	while (totlen) { -		len = min (totlen, (size_t) (1 << this->bbt_erase_shift)); -		res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob); +		len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); +		res = mtd->read(mtd, from, len, &retlen, buf);  		if (res < 0) {  			if (retlen != len) { -				printk (KERN_INFO "nand_bbt: Error reading bad block table\n"); +				printk(KERN_INFO "nand_bbt: Error reading bad block table\n");  				return res;  			} -			printk (KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); +			printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n");  		}  		/* Analyse data */ @@ -150,22 +186,23 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,  				uint8_t tmp = (dat >> j) & msk;  				if (tmp == msk)  					continue; -				if (reserved_block_code && -				    (tmp == reserved_block_code)) { -					printk (KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n", -						((offs << 2) + (act >> 1)) << this->bbt_erase_shift); +				if (reserved_block_code && (tmp == reserved_block_code)) { +					printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n", +					       ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);  					this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); +					mtd->ecc_stats.bbtblocks++;  					continue;  				}  				/* Leave it for now, if its matured we can move this  				 * message to MTD_DEBUG_LEVEL0 */ -				printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", -					((offs << 2) + (act >> 1)) << this->bbt_erase_shift); +				printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", +				       ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);  				/* Factory marked bad or worn out ? */  				if (tmp == 0)  					this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);  				else  					this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06); +				mtd->ecc_stats.badblocks++;  			}  		}  		totlen -= len; @@ -185,7 +222,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,   * Read the bad block table for all chips starting at a given page   * We assume that the bbt bits are in consecutive order.  */ -static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) +static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)  {  	struct nand_chip *this = mtd->priv;  	int res = 0, i; @@ -209,6 +246,42 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des  	return 0;  } +/* + * Scan read raw data from flash + */ +static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +			 size_t len) +{ +	struct mtd_oob_ops ops; + +	ops.mode = MTD_OOB_RAW; +	ops.ooboffs = 0; +	ops.ooblen = mtd->oobsize; +	ops.oobbuf = buf; +	ops.datbuf = buf; +	ops.len = len; + +	return mtd->read_oob(mtd, offs, &ops); +} + +/* + * Scan write data with oob to flash + */ +static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, +			  uint8_t *buf, uint8_t *oob) +{ +	struct mtd_oob_ops ops; + +	ops.mode = MTD_OOB_PLACE; +	ops.ooboffs = 0; +	ops.ooblen = mtd->oobsize; +	ops.datbuf = buf; +	ops.oobbuf = oob; +	ops.len = len; + +	return mtd->write_oob(mtd, offs, &ops); +} +  /**   * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page   * @mtd:	MTD device structure @@ -220,28 +293,84 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des   * We assume that the bbt bits are in consecutive order.   *  */ -static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, -	struct nand_bbt_descr *md) +static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, +			 struct nand_bbt_descr *td, struct nand_bbt_descr *md)  {  	struct nand_chip *this = mtd->priv;  	/* Read the primary version, if available */  	if (td->options & NAND_BBT_VERSION) { -		nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); -		td->version[0] = buf[mtd->oobblock + td->veroffs]; -		printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); +		scan_read_raw(mtd, buf, td->pages[0] << this->page_shift, +			      mtd->writesize); +		td->version[0] = buf[mtd->writesize + td->veroffs]; +		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", +		       td->pages[0], td->version[0]);  	}  	/* Read the mirror version, if available */  	if (md && (md->options & NAND_BBT_VERSION)) { -		nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); -		md->version[0] = buf[mtd->oobblock + md->veroffs]; -		printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); +		scan_read_raw(mtd, buf, md->pages[0] << this->page_shift, +			      mtd->writesize); +		md->version[0] = buf[mtd->writesize + md->veroffs]; +		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", +		       md->pages[0], md->version[0]);  	} -  	return 1;  } +/* + * Scan a given block full + */ +static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, +			   loff_t offs, uint8_t *buf, size_t readlen, +			   int scanlen, int len) +{ +	int ret, j; + +	ret = scan_read_raw(mtd, buf, offs, readlen); +	if (ret) +		return ret; + +	for (j = 0; j < len; j++, buf += scanlen) { +		if (check_pattern(buf, scanlen, mtd->writesize, bd)) +			return 1; +	} +	return 0; +} + +/* + * Scan a given block partially + */ +static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, +			   loff_t offs, uint8_t *buf, int len) +{ +	struct mtd_oob_ops ops; +	int j, ret; + +	ops.ooblen = mtd->oobsize; +	ops.oobbuf = buf; +	ops.ooboffs = 0; +	ops.datbuf = NULL; +	ops.mode = MTD_OOB_PLACE; + +	for (j = 0; j < len; j++) { +		/* +		 * Read the full oob until read_oob is fixed to +		 * handle single byte reads for 16 bit +		 * buswidth +		 */ +		ret = mtd->read_oob(mtd, offs, &ops); +		if (ret) +			return ret; + +		if (check_short_pattern(buf, bd)) +			return 1; + +		offs += mtd->writesize; +	} +	return 0; +} +  /**   * create_bbt - [GENERIC] Create a bad block table by scanning the device   * @mtd:	MTD device structure @@ -253,13 +382,16 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de   * Create a bad block table by scanning the device   * for the given good/bad block identify pattern   */ -static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) +static int create_bbt(struct mtd_info *mtd, uint8_t *buf, +	struct nand_bbt_descr *bd, int chip)  {  	struct nand_chip *this = mtd->priv; -	int i, j, numblocks, len, scanlen; +	int i, numblocks, len, scanlen;  	int startblock;  	loff_t from; -	size_t readlen, ooblen; +	size_t readlen; + +	printk(KERN_INFO "Scanning device for bad blocks\n");  	if (bd->options & NAND_BBT_SCANALLPAGES)  		len = 1 << (this->bbt_erase_shift - this->page_shift); @@ -269,21 +401,28 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  		else  			len = 1;  	} -	scanlen	= mtd->oobblock + mtd->oobsize; -	readlen = len * mtd->oobblock; -	ooblen = len * mtd->oobsize; + +	if (!(bd->options & NAND_BBT_SCANEMPTY)) { +		/* We need only read few bytes from the OOB area */ +		scanlen = 0; +		readlen = bd->len; +	} else { +		/* Full page content should be read */ +		scanlen = mtd->writesize + mtd->oobsize; +		readlen = len * mtd->writesize; +	}  	if (chip == -1) { -		/* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it -		 * makes shifting and masking less painful */ +		/* Note that numblocks is 2 * (real numblocks) here, see i+=2 +		 * below as it makes shifting and masking less painful */  		numblocks = mtd->size >> (this->bbt_erase_shift - 1);  		startblock = 0;  		from = 0;  	} else {  		if (chip >= this->numchips) { -			printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", -				chip + 1, this->numchips); -			return; +			printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", +			       chip + 1, this->numchips); +			return -EINVAL;  		}  		numblocks = this->chipsize >> (this->bbt_erase_shift - 1);  		startblock = chip * numblocks; @@ -292,16 +431,28 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  	}  	for (i = startblock; i < numblocks;) { -		nand_read_raw (mtd, buf, from, readlen, ooblen); -		for (j = 0; j < len; j++) { -			if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { -				this->bbt[i >> 3] |= 0x03 << (i & 0x6); -				break; -			} +		int ret; + +		if (bd->options & NAND_BBT_SCANALLPAGES) +			ret = scan_block_full(mtd, bd, from, buf, readlen, +					      scanlen, len); +		else +			ret = scan_block_fast(mtd, bd, from, buf, len); + +		if (ret < 0) +			return ret; + +		if (ret) { +			this->bbt[i >> 3] |= 0x03 << (i & 0x6); +			printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", +			       i >> 1, (unsigned int)from); +			mtd->ecc_stats.badblocks++;  		} +  		i += 2;  		from += (1 << this->bbt_erase_shift);  	} +	return 0;  }  /** @@ -316,22 +467,23 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc   * block.   * If the option NAND_BBT_PERCHIP is given, each chip is searched   * for a bbt, which contains the bad block information of this chip. - * This is neccecary to provide support for certain DOC devices. + * This is necessary to provide support for certain DOC devices.   *   * The bbt ident pattern resides in the oob area of the first page   * in a block.   */ -static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) +static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)  {  	struct nand_chip *this = mtd->priv;  	int i, chips;  	int bits, startblock, block, dir; -	int scanlen = mtd->oobblock + mtd->oobsize; +	int scanlen = mtd->writesize + mtd->oobsize;  	int bbtblocks; +	int blocktopage = this->bbt_erase_shift - this->page_shift;  	/* Search direction top -> down ? */  	if (td->options & NAND_BBT_LASTBLOCK) { -		startblock = (mtd->size >> this->bbt_erase_shift) -1; +		startblock = (mtd->size >> this->bbt_erase_shift) - 1;  		dir = -1;  	} else {  		startblock = 0; @@ -357,13 +509,16 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr  		td->pages[i] = -1;  		/* Scan the maximum number of blocks */  		for (block = 0; block < td->maxblocks; block++) { +  			int actblock = startblock + dir * block; +			loff_t offs = actblock << this->bbt_erase_shift; +  			/* Read first page */ -			nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); -			if (!check_pattern(buf, scanlen, mtd->oobblock, td)) { -				td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift); +			scan_read_raw(mtd, buf, offs, mtd->writesize); +			if (!check_pattern(buf, scanlen, mtd->writesize, td)) { +				td->pages[i] = actblock << blocktopage;  				if (td->options & NAND_BBT_VERSION) { -					td->version[i] = buf[mtd->oobblock + td->veroffs]; +					td->version[i] = buf[mtd->writesize + td->veroffs];  				}  				break;  			} @@ -373,9 +528,10 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr  	/* Check, if we found a bbt for each requested chip */  	for (i = 0; i < chips; i++) {  		if (td->pages[i] == -1) -			printk (KERN_WARNING "Bad block table not found for chip %d\n", i); +			printk(KERN_WARNING "Bad block table not found for chip %d\n", i);  		else -			printk (KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]); +			printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], +			       td->version[i]);  	}  	return 0;  } @@ -389,21 +545,19 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr   *   * Search and read the bad block table(s)  */ -static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, -	struct nand_bbt_descr *td, struct nand_bbt_descr *md) +static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)  {  	/* Search the primary table */ -	search_bbt (mtd, buf, td); +	search_bbt(mtd, buf, td);  	/* Search the mirror table */  	if (md) -		search_bbt (mtd, buf, md); +		search_bbt(mtd, buf, md);  	/* Force result check */  	return 1;  } -  /**   * write_bbt - [GENERIC] (Re)write the bad block table   * @@ -416,25 +570,31 @@ static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf,   * (Re)write the bad block table   *  */ -static int write_bbt (struct mtd_info *mtd, uint8_t *buf, -	struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) +static int write_bbt(struct mtd_info *mtd, uint8_t *buf, +		     struct nand_bbt_descr *td, struct nand_bbt_descr *md, +		     int chipsel)  {  	struct nand_chip *this = mtd->priv; -	struct nand_oobinfo oobinfo;  	struct erase_info einfo;  	int i, j, res, chip = 0;  	int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; -	int nrchips, bbtoffs, pageoffs; +	int nrchips, bbtoffs, pageoffs, ooboffs;  	uint8_t msk[4];  	uint8_t rcode = td->reserved_block_code;  	size_t retlen, len = 0;  	loff_t to; +	struct mtd_oob_ops ops; + +	ops.ooblen = mtd->oobsize; +	ops.ooboffs = 0; +	ops.datbuf = NULL; +	ops.mode = MTD_OOB_PLACE;  	if (!rcode)  		rcode = 0xff;  	/* Write bad block table per chip rather than per device ? */  	if (td->options & NAND_BBT_PERCHIP) { -		numblocks = (int) (this->chipsize >> this->bbt_erase_shift); +		numblocks = (int)(this->chipsize >> this->bbt_erase_shift);  		/* Full device write or specific chip ? */  		if (chipsel == -1) {  			nrchips = this->numchips; @@ -443,7 +603,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf,  			chip = chipsel;  		}  	} else { -		numblocks = (int) (mtd->size >> this->bbt_erase_shift); +		numblocks = (int)(mtd->size >> this->bbt_erase_shift);  		nrchips = 1;  	} @@ -472,27 +632,38 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf,  		for (i = 0; i < td->maxblocks; i++) {  			int block = startblock + dir * i;  			/* Check, if the block is bad */ -			switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) { +			switch ((this->bbt[block >> 2] >> +				 (2 * (block & 0x03))) & 0x03) {  			case 0x01:  			case 0x03:  				continue;  			} -			page = block << (this->bbt_erase_shift - this->page_shift); +			page = block << +				(this->bbt_erase_shift - this->page_shift);  			/* Check, if the block is used by the mirror table */  			if (!md || md->pages[chip] != page)  				goto write;  		} -		printk (KERN_ERR "No space left to write bad block table\n"); +		printk(KERN_ERR "No space left to write bad block table\n");  		return -ENOSPC; -write: +	write:  		/* Set up shift count and masks for the flash table */  		bits = td->options & NAND_BBT_NRBITS_MSK; +		msk[2] = ~rcode;  		switch (bits) { -		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x01; break; -		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x03; break; -		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; msk[2] = ~rcode; msk[3] = 0x0f; break; -		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break; +		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; +			msk[3] = 0x01; +			break; +		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; +			msk[3] = 0x03; +			break; +		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; +			msk[3] = 0x0f; +			break; +		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; +			msk[3] = 0xff; +			break;  		default: return -EINVAL;  		} @@ -500,82 +671,92 @@ write:  		to = ((loff_t) page) << this->page_shift; -		memcpy (&oobinfo, this->autooob, sizeof(oobinfo)); -		oobinfo.useecc = MTD_NANDECC_PLACEONLY; -  		/* Must we save the block contents ? */  		if (td->options & NAND_BBT_SAVECONTENT) {  			/* Make it block aligned */  			to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));  			len = 1 << this->bbt_erase_shift; -			res = mtd->read_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo); +			res = mtd->read(mtd, to, len, &retlen, buf);  			if (res < 0) {  				if (retlen != len) { -					printk (KERN_INFO "nand_bbt: Error reading block for writing the bad block table\n"); +					printk(KERN_INFO "nand_bbt: Error " +					       "reading block for writing " +					       "the bad block table\n");  					return res;  				} -				printk (KERN_WARNING "nand_bbt: ECC error while reading block for writing bad block table\n"); +				printk(KERN_WARNING "nand_bbt: ECC error " +				       "while reading block for writing " +				       "bad block table\n");  			} +			/* Read oob data */ +			ops.ooblen = (len >> this->page_shift) * mtd->oobsize; +			ops.oobbuf = &buf[len]; +			res = mtd->read_oob(mtd, to + mtd->writesize, &ops); +			if (res < 0 || ops.oobretlen != ops.ooblen) +				goto outerr; +  			/* Calc the byte offset in the buffer */  			pageoffs = page - (int)(to >> this->page_shift);  			offs = pageoffs << this->page_shift;  			/* Preset the bbt area with 0xff */ -			memset (&buf[offs], 0xff, (size_t)(numblocks >> sft)); -			/* Preset the bbt's oob area with 0xff */ -			memset (&buf[len + pageoffs * mtd->oobsize], 0xff, -				((len >> this->page_shift) - pageoffs) * mtd->oobsize); -			if (td->options & NAND_BBT_VERSION) { -				buf[len + (pageoffs * mtd->oobsize) + td->veroffs] = td->version[chip]; -			} +			memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); +			ooboffs = len + (pageoffs * mtd->oobsize); +  		} else {  			/* Calc length */  			len = (size_t) (numblocks >> sft);  			/* Make it page aligned ! */ -			len = (len + (mtd->oobblock-1)) & ~(mtd->oobblock-1); +			len = (len + (mtd->writesize - 1)) & +				~(mtd->writesize - 1);  			/* Preset the buffer with 0xff */ -			memset (buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize); +			memset(buf, 0xff, len + +			       (len >> this->page_shift)* mtd->oobsize);  			offs = 0; +			ooboffs = len;  			/* Pattern is located in oob area of first page */ -			memcpy (&buf[len + td->offs], td->pattern, td->len); -			if (td->options & NAND_BBT_VERSION) { -				buf[len + td->veroffs] = td->version[chip]; -			} +			memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);  		} +		if (td->options & NAND_BBT_VERSION) +			buf[ooboffs + td->veroffs] = td->version[chip]; +  		/* walk through the memory table */ -		for (i = 0; i < numblocks; ) { +		for (i = 0; i < numblocks;) {  			uint8_t dat;  			dat = this->bbt[bbtoffs + (i >> 2)]; -			for (j = 0; j < 4; j++ , i++) { +			for (j = 0; j < 4; j++, i++) {  				int sftcnt = (i << (3 - sft)) & sftmsk;  				/* Do not store the reserved bbt blocks ! */ -				buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt); +				buf[offs + (i >> sft)] &= +					~(msk[dat & 0x03] << sftcnt);  				dat >>= 2;  			}  		} -		memset (&einfo, 0, sizeof (einfo)); +		memset(&einfo, 0, sizeof(einfo));  		einfo.mtd = mtd; -		einfo.addr = (unsigned long) to; +		einfo.addr = (unsigned long)to;  		einfo.len = 1 << this->bbt_erase_shift; -		res = nand_erase_nand (mtd, &einfo, 1); -		if (res < 0) { -			printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res); -			return res; -		} +		res = nand_erase_nand(mtd, &einfo, 1); +		if (res < 0) +			goto outerr; -		res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo); -		if (res < 0) { -			printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); -			return res; -		} -		printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", -			(unsigned int) to, td->version[chip]); +		res = scan_write_bbt(mtd, to, len, buf, &buf[len]); +		if (res < 0) +			goto outerr; + +		printk(KERN_DEBUG "Bad block table written to 0x%08x, version " +		       "0x%02X\n", (unsigned int)to, td->version[chip]);  		/* Mark it as used */  		td->pages[chip] = page;  	}  	return 0; + + outerr: +	printk(KERN_WARNING +	       "nand_bbt: Error while writing bad block table %d\n", res); +	return res;  }  /** @@ -586,29 +767,27 @@ write:   * The function creates a memory based bbt by scanning the device   * for manufacturer / software marked good / bad blocks  */ -static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) +static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  {  	struct nand_chip *this = mtd->priv; -	/* Ensure that we only scan for the pattern and nothing else */ -	bd->options = 0; -	create_bbt (mtd, this->data_buf, bd, -1); -	return 0; +	bd->options &= ~NAND_BBT_SCANEMPTY; +	return create_bbt(mtd, this->buffers->databuf, bd, -1);  }  /** - * check_create - [GENERIC] create and write bbt(s) if neccecary + * check_create - [GENERIC] create and write bbt(s) if necessary   * @mtd:	MTD device structure   * @buf:	temporary buffer   * @bd:		descriptor for the good/bad block search pattern   *   * The function checks the results of the previous call to read_bbt - * and creates / updates the bbt(s) if neccecary - * Creation is neccecary if no bbt was found for the chip/device - * Update is neccecary if one of the tables is missing or the + * and creates / updates the bbt(s) if necessary + * Creation is necessary if no bbt was found for the chip/device + * Update is necessary if one of the tables is missing or the   * version nr. of one table is less than the other  */ -static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) +static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)  {  	int i, chips, writeops, chipsel, res;  	struct nand_chip *this = mtd->priv; @@ -676,35 +855,35 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des  			rd = td;  			goto writecheck;  		} -create: +	create:  		/* Create the bad block table by scanning the device ? */  		if (!(td->options & NAND_BBT_CREATE))  			continue;  		/* Create the table in memory by scanning the chip(s) */ -		create_bbt (mtd, buf, bd, chipsel); +		create_bbt(mtd, buf, bd, chipsel);  		td->version[i] = 1;  		if (md)  			md->version[i] = 1; -writecheck: +	writecheck:  		/* read back first ? */  		if (rd) -			read_abs_bbt (mtd, buf, rd, chipsel); +			read_abs_bbt(mtd, buf, rd, chipsel);  		/* If they weren't versioned, read both. */  		if (rd2) -			read_abs_bbt (mtd, buf, rd2, chipsel); +			read_abs_bbt(mtd, buf, rd2, chipsel);  		/* Write the bad block table to the device ? */  		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { -			res = write_bbt (mtd, buf, td, md, chipsel); +			res = write_bbt(mtd, buf, td, md, chipsel);  			if (res < 0)  				return res;  		}  		/* Write the mirror bad block table to the device ? */  		if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { -			res = write_bbt (mtd, buf, md, td, chipsel); +			res = write_bbt(mtd, buf, md, td, chipsel);  			if (res < 0)  				return res;  		} @@ -721,7 +900,7 @@ writecheck:   * accidental erasures / writes. The regions are identified by   * the mark 0x02.  */ -static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) +static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)  {  	struct nand_chip *this = mtd->priv;  	int i, j, chips, block, nrblocks, update; @@ -739,7 +918,8 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)  	for (i = 0; i < chips; i++) {  		if ((td->options & NAND_BBT_ABSPAGE) ||  		    !(td->options & NAND_BBT_WRITE)) { -			if (td->pages[i] == -1) continue; +			if (td->pages[i] == -1) +				continue;  			block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);  			block <<= 1;  			oldval = this->bbt[(block >> 3)]; @@ -759,7 +939,8 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)  			oldval = this->bbt[(block >> 3)];  			newval = oldval | (0x2 << (block & 0x06));  			this->bbt[(block >> 3)] = newval; -			if (oldval != newval) update = 1; +			if (oldval != newval) +				update = 1;  			block += 2;  		}  		/* If we want reserved blocks to be recorded to flash, and some @@ -784,7 +965,7 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)   * by calling the nand_free_bbt function.   *  */ -int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) +int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  {  	struct nand_chip *this = mtd->priv;  	int len, res = 0; @@ -793,53 +974,56 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)  	struct nand_bbt_descr *md = this->bbt_md;  	len = mtd->size >> (this->bbt_erase_shift + 2); -	/* Allocate memory (2bit per block) */ -	this->bbt = kmalloc (len, GFP_KERNEL); +	/* Allocate memory (2bit per block) and clear the memory bad block table */ +	this->bbt = kzalloc(len, GFP_KERNEL);  	if (!this->bbt) { -		printk (KERN_ERR "nand_scan_bbt: Out of memory\n"); +		printk(KERN_ERR "nand_scan_bbt: Out of memory\n");  		return -ENOMEM;  	} -	/* Clear the memory bad block table */ -	memset (this->bbt, 0x00, len);  	/* If no primary table decriptor is given, scan the device  	 * to build a memory based bad block table  	 */ -	if (!td) -		return nand_memory_bbt(mtd, bd); +	if (!td) { +		if ((res = nand_memory_bbt(mtd, bd))) { +			printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); +			kfree(this->bbt); +			this->bbt = NULL; +		} +		return res; +	}  	/* Allocate a temporary buffer for one eraseblock incl. oob */  	len = (1 << this->bbt_erase_shift);  	len += (len >> this->page_shift) * mtd->oobsize; -	buf = kmalloc (len, GFP_KERNEL); +	buf = vmalloc(len);  	if (!buf) { -		printk (KERN_ERR "nand_bbt: Out of memory\n"); -		kfree (this->bbt); +		printk(KERN_ERR "nand_bbt: Out of memory\n"); +		kfree(this->bbt);  		this->bbt = NULL;  		return -ENOMEM;  	}  	/* Is the bbt at a given page ? */  	if (td->options & NAND_BBT_ABSPAGE) { -		res = read_abs_bbts (mtd, buf, td, md); +		res = read_abs_bbts(mtd, buf, td, md);  	} else {  		/* Search the bad block table using a pattern in oob */ -		res = search_read_bbts (mtd, buf, td, md); +		res = search_read_bbts(mtd, buf, td, md);  	}  	if (res) -		res = check_create (mtd, buf, bd); +		res = check_create(mtd, buf, bd);  	/* Prevent the bbt regions from erasing / writing */ -	mark_bbt_region (mtd, td); +	mark_bbt_region(mtd, td);  	if (md) -		mark_bbt_region (mtd, md); +		mark_bbt_region(mtd, md); -	kfree (buf); +	vfree(buf);  	return res;  } -  /**   * nand_update_bbt - [NAND Interface] update bad block table(s)   * @mtd:	MTD device structure @@ -847,7 +1031,7 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)   *   * The function updates the bad block table(s)  */ -int nand_update_bbt (struct mtd_info *mtd, loff_t offs) +int nand_update_bbt(struct mtd_info *mtd, loff_t offs)  {  	struct nand_chip *this = mtd->priv;  	int len, res = 0, writeops = 0; @@ -863,9 +1047,9 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs)  	/* Allocate a temporary buffer for one eraseblock incl. oob */  	len = (1 << this->bbt_erase_shift);  	len += (len >> this->page_shift) * mtd->oobsize; -	buf = kmalloc (len, GFP_KERNEL); +	buf = kmalloc(len, GFP_KERNEL);  	if (!buf) { -		printk (KERN_ERR "nand_update_bbt: Out of memory\n"); +		printk(KERN_ERR "nand_update_bbt: Out of memory\n");  		return -ENOMEM;  	} @@ -873,7 +1057,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs)  	/* Do we have a bbt per chip ? */  	if (td->options & NAND_BBT_PERCHIP) { -		chip = (int) (offs >> this->chip_shift); +		chip = (int)(offs >> this->chip_shift);  		chipsel = chip;  	} else {  		chip = 0; @@ -886,29 +1070,26 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs)  	/* Write the bad block table to the device ? */  	if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { -		res = write_bbt (mtd, buf, td, md, chipsel); +		res = write_bbt(mtd, buf, td, md, chipsel);  		if (res < 0)  			goto out;  	}  	/* Write the mirror bad block table to the device ? */  	if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { -		res = write_bbt (mtd, buf, md, td, chipsel); +		res = write_bbt(mtd, buf, md, td, chipsel);  	} -out: -	kfree (buf); + out: +	kfree(buf);  	return res;  }  /* Define some generic bad / good block scan pattern which are used - * while scanning a device for factory marked good / bad blocks - * - * The memory based patterns just - */ + * while scanning a device for factory marked good / bad blocks. */  static uint8_t scan_ff_pattern[] = { 0xff, 0xff };  static struct nand_bbt_descr smallpage_memorybased = { -	.options = 0, +	.options = NAND_BBT_SCAN2NDPAGE,  	.offs = 5,  	.len = 1,  	.pattern = scan_ff_pattern @@ -922,14 +1103,14 @@ static struct nand_bbt_descr largepage_memorybased = {  };  static struct nand_bbt_descr smallpage_flashbased = { -	.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES, +	.options = NAND_BBT_SCAN2NDPAGE,  	.offs = 5,  	.len = 1,  	.pattern = scan_ff_pattern  };  static struct nand_bbt_descr largepage_flashbased = { -	.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES, +	.options = NAND_BBT_SCAN2NDPAGE,  	.offs = 0,  	.len = 2,  	.pattern = scan_ff_pattern @@ -977,7 +1158,7 @@ static struct nand_bbt_descr bbt_mirror_descr = {   * support for the device and calls the nand_scan_bbt function   *  */ -int nand_default_bbt (struct mtd_info *mtd) +int nand_default_bbt(struct mtd_info *mtd)  {  	struct nand_chip *this = mtd->priv; @@ -987,7 +1168,7 @@ int nand_default_bbt (struct mtd_info *mtd)  	 * of the good / bad information, so we _must_ store  	 * this information in a good / bad table during  	 * startup -	*/ +	 */  	if (this->options & NAND_IS_AND) {  		/* Use the default pattern descriptors */  		if (!this->bbt_td) { @@ -995,10 +1176,9 @@ int nand_default_bbt (struct mtd_info *mtd)  			this->bbt_md = &bbt_mirror_descr;  		}  		this->options |= NAND_USE_FLASH_BBT; -		return nand_scan_bbt (mtd, &agand_flashbased); +		return nand_scan_bbt(mtd, &agand_flashbased);  	} -  	/* Is a flash based bad block table requested ? */  	if (this->options & NAND_USE_FLASH_BBT) {  		/* Use the default pattern descriptors */ @@ -1007,18 +1187,17 @@ int nand_default_bbt (struct mtd_info *mtd)  			this->bbt_md = &bbt_mirror_descr;  		}  		if (!this->badblock_pattern) { -			this->badblock_pattern = (mtd->oobblock > 512) ? -				&largepage_flashbased : &smallpage_flashbased; +			this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased;  		}  	} else {  		this->bbt_td = NULL;  		this->bbt_md = NULL;  		if (!this->badblock_pattern) { -			this->badblock_pattern = (mtd->oobblock > 512) ? -				&largepage_memorybased : &smallpage_memorybased; +			this->badblock_pattern = (mtd->writesize > 512) ? +			    &largepage_memorybased : &smallpage_memorybased;  		}  	} -	return nand_scan_bbt (mtd, this->badblock_pattern); +	return nand_scan_bbt(mtd, this->badblock_pattern);  }  /** @@ -1027,26 +1206,35 @@ int nand_default_bbt (struct mtd_info *mtd)   * @offs:	offset in the device   * @allowbbt:	allow access to bad block table region   * - */ -int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt) +*/ +int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)  {  	struct nand_chip *this = mtd->priv;  	int block; -	uint8_t	res; +	uint8_t res;  	/* Get block number * 2 */ -	block = (int) (offs >> (this->bbt_erase_shift - 1)); +	block = (int)(offs >> (this->bbt_erase_shift - 1));  	res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;  	MTDDEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: "  	          "(block %d) 0x%02x\n", (unsigned int)offs, res, block >> 1);  	switch ((int)res) { -	case 0x00:	return 0; -	case 0x01:	return 1; -	case 0x02:	return allowbbt ? 0 : 1; +	case 0x00: +		return 0; +	case 0x01: +		return 1; +	case 0x02: +		return allowbbt ? 0 : 1;  	}  	return 1;  } +/* XXX U-BOOT XXX */ +#if 0 +EXPORT_SYMBOL(nand_scan_bbt); +EXPORT_SYMBOL(nand_default_bbt); +#endif +  #endif diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 4c532b079..e1d5154db 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -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 diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 736349039..f8b96cf02 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -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"}  }; diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 828cc338a..78e70cc80 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -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 @@ -163,7 +128,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)  	for (;  	     erase.addr < opts->offset + erase_length;  	     erase.addr += meminfo->erasesize) { - +		  		WATCHDOG_RESET ();  		if (!opts->scrub && bbtest) { @@ -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,27 +227,190 @@ static unsigned char data_buf[MAX_PAGE_SIZE];  static unsigned char oob_buf[MAX_OOB_SIZE];  /* OOB layouts to pass into the kernel as default */ -static struct nand_oobinfo none_oobinfo = { +static struct nand_ecclayout none_ecclayout = {  	.useecc = MTD_NANDECC_OFF,  }; -static struct nand_oobinfo jffs2_oobinfo = { +static struct nand_ecclayout jffs2_ecclayout = {  	.useecc = MTD_NANDECC_PLACE,  	.eccbytes = 6,  	.eccpos = { 0, 1, 2, 3, 6, 7 }  }; -static struct nand_oobinfo yaffs_oobinfo = { +static struct nand_ecclayout yaffs_ecclayout = {  	.useecc = MTD_NANDECC_PLACE,  	.eccbytes = 6,  	.eccpos = { 8, 9, 10, 13, 14, 15}  }; -static struct nand_oobinfo autoplace_oobinfo = { +static struct nand_ecclayout autoplace_ecclayout = {  	.useecc = MTD_NANDECC_AUTOPLACE  }; +#endif +  /** + * nand_fill_oob - [Internal] Transfer client buffer to oob + * @chip:	nand chip structure + * @oob:	oob data buffer + * @ops:	oob ops structure + *  + * Copied from nand_base.c + */ +static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, +				  struct mtd_oob_ops *ops) +{ +	size_t len = ops->ooblen; + +	switch(ops->mode) { + +	case MTD_OOB_PLACE: +	case MTD_OOB_RAW: +		memcpy(chip->oob_poi + ops->ooboffs, oob, len); +		return oob + len; + +	case MTD_OOB_AUTO: { +		struct nand_oobfree *free = chip->ecc.layout->oobfree; +		uint32_t boffs = 0, woffs = ops->ooboffs; +		size_t bytes = 0; + +		for(; free->length && len; free++, len -= bytes) { +			/* Write request not from offset 0 ? */ +			if (unlikely(woffs)) { +				if (woffs >= free->length) { +					woffs -= free->length; +					continue; +				} +				boffs = free->offset + woffs; +				bytes = min_t(size_t, len, +					      (free->length - woffs)); +				woffs = 0; +			} else { +				bytes = min_t(size_t, len, free->length); +				boffs = free->offset; +			} +			memcpy(chip->oob_poi + boffs, oob, bytes); +			oob += bytes; +		} +		return oob; +	} +	default: +		BUG(); +	} +	return NULL; +} + +#define NOTALIGNED(x)	(x & (chip->subpagesize - 1)) != 0 + + +/* copied from nand_base.c: nand_do_write_ops() + * Only very small changes + */ +int nand_write_opts(nand_info_t *mtd, loff_t to, mtd_oob_ops_t *ops) +{ +	int chipnr, realpage, page, blockmask, column; +	struct nand_chip *chip = mtd->priv; +	uint32_t writelen = ops->len; +	uint8_t *oob = ops->oobbuf; +	uint8_t *buf = ops->datbuf; +	int ret, subpage; +	 +	ops->retlen = 0; +	if (!writelen) +		return 0; + +	printk("nand_write_opts: to: 0x%08x, ops->len: 0x%08x\n", to, ops->len); +	 +	/* reject writes, which are not page aligned */ +	if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { +		printk(KERN_NOTICE "nand_write: " +		       "Attempt to write not page aligned data\n"); +		return -EINVAL; +	} + +	column = to & (mtd->writesize - 1); +	subpage = column || (writelen & (mtd->writesize - 1)); + +	if (subpage && oob) { +		printk(KERN_NOTICE "nand_write: " +		       "Attempt to write oob to subpage\n"); +		return -EINVAL; +	} + +	chipnr = (int)(to >> chip->chip_shift); +	chip->select_chip(mtd, chipnr); + +	/* XXX U-BOOT XXX */ +#if 0 +	/* Check, if it is write protected */ +	if (nand_check_wp(mtd)) +		return -EIO; +#endif + +	realpage = (int)(to >> chip->page_shift); +	page = realpage & chip->pagemask; +	blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; + +	/* Invalidate the page cache, when we write to the cached page */ +	if (to <= (chip->pagebuf << chip->page_shift) && +	    (chip->pagebuf << chip->page_shift) < (to + ops->len)) +		chip->pagebuf = -1; + +	/* If we're not given explicit OOB data, let it be 0xFF */ +	if (likely(!oob)) { +		printf("!oob, writing %d bytes with 0xff to chip->oob_poi (0x%08x)\n", mtd->oobsize, chip->oob_poi); +		memset(chip->oob_poi, 0xff, mtd->oobsize); +	} + +	while(1) { +		int bytes = mtd->writesize; +		int cached = writelen > bytes && page != blockmask; +		uint8_t *wbuf = buf; + +		/* Partial page write ? */ +		if (unlikely(column || writelen < (mtd->writesize - 1))) { +			cached = 0; +			bytes = min_t(int, bytes - column, (int) writelen); +			chip->pagebuf = -1; +			memset(chip->buffers->databuf, 0xff, mtd->writesize); +			memcpy(&chip->buffers->databuf[column], buf, bytes); +			wbuf = chip->buffers->databuf; +		} + +		if (unlikely(oob)) +			oob = nand_fill_oob(chip, oob, ops); + +		ret = chip->write_page(mtd, chip, wbuf, page, cached, +				       (ops->mode == MTD_OOB_RAW)); +		if (ret) +			break; + +		writelen -= bytes; +		if (!writelen) +			break; + +		column = 0; +		buf += bytes; +		realpage++; + +		page = realpage & chip->pagemask; +		/* Check, if we cross a chip boundary */ +		if (!page) { +			chipnr++; +			chip->select_chip(mtd, -1); +			chip->select_chip(mtd, chipnr); +		} +	} + +	ops->retlen = ops->len - writelen; +	if (unlikely(oob)) +		ops->oobretlen = ops->ooblen; +	return ret; +} + +/* XXX U-BOOT XXX */ +#if 0 +/**   * nand_write_opts: - write image to NAND flash with support for various options   *   * @param meminfo	NAND device to erase @@ -301,9 +428,9 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)  	int blockstart = -1;  	loff_t offs;  	int readlen; -	int oobinfochanged = 0; +	int ecclayoutchanged = 0;  	int percent_complete = -1; -	struct nand_oobinfo old_oobinfo; +	struct nand_ecclayout old_ecclayout;  	ulong mtdoffset = opts->offset;  	ulong erasesize_blockalign;  	u_char *buffer = opts->buffer; @@ -324,35 +451,35 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)  	}  	/* make sure device page sizes are valid */ -	if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512) -	    && !(meminfo->oobsize == 8 && meminfo->oobblock == 256) -	    && !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) { +	if (!(meminfo->oobsize == 16 && meminfo->writesize == 512) +	    && !(meminfo->oobsize == 8 && meminfo->writesize == 256) +	    && !(meminfo->oobsize == 64 && meminfo->writesize == 2048)) {  		printf("Unknown flash (not normal NAND)\n");  		return -1;  	}  	/* read the current oob info */ -	memcpy(&old_oobinfo, &meminfo->oobinfo, sizeof(old_oobinfo)); +	memcpy(&old_ecclayout, &meminfo->ecclayout, sizeof(old_ecclayout));  	/* write without ecc? */  	if (opts->noecc) { -		memcpy(&meminfo->oobinfo, &none_oobinfo, -		       sizeof(meminfo->oobinfo)); -		oobinfochanged = 1; +		memcpy(&meminfo->ecclayout, &none_ecclayout, +		       sizeof(meminfo->ecclayout)); +		ecclayoutchanged = 1;  	}  	/* autoplace ECC? */ -	if (opts->autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) { +	if (opts->autoplace && (old_ecclayout.useecc != MTD_NANDECC_AUTOPLACE)) { -		memcpy(&meminfo->oobinfo, &autoplace_oobinfo, -		       sizeof(meminfo->oobinfo)); -		oobinfochanged = 1; +		memcpy(&meminfo->ecclayout, &autoplace_ecclayout, +		       sizeof(meminfo->ecclayout)); +		ecclayoutchanged = 1;  	}  	/* force OOB layout for jffs2 or yaffs? */  	if (opts->forcejffs2 || opts->forceyaffs) { -		struct nand_oobinfo *oobsel = -			opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo; +		struct nand_ecclayout *oobsel = +			opts->forcejffs2 ? &jffs2_ecclayout : &yaffs_ecclayout;  		if (meminfo->oobsize == 8) {  			if (opts->forceyaffs) { @@ -361,15 +488,15 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)  				goto restoreoob;  			}  			/* Adjust number of ecc bytes */ -			jffs2_oobinfo.eccbytes = 3; +			jffs2_ecclayout.eccbytes = 3;  		} -		memcpy(&meminfo->oobinfo, oobsel, sizeof(meminfo->oobinfo)); +		memcpy(&meminfo->ecclayout, oobsel, sizeof(meminfo->ecclayout));  	}  	/* get image length */  	imglen = opts->length; -	pagelen = meminfo->oobblock +	pagelen = meminfo->writesize  		+ ((opts->writeoob != 0) ? meminfo->oobsize : 0);  	/* check, if file is pagealigned */ @@ -379,11 +506,11 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)  	}  	/* check, if length fits into device */ -	if (((imglen / pagelen) * meminfo->oobblock) +	if (((imglen / pagelen) * meminfo->writesize)  	     > (meminfo->size - opts->offset)) {  		printf("Image %d bytes, NAND page %d bytes, "  		       "OOB area %u bytes, device size %u bytes\n", -		       imglen, pagelen, meminfo->oobblock, meminfo->size); +		       imglen, pagelen, meminfo->writesize, meminfo->size);  		printf("Input block does not fit into device\n");  		goto restoreoob;  	} @@ -437,11 +564,11 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)  			} while (offs < blockstart + erasesize_blockalign);  		} -		readlen = meminfo->oobblock; +		readlen = meminfo->writesize;  		if (opts->pad && (imglen < readlen)) {  			readlen = imglen;  			memset(data_buf + readlen, 0xff, -			       meminfo->oobblock - readlen); +			       meminfo->writesize - readlen);  		}  		/* read page data from input memory buffer */ @@ -474,7 +601,7 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)  		/* write out the page data */  		result = meminfo->write(meminfo,  					mtdoffset, -					meminfo->oobblock, +					meminfo->writesize,  					&written,  					(unsigned char *) &data_buf); @@ -505,16 +632,16 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)  			}  		} -		mtdoffset += meminfo->oobblock; +		mtdoffset += meminfo->writesize;  	}  	if (!opts->quiet)  		printf("\n");  restoreoob: -	if (oobinfochanged) { -		memcpy(&meminfo->oobinfo, &old_oobinfo, -		       sizeof(meminfo->oobinfo)); +	if (ecclayoutchanged) { +		memcpy(&meminfo->ecclayout, &old_ecclayout, +		       sizeof(meminfo->ecclayout));  	}  	if (imglen > 0) { @@ -548,22 +675,22 @@ int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)  	int result;  	/* make sure device page sizes are valid */ -	if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512) -	    && !(meminfo->oobsize == 8 && meminfo->oobblock == 256) -	    && !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) { +	if (!(meminfo->oobsize == 16 && meminfo->writesize == 512) +	    && !(meminfo->oobsize == 8 && meminfo->writesize == 256) +	    && !(meminfo->oobsize == 64 && meminfo->writesize == 2048)) {  		printf("Unknown flash (not normal NAND)\n");  		return -1;  	} -	pagelen = meminfo->oobblock +	pagelen = meminfo->writesize  		+ ((opts->readoob != 0) ? meminfo->oobsize : 0);  	/* check, if length is not larger than device */ -	if (((imglen / pagelen) * meminfo->oobblock) +	if (((imglen / pagelen) * meminfo->writesize)  	     > (meminfo->size - opts->offset)) {  		printf("Image %d bytes, NAND page %d bytes, "  		       "OOB area %u bytes, device size %u bytes\n", -		       imglen, pagelen, meminfo->oobblock, meminfo->size); +		       imglen, pagelen, meminfo->writesize, meminfo->size);  		printf("Input block is larger than device\n");  		return -1;  	} @@ -621,7 +748,7 @@ int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)  		/* read page data to memory buffer */  		result = meminfo->read(meminfo,  				       mtdoffset, -				       meminfo->oobblock, +				       meminfo->writesize,  				       &readlen,  				       (unsigned char *) &data_buf); @@ -685,7 +812,7 @@ int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)  			}  		} -		mtdoffset += meminfo->oobblock; +		mtdoffset += meminfo->writesize;  	}  	if (!opts->quiet) @@ -699,7 +826,10 @@ int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)  	/* return happy */  	return 0;  } +#endif +/* XXX U-BOOT XXX */ +#if 0  /******************************************************************************   * Support for locking / unlocking operations of some NAND devices   *****************************************************************************/ @@ -784,7 +914,7 @@ int nand_get_lock_status(nand_info_t *meminfo, ulong offset)  	this->select_chip(meminfo, chipnr); -	if ((offset & (meminfo->oobblock - 1)) != 0) { +	if ((offset & (meminfo->writesize - 1)) != 0) {  		printf ("nand_get_lock_status: "  			"Start address must be beginning of "  			"nand page!\n"); @@ -813,7 +943,7 @@ int nand_get_lock_status(nand_info_t *meminfo, ulong offset)   * @param meminfo	nand mtd instance   * @param start		start byte address   * @param length	number of bytes to unlock (must be a multiple of - *			page size nand->oobblock) + *			page size nand->writesize)   *   * @return		0 on success, -1 in case of error   */ @@ -839,14 +969,14 @@ int nand_unlock(nand_info_t *meminfo, ulong start, ulong length)  		goto out;  	} -	if ((start & (meminfo->oobblock - 1)) != 0) { +	if ((start & (meminfo->writesize - 1)) != 0) {  		printf ("nand_unlock: Start address must be beginning of "  			"nand page!\n");  		ret = -1;  		goto out;  	} -	if (length == 0 || (length & (meminfo->oobblock - 1)) != 0) { +	if (length == 0 || (length & (meminfo->writesize - 1)) != 0) {  		printf ("nand_unlock: Length must be a multiple of nand page "  			"size!\n");  		ret = -1; @@ -875,5 +1005,6 @@ int nand_unlock(nand_info_t *meminfo, ulong start, ulong length)  	this->select_chip(meminfo, -1);  	return ret;  } +#endif  #endif diff --git a/include/common.h b/include/common.h index 2fcb1fd37..06ed27806 100644 --- a/include/common.h +++ b/include/common.h @@ -119,11 +119,13 @@ typedef volatile unsigned char	vu_char;  #define debugX(level,fmt,args...)  #endif	/* DEBUG */ +#ifndef BUG  #define BUG() do { \  	printf("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \  	panic("BUG!"); \  } while (0)  #define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) +#endif /* BUG */  typedef void (interrupt_handler_t)(void *); diff --git a/include/linux/err.h b/include/linux/err.h new file mode 100644 index 000000000..4e08c4fe6 --- /dev/null +++ b/include/linux/err.h @@ -0,0 +1,45 @@ +#ifndef _LINUX_ERR_H +#define _LINUX_ERR_H + +/* XXX U-BOOT XXX */ +#if 0 +#include <linux/compiler.h> +#else +#include <linux/mtd/compat.h> +#endif + +#include <asm/errno.h> + + +/* + * Kernel pointers have redundant information, so we can use a + * scheme where we can return either an error code or a dentry + * pointer with the same return value. + * + * This should be a per-architecture thing, to allow different + * error and pointer decisions. + */ +#define MAX_ERRNO	4095 + +#ifndef __ASSEMBLY__ + +#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO) + +static inline void *ERR_PTR(long error) +{ +	return (void *) error; +} + +static inline long PTR_ERR(const void *ptr) +{ +	return (long) ptr; +} + +static inline long IS_ERR(const void *ptr) +{ +	return IS_ERR_VALUE((unsigned long)ptr); +} + +#endif + +#endif /* _LINUX_ERR_H */ diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h new file mode 100644 index 000000000..d1ded51d7 --- /dev/null +++ b/include/linux/mtd/blktrans.h @@ -0,0 +1,81 @@ +/* + * $Id: blktrans.h,v 1.6 2005/11/07 11:14:54 gleixner Exp $ + * + * (C) 2003 David Woodhouse <dwmw2@infradead.org> + * + * Interface to Linux block layer for MTD 'translation layers'. + * + */ + +#ifndef __MTD_TRANS_H__ +#define __MTD_TRANS_H__ + +/* XXX U-BOOT XXX */ +#if 0 +#include <linux/mutex.h> +#else +#include <linux/list.h> +#endif + +struct hd_geometry; +struct mtd_info; +struct mtd_blktrans_ops; +struct file; +struct inode; + +struct mtd_blktrans_dev { +	struct mtd_blktrans_ops *tr; +	struct list_head list; +	struct mtd_info *mtd; +/* XXX U-BOOT XXX */ +#if 0 +	struct mutex lock; +#endif +	int devnum; +	unsigned long size; +	int readonly; +	void *blkcore_priv; /* gendisk in 2.5, devfs_handle in 2.4 */ +}; + +struct blkcore_priv; /* Differs for 2.4 and 2.5 kernels; private */ + +struct mtd_blktrans_ops { +	char *name; +	int major; +	int part_bits; +	int blksize; +	int blkshift; + +	/* Access functions */ +	int (*readsect)(struct mtd_blktrans_dev *dev, +		    unsigned long block, char *buffer); +	int (*writesect)(struct mtd_blktrans_dev *dev, +		     unsigned long block, char *buffer); + +	/* Block layer ioctls */ +	int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo); +	int (*flush)(struct mtd_blktrans_dev *dev); + +	/* Called with mtd_table_mutex held; no race with add/remove */ +	int (*open)(struct mtd_blktrans_dev *dev); +	int (*release)(struct mtd_blktrans_dev *dev); + +	/* Called on {de,}registration and on subsequent addition/removal +	   of devices, with mtd_table_mutex held. */ +	void (*add_mtd)(struct mtd_blktrans_ops *tr, struct mtd_info *mtd); +	void (*remove_dev)(struct mtd_blktrans_dev *dev); + +	struct list_head devs; +	struct list_head list; +	struct module *owner; + +	struct mtd_blkcore_priv *blkcore_priv; +}; + +extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr); +extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr); +extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); +extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); + + +#endif /* __MTD_TRANS_H__ */ diff --git a/include/linux/mtd/compat.h b/include/linux/mtd/compat.h index fe55087ea..86a6e43ca 100644 --- a/include/linux/mtd/compat.h +++ b/include/linux/mtd/compat.h @@ -18,7 +18,12 @@  #define KERN_DEBUG  #define kmalloc(size, flags)	malloc(size) -#define kfree(ptr)		free(ptr) +#define kzalloc(size, flags)    calloc(size, 1) +#define vmalloc(size)			malloc(size) +#define kfree(ptr)		        free(ptr) +#define vfree(ptr)              free(ptr) + +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))  /*   * ..and if you can't take the strict diff --git a/include/linux/mtd/doc2000.h b/include/linux/mtd/doc2000.h index 29f676786..12de2845a 100644 --- a/include/linux/mtd/doc2000.h +++ b/include/linux/mtd/doc2000.h @@ -1,15 +1,23 @@ - -/* Linux driver for Disk-On-Chip 2000       */ -/* (c) 1999 Machine Vision Holdings, Inc.   */ -/* Author: David Woodhouse <dwmw2@mvhi.com> */ -/* $Id: doc2000.h,v 1.15 2001/09/19 00:22:15 dwmw2 Exp $ */ +/* + * Linux driver for Disk-On-Chip devices + * + * Copyright (C) 1999 Machine Vision Holdings, Inc. + * Copyright (C) 2001-2003 David Woodhouse <dwmw2@infradead.org> + * Copyright (C) 2002-2003 Greg Ungerer <gerg@snapgear.com> + * Copyright (C) 2002-2003 SnapGear Inc + * + * $Id: doc2000.h,v 1.25 2005/11/07 11:14:54 gleixner Exp $ + * + * Released under GPL + */  #ifndef __MTD_DOC2000_H__  #define __MTD_DOC2000_H__ -struct DiskOnChip; - -#include <linux/mtd/nftl.h> +#include <linux/mtd/mtd.h> +#if 0 +#include <linux/mutex.h> +#endif  #define DoC_Sig1 0  #define DoC_Sig2 1 @@ -40,10 +48,58 @@ struct DiskOnChip;  #define DoC_Mil_CDSN_IO		0x0800  #define DoC_2k_CDSN_IO		0x1800 -#define ReadDOC_(adr, reg)      ((volatile unsigned char)(*(volatile __u8 *)(((unsigned long)adr)+((reg))))) -#define WriteDOC_(d, adr, reg)  do{ *(volatile __u8 *)(((unsigned long)adr)+((reg))) = (__u8)d; eieio();} while(0) +#define DoC_Mplus_NOP			0x1002 +#define DoC_Mplus_AliasResolution	0x1004 +#define DoC_Mplus_DOCControl		0x1006 +#define DoC_Mplus_AccessStatus		0x1008 +#define DoC_Mplus_DeviceSelect		0x1008 +#define DoC_Mplus_Configuration		0x100a +#define DoC_Mplus_OutputControl		0x100c +#define DoC_Mplus_FlashControl		0x1020 +#define DoC_Mplus_FlashSelect 		0x1022 +#define DoC_Mplus_FlashCmd		0x1024 +#define DoC_Mplus_FlashAddress		0x1026 +#define DoC_Mplus_FlashData0		0x1028 +#define DoC_Mplus_FlashData1		0x1029 +#define DoC_Mplus_ReadPipeInit		0x102a +#define DoC_Mplus_LastDataRead		0x102c +#define DoC_Mplus_LastDataRead1		0x102d +#define DoC_Mplus_WritePipeTerm 	0x102e +#define DoC_Mplus_ECCSyndrome0		0x1040 +#define DoC_Mplus_ECCSyndrome1		0x1041 +#define DoC_Mplus_ECCSyndrome2		0x1042 +#define DoC_Mplus_ECCSyndrome3		0x1043 +#define DoC_Mplus_ECCSyndrome4		0x1044 +#define DoC_Mplus_ECCSyndrome5		0x1045 +#define DoC_Mplus_ECCConf 		0x1046 +#define DoC_Mplus_Toggle		0x1046 +#define DoC_Mplus_DownloadStatus	0x1074 +#define DoC_Mplus_CtrlConfirm		0x1076 +#define DoC_Mplus_Power			0x1fff -#define DOC_IOREMAP_LEN		0x4000 +/* How to access the device? + * On ARM, it'll be mmap'd directly with 32-bit wide accesses. + * On PPC, it's mmap'd and 16-bit wide. + * Others use readb/writeb + */ +#if defined(__arm__) +#define ReadDOC_(adr, reg)      ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)))) +#define WriteDOC_(d, adr, reg)  do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0) +#define DOC_IOREMAP_LEN 0x8000 +#elif defined(__ppc__) +#define ReadDOC_(adr, reg)      ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)))) +#define WriteDOC_(d, adr, reg)  do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0) +#define DOC_IOREMAP_LEN 0x4000 +#else +#define ReadDOC_(adr, reg)      readb((void __iomem *)(adr) + (reg)) +#define WriteDOC_(d, adr, reg)  writeb(d, (void __iomem *)(adr) + (reg)) +#define DOC_IOREMAP_LEN 0x2000 + +#endif + +#if defined(__i386__) || defined(__x86_64__) +#define USE_MEMCPY +#endif  /* These are provided to directly use the DoC_xxx defines */  #define ReadDOC(adr, reg)      ReadDOC_(adr,DoC_##reg) @@ -54,14 +110,21 @@ struct DiskOnChip;  #define DOC_MODE_RESERVED1	2  #define DOC_MODE_RESERVED2	3 -#define DOC_MODE_MDWREN		4  #define DOC_MODE_CLR_ERR	0x80 +#define	DOC_MODE_RST_LAT	0x10 +#define	DOC_MODE_BDECT		0x08 +#define DOC_MODE_MDWREN	0x04 -#define DOC_ChipID_UNKNOWN	0x00  #define DOC_ChipID_Doc2k	0x20 +#define DOC_ChipID_Doc2kTSOP	0x21	/* internal number for MTD */  #define DOC_ChipID_DocMil	0x30 +#define DOC_ChipID_DocMilPlus32	0x40 +#define DOC_ChipID_DocMilPlus16	0x41  #define CDSN_CTRL_FR_B		0x80 +#define CDSN_CTRL_FR_B0		0x40 +#define CDSN_CTRL_FR_B1		0x80 +  #define CDSN_CTRL_ECC_IO	0x20  #define CDSN_CTRL_FLASH_IO	0x10  #define CDSN_CTRL_WP		0x08 @@ -77,41 +140,47 @@ struct DiskOnChip;  #define DOC_ECC_RESV		0x02  #define DOC_ECC_IGNORE		0x01 +#define DOC_FLASH_CE		0x80 +#define DOC_FLASH_WP		0x40 +#define DOC_FLASH_BANK		0x02 +  /* We have to also set the reserved bit 1 for enable */  #define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV)  #define DOC_ECC_DIS (DOC_ECC_RESV) +struct Nand { +	char floor, chip; +	unsigned long curadr; +	unsigned char curmode; +	/* Also some erase/write/pipeline info when we get that far */ +}; +  #define MAX_FLOORS 4  #define MAX_CHIPS 4 -#define MAX_FLOORS_MIL 4 +#define MAX_FLOORS_MIL 1  #define MAX_CHIPS_MIL 1 +#define MAX_FLOORS_MPLUS 2 +#define MAX_CHIPS_MPLUS 1 +  #define ADDR_COLUMN 1  #define ADDR_PAGE 2  #define ADDR_COLUMN_PAGE 3 -struct Nand { -	char floor, chip; -	unsigned long curadr; -	unsigned char curmode; -	/* Also some erase/write/pipeline info when we get that far */ -}; -  struct DiskOnChip {  	unsigned long physadr; -	unsigned long virtadr; +	void __iomem *virtadr;  	unsigned long totlen; -	char* name; -	char ChipID; /* Type of DiskOnChip */ +	unsigned char ChipID; /* Type of DiskOnChip */  	int ioreg; -	char* chips_name;  	unsigned long mfr; /* Flash IDs - only one type of flash per device */  	unsigned long id;  	int chipshift;  	char page256;  	char pageadrlen; +	char interleave; /* Internal interleaving - Millennium Plus style */  	unsigned long erasesize;  	int curfloor; @@ -119,98 +188,22 @@ struct DiskOnChip {  	int numchips;  	struct Nand *chips; - -	int nftl_found; -	struct NFTLrecord nftl; +	struct mtd_info *nextdoc; +/* XXX U-BOOT XXX */ +#if 0 +	struct mutex lock; +#endif  }; -#define SECTORSIZE 512 - -/* Return codes from doc_write(), doc_read(), and doc_erase(). - */ -#define DOC_OK		0 -#define DOC_EIO		1 -#define DOC_EINVAL	2 -#define DOC_EECC	3 -#define DOC_ETIMEOUT	4 - -/* - * Function Prototypes - */  int doc_decode_ecc(unsigned char sector[512], unsigned char ecc1[6]); -int doc_rw(struct DiskOnChip* this, int cmd, loff_t from, size_t len, -	   size_t *retlen, u_char *buf); -int doc_read_ecc(struct DiskOnChip* this, loff_t from, size_t len, -		 size_t *retlen, u_char *buf, u_char *eccbuf); -int doc_write_ecc(struct DiskOnChip* this, loff_t to, size_t len, -		  size_t *retlen, const u_char *buf, u_char *eccbuf); -int doc_read_oob(struct DiskOnChip* this, loff_t ofs, size_t len, -		 size_t *retlen, u_char *buf); -int doc_write_oob(struct DiskOnChip* this, loff_t ofs, size_t len, -		  size_t *retlen, const u_char *buf); -int doc_erase (struct DiskOnChip* this, loff_t ofs, size_t len); - -void doc_probe(unsigned long physadr); - -void doc_print(struct DiskOnChip*); - -/* - * Standard NAND flash commands - */ -#define NAND_CMD_READ0		0 -#define NAND_CMD_READ1		1 -#define NAND_CMD_PAGEPROG	0x10 -#define NAND_CMD_READOOB	0x50 -#define NAND_CMD_ERASE1		0x60 -#define NAND_CMD_STATUS		0x70 -#define NAND_CMD_SEQIN		0x80 -#define NAND_CMD_READID		0x90 -#define NAND_CMD_ERASE2		0xd0 -#define NAND_CMD_RESET		0xff - +/* XXX U-BOOT XXX */ +#if 1  /*   * NAND Flash Manufacturer ID Codes   */ -#define NAND_MFR_TOSHIBA	0x98 -#define NAND_MFR_SAMSUNG	0xec - -/* - * NAND Flash Device ID Structure - * - * Structure overview: - * - *  name - Complete name of device - * - *  manufacture_id - manufacturer ID code of device. - * - *  model_id - model ID code of device. - * - *  chipshift - total number of address bits for the device which - *              is used to calculate address offsets and the total - *              number of bytes the device is capable of. - * - *  page256 - denotes if flash device has 256 byte pages or not. - * - *  pageadrlen - number of bytes minus one needed to hold the - *               complete address into the flash array. Keep in - *               mind that when a read or write is done to a - *               specific address, the address is input serially - *               8 bits at a time. This structure member is used - *               by the read/write routines as a loop index for - *               shifting the address out 8 bits at a time. - * - *  erasesize - size of an erase block in the flash device. - */ -struct nand_flash_dev { -	char * name; -	int manufacture_id; -	int model_id; -	int chipshift; -	char page256; -	char pageadrlen; -	unsigned long erasesize; -	int bus16; -}; +#define NAND_MFR_TOSHIBA   0x98 +#define NAND_MFR_SAMSUNG   0xec +#endif  #endif /* __MTD_DOC2000_H__ */ diff --git a/include/linux/mtd/inftl-user.h b/include/linux/mtd/inftl-user.h new file mode 100644 index 000000000..9b1e2526b --- /dev/null +++ b/include/linux/mtd/inftl-user.h @@ -0,0 +1,91 @@ +/* + * $Id: inftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $ + * + * Parts of INFTL headers shared with userspace + * + */ + +#ifndef __MTD_INFTL_USER_H__ +#define __MTD_INFTL_USER_H__ + +#define	OSAK_VERSION	0x5120 +#define	PERCENTUSED	98 + +#define	SECTORSIZE	512 + +/* Block Control Information */ + +struct inftl_bci { +	uint8_t ECCsig[6]; +	uint8_t Status; +	uint8_t Status1; +} __attribute__((packed)); + +struct inftl_unithead1 { +	uint16_t virtualUnitNo; +	uint16_t prevUnitNo; +	uint8_t ANAC; +	uint8_t NACs; +	uint8_t parityPerField; +	uint8_t discarded; +} __attribute__((packed)); + +struct inftl_unithead2 { +	uint8_t parityPerField; +	uint8_t ANAC; +	uint16_t prevUnitNo; +	uint16_t virtualUnitNo; +	uint8_t NACs; +	uint8_t discarded; +} __attribute__((packed)); + +struct inftl_unittail { +	uint8_t Reserved[4]; +	uint16_t EraseMark; +	uint16_t EraseMark1; +} __attribute__((packed)); + +union inftl_uci { +	struct inftl_unithead1 a; +	struct inftl_unithead2 b; +	struct inftl_unittail c; +}; + +struct inftl_oob { +	struct inftl_bci b; +	union inftl_uci u; +}; + + +/* INFTL Media Header */ + +struct INFTLPartition { +	__u32 virtualUnits; +	__u32 firstUnit; +	__u32 lastUnit; +	__u32 flags; +	__u32 spareUnits; +	__u32 Reserved0; +	__u32 Reserved1; +} __attribute__((packed)); + +struct INFTLMediaHeader { +	char bootRecordID[8]; +	__u32 NoOfBootImageBlocks; +	__u32 NoOfBinaryPartitions; +	__u32 NoOfBDTLPartitions; +	__u32 BlockMultiplierBits; +	__u32 FormatFlags; +	__u32 OsakVersion; +	__u32 PercentUsed; +	struct INFTLPartition Partitions[4]; +} __attribute__((packed)); + +/* Partition flag types */ +#define	INFTL_BINARY	0x20000000 +#define	INFTL_BDTL	0x40000000 +#define	INFTL_LAST	0x80000000 + +#endif /* __MTD_INFTL_USER_H__ */ + + diff --git a/include/linux/mtd/jffs2-user.h b/include/linux/mtd/jffs2-user.h new file mode 100644 index 000000000..d508ef0ae --- /dev/null +++ b/include/linux/mtd/jffs2-user.h @@ -0,0 +1,35 @@ +/* + * $Id: jffs2-user.h,v 1.1 2004/05/05 11:57:54 dwmw2 Exp $ + * + * JFFS2 definitions for use in user space only + */ + +#ifndef __JFFS2_USER_H__ +#define __JFFS2_USER_H__ + +/* This file is blessed for inclusion by userspace */ +#include <linux/jffs2.h> +#include <endian.h> +#include <byteswap.h> + +#undef cpu_to_je16 +#undef cpu_to_je32 +#undef cpu_to_jemode +#undef je16_to_cpu +#undef je32_to_cpu +#undef jemode_to_cpu + +extern int target_endian; + +#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); }) +#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); }) + +#define cpu_to_je16(x) ((jint16_t){t16(x)}) +#define cpu_to_je32(x) ((jint32_t){t32(x)}) +#define cpu_to_jemode(x) ((jmode_t){t32(x)}) + +#define je16_to_cpu(x) (t16((x).v16)) +#define je32_to_cpu(x) (t32((x).v32)) +#define jemode_to_cpu(x) (t32((x).m)) + +#endif /* __JFFS2_USER_H__ */ diff --git a/include/linux/mtd/mtd-abi.h b/include/linux/mtd/mtd-abi.h index 4cebea959..0ce2099d6 100644 --- a/include/linux/mtd/mtd-abi.h +++ b/include/linux/mtd/mtd-abi.h @@ -1,5 +1,5 @@  /* - * $Id: mtd-abi.h,v 1.7 2004/11/23 15:37:32 gleixner Exp $ + * $Id: mtd-abi.h,v 1.13 2005/11/07 11:14:56 gleixner Exp $   *   * Portions of MTD ABI definition which are shared by kernel and user space   */ @@ -7,6 +7,10 @@  #ifndef __MTD_ABI_H__  #define __MTD_ABI_H__ +#if 1 +#include <linux/mtd/compat.h> +#endif +  struct erase_info_user {  	uint32_t start;  	uint32_t length; @@ -15,7 +19,7 @@ struct erase_info_user {  struct mtd_oob_buf {  	uint32_t start;  	uint32_t length; -	unsigned char *ptr; +	unsigned char __user *ptr;  };  #define MTD_ABSENT		0 @@ -23,47 +27,41 @@ struct mtd_oob_buf {  #define MTD_ROM			2  #define MTD_NORFLASH		3  #define MTD_NANDFLASH		4 -#define MTD_PEROM		5 -#define MTD_OTHER		14 -#define MTD_UNKNOWN		15 +#define MTD_DATAFLASH		6 +#define MTD_UBIVOLUME		7 -#define MTD_CLEAR_BITS		1       /* Bits can be cleared (flash) */ -#define MTD_SET_BITS		2       /* Bits can be set */ -#define MTD_ERASEABLE		4       /* Has an erase function */ -#define MTD_WRITEB_WRITEABLE	8       /* Direct IO is possible */ -#define MTD_VOLATILE		16      /* Set for RAMs */ -#define MTD_XIP			32	/* eXecute-In-Place possible */ -#define MTD_OOB			64	/* Out-of-band data (NAND flash) */ -#define MTD_ECC			128	/* Device capable of automatic ECC */ -#define MTD_NO_VIRTBLOCKS	256	/* Virtual blocks not allowed */ +#define MTD_WRITEABLE		0x400	/* Device is writeable */ +#define MTD_BIT_WRITEABLE	0x800	/* Single bits can be flipped */ +#define MTD_NO_ERASE		0x1000	/* No erase necessary */ +#define MTD_STUPID_LOCK		0x2000	/* Always locked after reset */ -/* Some common devices / combinations of capabilities */ +// Some common devices / combinations of capabilities  #define MTD_CAP_ROM		0 -#define MTD_CAP_RAM		(MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEB_WRITEABLE) -#define MTD_CAP_NORFLASH        (MTD_CLEAR_BITS|MTD_ERASEABLE) -#define MTD_CAP_NANDFLASH       (MTD_CLEAR_BITS|MTD_ERASEABLE|MTD_OOB) -#define MTD_WRITEABLE		(MTD_CLEAR_BITS|MTD_SET_BITS) - - -/* Types of automatic ECC/Checksum available */ -#define MTD_ECC_NONE		0	/* No automatic ECC available */ -#define MTD_ECC_RS_DiskOnChip	1	/* Automatic ECC on DiskOnChip */ -#define MTD_ECC_SW		2	/* SW ECC for Toshiba & Samsung devices */ +#define MTD_CAP_RAM		(MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE) +#define MTD_CAP_NORFLASH	(MTD_WRITEABLE | MTD_BIT_WRITEABLE) +#define MTD_CAP_NANDFLASH	(MTD_WRITEABLE)  /* ECC byte placement */ -#define MTD_NANDECC_OFF		0	/* Switch off ECC (Not recommended) */ -#define MTD_NANDECC_PLACE	1	/* Use the given placement in the structure (YAFFS1 legacy mode) */ -#define MTD_NANDECC_AUTOPLACE	2	/* Use the default placement scheme */ -#define MTD_NANDECC_PLACEONLY	3	/* Use the given placement in the structure (Do not store ecc result on read) */ -#define MTD_NANDECC_AUTOPL_USR	4	/* Use the given autoplacement scheme rather than using the default */ +#define MTD_NANDECC_OFF		0	// Switch off ECC (Not recommended) +#define MTD_NANDECC_PLACE	1	// Use the given placement in the structure (YAFFS1 legacy mode) +#define MTD_NANDECC_AUTOPLACE	2	// Use the default placement scheme +#define MTD_NANDECC_PLACEONLY	3	// Use the given placement in the structure (Do not store ecc result on read) +#define MTD_NANDECC_AUTOPL_USR	4	// Use the given autoplacement scheme rather than using the default + +/* OTP mode selection */ +#define MTD_OTP_OFF		0 +#define MTD_OTP_FACTORY		1 +#define MTD_OTP_USER		2  struct mtd_info_user {  	uint8_t type;  	uint32_t flags; -	uint32_t size;	 /* Total size of the MTD */ +	uint32_t size;	 // Total size of the MTD  	uint32_t erasesize; -	uint32_t oobblock;  /* Size of OOB blocks (e.g. 512) */ -	uint32_t oobsize;   /* Amount of OOB data per block (e.g. 16) */ +	uint32_t writesize; +	uint32_t oobsize;   // Amount of OOB data per block (e.g. 16) +	/* The below two fields are obsolete and broken, do not use them +	 * (TODO: remove at some point) */  	uint32_t ecctype;  	uint32_t eccsize;  }; @@ -76,19 +74,36 @@ struct region_info_user {  	uint32_t regionindex;  }; -#define MEMGETINFO              _IOR('M', 1, struct mtd_info_user) -#define MEMERASE                _IOW('M', 2, struct erase_info_user) -#define MEMWRITEOOB             _IOWR('M', 3, struct mtd_oob_buf) -#define MEMREADOOB              _IOWR('M', 4, struct mtd_oob_buf) -#define MEMLOCK                 _IOW('M', 5, struct erase_info_user) -#define MEMUNLOCK               _IOW('M', 6, struct erase_info_user) +struct otp_info { +	uint32_t start; +	uint32_t length; +	uint32_t locked; +}; + +#define MEMGETINFO		_IOR('M', 1, struct mtd_info_user) +#define MEMERASE		_IOW('M', 2, struct erase_info_user) +#define MEMWRITEOOB		_IOWR('M', 3, struct mtd_oob_buf) +#define MEMREADOOB		_IOWR('M', 4, struct mtd_oob_buf) +#define MEMLOCK			_IOW('M', 5, struct erase_info_user) +#define MEMUNLOCK		_IOW('M', 6, struct erase_info_user)  #define MEMGETREGIONCOUNT	_IOR('M', 7, int)  #define MEMGETREGIONINFO	_IOWR('M', 8, struct region_info_user)  #define MEMSETOOBSEL		_IOW('M', 9, struct nand_oobinfo)  #define MEMGETOOBSEL		_IOR('M', 10, struct nand_oobinfo)  #define MEMGETBADBLOCK		_IOW('M', 11, loff_t)  #define MEMSETBADBLOCK		_IOW('M', 12, loff_t) +#define OTPSELECT		_IOR('M', 13, int) +#define OTPGETREGIONCOUNT	_IOW('M', 14, int) +#define OTPGETREGIONINFO	_IOW('M', 15, struct otp_info) +#define OTPLOCK			_IOR('M', 16, struct otp_info) +#define ECCGETLAYOUT		_IOR('M', 17, struct nand_ecclayout) +#define ECCGETSTATS		_IOR('M', 18, struct mtd_ecc_stats) +#define MTDFILEMODE		_IO('M', 19) +/* + * Obsolete legacy interface. Keep it in order not to break userspace + * interfaces + */  struct nand_oobinfo {  	uint32_t useecc;  	uint32_t eccbytes; @@ -96,4 +111,46 @@ struct nand_oobinfo {  	uint32_t eccpos[48];  }; +struct nand_oobfree { +	uint32_t offset; +	uint32_t length; +}; + +#define MTD_MAX_OOBFREE_ENTRIES	8 +/* + * ECC layout control structure. Exported to userspace for + * diagnosis and to allow creation of raw images + */ +struct nand_ecclayout { +	uint32_t eccbytes; +	uint32_t eccpos[64]; +	uint32_t oobavail; +	struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; +}; + +/** + * struct mtd_ecc_stats - error correction stats + * + * @corrected:	number of corrected bits + * @failed:	number of uncorrectable errors + * @badblocks:	number of bad blocks in this partition + * @bbtblocks:	number of blocks reserved for bad block tables + */ +struct mtd_ecc_stats { +	uint32_t corrected; +	uint32_t failed; +	uint32_t badblocks; +	uint32_t bbtblocks; +}; + +/* + * Read/write file modes for access to MTD + */ +enum mtd_file_modes { +	MTD_MODE_NORMAL = MTD_OTP_OFF, +	MTD_MODE_OTP_FACTORY = MTD_OTP_FACTORY, +	MTD_MODE_OTP_USER = MTD_OTP_USER, +	MTD_MODE_RAW, +}; +  #endif /* __MTD_ABI_H__ */ diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 05ba375a8..8e0dc00f7 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -1,5 +1,5 @@  /* - * $Id: mtd.h,v 1.56 2004/08/09 18:46:04 dmarlin Exp $ + * $Id: mtd.h,v 1.61 2005/11/07 11:14:54 gleixner Exp $   *   * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.   * @@ -8,10 +8,13 @@  #ifndef __MTD_MTD_H__  #define __MTD_MTD_H__ +  #include <linux/types.h>  #include <linux/mtd/mtd-abi.h> -#define MAX_MTD_DEVICES 16 +#define MTD_CHAR_MAJOR 90 +#define MTD_BLOCK_MAJOR 31 +#define MAX_MTD_DEVICES 32  #define MTD_ERASE_PENDING	0x01  #define MTD_ERASING		0x02 @@ -41,32 +44,83 @@ struct mtd_erase_region_info {  	u_int32_t offset;			/* At which this region starts, from the beginning of the MTD */  	u_int32_t erasesize;		/* For this region */  	u_int32_t numblocks;		/* Number of blocks of erasesize in this region */ +	unsigned long *lockmap;		/* If keeping bitmap of locks */ +}; + +/* + * oob operation modes + * + * MTD_OOB_PLACE:	oob data are placed at the given offset + * MTD_OOB_AUTO:	oob data are automatically placed at the free areas + *			which are defined by the ecclayout + * MTD_OOB_RAW:		mode to read raw data+oob in one chunk. The oob data + *			is inserted into the data. Thats a raw image of the + *			flash contents. + */ +typedef enum { +	MTD_OOB_PLACE, +	MTD_OOB_AUTO, +	MTD_OOB_RAW, +} mtd_oob_mode_t; + +/** + * struct mtd_oob_ops - oob operation operands + * @mode:	operation mode + * + * @len:	number of data bytes to write/read + * + * @retlen:	number of data bytes written/read + * + * @ooblen:	number of oob bytes to write/read + * @oobretlen:	number of oob bytes written/read + * @ooboffs:	offset of oob data in the oob area (only relevant when + *		mode = MTD_OOB_PLACE) + * @datbuf:	data buffer - if NULL only oob data are read/written + * @oobbuf:	oob data buffer + * + * Note, it is allowed to read more then one OOB area at one go, but not write. + * The interface assumes that the OOB write requests program only one page's + * OOB area. + */ +struct mtd_oob_ops { +	mtd_oob_mode_t	mode; +	size_t		len; +	size_t		retlen; +	size_t		ooblen; +	size_t		oobretlen; +	uint32_t	ooboffs; +	uint8_t		*datbuf; +	uint8_t		*oobbuf;  };  struct mtd_info {  	u_char type;  	u_int32_t flags; -	u_int32_t size;	 /* Total size of the MTD */ +	u_int32_t size;	 // Total size of the MTD -	/* "Major" erase size for the device. Nave users may take this +	/* "Major" erase size for the device. Naïve users may take this  	 * to be the only erase size available, or may use the more detailed  	 * information below if they desire  	 */  	u_int32_t erasesize; +	/* Minimal writable flash unit size. In case of NOR flash it is 1 (even +	 * though individual bits can be cleared), in case of NAND flash it is +	 * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR +	 * it is of ECC block size, etc. It is illegal to have writesize = 0. +	 * Any driver registering a struct mtd_info must ensure a writesize of +	 * 1 or larger. +	 */ +	u_int32_t writesize; -	u_int32_t oobblock;  /* Size of OOB blocks (e.g. 512) */ -	u_int32_t oobsize;   /* Amount of OOB data per block (e.g. 16) */ -	u_int32_t oobavail;  /* Number of bytes in OOB area available for fs  */ -	u_int32_t ecctype; -	u_int32_t eccsize; - +	u_int32_t oobsize;   // Amount of OOB data per block (e.g. 16) +	u_int32_t oobavail;  // Available OOB bytes per block -	/* Kernel-only stuff starts here. */ +	// Kernel-only stuff starts here.  	char *name;  	int index; -	/* oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) */ -	struct nand_oobinfo oobinfo; +	/* ecc layout structure pointer - read only ! */ +	struct nand_ecclayout *ecclayout;  	/* Data for variable erase regions. If numeraseregions is zero,  	 * it means that the whole device has erasesize as given above. @@ -74,9 +128,6 @@ struct mtd_info {  	int numeraseregions;  	struct mtd_erase_region_info *eraseregions; -	/* This really shouldn't be here. It can go away in 2.5 */ -	u_int32_t bank_size; -  	int (*erase) (struct mtd_info *mtd, struct erase_info *instr);  	/* This stuff for eXecute-In-Place */ @@ -89,39 +140,35 @@ struct mtd_info {  	int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  	int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); -	int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); -	int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); - -	int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); -	int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); +	int (*read_oob) (struct mtd_info *mtd, loff_t from, +			 struct mtd_oob_ops *ops); +	int (*write_oob) (struct mtd_info *mtd, loff_t to, +			 struct mtd_oob_ops *ops);  	/*  	 * Methods to access the protection register area, present in some  	 * flash devices. The user data is one time programmable but the  	 * factory data is read only.  	 */ -	int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - +	int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);  	int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - -	/* This function is not yet implemented */ +	int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); +	int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  	int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); +	int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len); + +/* XXX U-BOOT XXX */  #if 0 -	/* kvec-based read/write methods. We need these especially for NAND flash, -	   with its limited number of write cycles per erase. +	/* kvec-based read/write methods.  	   NB: The 'count' parameter is the number of _vectors_, each of  	   which contains an (ofs, len) tuple.  	*/ -	int (*readv) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen); -	int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, -		size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);  	int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); -	int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, -		size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);  #endif +  	/* Sync */  	void (*sync) (struct mtd_info *mtd); -#if 0 +  	/* Chip-supported device locking */  	int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len);  	int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len); @@ -129,15 +176,32 @@ struct mtd_info {  	/* Power Management functions */  	int (*suspend) (struct mtd_info *mtd);  	void (*resume) (struct mtd_info *mtd); -#endif +  	/* Bad block management functions */  	int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);  	int (*block_markbad) (struct mtd_info *mtd, loff_t ofs); +/* XXX U-BOOT XXX */ +#if 0 +	struct notifier_block reboot_notifier;  /* default mode before reboot */ +#endif + +	/* ECC status information */ +	struct mtd_ecc_stats ecc_stats; +	/* Subpage shift (NAND) */ +	int subpage_sft; +  	void *priv;  	struct module *owner;  	int usecount; + +	/* If the driver is something smart, like UBI, it may need to maintain +	 * its own reference counting. The below functions are only for driver. +	 * The driver may register its callbacks. These callbacks are not +	 * supposed to be called by MTD users */ +	int (*get_device) (struct mtd_info *mtd); +	void (*put_device) (struct mtd_info *mtd);  }; @@ -147,9 +211,11 @@ extern int add_mtd_device(struct mtd_info *mtd);  extern int del_mtd_device (struct mtd_info *mtd);  extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); +extern struct mtd_info *get_mtd_device_nm(const char *name);  extern void put_mtd_device(struct mtd_info *mtd); +/* XXX U-BOOT XXX */  #if 0  struct mtd_notifier {  	void (*add)(struct mtd_info *mtd); @@ -157,7 +223,6 @@ struct mtd_notifier {  	struct list_head list;  }; -  extern void register_mtd_user (struct mtd_notifier *new);  extern int unregister_mtd_user (struct mtd_notifier *old); @@ -168,20 +233,6 @@ int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,  		      unsigned long count, loff_t from, size_t *retlen);  #endif -#define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args) -#define MTD_POINT(mtd, a,b,c,d) (*(mtd->point))(mtd, a,b,c, (u_char **)(d)) -#define MTD_UNPOINT(mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg) -#define MTD_READ(mtd, args...) (*(mtd->read))(mtd, args) -#define MTD_WRITE(mtd, args...) (*(mtd->write))(mtd, args) -#define MTD_READV(mtd, args...) (*(mtd->readv))(mtd, args) -#define MTD_WRITEV(mtd, args...) (*(mtd->writev))(mtd, args) -#define MTD_READECC(mtd, args...) (*(mtd->read_ecc))(mtd, args) -#define MTD_WRITEECC(mtd, args...) (*(mtd->write_ecc))(mtd, args) -#define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args) -#define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args) -#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd);  } while (0) - -  #ifdef CONFIG_MTD_PARTITIONS  void mtd_erase_callback(struct erase_info *instr);  #else @@ -208,7 +259,6 @@ static inline void mtd_erase_callback(struct erase_info *instr)  	} while(0)  #else /* CONFIG_MTD_DEBUG */  #define MTDDEBUG(n, args...) do { } while(0) -  #endif /* CONFIG_MTD_DEBUG */  #endif /* __MTD_MTD_H__ */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index e2a25a60d..db8bd7ba2 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -2,114 +2,123 @@   *  linux/include/linux/mtd/nand.h   *   *  Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com> - *		       Steven J. Hill <sjhill@realitydiluted.com> + *                     Steven J. Hill <sjhill@realitydiluted.com>   *		       Thomas Gleixner <tglx@linutronix.de>   * - * $Id: nand.h,v 1.68 2004/11/12 10:40:37 gleixner Exp $ + * $Id: nand.h,v 1.74 2005/09/15 13:58:50 vwool Exp $   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License version 2 as   * published by the Free Software Foundation.   * - *  Info: - *   Contains standard defines and IDs for NAND flash devices + * Info: + *	Contains standard defines and IDs for NAND flash devices   * - *  Changelog: - *   01-31-2000 DMW	Created - *   09-18-2000 SJH	Moved structure out of the Disk-On-Chip drivers - *			so it can be used by other NAND flash device - *			drivers. I also changed the copyright since none - *			of the original contents of this file are specific - *			to DoC devices. David can whack me with a baseball - *			bat later if I did something naughty. - *   10-11-2000 SJH	Added private NAND flash structure for driver - *   10-24-2000 SJH	Added prototype for 'nand_scan' function - *   10-29-2001 TG	changed nand_chip structure to support - *			hardwarespecific function for accessing control lines - *   02-21-2002 TG	added support for different read/write adress and - *			ready/busy line access function - *   02-26-2002 TG	added chip_delay to nand_chip structure to optimize - *			command delay times for different chips - *   04-28-2002 TG	OOB config defines moved from nand.c to avoid duplicate - *			defines in jffs2/wbuf.c - *   08-07-2002 TG	forced bad block location to byte 5 of OOB, even if - *			CONFIG_MTD_NAND_ECC_JFFS2 is not set - *   08-10-2002 TG	extensions to nand_chip structure to support HW-ECC - * - *   08-29-2002 tglx	nand_chip structure: data_poi for selecting - *			internal / fs-driver buffer - *			support for 6byte/512byte hardware ECC - *			read_ecc, write_ecc extended for different oob-layout - *			oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB, - *			NAND_YAFFS_OOB - *  11-25-2002 tglx	Added Manufacturer code FUJITSU, NATIONAL - *			Split manufacturer and device ID structures - * - *  02-08-2004 tglx	added option field to nand structure for chip anomalities - *  05-25-2004 tglx	added bad block table support, ST-MICRO manufacturer id - *			update of nand_chip structure description + * Changelog: + *	See git changelog.   */  #ifndef __LINUX_MTD_NAND_H  #define __LINUX_MTD_NAND_H -#include <linux/mtd/compat.h> +/* XXX U-BOOT XXX */ +#if 0 +#include <linux/wait.h> +#include <linux/spinlock.h>  #include <linux/mtd/mtd.h> +#endif + +#include "config.h" + +#include "linux/mtd/compat.h" +#include "linux/mtd/mtd.h" +  struct mtd_info;  /* Scan and identify a NAND device */  extern int nand_scan (struct mtd_info *mtd, int max_chips); +/* Separate phases of nand_scan(), allowing board driver to intervene + * and override command or ECC setup according to flash type */ +extern int nand_scan_ident(struct mtd_info *mtd, int max_chips); +extern int nand_scan_tail(struct mtd_info *mtd); +  /* Free resources held by the NAND device */  extern void nand_release (struct mtd_info *mtd); -/* Read raw data from the device without ECC */ -extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen); +/* Internal helper for board drivers which need to override command function */ +extern void nand_wait_ready(struct mtd_info *mtd); +/* The maximum number of NAND chips in an array */ +#ifndef NAND_MAX_CHIPS +#define NAND_MAX_CHIPS		8 +#endif  /* This constant declares the max. oobsize / page, which   * is supported now. If you add a chip with bigger oobsize/page   * adjust this accordingly.   */ -#define NAND_MAX_OOBSIZE	64 +#define NAND_MAX_OOBSIZE	128 +#define NAND_MAX_PAGESIZE	4096  /*   * Constants for hardware specific CLE/ALE/NCE function -*/ + * + * These are bits which can be or'ed to set/clear multiple + * bits in one go. + */  /* Select the chip by setting nCE to low */ -#define NAND_CTL_SETNCE		1 -/* Deselect the chip by setting nCE to high */ -#define NAND_CTL_CLRNCE		2 +#define NAND_NCE		0x01  /* Select the command latch by setting CLE to high */ -#define NAND_CTL_SETCLE		3 -/* Deselect the command latch by setting CLE to low */ -#define NAND_CTL_CLRCLE		4 +#define NAND_CLE		0x02  /* Select the address latch by setting ALE to high */ -#define NAND_CTL_SETALE		5 -/* Deselect the address latch by setting ALE to low */ -#define NAND_CTL_CLRALE		6 -/* Set write protection by setting WP to high. Not used! */ -#define NAND_CTL_SETWP		7 -/* Clear write protection by setting WP to low. Not used! */ -#define NAND_CTL_CLRWP		8 +#define NAND_ALE		0x04 + +#define NAND_CTRL_CLE		(NAND_NCE | NAND_CLE) +#define NAND_CTRL_ALE		(NAND_NCE | NAND_ALE) +#define NAND_CTRL_CHANGE	0x80  /*   * Standard NAND flash commands   */  #define NAND_CMD_READ0		0  #define NAND_CMD_READ1		1 +#define NAND_CMD_RNDOUT		5  #define NAND_CMD_PAGEPROG	0x10  #define NAND_CMD_READOOB	0x50  #define NAND_CMD_ERASE1		0x60  #define NAND_CMD_STATUS		0x70  #define NAND_CMD_STATUS_MULTI	0x71  #define NAND_CMD_SEQIN		0x80 +#define NAND_CMD_RNDIN		0x85  #define NAND_CMD_READID		0x90  #define NAND_CMD_ERASE2		0xd0  #define NAND_CMD_RESET		0xff  /* Extended commands for large page devices */  #define NAND_CMD_READSTART	0x30 +#define NAND_CMD_RNDOUTSTART	0xE0  #define NAND_CMD_CACHEDPROG	0x15 +/* Extended commands for AG-AND device */ +/* + * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but + *       there is no way to distinguish that from NAND_CMD_READ0 + *       until the remaining sequence of commands has been completed + *       so add a high order bit and mask it off in the command. + */ +#define NAND_CMD_DEPLETE1	0x100 +#define NAND_CMD_DEPLETE2	0x38 +#define NAND_CMD_STATUS_MULTI	0x71 +#define NAND_CMD_STATUS_ERROR	0x72 +/* multi-bank error status (banks 0-3) */ +#define NAND_CMD_STATUS_ERROR0	0x73 +#define NAND_CMD_STATUS_ERROR1	0x74 +#define NAND_CMD_STATUS_ERROR2	0x75 +#define NAND_CMD_STATUS_ERROR3	0x76 +#define NAND_CMD_STATUS_RESET	0x7f +#define NAND_CMD_STATUS_CLEAR	0xff + +#define NAND_CMD_NONE		-1 +  /* Status bits */  #define NAND_STATUS_FAIL	0x01  #define NAND_STATUS_FAIL_N1	0x02 @@ -120,25 +129,16 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_  /*   * Constants for ECC_MODES   */ - -/* No ECC. Usage is not recommended ! */ -#define NAND_ECC_NONE		0 -/* Software ECC 3 byte ECC per 256 Byte data */ -#define NAND_ECC_SOFT		1 -/* Hardware ECC 3 byte ECC per 256 Byte data */ -#define NAND_ECC_HW3_256	2 -/* Hardware ECC 3 byte ECC per 512 Byte data */ -#define NAND_ECC_HW3_512	3 -/* Hardware ECC 6 byte ECC per 512 Byte data */ -#define NAND_ECC_HW6_512	4 -/* Hardware ECC 8 byte ECC per 512 Byte data */ -#define NAND_ECC_HW8_512	6 -/* Hardware ECC 12 byte ECC per 2048 Byte data */ -#define NAND_ECC_HW12_2048	7 +typedef enum { +	NAND_ECC_NONE, +	NAND_ECC_SOFT, +	NAND_ECC_HW, +	NAND_ECC_HW_SYNDROME, +} nand_ecc_modes_t;  /*   * Constants for Hardware ECC -*/ + */  /* Reset Hardware ECC for read */  #define NAND_ECC_READ		0  /* Reset Hardware ECC for write */ @@ -146,6 +146,10 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_  /* Enable Hardware ECC before syndrom is read back from flash */  #define NAND_ECC_READSYN	2 +/* Bit mask for flags passed to do_nand_read_ecc */ +#define NAND_GET_DEVICE		0x80 + +  /* Option constants for bizarre disfunctionality and real  *  features  */ @@ -165,6 +169,17 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_  /* Chip has a array of 4 pages which can be read without   * additional ready /busy waits */  #define NAND_4PAGE_ARRAY	0x00000040 +/* Chip requires that BBT is periodically rewritten to prevent + * bits from adjacent blocks from 'leaking' in altering data. + * This happens with the Renesas AG-AND chips, possibly others.  */ +#define BBT_AUTO_REFRESH	0x00000080 +/* Chip does not require ready check on read. True + * for all large page devices, as they do not support + * autoincrement.*/ +#define NAND_NO_READRDY		0x00000100 +/* Chip does not allow subpage writes */ +#define NAND_NO_SUBPAGE_WRITE	0x00000200 +  /* Options valid for Samsung large page devices */  #define NAND_SAMSUNG_LP_OPTIONS \ @@ -183,18 +198,18 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_  /* Use a flash based bad block table. This option is passed to the   * default bad block table function. */  #define NAND_USE_FLASH_BBT	0x00010000 -/* The hw ecc generator provides a syndrome instead a ecc value on read - * This can only work if we have the ecc bytes directly behind the - * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */ -#define NAND_HWECC_SYNDROME	0x00020000 - - +/* This option skips the bbt scan during initialization. */ +#define NAND_SKIP_BBTSCAN	0x00020000 +/* This option is defined if the board driver allocates its own buffers +   (e.g. because it needs them DMA-coherent */ +#define NAND_OWN_BUFFERS	0x00040000  /* Options set by nand scan */ -/* Nand scan has allocated oob_buf */ -#define NAND_OOBBUF_ALLOC	0x40000000 -/* Nand scan has allocated data_buf */ -#define NAND_DATABUF_ALLOC	0x80000000 +/* Nand scan has allocated controller struct */ +#define NAND_CONTROLLER_ALLOC	0x80000000 +/* Cell info constants */ +#define NAND_CI_CHIPNR_MSK	0x03 +#define NAND_CI_CELLTYPE_MSK	0x0C  /*   * nand_state_t - chip states @@ -207,135 +222,216 @@ typedef enum {  	FL_ERASING,  	FL_SYNCING,  	FL_CACHEDPRG, +	FL_PM_SUSPENDED,  } nand_state_t;  /* Keep gcc happy */  struct nand_chip; -#if 0  /** - * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices - * @lock:		protection lock + * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices + * @lock:               protection lock   * @active:		the mtd device which holds the controller currently + * @wq:			wait queue to sleep on if a NAND operation is in progress + *                      used instead of the per chip wait queue when a hw controller is available   */  struct nand_hw_control { -	spinlock_t	 lock; -	struct nand_chip *active; -}; +#if 0 +    spinlock_t	 lock; +    wait_queue_head_t wq;  #endif +    struct nand_chip *active; +}; + +/** + * struct nand_ecc_ctrl - Control structure for ecc + * @mode:	ecc mode + * @steps:	number of ecc steps per page + * @size:	data bytes per ecc step + * @bytes:	ecc bytes per step + * @total:	total number of ecc bytes per page + * @prepad:	padding information for syndrome based ecc generators + * @postpad:	padding information for syndrome based ecc generators + * @layout:	ECC layout control struct pointer + * @hwctl:	function to control hardware ecc generator. Must only + *		be provided if an hardware ECC is available + * @calculate:	function for ecc calculation or readback from ecc hardware + * @correct:	function for ecc correction, matching to ecc generator (sw/hw) + * @read_page_raw:	function to read a raw page without ECC + * @write_page_raw:	function to write a raw page without ECC + * @read_page:	function to read a page according to the ecc generator requirements + * @write_page:	function to write a page according to the ecc generator requirements + * @read_oob:	function to read chip OOB data + * @write_oob:	function to write chip OOB data + */ +struct nand_ecc_ctrl { +	nand_ecc_modes_t	mode; +	int			steps; +	int			size; +	int			bytes; +	int			total; +	int			prepad; +	int			postpad; +	struct nand_ecclayout	*layout; +	void			(*hwctl)(struct mtd_info *mtd, int mode); +	int			(*calculate)(struct mtd_info *mtd, +					     const uint8_t *dat, +					     uint8_t *ecc_code); +	int			(*correct)(struct mtd_info *mtd, uint8_t *dat, +					   uint8_t *read_ecc, +					   uint8_t *calc_ecc); +	int			(*read_page_raw)(struct mtd_info *mtd, +						 struct nand_chip *chip, +						 uint8_t *buf); +	void			(*write_page_raw)(struct mtd_info *mtd, +						  struct nand_chip *chip, +						  const uint8_t *buf); +	int			(*read_page)(struct mtd_info *mtd, +					     struct nand_chip *chip, +					     uint8_t *buf); +	void			(*write_page)(struct mtd_info *mtd, +					      struct nand_chip *chip, +					      const uint8_t *buf); +	int			(*read_oob)(struct mtd_info *mtd, +					    struct nand_chip *chip, +					    int page, +					    int sndcmd); +	int			(*write_oob)(struct mtd_info *mtd, +					     struct nand_chip *chip, +					     int page); +}; + +/** + * struct nand_buffers - buffer structure for read/write + * @ecccalc:	buffer for calculated ecc + * @ecccode:	buffer for ecc read from flash + * @databuf:	buffer for data - dynamically sized + * + * Do not change the order of buffers. databuf and oobrbuf must be in + * consecutive order. + */ +struct nand_buffers { +	uint8_t	ecccalc[NAND_MAX_OOBSIZE]; +	uint8_t	ecccode[NAND_MAX_OOBSIZE]; +	uint8_t databuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE]; +};  /**   * struct nand_chip - NAND Private Flash Chip Data   * @IO_ADDR_R:		[BOARDSPECIFIC] address to read the 8 I/O lines of the flash device   * @IO_ADDR_W:		[BOARDSPECIFIC] address to write the 8 I/O lines of the flash device   * @read_byte:		[REPLACEABLE] read one byte from the chip - * @write_byte:		[REPLACEABLE] write one byte to the chip   * @read_word:		[REPLACEABLE] read one word from the chip - * @write_word:		[REPLACEABLE] write one word to the chip   * @write_buf:		[REPLACEABLE] write data from the buffer to the chip   * @read_buf:		[REPLACEABLE] read data from the chip into the buffer   * @verify_buf:		[REPLACEABLE] verify buffer contents against the chip data   * @select_chip:	[REPLACEABLE] select chip nr   * @block_bad:		[REPLACEABLE] check, if the block is bad   * @block_markbad:	[REPLACEABLE] mark the block bad - * @hwcontrol:		[BOARDSPECIFIC] hardwarespecific function for accesing control-lines + * @cmd_ctrl:		[BOARDSPECIFIC] hardwarespecific funtion for controlling + *			ALE/CLE/nCE. Also used to write command and address   * @dev_ready:		[BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line   *			If set to NULL no access to ready/busy is available and the ready/busy information   *			is read from the chip status register   * @cmdfunc:		[REPLACEABLE] hardwarespecific function for writing commands to the chip   * @waitfunc:		[REPLACEABLE] hardwarespecific function for wait on ready - * @calculate_ecc:	[REPLACEABLE] function for ecc calculation or readback from ecc hardware - * @correct_data:	[REPLACEABLE] function for ecc correction, matching to ecc generator (sw/hw) - * @enable_hwecc:	[BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only - *			be provided if a hardware ECC is available + * @ecc:		[BOARDSPECIFIC] ecc control ctructure + * @buffers:		buffer structure for read/write + * @hwcontrol:		platform-specific hardware control structure + * @ops:		oob operation operands   * @erase_cmd:		[INTERN] erase command write function, selectable due to AND support   * @scan_bbt:		[REPLACEABLE] function to scan bad block table - * @eccmode:		[BOARDSPECIFIC] mode of ecc, see defines - * @eccsize:		[INTERN] databytes used per ecc-calculation - * @eccbytes:		[INTERN] number of ecc bytes per ecc-calculation step - * @eccsteps:		[INTERN] number of ecc calculation steps per page   * @chip_delay:		[BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR) - * @chip_lock:		[INTERN] spinlock used to protect access to this structure and the chip   * @wq:			[INTERN] wait queue to sleep on if a NAND operation is in progress   * @state:		[INTERN] the current state of the NAND device + * @oob_poi:		poison value buffer   * @page_shift:		[INTERN] number of address bits in a page (column address bits)   * @phys_erase_shift:	[INTERN] number of address bits in a physical eraseblock   * @bbt_erase_shift:	[INTERN] number of address bits in a bbt entry   * @chip_shift:		[INTERN] number of address bits in one chip - * @data_buf:		[INTERN] internal buffer for one page + oob - * @oob_buf:		[INTERN] oob buffer for one eraseblock + * @datbuf:		[INTERN] internal buffer for one page + oob + * @oobbuf:		[INTERN] oob buffer for one eraseblock   * @oobdirty:		[INTERN] indicates that oob_buf must be reinitialized   * @data_poi:		[INTERN] pointer to a data buffer   * @options:		[BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about   *			special functionality. See the defines for further explanation   * @badblockpos:	[INTERN] position of the bad block marker in the oob area + * @cellinfo:		[INTERN] MLC/multichip data from chip ident   * @numchips:		[INTERN] number of physical chips   * @chipsize:		[INTERN] the size of one chip for multichip arrays   * @pagemask:		[INTERN] page number mask = number of (pages / chip) - 1   * @pagebuf:		[INTERN] holds the pagenumber which is currently in data_buf - * @autooob:		[REPLACEABLE] the default (auto)placement scheme + * @subpagesize:	[INTERN] holds the subpagesize + * @ecclayout:		[REPLACEABLE] the default ecc placement scheme   * @bbt:		[INTERN] bad block table pointer   * @bbt_td:		[REPLACEABLE] bad block table descriptor for flash lookup   * @bbt_md:		[REPLACEABLE] bad block table mirror descriptor   * @badblock_pattern:	[REPLACEABLE] bad block scan pattern used for initial bad block scan - * @controller:		[OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices + * @controller:		[REPLACEABLE] a pointer to a hardware controller structure + *			which is shared among multiple independend devices   * @priv:		[OPTIONAL] pointer to private chip date + * @errstat:		[OPTIONAL] hardware specific function to perform additional error status checks + *			(determine if errors are correctable) + * @write_page:		[REPLACEABLE] High-level page write function   */  struct nand_chip {  	void  __iomem	*IO_ADDR_R;  	void  __iomem	*IO_ADDR_W; -	u_char		(*read_byte)(struct mtd_info *mtd); -	void		(*write_byte)(struct mtd_info *mtd, u_char byte); +	uint8_t		(*read_byte)(struct mtd_info *mtd);  	u16		(*read_word)(struct mtd_info *mtd); -	void		(*write_word)(struct mtd_info *mtd, u16 word); - -	void		(*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); -	void		(*read_buf)(struct mtd_info *mtd, u_char *buf, int len); -	int		(*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len); +	void		(*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); +	void		(*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); +	int		(*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);  	void		(*select_chip)(struct mtd_info *mtd, int chip);  	int		(*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);  	int		(*block_markbad)(struct mtd_info *mtd, loff_t ofs); -	void		(*hwcontrol)(struct mtd_info *mtd, int cmd); +	void		(*cmd_ctrl)(struct mtd_info *mtd, int dat, +				    unsigned int ctrl);  	int		(*dev_ready)(struct mtd_info *mtd);  	void		(*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); -	int		(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); -	int		(*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); -	int		(*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); -	void		(*enable_hwecc)(struct mtd_info *mtd, int mode); +	int		(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);  	void		(*erase_cmd)(struct mtd_info *mtd, int page);  	int		(*scan_bbt)(struct mtd_info *mtd); -	int		eccmode; -	int		eccsize; -	int		eccbytes; -	int		eccsteps; +	int		(*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); +	int		(*write_page)(struct mtd_info *mtd, struct nand_chip *chip, +				      const uint8_t *buf, int page, int cached, int raw); +  	int		chip_delay; -#if 0 -	spinlock_t	chip_lock; -	wait_queue_head_t wq; -	nand_state_t	state; -#endif +	unsigned int	options; +  	int		page_shift;  	int		phys_erase_shift;  	int		bbt_erase_shift;  	int		chip_shift; -	u_char		*data_buf; -	u_char		*oob_buf; -	int		oobdirty; -	u_char		*data_poi; -	unsigned int	options; -	int		badblockpos;  	int		numchips;  	unsigned long	chipsize;  	int		pagemask;  	int		pagebuf; -	struct nand_oobinfo	*autooob; +	int		subpagesize; +	uint8_t		cellinfo; +	int		badblockpos; + +	nand_state_t	state; + +	uint8_t		*oob_poi; +	struct nand_hw_control  *controller; +	struct nand_ecclayout	*ecclayout; + +	struct nand_ecc_ctrl ecc; +	struct nand_buffers *buffers; +	 +	struct nand_hw_control hwcontrol; + +	struct mtd_oob_ops ops; +  	uint8_t		*bbt;  	struct nand_bbt_descr	*bbt_td;  	struct nand_bbt_descr	*bbt_md; +  	struct nand_bbt_descr	*badblock_pattern; -	struct nand_hw_control	*controller; +  	void		*priv;  }; @@ -348,11 +444,11 @@ struct nand_chip {  #define NAND_MFR_NATIONAL	0x8f  #define NAND_MFR_RENESAS	0x07  #define NAND_MFR_STMICRO	0x20 +#define NAND_MFR_HYNIX		0xad  #define NAND_MFR_MICRON		0x2c  /**   * struct nand_flash_dev - NAND Flash Device ID Structure - *   * @name:	Identify the device type   * @id:		device ID code   * @pagesize:	Pagesize in bytes. Either 256 or 512 or 0 @@ -403,7 +499,7 @@ extern struct nand_manufacturers nand_manuf_ids[];   *		blocks is reserved at the end of the device where the tables are   *		written.   * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than - *		bad) block in the stored bbt + *              bad) block in the stored bbt   * @pattern:	pattern to identify bad block table or factory marked good /   *		bad blocks, can be NULL, if len = 0   * @@ -417,11 +513,11 @@ struct nand_bbt_descr {  	int	pages[NAND_MAX_CHIPS];  	int	offs;  	int	veroffs; -	uint8_t version[NAND_MAX_CHIPS]; +	uint8_t	version[NAND_MAX_CHIPS];  	int	len;  	int	maxblocks;  	int	reserved_block_code; -	uint8_t *pattern; +	uint8_t	*pattern;  };  /* Options for the bad block table descriptors */ @@ -433,7 +529,7 @@ struct nand_bbt_descr {  #define NAND_BBT_4BIT		0x00000004  #define NAND_BBT_8BIT		0x00000008  /* The bad block table is in the last good block of the device */ -#define NAND_BBT_LASTBLOCK	0x00000010 +#define	NAND_BBT_LASTBLOCK	0x00000010  /* The bbt is at the given page, else we must scan for the bbt */  #define NAND_BBT_ABSPAGE	0x00000020  /* The bbt is at the given page, else we must scan for the bbt */ @@ -456,13 +552,16 @@ struct nand_bbt_descr {  #define NAND_BBT_SCAN2NDPAGE	0x00004000  /* The maximum number of blocks to scan for a bbt */ -#define NAND_BBT_SCAN_MAXBLOCKS 4 +#define NAND_BBT_SCAN_MAXBLOCKS	4 -extern int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd); -extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs); -extern int nand_default_bbt (struct mtd_info *mtd); -extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt); -extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt); +extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd); +extern int nand_update_bbt(struct mtd_info *mtd, loff_t offs); +extern int nand_default_bbt(struct mtd_info *mtd); +extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt); +extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, +			   int allowbbt); +extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, +			size_t * retlen, uint8_t * buf);  /*  * Constants for oob configuration @@ -470,4 +569,67 @@ extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int  #define NAND_SMALL_BADBLOCK_POS		5  #define NAND_LARGE_BADBLOCK_POS		0 +/** + * struct platform_nand_chip - chip level device structure + * @nr_chips:		max. number of chips to scan for + * @chip_offset:	chip number offset + * @nr_partitions:	number of partitions pointed to by partitions (or zero) + * @partitions:		mtd partition list + * @chip_delay:		R/B delay value in us + * @options:		Option flags, e.g. 16bit buswidth + * @ecclayout:		ecc layout info structure + * @part_probe_types:	NULL-terminated array of probe types + * @priv:		hardware controller specific settings + */ +struct platform_nand_chip { +	int			nr_chips; +	int			chip_offset; +	int			nr_partitions; +	struct mtd_partition	*partitions; +	struct nand_ecclayout	*ecclayout; +	int			chip_delay; +	unsigned int		options; +	const char		**part_probe_types; +	void			*priv; +}; + +/** + * struct platform_nand_ctrl - controller level device structure + * @hwcontrol:		platform specific hardware control structure + * @dev_ready:		platform specific function to read ready/busy pin + * @select_chip:	platform specific chip select function + * @cmd_ctrl:		platform specific function for controlling + *			ALE/CLE/nCE. Also used to write command and address + * @priv:		private data to transport driver specific settings + * + * All fields are optional and depend on the hardware driver requirements + */ +struct platform_nand_ctrl { +	void		(*hwcontrol)(struct mtd_info *mtd, int cmd); +	int		(*dev_ready)(struct mtd_info *mtd); +	void		(*select_chip)(struct mtd_info *mtd, int chip); +	void		(*cmd_ctrl)(struct mtd_info *mtd, int dat, +				    unsigned int ctrl); +	void		*priv; +}; + +/** + * struct platform_nand_data - container structure for platform-specific data + * @chip:		chip level chip structure + * @ctrl:		controller level device structure + */ +struct platform_nand_data { +	struct platform_nand_chip	chip; +	struct platform_nand_ctrl	ctrl; +}; + +/* Some helpers to access the data structures */ +static inline +struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd) +{ +	struct nand_chip *chip = mtd->priv; + +	return chip->priv; +} +  #endif /* __LINUX_MTD_NAND_H */ diff --git a/include/linux/mtd/nftl-user.h b/include/linux/mtd/nftl-user.h new file mode 100644 index 000000000..b2bca18e7 --- /dev/null +++ b/include/linux/mtd/nftl-user.h @@ -0,0 +1,76 @@ +/* + * $Id: nftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $ + * + * Parts of NFTL headers shared with userspace + * + */ + +#ifndef __MTD_NFTL_USER_H__ +#define __MTD_NFTL_USER_H__ + +/* Block Control Information */ + +struct nftl_bci { +	unsigned char ECCSig[6]; +	uint8_t Status; +	uint8_t Status1; +}__attribute__((packed)); + +/* Unit Control Information */ + +struct nftl_uci0 { +	uint16_t VirtUnitNum; +	uint16_t ReplUnitNum; +	uint16_t SpareVirtUnitNum; +	uint16_t SpareReplUnitNum; +} __attribute__((packed)); + +struct nftl_uci1 { +	uint32_t WearInfo; +	uint16_t EraseMark; +	uint16_t EraseMark1; +} __attribute__((packed)); + +struct nftl_uci2 { +        uint16_t FoldMark; +        uint16_t FoldMark1; +	uint32_t unused; +} __attribute__((packed)); + +union nftl_uci { +	struct nftl_uci0 a; +	struct nftl_uci1 b; +	struct nftl_uci2 c; +}; + +struct nftl_oob { +	struct nftl_bci b; +	union nftl_uci u; +}; + +/* NFTL Media Header */ + +struct NFTLMediaHeader { +	char DataOrgID[6]; +	uint16_t NumEraseUnits; +	uint16_t FirstPhysicalEUN; +	uint32_t FormattedSize; +	unsigned char UnitSizeFactor; +} __attribute__((packed)); + +#define MAX_ERASE_ZONES (8192 - 512) + +#define ERASE_MARK 0x3c69 +#define SECTOR_FREE 0xff +#define SECTOR_USED 0x55 +#define SECTOR_IGNORE 0x11 +#define SECTOR_DELETED 0x00 + +#define FOLD_MARK_IN_PROGRESS 0x5555 + +#define ZONE_GOOD 0xff +#define ZONE_BAD_ORIGINAL 0 +#define ZONE_BAD_MARKED 7 + + +#endif /* __MTD_NFTL_USER_H__ */ diff --git a/include/linux/mtd/nftl.h b/include/linux/mtd/nftl.h index b0337c340..04963a52e 100644 --- a/include/linux/mtd/nftl.h +++ b/include/linux/mtd/nftl.h @@ -1,75 +1,16 @@ - -/* Defines for NAND Flash Translation Layer  */ -/* (c) 1999 Machine Vision Holdings, Inc.    */ -/* Author: David Woodhouse <dwmw2@mvhi.com>  */ -/* $Id: nftl.h,v 1.10 2000/12/29 00:25:38 dwmw2 Exp $ */ +/* + * $Id: nftl.h,v 1.16 2004/06/30 14:49:00 dbrown Exp $ + * + * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> + */  #ifndef __MTD_NFTL_H__  #define __MTD_NFTL_H__ -/* Block Control Information */ - -struct nftl_bci { -	unsigned char ECCSig[6]; -	__u8 Status; -	__u8 Status1; -}__attribute__((packed)); - -/* Unit Control Information */ - -struct nftl_uci0 { -	__u16 VirtUnitNum; -	__u16 ReplUnitNum; -	__u16 SpareVirtUnitNum; -	__u16 SpareReplUnitNum; -} __attribute__((packed)); - -struct nftl_uci1 { -	__u32 WearInfo; -	__u16 EraseMark; -	__u16 EraseMark1; -} __attribute__((packed)); +#include <linux/mtd/mtd.h> +#include <linux/mtd/blktrans.h> -struct nftl_uci2 { -	__u16 FoldMark; -	__u16 FoldMark1; -	__u32 unused; -} __attribute__((packed)); - -union nftl_uci { -	struct nftl_uci0 a; -	struct nftl_uci1 b; -	struct nftl_uci2 c; -}; - -struct nftl_oob { -	struct nftl_bci b; -	union nftl_uci u; -}; - -/* NFTL Media Header */ - -struct NFTLMediaHeader { -	char DataOrgID[6]; -	__u16 NumEraseUnits; -	__u16 FirstPhysicalEUN; -	__u32 FormattedSize; -	unsigned char UnitSizeFactor; -} __attribute__((packed)); - -#define MAX_ERASE_ZONES (8192 - 512) - -#define ERASE_MARK 0x3c69 -#define SECTOR_FREE 0xff -#define SECTOR_USED 0x55 -#define SECTOR_IGNORE 0x11 -#define SECTOR_DELETED 0x00 - -#define FOLD_MARK_IN_PROGRESS 0x5555 - -#define ZONE_GOOD 0xff -#define ZONE_BAD_ORIGINAL 0 -#define ZONE_BAD_MARKED 7 +#include <linux/mtd/nftl-user.h>  /* these info are used in ReplUnitTable */  #define BLOCK_NIL          0xffff /* last block of a chain */ @@ -78,7 +19,7 @@ struct NFTLMediaHeader {  #define BLOCK_RESERVED     0xfffc /* bios block or bad block */  struct NFTLrecord { -	struct DiskOnChip *mtd; +	struct mtd_blktrans_dev mbd;  	__u16 MediaUnit, SpareMediaUnit;  	__u32 EraseSize;  	struct NFTLMediaHeader MediaHdr; @@ -90,16 +31,24 @@ struct NFTLrecord {  	__u16 lastEUN;                  /* should be suppressed */  	__u16 numfreeEUNs;  	__u16 LastFreeEUN;		/* To speed up finding a free EUN */ -	__u32 nr_sects;  	int head,sect,cyl;  	__u16 *EUNtable;		/* [numvunits]: First EUN for each virtual unit  */  	__u16 *ReplUnitTable;		/* [numEUNs]: ReplUnitNumber for each */ -	unsigned int nb_blocks;		/* number of physical blocks */ -	unsigned int nb_boot_blocks;	/* number of blocks used by the bios */ +        unsigned int nb_blocks;		/* number of physical blocks */ +        unsigned int nb_boot_blocks;	/* number of blocks used by the bios */ +        struct erase_info instr; +	struct nand_ecclayout oobinfo;  }; +int NFTL_mount(struct NFTLrecord *s); +int NFTL_formatblock(struct NFTLrecord *s, int block); + +#ifndef NFTL_MAJOR +#define NFTL_MAJOR 93 +#endif +  #define MAX_NFTLS 16 -#define MAX_SECTORS_PER_UNIT 32 +#define MAX_SECTORS_PER_UNIT 64  #define NFTL_PARTN_BITS 4  #endif /* __MTD_NFTL_H__ */ diff --git a/include/linux/mtd/ubi-header.h b/include/linux/mtd/ubi-header.h new file mode 100644 index 000000000..fa479c71a --- /dev/null +++ b/include/linux/mtd/ubi-header.h @@ -0,0 +1,360 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Artem Bityutskiy (Битюцкий Артём) + *          Thomas Gleixner + *          Frank Haverkamp + *          Oliver Lohmann + *          Andreas Arnez + */ + +/* + * This file defines the layout of UBI headers and all the other UBI on-flash + * data structures. May be included by user-space. + */ + +#ifndef __UBI_HEADER_H__ +#define __UBI_HEADER_H__ + +#include <asm/byteorder.h> + +/* The version of UBI images supported by this implementation */ +#define UBI_VERSION 1 + +/* The highest erase counter value supported by this implementation */ +#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF + +/* The initial CRC32 value used when calculating CRC checksums */ +#define UBI_CRC32_INIT 0xFFFFFFFFU + +/* Erase counter header magic number (ASCII "UBI#") */ +#define UBI_EC_HDR_MAGIC  0x55424923 +/* Volume identifier header magic number (ASCII "UBI!") */ +#define UBI_VID_HDR_MAGIC 0x55424921 + +/* + * Volume type constants used in the volume identifier header. + * + * @UBI_VID_DYNAMIC: dynamic volume + * @UBI_VID_STATIC: static volume + */ +enum { +	UBI_VID_DYNAMIC = 1, +	UBI_VID_STATIC  = 2 +}; + +/* + * Compatibility constants used by internal volumes. + * + * @UBI_COMPAT_DELETE: delete this internal volume before anything is written + * to the flash + * @UBI_COMPAT_RO: attach this device in read-only mode + * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its + * physical eraseblocks, don't allow the wear-leveling unit to move them + * @UBI_COMPAT_REJECT: reject this UBI image + */ +enum { +	UBI_COMPAT_DELETE   = 1, +	UBI_COMPAT_RO       = 2, +	UBI_COMPAT_PRESERVE = 4, +	UBI_COMPAT_REJECT   = 5 +}; + +/* + * ubi16_t/ubi32_t/ubi64_t - 16, 32, and 64-bit integers used in UBI on-flash + * data structures. + */ +typedef struct { +	uint16_t int16; +} __attribute__ ((packed)) ubi16_t; + +typedef struct { +	uint32_t int32; +} __attribute__ ((packed)) ubi32_t; + +typedef struct { +	uint64_t int64; +} __attribute__ ((packed)) ubi64_t; + +/* + * In this implementation of UBI uses the big-endian format for on-flash + * integers. The below are the corresponding conversion macros. + */ +#define cpu_to_ubi16(x) ((ubi16_t){__cpu_to_be16(x)}) +#define ubi16_to_cpu(x) ((uint16_t)__be16_to_cpu((x).int16)) + +#define cpu_to_ubi32(x) ((ubi32_t){__cpu_to_be32(x)}) +#define ubi32_to_cpu(x) ((uint32_t)__be32_to_cpu((x).int32)) + +#define cpu_to_ubi64(x) ((ubi64_t){__cpu_to_be64(x)}) +#define ubi64_to_cpu(x) ((uint64_t)__be64_to_cpu((x).int64)) + +/* Sizes of UBI headers */ +#define UBI_EC_HDR_SIZE  sizeof(struct ubi_ec_hdr) +#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr) + +/* Sizes of UBI headers without the ending CRC */ +#define UBI_EC_HDR_SIZE_CRC  (UBI_EC_HDR_SIZE  - sizeof(ubi32_t)) +#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(ubi32_t)) + +/** + * struct ubi_ec_hdr - UBI erase counter header. + * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC) + * @version: version of UBI implementation which is supposed to accept this + * UBI image + * @padding1: reserved for future, zeroes + * @ec: the erase counter + * @vid_hdr_offset: where the VID header starts + * @data_offset: where the user data start + * @padding2: reserved for future, zeroes + * @hdr_crc: erase counter header CRC checksum + * + * The erase counter header takes 64 bytes and has a plenty of unused space for + * future usage. The unused fields are zeroed. The @version field is used to + * indicate the version of UBI implementation which is supposed to be able to + * work with this UBI image. If @version is greater then the current UBI + * version, the image is rejected. This may be useful in future if something + * is changed radically. This field is duplicated in the volume identifier + * header. + * + * The @vid_hdr_offset and @data_offset fields contain the offset of the the + * volume identifier header and user data, relative to the beginning of the + * physical eraseblock. These values have to be the same for all physical + * eraseblocks. + */ +struct ubi_ec_hdr { +	ubi32_t magic; +	uint8_t version; +	uint8_t padding1[3]; +	ubi64_t ec; /* Warning: the current limit is 31-bit anyway! */ +	ubi32_t vid_hdr_offset; +	ubi32_t data_offset; +	uint8_t padding2[36]; +	ubi32_t hdr_crc; +} __attribute__ ((packed)); + +/** + * struct ubi_vid_hdr - on-flash UBI volume identifier header. + * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC) + * @version: UBI implementation version which is supposed to accept this UBI + * image (%UBI_VERSION) + * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) + * @copy_flag: if this logical eraseblock was copied from another physical + * eraseblock (for wear-leveling reasons) + * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE, + * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) + * @vol_id: ID of this volume + * @lnum: logical eraseblock number + * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be + * removed, kept only for not breaking older UBI users) + * @data_size: how many bytes of data this logical eraseblock contains + * @used_ebs: total number of used logical eraseblocks in this volume + * @data_pad: how many bytes at the end of this physical eraseblock are not + * used + * @data_crc: CRC checksum of the data stored in this logical eraseblock + * @padding1: reserved for future, zeroes + * @sqnum: sequence number + * @padding2: reserved for future, zeroes + * @hdr_crc: volume identifier header CRC checksum + * + * The @sqnum is the value of the global sequence counter at the time when this + * VID header was created. The global sequence counter is incremented each time + * UBI writes a new VID header to the flash, i.e. when it maps a logical + * eraseblock to a new physical eraseblock. The global sequence counter is an + * unsigned 64-bit integer and we assume it never overflows. The @sqnum + * (sequence number) is used to distinguish between older and newer versions of + * logical eraseblocks. + * + * There are 2 situations when there may be more then one physical eraseblock + * corresponding to the same logical eraseblock, i.e., having the same @vol_id + * and @lnum values in the volume identifier header. Suppose we have a logical + * eraseblock L and it is mapped to the physical eraseblock P. + * + * 1. Because UBI may erase physical eraseblocks asynchronously, the following + * situation is possible: L is asynchronously erased, so P is scheduled for + * erasure, then L is written to,i.e. mapped to another physical eraseblock P1, + * so P1 is written to, then an unclean reboot happens. Result - there are 2 + * physical eraseblocks P and P1 corresponding to the same logical eraseblock + * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the + * flash. + * + * 2. From time to time UBI moves logical eraseblocks to other physical + * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P + * to P1, and an unclean reboot happens before P is physically erased, there + * are two physical eraseblocks P and P1 corresponding to L and UBI has to + * select one of them when the flash is attached. The @sqnum field says which + * PEB is the original (obviously P will have lower @sqnum) and the copy. But + * it is not enough to select the physical eraseblock with the higher sequence + * number, because the unclean reboot could have happen in the middle of the + * copying process, so the data in P is corrupted. It is also not enough to + * just select the physical eraseblock with lower sequence number, because the + * data there may be old (consider a case if more data was added to P1 after + * the copying). Moreover, the unclean reboot may happen when the erasure of P + * was just started, so it result in unstable P, which is "mostly" OK, but + * still has unstable bits. + * + * UBI uses the @copy_flag field to indicate that this logical eraseblock is a + * copy. UBI also calculates data CRC when the data is moved and stores it at + * the @data_crc field of the copy (P1). So when UBI needs to pick one physical + * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is + * examined. If it is cleared, the situation* is simple and the newer one is + * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC + * checksum is correct, this physical eraseblock is selected (P1). Otherwise + * the older one (P) is selected. + * + * Note, there is an obsolete @leb_ver field which was used instead of @sqnum + * in the past. But it is not used anymore and we keep it in order to be able + * to deal with old UBI images. It will be removed at some point. + * + * There are 2 sorts of volumes in UBI: user volumes and internal volumes. + * Internal volumes are not seen from outside and are used for various internal + * UBI purposes. In this implementation there is only one internal volume - the + * layout volume. Internal volumes are the main mechanism of UBI extensions. + * For example, in future one may introduce a journal internal volume. Internal + * volumes have their own reserved range of IDs. + * + * The @compat field is only used for internal volumes and contains the "degree + * of their compatibility". It is always zero for user volumes. This field + * provides a mechanism to introduce UBI extensions and to be still compatible + * with older UBI binaries. For example, if someone introduced a journal in + * future, he would probably use %UBI_COMPAT_DELETE compatibility for the + * journal volume.  And in this case, older UBI binaries, which know nothing + * about the journal volume, would just delete this volume and work perfectly + * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image + * - it just ignores the Ext3fs journal. + * + * The @data_crc field contains the CRC checksum of the contents of the logical + * eraseblock if this is a static volume. In case of dynamic volumes, it does + * not contain the CRC checksum as a rule. The only exception is when the + * data of the physical eraseblock was moved by the wear-leveling unit, then + * the wear-leveling unit calculates the data CRC and stores it in the + * @data_crc field. And of course, the @copy_flag is %in this case. + * + * The @data_size field is used only for static volumes because UBI has to know + * how many bytes of data are stored in this eraseblock. For dynamic volumes, + * this field usually contains zero. The only exception is when the data of the + * physical eraseblock was moved to another physical eraseblock for + * wear-leveling reasons. In this case, UBI calculates CRC checksum of the + * contents and uses both @data_crc and @data_size fields. In this case, the + * @data_size field contains data size. + * + * The @used_ebs field is used only for static volumes and indicates how many + * eraseblocks the data of the volume takes. For dynamic volumes this field is + * not used and always contains zero. + * + * The @data_pad is calculated when volumes are created using the alignment + * parameter. So, effectively, the @data_pad field reduces the size of logical + * eraseblocks of this volume. This is very handy when one uses block-oriented + * software (say, cramfs) on top of the UBI volume. + */ +struct ubi_vid_hdr { +	ubi32_t magic; +	uint8_t version; +	uint8_t vol_type; +	uint8_t copy_flag; +	uint8_t compat; +	ubi32_t vol_id; +	ubi32_t lnum; +	ubi32_t leb_ver; /* obsolete, to be removed, don't use */ +	ubi32_t data_size; +	ubi32_t used_ebs; +	ubi32_t data_pad; +	ubi32_t data_crc; +	uint8_t padding1[4]; +	ubi64_t sqnum; +	uint8_t padding2[12]; +	ubi32_t hdr_crc; +} __attribute__ ((packed)); + +/* Internal UBI volumes count */ +#define UBI_INT_VOL_COUNT 1 + +/* + * Starting ID of internal volumes. There is reserved room for 4096 internal + * volumes. + */ +#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096) + +/* The layout volume contains the volume table */ + +#define UBI_LAYOUT_VOL_ID        UBI_INTERNAL_VOL_START +#define UBI_LAYOUT_VOLUME_EBS    2 +#define UBI_LAYOUT_VOLUME_NAME   "layout volume" +#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT + +/* The maximum number of volumes per one UBI device */ +#define UBI_MAX_VOLUMES 128 + +/* The maximum volume name length */ +#define UBI_VOL_NAME_MAX 127 + +/* Size of the volume table record */ +#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record) + +/* Size of the volume table record without the ending CRC */ +#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(ubi32_t)) + +/** + * struct ubi_vtbl_record - a record in the volume table. + * @reserved_pebs: how many physical eraseblocks are reserved for this volume + * @alignment: volume alignment + * @data_pad: how many bytes are unused at the end of the each physical + * eraseblock to satisfy the requested alignment + * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * @upd_marker: if volume update was started but not finished + * @name_len: volume name length + * @name: the volume name + * @padding2: reserved, zeroes + * @crc: a CRC32 checksum of the record + * + * The volume table records are stored in the volume table, which is stored in + * the layout volume. The layout volume consists of 2 logical eraseblock, each + * of which contains a copy of the volume table (i.e., the volume table is + * duplicated). The volume table is an array of &struct ubi_vtbl_record + * objects indexed by the volume ID. + * + * If the size of the logical eraseblock is large enough to fit + * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES + * records. Otherwise, it contains as many records as it can fit (i.e., size of + * logical eraseblock divided by sizeof(struct ubi_vtbl_record)). + * + * The @upd_marker flag is used to implement volume update. It is set to %1 + * before update and set to %0 after the update. So if the update operation was + * interrupted, UBI knows that the volume is corrupted. + * + * The @alignment field is specified when the volume is created and cannot be + * later changed. It may be useful, for example, when a block-oriented file + * system works on top of UBI. The @data_pad field is calculated using the + * logical eraseblock size and @alignment. The alignment must be multiple to the + * minimal flash I/O unit. If @alignment is 1, all the available space of + * the physical eraseblocks is used. + * + * Empty records contain all zeroes and the CRC checksum of those zeroes. + */ +struct ubi_vtbl_record { +	ubi32_t reserved_pebs; +	ubi32_t alignment; +	ubi32_t data_pad; +	uint8_t vol_type; +	uint8_t upd_marker; +	ubi16_t name_len; +	uint8_t name[UBI_VOL_NAME_MAX+1]; +	uint8_t padding2[24]; +	ubi32_t crc; +} __attribute__ ((packed)); + +#endif /* !__UBI_HEADER_H__ */ diff --git a/include/linux/mtd/ubi-user.h b/include/linux/mtd/ubi-user.h new file mode 100644 index 000000000..fe06ded0e --- /dev/null +++ b/include/linux/mtd/ubi-user.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +#ifndef __UBI_USER_H__ +#define __UBI_USER_H__ + +/* + * UBI volume creation + * ~~~~~~~~~~~~~~~~~~~ + * + * UBI volumes are created via the %UBI_IOCMKVOL IOCTL command of UBI character + * device. A &struct ubi_mkvol_req object has to be properly filled and a + * pointer to it has to be passed to the IOCTL. + * + * UBI volume deletion + * ~~~~~~~~~~~~~~~~~~~ + * + * To delete a volume, the %UBI_IOCRMVOL IOCTL command of the UBI character + * device should be used. A pointer to the 32-bit volume ID hast to be passed + * to the IOCTL. + * + * UBI volume re-size + * ~~~~~~~~~~~~~~~~~~ + * + * To re-size a volume, the %UBI_IOCRSVOL IOCTL command of the UBI character + * device should be used. A &struct ubi_rsvol_req object has to be properly + * filled and a pointer to it has to be passed to the IOCTL. + * + * UBI volume update + * ~~~~~~~~~~~~~~~~~ + * + * Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the + * corresponding UBI volume character device. A pointer to a 64-bit update + * size should be passed to the IOCTL. After then, UBI expects user to write + * this number of bytes to the volume character device. The update is finished + * when the claimed number of bytes is passed. So, the volume update sequence + * is something like: + * + * fd = open("/dev/my_volume"); + * ioctl(fd, UBI_IOCVOLUP, &image_size); + * write(fd, buf, image_size); + * close(fd); + */ + +/* + * When a new volume is created, users may either specify the volume number they + * want to create or to let UBI automatically assign a volume number using this + * constant. + */ +#define UBI_VOL_NUM_AUTO (-1) + +/* Maximum volume name length */ +#define UBI_MAX_VOLUME_NAME 127 + +/* IOCTL commands of UBI character devices */ + +#define UBI_IOC_MAGIC 'o' + +/* Create an UBI volume */ +#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req) +/* Remove an UBI volume */ +#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t) +/* Re-size an UBI volume */ +#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req) + +/* IOCTL commands of UBI volume character devices */ + +#define UBI_VOL_IOC_MAGIC 'O' + +/* Start UBI volume update */ +#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t) +/* An eraseblock erasure command, used for debugging, disabled by default */ +#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t) + +/* + * UBI volume type constants. + * + * @UBI_DYNAMIC_VOLUME: dynamic volume + * @UBI_STATIC_VOLUME:  static volume + */ +enum { +	UBI_DYNAMIC_VOLUME = 3, +	UBI_STATIC_VOLUME = 4 +}; + +/** + * struct ubi_mkvol_req - volume description data structure used in + * volume creation requests. + * @vol_id: volume number + * @alignment: volume alignment + * @bytes: volume size in bytes + * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * @padding1: reserved for future, not used + * @name_len: volume name length + * @padding2: reserved for future, not used + * @name: volume name + * + * This structure is used by userspace programs when creating new volumes. The + * @used_bytes field is only necessary when creating static volumes. + * + * The @alignment field specifies the required alignment of the volume logical + * eraseblock. This means, that the size of logical eraseblocks will be aligned + * to this number, i.e., + *	(UBI device logical eraseblock size) mod (@alignment) = 0. + * + * To put it differently, the logical eraseblock of this volume may be slightly + * shortened in order to make it properly aligned. The alignment has to be + * multiple of the flash minimal input/output unit, or %1 to utilize the entire + * available space of logical eraseblocks. + * + * The @alignment field may be useful, for example, when one wants to maintain + * a block device on top of an UBI volume. In this case, it is desirable to fit + * an integer number of blocks in logical eraseblocks of this UBI volume. With + * alignment it is possible to update this volume using plane UBI volume image + * BLOBs, without caring about how to properly align them. + */ +struct ubi_mkvol_req { +	int32_t vol_id; +	int32_t alignment; +	int64_t bytes; +	int8_t vol_type; +	int8_t padding1; +	int16_t name_len; +	int8_t padding2[4]; +	char name[UBI_MAX_VOLUME_NAME+1]; +} __attribute__ ((packed)); + +/** + * struct ubi_rsvol_req - a data structure used in volume re-size requests. + * @vol_id: ID of the volume to re-size + * @bytes: new size of the volume in bytes + * + * Re-sizing is possible for both dynamic and static volumes. But while dynamic + * volumes may be re-sized arbitrarily, static volumes cannot be made to be + * smaller then the number of bytes they bear. To arbitrarily shrink a static + * volume, it must be wiped out first (by means of volume update operation with + * zero number of bytes). + */ +struct ubi_rsvol_req { +	int64_t bytes; +	int32_t vol_id; +} __attribute__ ((packed)); + +#endif /* __UBI_USER_H__ */ diff --git a/include/nand.h b/include/nand.h index e1285cdae..83d597dc7 100644 --- a/include/nand.h +++ b/include/nand.h @@ -84,6 +84,7 @@ struct nand_write_options {  };  typedef struct nand_write_options nand_write_options_t; +typedef struct mtd_oob_ops mtd_oob_ops_t;  struct nand_read_options {  	u_char *buffer;		/* memory block in which read image is written*/ @@ -107,7 +108,7 @@ struct nand_erase_options {  typedef struct nand_erase_options nand_erase_options_t; -int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts); +int nand_write_opts(nand_info_t *mtd, loff_t to, mtd_oob_ops_t *ops);  int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts);  int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts); |