[MTD] NAND: Clean up trailing white spaces
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
parent
e5580fbe8a
commit
61b03bd7c3
|
@ -1,5 +1,5 @@
|
||||||
# drivers/mtd/nand/Kconfig
|
# drivers/mtd/nand/Kconfig
|
||||||
# $Id: Kconfig,v 1.34 2005/09/23 01:44:55 ppopov Exp $
|
# $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $
|
||||||
|
|
||||||
menu "NAND Flash Device Drivers"
|
menu "NAND Flash Device Drivers"
|
||||||
depends on MTD!=n
|
depends on MTD!=n
|
||||||
|
@ -27,14 +27,14 @@ config MTD_NAND_AUTCPU12
|
||||||
tristate "SmartMediaCard on autronix autcpu12 board"
|
tristate "SmartMediaCard on autronix autcpu12 board"
|
||||||
depends on MTD_NAND && ARCH_AUTCPU12
|
depends on MTD_NAND && ARCH_AUTCPU12
|
||||||
help
|
help
|
||||||
This enables the driver for the autronix autcpu12 board to
|
This enables the driver for the autronix autcpu12 board to
|
||||||
access the SmartMediaCard.
|
access the SmartMediaCard.
|
||||||
|
|
||||||
config MTD_NAND_EDB7312
|
config MTD_NAND_EDB7312
|
||||||
tristate "Support for Cirrus Logic EBD7312 evaluation board"
|
tristate "Support for Cirrus Logic EBD7312 evaluation board"
|
||||||
depends on MTD_NAND && ARCH_EDB7312
|
depends on MTD_NAND && ARCH_EDB7312
|
||||||
help
|
help
|
||||||
This enables the driver for the Cirrus Logic EBD7312 evaluation
|
This enables the driver for the Cirrus Logic EBD7312 evaluation
|
||||||
board to access the onboard NAND Flash.
|
board to access the onboard NAND Flash.
|
||||||
|
|
||||||
config MTD_NAND_H1900
|
config MTD_NAND_H1900
|
||||||
|
@ -71,7 +71,7 @@ config MTD_NAND_RTC_FROM4
|
||||||
select REED_SOLOMON
|
select REED_SOLOMON
|
||||||
select REED_SOLOMON_DEC8
|
select REED_SOLOMON_DEC8
|
||||||
help
|
help
|
||||||
This enables the driver for the Renesas Technology AG-AND
|
This enables the driver for the Renesas Technology AG-AND
|
||||||
flash interface board (FROM_BOARD4)
|
flash interface board (FROM_BOARD4)
|
||||||
|
|
||||||
config MTD_NAND_PPCHAMELEONEVB
|
config MTD_NAND_PPCHAMELEONEVB
|
||||||
|
@ -88,7 +88,7 @@ config MTD_NAND_S3C2410
|
||||||
SoCs
|
SoCs
|
||||||
|
|
||||||
No board specfic support is done by this driver, each board
|
No board specfic support is done by this driver, each board
|
||||||
must advertise a platform_device for the driver to attach.
|
must advertise a platform_device for the driver to attach.
|
||||||
|
|
||||||
config MTD_NAND_S3C2410_DEBUG
|
config MTD_NAND_S3C2410_DEBUG
|
||||||
bool "S3C2410 NAND driver debug"
|
bool "S3C2410 NAND driver debug"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2004 Embedded Edge, LLC
|
* Copyright (C) 2004 Embedded Edge, LLC
|
||||||
*
|
*
|
||||||
* $Id: au1550nd.c,v 1.12 2005/09/23 01:44:55 ppopov Exp $
|
* $Id: au1550nd.c,v 1.13 2005/11/07 11:14:30 gleixner Exp $
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -25,10 +25,10 @@
|
||||||
#else
|
#else
|
||||||
#include <asm/au1000.h>
|
#include <asm/au1000.h>
|
||||||
#ifdef CONFIG_MIPS_PB1550
|
#ifdef CONFIG_MIPS_PB1550
|
||||||
#include <asm/pb1550.h>
|
#include <asm/pb1550.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_MIPS_DB1550
|
#ifdef CONFIG_MIPS_DB1550
|
||||||
#include <asm/db1x00.h>
|
#include <asm/db1x00.h>
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -43,12 +43,12 @@ static int nand_width = 1; /* default x8*/
|
||||||
* Define partitions for flash device
|
* Define partitions for flash device
|
||||||
*/
|
*/
|
||||||
const static struct mtd_partition partition_info[] = {
|
const static struct mtd_partition partition_info[] = {
|
||||||
{
|
{
|
||||||
.name = "NAND FS 0",
|
.name = "NAND FS 0",
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = 8*1024*1024
|
.size = 8*1024*1024
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "NAND FS 1",
|
.name = "NAND FS 1",
|
||||||
.offset = MTDPART_OFS_APPEND,
|
.offset = MTDPART_OFS_APPEND,
|
||||||
.size = MTDPART_SIZ_FULL
|
.size = MTDPART_SIZ_FULL
|
||||||
|
@ -89,7 +89,7 @@ static void au_write_byte(struct mtd_info *mtd, u_char byte)
|
||||||
* au_read_byte16 - read one byte endianess aware from the chip
|
* au_read_byte16 - read one byte endianess aware from the chip
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
*
|
*
|
||||||
* read function for 16bit buswith with
|
* read function for 16bit buswith with
|
||||||
* endianess conversion
|
* endianess conversion
|
||||||
*/
|
*/
|
||||||
static u_char au_read_byte16(struct mtd_info *mtd)
|
static u_char au_read_byte16(struct mtd_info *mtd)
|
||||||
|
@ -119,7 +119,7 @@ static void au_write_byte16(struct mtd_info *mtd, u_char byte)
|
||||||
* au_read_word - read one word from the chip
|
* au_read_word - read one word from the chip
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
*
|
*
|
||||||
* read function for 16bit buswith without
|
* read function for 16bit buswith without
|
||||||
* endianess conversion
|
* endianess conversion
|
||||||
*/
|
*/
|
||||||
static u16 au_read_word(struct mtd_info *mtd)
|
static u16 au_read_word(struct mtd_info *mtd)
|
||||||
|
@ -135,7 +135,7 @@ static u16 au_read_word(struct mtd_info *mtd)
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @word: data word to write
|
* @word: data word to write
|
||||||
*
|
*
|
||||||
* write function for 16bit buswith without
|
* write function for 16bit buswith without
|
||||||
* endianess conversion
|
* endianess conversion
|
||||||
*/
|
*/
|
||||||
static void au_write_word(struct mtd_info *mtd, u16 word)
|
static void au_write_word(struct mtd_info *mtd, u16 word)
|
||||||
|
@ -165,7 +165,7 @@ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* au_read_buf - read chip data into buffer
|
* au_read_buf - read chip data into buffer
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @buf: buffer to store date
|
* @buf: buffer to store date
|
||||||
* @len: number of bytes to read
|
* @len: number of bytes to read
|
||||||
|
@ -179,12 +179,12 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||||
|
|
||||||
for (i=0; i<len; i++) {
|
for (i=0; i<len; i++) {
|
||||||
buf[i] = readb(this->IO_ADDR_R);
|
buf[i] = readb(this->IO_ADDR_R);
|
||||||
au_sync();
|
au_sync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* au_verify_buf - Verify chip data against buffer
|
* au_verify_buf - Verify chip data against buffer
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @buf: buffer containing the data to compare
|
* @buf: buffer containing the data to compare
|
||||||
* @len: number of bytes to compare
|
* @len: number of bytes to compare
|
||||||
|
@ -219,16 +219,16 @@ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
u16 *p = (u16 *) buf;
|
u16 *p = (u16 *) buf;
|
||||||
len >>= 1;
|
len >>= 1;
|
||||||
|
|
||||||
for (i=0; i<len; i++) {
|
for (i=0; i<len; i++) {
|
||||||
writew(p[i], this->IO_ADDR_W);
|
writew(p[i], this->IO_ADDR_W);
|
||||||
au_sync();
|
au_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* au_read_buf16 - read chip data into buffer
|
* au_read_buf16 - read chip data into buffer
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @buf: buffer to store date
|
* @buf: buffer to store date
|
||||||
* @len: number of bytes to read
|
* @len: number of bytes to read
|
||||||
|
@ -249,7 +249,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* au_verify_buf16 - Verify chip data against buffer
|
* au_verify_buf16 - Verify chip data against buffer
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @buf: buffer containing the data to compare
|
* @buf: buffer containing the data to compare
|
||||||
* @len: number of bytes to compare
|
* @len: number of bytes to compare
|
||||||
|
@ -282,26 +282,26 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
|
||||||
case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break;
|
case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break;
|
||||||
|
|
||||||
case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break;
|
case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break;
|
||||||
case NAND_CTL_CLRALE:
|
case NAND_CTL_CLRALE:
|
||||||
this->IO_ADDR_W = p_nand + MEM_STNAND_DATA;
|
this->IO_ADDR_W = p_nand + MEM_STNAND_DATA;
|
||||||
/* FIXME: Nobody knows why this is neccecary,
|
/* FIXME: Nobody knows why this is neccecary,
|
||||||
* but it works only that way */
|
* but it works only that way */
|
||||||
udelay(1);
|
udelay(1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_CTL_SETNCE:
|
case NAND_CTL_SETNCE:
|
||||||
/* assert (force assert) chip enable */
|
/* assert (force assert) chip enable */
|
||||||
au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break;
|
au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_CTL_CLRNCE:
|
case NAND_CTL_CLRNCE:
|
||||||
/* deassert chip enable */
|
/* deassert chip enable */
|
||||||
au_writel(0, MEM_STNDCTL); break;
|
au_writel(0, MEM_STNDCTL); break;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->IO_ADDR_R = this->IO_ADDR_W;
|
this->IO_ADDR_R = this->IO_ADDR_W;
|
||||||
|
|
||||||
/* Drain the writebuffer */
|
/* Drain the writebuffer */
|
||||||
au_sync();
|
au_sync();
|
||||||
}
|
}
|
||||||
|
@ -325,7 +325,7 @@ int __init au1xxx_nand_init (void)
|
||||||
u32 nand_phys;
|
u32 nand_phys;
|
||||||
|
|
||||||
/* Allocate memory for MTD device structure and private data */
|
/* Allocate memory for MTD device structure and private data */
|
||||||
au1550_mtd = kmalloc (sizeof(struct mtd_info) +
|
au1550_mtd = kmalloc (sizeof(struct mtd_info) +
|
||||||
sizeof (struct nand_chip), GFP_KERNEL);
|
sizeof (struct nand_chip), GFP_KERNEL);
|
||||||
if (!au1550_mtd) {
|
if (!au1550_mtd) {
|
||||||
printk ("Unable to allocate NAND MTD dev structure.\n");
|
printk ("Unable to allocate NAND MTD dev structure.\n");
|
||||||
|
@ -345,7 +345,7 @@ int __init au1xxx_nand_init (void)
|
||||||
|
|
||||||
/* disable interrupts */
|
/* disable interrupts */
|
||||||
au_writel(au_readl(MEM_STNDCTL) & ~(1<<8), MEM_STNDCTL);
|
au_writel(au_readl(MEM_STNDCTL) & ~(1<<8), MEM_STNDCTL);
|
||||||
|
|
||||||
/* disable NAND boot */
|
/* disable NAND boot */
|
||||||
au_writel(au_readl(MEM_STNDCTL) & ~(1<<0), MEM_STNDCTL);
|
au_writel(au_readl(MEM_STNDCTL) & ~(1<<0), MEM_STNDCTL);
|
||||||
|
|
||||||
|
@ -353,7 +353,7 @@ int __init au1xxx_nand_init (void)
|
||||||
/* set gpio206 high */
|
/* set gpio206 high */
|
||||||
au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR);
|
au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR);
|
||||||
|
|
||||||
boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) |
|
boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) |
|
||||||
((bcsr->status >> 6) & 0x1);
|
((bcsr->status >> 6) & 0x1);
|
||||||
switch (boot_swapboot) {
|
switch (boot_swapboot) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -402,7 +402,7 @@ int __init au1xxx_nand_init (void)
|
||||||
au_writel(NAND_STADDR, MEM_STADDR3);
|
au_writel(NAND_STADDR, MEM_STADDR3);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Locate NAND chip-select in order to determine NAND phys address */
|
/* Locate NAND chip-select in order to determine NAND phys address */
|
||||||
mem_staddr = 0x00000000;
|
mem_staddr = 0x00000000;
|
||||||
if (((au_readl(MEM_STCFG0) & 0x7) == 0x5) && (NAND_CS == 0))
|
if (((au_readl(MEM_STCFG0) & 0x7) == 0x5) && (NAND_CS == 0))
|
||||||
|
@ -438,7 +438,7 @@ int __init au1xxx_nand_init (void)
|
||||||
this->hwcontrol = au1550_hwcontrol;
|
this->hwcontrol = au1550_hwcontrol;
|
||||||
this->dev_ready = au1550_device_ready;
|
this->dev_ready = au1550_device_ready;
|
||||||
/* 30 us command delay time */
|
/* 30 us command delay time */
|
||||||
this->chip_delay = 30;
|
this->chip_delay = 30;
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->eccmode = NAND_ECC_SOFT;
|
||||||
|
|
||||||
this->options = NAND_NO_AUTOINCR;
|
this->options = NAND_NO_AUTOINCR;
|
||||||
|
@ -467,7 +467,7 @@ int __init au1xxx_nand_init (void)
|
||||||
|
|
||||||
outio:
|
outio:
|
||||||
iounmap ((void *)p_nand);
|
iounmap ((void *)p_nand);
|
||||||
|
|
||||||
outmem:
|
outmem:
|
||||||
kfree (au1550_mtd);
|
kfree (au1550_mtd);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
*
|
*
|
||||||
* Derived from drivers/mtd/spia.c
|
* Derived from drivers/mtd/spia.c
|
||||||
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
|
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
|
||||||
*
|
*
|
||||||
* $Id: autcpu12.c,v 1.22 2004/11/04 12:53:10 gleixner Exp $
|
* $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 gleixner Exp $
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
*
|
*
|
||||||
* Overview:
|
* Overview:
|
||||||
* This is a device driver for the NAND flash device found on the
|
* This is a device driver for the NAND flash device found on the
|
||||||
* autronix autcpu12 board, which is a SmartMediaCard. It supports
|
* autronix autcpu12 board, which is a SmartMediaCard. It supports
|
||||||
* 16MiB, 32MiB and 64MiB cards.
|
* 16MiB, 32MiB and 64MiB cards.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -93,7 +93,7 @@ static struct mtd_partition partition_info128k[] = {
|
||||||
#define NUM_PARTITIONS32K 2
|
#define NUM_PARTITIONS32K 2
|
||||||
#define NUM_PARTITIONS64K 2
|
#define NUM_PARTITIONS64K 2
|
||||||
#define NUM_PARTITIONS128K 2
|
#define NUM_PARTITIONS128K 2
|
||||||
/*
|
/*
|
||||||
* hardware specific access to control-lines
|
* hardware specific access to control-lines
|
||||||
*/
|
*/
|
||||||
static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd)
|
static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd)
|
||||||
|
@ -163,7 +163,7 @@ int __init autcpu12_init (void)
|
||||||
this->hwcontrol = autcpu12_hwcontrol;
|
this->hwcontrol = autcpu12_hwcontrol;
|
||||||
this->dev_ready = autcpu12_device_ready;
|
this->dev_ready = autcpu12_device_ready;
|
||||||
/* 20 us command delay time */
|
/* 20 us command delay time */
|
||||||
this->chip_delay = 20;
|
this->chip_delay = 20;
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->eccmode = NAND_ECC_SOFT;
|
||||||
|
|
||||||
/* Enable the following for a flash based bad block table */
|
/* Enable the following for a flash based bad block table */
|
||||||
|
@ -171,21 +171,21 @@ int __init autcpu12_init (void)
|
||||||
this->options = NAND_USE_FLASH_BBT;
|
this->options = NAND_USE_FLASH_BBT;
|
||||||
*/
|
*/
|
||||||
this->options = NAND_USE_FLASH_BBT;
|
this->options = NAND_USE_FLASH_BBT;
|
||||||
|
|
||||||
/* Scan to find existance of the device */
|
/* Scan to find existance of the device */
|
||||||
if (nand_scan (autcpu12_mtd, 1)) {
|
if (nand_scan (autcpu12_mtd, 1)) {
|
||||||
err = -ENXIO;
|
err = -ENXIO;
|
||||||
goto out_ior;
|
goto out_ior;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register the partitions */
|
/* Register the partitions */
|
||||||
switch(autcpu12_mtd->size){
|
switch(autcpu12_mtd->size){
|
||||||
case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
|
case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
|
||||||
case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break;
|
case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break;
|
||||||
case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break;
|
case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break;
|
||||||
case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break;
|
case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break;
|
||||||
default: {
|
default: {
|
||||||
printk ("Unsupported SmartMedia device\n");
|
printk ("Unsupported SmartMedia device\n");
|
||||||
err = -ENXIO;
|
err = -ENXIO;
|
||||||
goto out_ior;
|
goto out_ior;
|
||||||
}
|
}
|
||||||
|
@ -213,7 +213,7 @@ static void __exit autcpu12_cleanup (void)
|
||||||
|
|
||||||
/* unmap physical adress */
|
/* unmap physical adress */
|
||||||
iounmap((void *)autcpu12_fio_base);
|
iounmap((void *)autcpu12_fio_base);
|
||||||
|
|
||||||
/* Free the MTD device structure */
|
/* Free the MTD device structure */
|
||||||
kfree (autcpu12_mtd);
|
kfree (autcpu12_mtd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* drivers/mtd/nand/diskonchip.c
|
* drivers/mtd/nand/diskonchip.c
|
||||||
*
|
*
|
||||||
* (C) 2003 Red Hat, Inc.
|
* (C) 2003 Red Hat, Inc.
|
||||||
|
@ -8,15 +8,15 @@
|
||||||
* Author: David Woodhouse <dwmw2@infradead.org>
|
* Author: David Woodhouse <dwmw2@infradead.org>
|
||||||
* Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
|
* Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
|
||||||
* Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
|
* Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
|
||||||
*
|
*
|
||||||
* Error correction code lifted from the old docecc code
|
* Error correction code lifted from the old docecc code
|
||||||
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
|
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
|
||||||
* Copyright (C) 2000 Netgem S.A.
|
* Copyright (C) 2000 Netgem S.A.
|
||||||
* converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
|
* converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
|
||||||
*
|
*
|
||||||
* Interface to generic NAND code for M-Systems DiskOnChip devices
|
* Interface to generic NAND code for M-Systems DiskOnChip devices
|
||||||
*
|
*
|
||||||
* $Id: diskonchip.c,v 1.54 2005/04/07 14:22:55 dbrown Exp $
|
* $Id: diskonchip.c,v 1.55 2005/11/07 11:14:30 gleixner Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
@ -42,16 +42,16 @@
|
||||||
static unsigned long __initdata doc_locations[] = {
|
static unsigned long __initdata doc_locations[] = {
|
||||||
#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
|
#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
|
||||||
#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
|
#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
|
||||||
0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
|
0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
|
||||||
0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
|
0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
|
||||||
0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
|
0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
|
||||||
0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
|
0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
|
||||||
0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
|
0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
|
||||||
#else /* CONFIG_MTD_DOCPROBE_HIGH */
|
#else /* CONFIG_MTD_DOCPROBE_HIGH */
|
||||||
0xc8000, 0xca000, 0xcc000, 0xce000,
|
0xc8000, 0xca000, 0xcc000, 0xce000,
|
||||||
0xd0000, 0xd2000, 0xd4000, 0xd6000,
|
0xd0000, 0xd2000, 0xd4000, 0xd6000,
|
||||||
0xd8000, 0xda000, 0xdc000, 0xde000,
|
0xd8000, 0xda000, 0xdc000, 0xde000,
|
||||||
0xe0000, 0xe2000, 0xe4000, 0xe6000,
|
0xe0000, 0xe2000, 0xe4000, 0xe6000,
|
||||||
0xe8000, 0xea000, 0xec000, 0xee000,
|
0xe8000, 0xea000, 0xec000, 0xee000,
|
||||||
#endif /* CONFIG_MTD_DOCPROBE_HIGH */
|
#endif /* CONFIG_MTD_DOCPROBE_HIGH */
|
||||||
#elif defined(__PPC__)
|
#elif defined(__PPC__)
|
||||||
|
@ -138,7 +138,7 @@ MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe
|
||||||
/* the Reed Solomon control structure */
|
/* the Reed Solomon control structure */
|
||||||
static struct rs_control *rs_decoder;
|
static struct rs_control *rs_decoder;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The HW decoder in the DoC ASIC's provides us a error syndrome,
|
* The HW decoder in the DoC ASIC's provides us a error syndrome,
|
||||||
* which we must convert to a standard syndrom usable by the generic
|
* which we must convert to a standard syndrom usable by the generic
|
||||||
* Reed-Solomon library code.
|
* Reed-Solomon library code.
|
||||||
|
@ -163,8 +163,8 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
|
||||||
/* Initialize the syndrom buffer */
|
/* Initialize the syndrom buffer */
|
||||||
for (i = 0; i < NROOTS; i++)
|
for (i = 0; i < NROOTS; i++)
|
||||||
s[i] = ds[0];
|
s[i] = ds[0];
|
||||||
/*
|
/*
|
||||||
* Evaluate
|
* Evaluate
|
||||||
* s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
|
* s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
|
||||||
* where x = alpha^(FCR + i)
|
* where x = alpha^(FCR + i)
|
||||||
*/
|
*/
|
||||||
|
@ -188,7 +188,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
|
||||||
if (nerr < 0)
|
if (nerr < 0)
|
||||||
return nerr;
|
return nerr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Correct the errors. The bitpositions are a bit of magic,
|
* Correct the errors. The bitpositions are a bit of magic,
|
||||||
* but they are given by the design of the de/encoder circuit
|
* but they are given by the design of the de/encoder circuit
|
||||||
* in the DoC ASIC's.
|
* in the DoC ASIC's.
|
||||||
|
@ -205,7 +205,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
|
||||||
can be modified since pos is even */
|
can be modified since pos is even */
|
||||||
index = (pos >> 3) ^ 1;
|
index = (pos >> 3) ^ 1;
|
||||||
bitpos = pos & 7;
|
bitpos = pos & 7;
|
||||||
if ((index >= 0 && index < SECTOR_SIZE) ||
|
if ((index >= 0 && index < SECTOR_SIZE) ||
|
||||||
index == (SECTOR_SIZE + 1)) {
|
index == (SECTOR_SIZE + 1)) {
|
||||||
val = (uint8_t) (errval[i] >> (2 + bitpos));
|
val = (uint8_t) (errval[i] >> (2 + bitpos));
|
||||||
parity ^= val;
|
parity ^= val;
|
||||||
|
@ -216,7 +216,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
|
||||||
bitpos = (bitpos + 10) & 7;
|
bitpos = (bitpos + 10) & 7;
|
||||||
if (bitpos == 0)
|
if (bitpos == 0)
|
||||||
bitpos = 8;
|
bitpos = 8;
|
||||||
if ((index >= 0 && index < SECTOR_SIZE) ||
|
if ((index >= 0 && index < SECTOR_SIZE) ||
|
||||||
index == (SECTOR_SIZE + 1)) {
|
index == (SECTOR_SIZE + 1)) {
|
||||||
val = (uint8_t)(errval[i] << (8 - bitpos));
|
val = (uint8_t)(errval[i] << (8 - bitpos));
|
||||||
parity ^= val;
|
parity ^= val;
|
||||||
|
@ -233,7 +233,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
|
||||||
{
|
{
|
||||||
volatile char dummy;
|
volatile char dummy;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < cycles; i++) {
|
for (i = 0; i < cycles; i++) {
|
||||||
if (DoC_is_Millennium(doc))
|
if (DoC_is_Millennium(doc))
|
||||||
dummy = ReadDOC(doc->virtadr, NOP);
|
dummy = ReadDOC(doc->virtadr, NOP);
|
||||||
|
@ -242,7 +242,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
|
||||||
else
|
else
|
||||||
dummy = ReadDOC(doc->virtadr, DOCStatus);
|
dummy = ReadDOC(doc->virtadr, DOCStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
|
#define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
|
||||||
|
@ -327,7 +327,7 @@ static u_char doc2000_read_byte(struct mtd_info *mtd)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void doc2000_writebuf(struct mtd_info *mtd,
|
static void doc2000_writebuf(struct mtd_info *mtd,
|
||||||
const u_char *buf, int len)
|
const u_char *buf, int len)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
@ -343,7 +343,7 @@ static void doc2000_writebuf(struct mtd_info *mtd,
|
||||||
if (debug) printk("\n");
|
if (debug) printk("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void doc2000_readbuf(struct mtd_info *mtd,
|
static void doc2000_readbuf(struct mtd_info *mtd,
|
||||||
u_char *buf, int len)
|
u_char *buf, int len)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
@ -358,7 +358,7 @@ static void doc2000_readbuf(struct mtd_info *mtd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void doc2000_readbuf_dword(struct mtd_info *mtd,
|
static void doc2000_readbuf_dword(struct mtd_info *mtd,
|
||||||
u_char *buf, int len)
|
u_char *buf, int len)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
@ -379,7 +379,7 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int doc2000_verifybuf(struct mtd_info *mtd,
|
static int doc2000_verifybuf(struct mtd_info *mtd,
|
||||||
const u_char *buf, int len)
|
const u_char *buf, int len)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
@ -406,12 +406,12 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
|
||||||
doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
|
doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
|
||||||
this->write_byte(mtd, 0);
|
this->write_byte(mtd, 0);
|
||||||
doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
|
doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
|
||||||
|
|
||||||
/* We cant' use dev_ready here, but at least we wait for the
|
/* We cant' use dev_ready here, but at least we wait for the
|
||||||
* command to complete
|
* command to complete
|
||||||
*/
|
*/
|
||||||
udelay(50);
|
udelay(50);
|
||||||
|
|
||||||
ret = this->read_byte(mtd) << 8;
|
ret = this->read_byte(mtd) << 8;
|
||||||
ret |= this->read_byte(mtd);
|
ret |= this->read_byte(mtd);
|
||||||
|
|
||||||
|
@ -438,7 +438,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
|
||||||
this->read_buf = &doc2000_readbuf_dword;
|
this->read_buf = &doc2000_readbuf_dword;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,7 +469,7 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
|
||||||
struct doc_priv *doc = this->priv;
|
struct doc_priv *doc = this->priv;
|
||||||
|
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
DoC_WaitReady(doc);
|
DoC_WaitReady(doc);
|
||||||
this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
|
this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
|
||||||
DoC_WaitReady(doc);
|
DoC_WaitReady(doc);
|
||||||
|
@ -503,7 +503,7 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)
|
||||||
return ReadDOC(docptr, LastDataRead);
|
return ReadDOC(docptr, LastDataRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void doc2001_writebuf(struct mtd_info *mtd,
|
static void doc2001_writebuf(struct mtd_info *mtd,
|
||||||
const u_char *buf, int len)
|
const u_char *buf, int len)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
@ -517,7 +517,7 @@ static void doc2001_writebuf(struct mtd_info *mtd,
|
||||||
WriteDOC(0x00, docptr, WritePipeTerm);
|
WriteDOC(0x00, docptr, WritePipeTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void doc2001_readbuf(struct mtd_info *mtd,
|
static void doc2001_readbuf(struct mtd_info *mtd,
|
||||||
u_char *buf, int len)
|
u_char *buf, int len)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
@ -535,7 +535,7 @@ static void doc2001_readbuf(struct mtd_info *mtd,
|
||||||
buf[i] = ReadDOC(docptr, LastDataRead);
|
buf[i] = ReadDOC(docptr, LastDataRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int doc2001_verifybuf(struct mtd_info *mtd,
|
static int doc2001_verifybuf(struct mtd_info *mtd,
|
||||||
const u_char *buf, int len)
|
const u_char *buf, int len)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
@ -570,7 +570,7 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void doc2001plus_writebuf(struct mtd_info *mtd,
|
static void doc2001plus_writebuf(struct mtd_info *mtd,
|
||||||
const u_char *buf, int len)
|
const u_char *buf, int len)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
@ -587,7 +587,7 @@ static void doc2001plus_writebuf(struct mtd_info *mtd,
|
||||||
if (debug) printk("\n");
|
if (debug) printk("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void doc2001plus_readbuf(struct mtd_info *mtd,
|
static void doc2001plus_readbuf(struct mtd_info *mtd,
|
||||||
u_char *buf, int len)
|
u_char *buf, int len)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
@ -617,7 +617,7 @@ static void doc2001plus_readbuf(struct mtd_info *mtd,
|
||||||
if (debug) printk("\n");
|
if (debug) printk("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int doc2001plus_verifybuf(struct mtd_info *mtd,
|
static int doc2001plus_verifybuf(struct mtd_info *mtd,
|
||||||
const u_char *buf, int len)
|
const u_char *buf, int len)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
@ -797,7 +797,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col
|
||||||
WriteDOC(0, docptr, Mplus_FlashControl);
|
WriteDOC(0, docptr, Mplus_FlashControl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* program and erase have their own busy handlers
|
* program and erase have their own busy handlers
|
||||||
* status and sequential in needs no delay
|
* status and sequential in needs no delay
|
||||||
*/
|
*/
|
||||||
|
@ -822,7 +822,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col
|
||||||
|
|
||||||
/* This applies to read commands */
|
/* This applies to read commands */
|
||||||
default:
|
default:
|
||||||
/*
|
/*
|
||||||
* If we don't have access to the busy pin, we apply the given
|
* If we don't have access to the busy pin, we apply the given
|
||||||
* command delay
|
* command delay
|
||||||
*/
|
*/
|
||||||
|
@ -945,7 +945,7 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
||||||
for (i = 0; i < 6; i++) {
|
for (i = 0; i < 6; i++) {
|
||||||
if (DoC_is_MillenniumPlus(doc))
|
if (DoC_is_MillenniumPlus(doc))
|
||||||
ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
|
ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
|
||||||
else
|
else
|
||||||
ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
|
ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
|
||||||
if (ecc_code[i] != empty_write_ecc[i])
|
if (ecc_code[i] != empty_write_ecc[i])
|
||||||
emptymatch = 0;
|
emptymatch = 0;
|
||||||
|
@ -982,7 +982,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
|
||||||
void __iomem *docptr = doc->virtadr;
|
void __iomem *docptr = doc->virtadr;
|
||||||
volatile u_char dummy;
|
volatile u_char dummy;
|
||||||
int emptymatch = 1;
|
int emptymatch = 1;
|
||||||
|
|
||||||
/* flush the pipeline */
|
/* flush the pipeline */
|
||||||
if (DoC_is_2000(doc)) {
|
if (DoC_is_2000(doc)) {
|
||||||
dummy = ReadDOC(docptr, 2k_ECCStatus);
|
dummy = ReadDOC(docptr, 2k_ECCStatus);
|
||||||
|
@ -997,7 +997,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
|
||||||
dummy = ReadDOC(docptr, ECCConf);
|
dummy = ReadDOC(docptr, ECCConf);
|
||||||
dummy = ReadDOC(docptr, ECCConf);
|
dummy = ReadDOC(docptr, ECCConf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Error occured ? */
|
/* Error occured ? */
|
||||||
if (dummy & 0x80) {
|
if (dummy & 0x80) {
|
||||||
for (i = 0; i < 6; i++) {
|
for (i = 0; i < 6; i++) {
|
||||||
|
@ -1035,7 +1035,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
|
||||||
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)
|
if (ret > 0)
|
||||||
printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
|
printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
|
||||||
}
|
}
|
||||||
if (DoC_is_MillenniumPlus(doc))
|
if (DoC_is_MillenniumPlus(doc))
|
||||||
WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
|
WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
|
||||||
else
|
else
|
||||||
|
@ -1046,7 +1046,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
//u_char mydatabuf[528];
|
//u_char mydatabuf[528];
|
||||||
|
|
||||||
/* The strange out-of-order .oobfree list below is a (possibly unneeded)
|
/* The strange out-of-order .oobfree list below is a (possibly unneeded)
|
||||||
|
@ -1065,7 +1065,7 @@ static struct nand_oobinfo doc200x_oobinfo = {
|
||||||
.eccpos = {0, 1, 2, 3, 4, 5},
|
.eccpos = {0, 1, 2, 3, 4, 5},
|
||||||
.oobfree = { {8, 8}, {6, 2} }
|
.oobfree = { {8, 8}, {6, 2} }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
|
/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
|
||||||
On sucessful return, buf will contain a copy of the media header for
|
On sucessful return, buf will contain a copy of the media header for
|
||||||
further processing. id is the string to scan for, and will presumably be
|
further processing. id is the string to scan for, and will presumably be
|
||||||
|
@ -1251,7 +1251,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
|
||||||
mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits);
|
mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits);
|
||||||
mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
|
mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
|
||||||
mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
|
mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
|
||||||
|
|
||||||
printk(KERN_INFO " bootRecordID = %s\n"
|
printk(KERN_INFO " bootRecordID = %s\n"
|
||||||
" NoOfBootImageBlocks = %d\n"
|
" NoOfBootImageBlocks = %d\n"
|
||||||
" NoOfBinaryPartitions = %d\n"
|
" NoOfBinaryPartitions = %d\n"
|
||||||
|
@ -1468,7 +1468,7 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
|
||||||
ReadDOC(doc->virtadr, ChipID);
|
ReadDOC(doc->virtadr, ChipID);
|
||||||
if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {
|
if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {
|
||||||
/* It's not a Millennium; it's one of the newer
|
/* It's not a Millennium; it's one of the newer
|
||||||
DiskOnChip 2000 units with a similar ASIC.
|
DiskOnChip 2000 units with a similar ASIC.
|
||||||
Treat it like a Millennium, except that it
|
Treat it like a Millennium, except that it
|
||||||
can have multiple chips. */
|
can have multiple chips. */
|
||||||
doc2000_count_chips(mtd);
|
doc2000_count_chips(mtd);
|
||||||
|
@ -1530,20 +1530,20 @@ static inline int __init doc_probe(unsigned long physadr)
|
||||||
* to the DOCControl register. So we store the current contents
|
* to the DOCControl register. So we store the current contents
|
||||||
* of the DOCControl register's location, in case we later decide
|
* of the DOCControl register's location, in case we later decide
|
||||||
* that it's not a DiskOnChip, and want to put it back how we
|
* that it's not a DiskOnChip, and want to put it back how we
|
||||||
* found it.
|
* found it.
|
||||||
*/
|
*/
|
||||||
save_control = ReadDOC(virtadr, DOCControl);
|
save_control = ReadDOC(virtadr, DOCControl);
|
||||||
|
|
||||||
/* Reset the DiskOnChip ASIC */
|
/* Reset the DiskOnChip ASIC */
|
||||||
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
|
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
|
||||||
virtadr, DOCControl);
|
virtadr, DOCControl);
|
||||||
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
|
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
|
||||||
virtadr, DOCControl);
|
virtadr, DOCControl);
|
||||||
|
|
||||||
/* Enable the DiskOnChip ASIC */
|
/* Enable the DiskOnChip ASIC */
|
||||||
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
|
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
|
||||||
virtadr, DOCControl);
|
virtadr, DOCControl);
|
||||||
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
|
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
|
||||||
virtadr, DOCControl);
|
virtadr, DOCControl);
|
||||||
|
|
||||||
ChipID = ReadDOC(virtadr, ChipID);
|
ChipID = ReadDOC(virtadr, ChipID);
|
||||||
|
@ -1738,7 +1738,7 @@ static int __init init_nanddoc(void)
|
||||||
int i, ret = 0;
|
int i, ret = 0;
|
||||||
|
|
||||||
/* We could create the decoder on demand, if memory is a concern.
|
/* We could create the decoder on demand, if memory is a concern.
|
||||||
* This way we have it handy, if an error happens
|
* This way we have it handy, if an error happens
|
||||||
*
|
*
|
||||||
* Symbolsize is 10 (bits)
|
* Symbolsize is 10 (bits)
|
||||||
* Primitve polynomial is x^10+x^3+1
|
* Primitve polynomial is x^10+x^3+1
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Derived from drivers/mtd/nand/autcpu12.c
|
* Derived from drivers/mtd/nand/autcpu12.c
|
||||||
* Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
|
* Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
|
||||||
*
|
*
|
||||||
* $Id: edb7312.c,v 1.11 2004/11/04 12:53:10 gleixner Exp $
|
* $Id: edb7312.c,v 1.12 2005/11/07 11:14:30 gleixner Exp $
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -71,27 +71,27 @@ static struct mtd_partition partition_info[] = {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hardware specific access to control-lines
|
* hardware specific access to control-lines
|
||||||
*/
|
*/
|
||||||
static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd)
|
static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd)
|
||||||
{
|
{
|
||||||
switch(cmd) {
|
switch(cmd) {
|
||||||
|
|
||||||
case NAND_CTL_SETCLE:
|
case NAND_CTL_SETCLE:
|
||||||
clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr);
|
clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr);
|
||||||
break;
|
break;
|
||||||
case NAND_CTL_CLRCLE:
|
case NAND_CTL_CLRCLE:
|
||||||
clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr);
|
clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_CTL_SETALE:
|
case NAND_CTL_SETALE:
|
||||||
clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr);
|
clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr);
|
||||||
break;
|
break;
|
||||||
case NAND_CTL_CLRALE:
|
case NAND_CTL_CLRALE:
|
||||||
clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr);
|
clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_CTL_SETNCE:
|
case NAND_CTL_SETNCE:
|
||||||
clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr);
|
clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr);
|
||||||
break;
|
break;
|
||||||
|
@ -122,16 +122,16 @@ static int __init ep7312_init (void)
|
||||||
int mtd_parts_nb = 0;
|
int mtd_parts_nb = 0;
|
||||||
struct mtd_partition *mtd_parts = 0;
|
struct mtd_partition *mtd_parts = 0;
|
||||||
void __iomem * ep7312_fio_base;
|
void __iomem * ep7312_fio_base;
|
||||||
|
|
||||||
/* Allocate memory for MTD device structure and private data */
|
/* Allocate memory for MTD device structure and private data */
|
||||||
ep7312_mtd = kmalloc(sizeof(struct mtd_info) +
|
ep7312_mtd = kmalloc(sizeof(struct mtd_info) +
|
||||||
sizeof(struct nand_chip),
|
sizeof(struct nand_chip),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!ep7312_mtd) {
|
if (!ep7312_mtd) {
|
||||||
printk("Unable to allocate EDB7312 NAND MTD device structure.\n");
|
printk("Unable to allocate EDB7312 NAND MTD device structure.\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* map physical adress */
|
/* map physical adress */
|
||||||
ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K);
|
ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K);
|
||||||
if(!ep7312_fio_base) {
|
if(!ep7312_fio_base) {
|
||||||
|
@ -139,23 +139,23 @@ static int __init ep7312_init (void)
|
||||||
kfree(ep7312_mtd);
|
kfree(ep7312_mtd);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get pointer to private data */
|
/* Get pointer to private data */
|
||||||
this = (struct nand_chip *) (&ep7312_mtd[1]);
|
this = (struct nand_chip *) (&ep7312_mtd[1]);
|
||||||
|
|
||||||
/* Initialize structures */
|
/* Initialize structures */
|
||||||
memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info));
|
memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info));
|
||||||
memset((char *) this, 0, sizeof(struct nand_chip));
|
memset((char *) this, 0, sizeof(struct nand_chip));
|
||||||
|
|
||||||
/* Link the private data with the MTD structure */
|
/* Link the private data with the MTD structure */
|
||||||
ep7312_mtd->priv = this;
|
ep7312_mtd->priv = this;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set GPIO Port B control register so that the pins are configured
|
* Set GPIO Port B control register so that the pins are configured
|
||||||
* to be outputs for controlling the NAND flash.
|
* to be outputs for controlling the NAND flash.
|
||||||
*/
|
*/
|
||||||
clps_writeb(0xf0, ep7312_pxddr);
|
clps_writeb(0xf0, ep7312_pxddr);
|
||||||
|
|
||||||
/* insert callbacks */
|
/* insert callbacks */
|
||||||
this->IO_ADDR_R = ep7312_fio_base;
|
this->IO_ADDR_R = ep7312_fio_base;
|
||||||
this->IO_ADDR_W = ep7312_fio_base;
|
this->IO_ADDR_W = ep7312_fio_base;
|
||||||
|
@ -163,14 +163,14 @@ static int __init ep7312_init (void)
|
||||||
this->dev_ready = ep7312_device_ready;
|
this->dev_ready = ep7312_device_ready;
|
||||||
/* 15 us command delay time */
|
/* 15 us command delay time */
|
||||||
this->chip_delay = 15;
|
this->chip_delay = 15;
|
||||||
|
|
||||||
/* Scan to find existence of the device */
|
/* Scan to find existence of the device */
|
||||||
if (nand_scan (ep7312_mtd, 1)) {
|
if (nand_scan (ep7312_mtd, 1)) {
|
||||||
iounmap((void *)ep7312_fio_base);
|
iounmap((void *)ep7312_fio_base);
|
||||||
kfree (ep7312_mtd);
|
kfree (ep7312_mtd);
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MTD_PARTITIONS
|
#ifdef CONFIG_MTD_PARTITIONS
|
||||||
ep7312_mtd->name = "edb7312-nand";
|
ep7312_mtd->name = "edb7312-nand";
|
||||||
mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes,
|
mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes,
|
||||||
|
@ -185,11 +185,11 @@ static int __init ep7312_init (void)
|
||||||
mtd_parts_nb = NUM_PARTITIONS;
|
mtd_parts_nb = NUM_PARTITIONS;
|
||||||
part_type = "static";
|
part_type = "static";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register the partitions */
|
/* Register the partitions */
|
||||||
printk(KERN_NOTICE "Using %s partition definition\n", part_type);
|
printk(KERN_NOTICE "Using %s partition definition\n", part_type);
|
||||||
add_mtd_partitions(ep7312_mtd, mtd_parts, mtd_parts_nb);
|
add_mtd_partitions(ep7312_mtd, mtd_parts, mtd_parts_nb);
|
||||||
|
|
||||||
/* Return happy */
|
/* Return happy */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -201,13 +201,13 @@ module_init(ep7312_init);
|
||||||
static void __exit ep7312_cleanup (void)
|
static void __exit ep7312_cleanup (void)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1];
|
struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1];
|
||||||
|
|
||||||
/* Release resources, unregister device */
|
/* Release resources, unregister device */
|
||||||
nand_release (ap7312_mtd);
|
nand_release (ap7312_mtd);
|
||||||
|
|
||||||
/* Free internal data buffer */
|
/* Free internal data buffer */
|
||||||
kfree (this->data_buf);
|
kfree (this->data_buf);
|
||||||
|
|
||||||
/* Free the MTD device structure */
|
/* Free the MTD device structure */
|
||||||
kfree (ep7312_mtd);
|
kfree (ep7312_mtd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
|
* Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
|
||||||
* Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
|
* Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
|
||||||
*
|
*
|
||||||
* $Id: h1910.c,v 1.5 2004/11/04 12:53:10 gleixner Exp $
|
* $Id: h1910.c,v 1.6 2005/11/07 11:14:30 gleixner Exp $
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -54,24 +54,24 @@ static struct mtd_partition partition_info[] = {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hardware specific access to control-lines
|
* hardware specific access to control-lines
|
||||||
*/
|
*/
|
||||||
static void h1910_hwcontrol(struct mtd_info *mtd, int cmd)
|
static void h1910_hwcontrol(struct mtd_info *mtd, int cmd)
|
||||||
{
|
{
|
||||||
struct nand_chip* this = (struct nand_chip *) (mtd->priv);
|
struct nand_chip* this = (struct nand_chip *) (mtd->priv);
|
||||||
|
|
||||||
switch(cmd) {
|
switch(cmd) {
|
||||||
|
|
||||||
case NAND_CTL_SETCLE:
|
case NAND_CTL_SETCLE:
|
||||||
this->IO_ADDR_R |= (1 << 2);
|
this->IO_ADDR_R |= (1 << 2);
|
||||||
this->IO_ADDR_W |= (1 << 2);
|
this->IO_ADDR_W |= (1 << 2);
|
||||||
break;
|
break;
|
||||||
case NAND_CTL_CLRCLE:
|
case NAND_CTL_CLRCLE:
|
||||||
this->IO_ADDR_R &= ~(1 << 2);
|
this->IO_ADDR_R &= ~(1 << 2);
|
||||||
this->IO_ADDR_W &= ~(1 << 2);
|
this->IO_ADDR_W &= ~(1 << 2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_CTL_SETALE:
|
case NAND_CTL_SETALE:
|
||||||
this->IO_ADDR_R |= (1 << 3);
|
this->IO_ADDR_R |= (1 << 3);
|
||||||
this->IO_ADDR_W |= (1 << 3);
|
this->IO_ADDR_W |= (1 << 3);
|
||||||
|
@ -80,7 +80,7 @@ static void h1910_hwcontrol(struct mtd_info *mtd, int cmd)
|
||||||
this->IO_ADDR_R &= ~(1 << 3);
|
this->IO_ADDR_R &= ~(1 << 3);
|
||||||
this->IO_ADDR_W &= ~(1 << 3);
|
this->IO_ADDR_W &= ~(1 << 3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_CTL_SETNCE:
|
case NAND_CTL_SETNCE:
|
||||||
break;
|
break;
|
||||||
case NAND_CTL_CLRNCE:
|
case NAND_CTL_CLRNCE:
|
||||||
|
@ -108,18 +108,18 @@ static int __init h1910_init (void)
|
||||||
int mtd_parts_nb = 0;
|
int mtd_parts_nb = 0;
|
||||||
struct mtd_partition *mtd_parts = 0;
|
struct mtd_partition *mtd_parts = 0;
|
||||||
void __iomem *nandaddr;
|
void __iomem *nandaddr;
|
||||||
|
|
||||||
if (!machine_is_h1900())
|
if (!machine_is_h1900())
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
nandaddr = __ioremap(0x08000000, 0x1000, 0, 1);
|
nandaddr = __ioremap(0x08000000, 0x1000, 0, 1);
|
||||||
if (!nandaddr) {
|
if (!nandaddr) {
|
||||||
printk("Failed to ioremap nand flash.\n");
|
printk("Failed to ioremap nand flash.\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate memory for MTD device structure and private data */
|
/* Allocate memory for MTD device structure and private data */
|
||||||
h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) +
|
h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) +
|
||||||
sizeof(struct nand_chip),
|
sizeof(struct nand_chip),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!h1910_nand_mtd) {
|
if (!h1910_nand_mtd) {
|
||||||
|
@ -127,22 +127,22 @@ static int __init h1910_init (void)
|
||||||
iounmap ((void *) nandaddr);
|
iounmap ((void *) nandaddr);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get pointer to private data */
|
/* Get pointer to private data */
|
||||||
this = (struct nand_chip *) (&h1910_nand_mtd[1]);
|
this = (struct nand_chip *) (&h1910_nand_mtd[1]);
|
||||||
|
|
||||||
/* Initialize structures */
|
/* Initialize structures */
|
||||||
memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info));
|
memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info));
|
||||||
memset((char *) this, 0, sizeof(struct nand_chip));
|
memset((char *) this, 0, sizeof(struct nand_chip));
|
||||||
|
|
||||||
/* Link the private data with the MTD structure */
|
/* Link the private data with the MTD structure */
|
||||||
h1910_nand_mtd->priv = this;
|
h1910_nand_mtd->priv = this;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable VPEN
|
* Enable VPEN
|
||||||
*/
|
*/
|
||||||
GPSR(37) = GPIO_bit(37);
|
GPSR(37) = GPIO_bit(37);
|
||||||
|
|
||||||
/* insert callbacks */
|
/* insert callbacks */
|
||||||
this->IO_ADDR_R = nandaddr;
|
this->IO_ADDR_R = nandaddr;
|
||||||
this->IO_ADDR_W = nandaddr;
|
this->IO_ADDR_W = nandaddr;
|
||||||
|
@ -152,7 +152,7 @@ static int __init h1910_init (void)
|
||||||
this->chip_delay = 50;
|
this->chip_delay = 50;
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->eccmode = NAND_ECC_SOFT;
|
||||||
this->options = NAND_NO_AUTOINCR;
|
this->options = NAND_NO_AUTOINCR;
|
||||||
|
|
||||||
/* Scan to find existence of the device */
|
/* Scan to find existence of the device */
|
||||||
if (nand_scan (h1910_nand_mtd, 1)) {
|
if (nand_scan (h1910_nand_mtd, 1)) {
|
||||||
printk(KERN_NOTICE "No NAND device - returning -ENXIO\n");
|
printk(KERN_NOTICE "No NAND device - returning -ENXIO\n");
|
||||||
|
@ -160,9 +160,9 @@ static int __init h1910_init (void)
|
||||||
iounmap ((void *) nandaddr);
|
iounmap ((void *) nandaddr);
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MTD_CMDLINE_PARTS
|
#ifdef CONFIG_MTD_CMDLINE_PARTS
|
||||||
mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts,
|
mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts,
|
||||||
"h1910-nand");
|
"h1910-nand");
|
||||||
if (mtd_parts_nb > 0)
|
if (mtd_parts_nb > 0)
|
||||||
part_type = "command line";
|
part_type = "command line";
|
||||||
|
@ -175,11 +175,11 @@ static int __init h1910_init (void)
|
||||||
mtd_parts_nb = NUM_PARTITIONS;
|
mtd_parts_nb = NUM_PARTITIONS;
|
||||||
part_type = "static";
|
part_type = "static";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register the partitions */
|
/* Register the partitions */
|
||||||
printk(KERN_NOTICE "Using %s partition definition\n", part_type);
|
printk(KERN_NOTICE "Using %s partition definition\n", part_type);
|
||||||
add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb);
|
add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb);
|
||||||
|
|
||||||
/* Return happy */
|
/* Return happy */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ module_init(h1910_init);
|
||||||
static void __exit h1910_cleanup (void)
|
static void __exit h1910_cleanup (void)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1];
|
struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1];
|
||||||
|
|
||||||
/* Release resources, unregister device */
|
/* Release resources, unregister device */
|
||||||
nand_release (h1910_nand_mtd);
|
nand_release (h1910_nand_mtd);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,10 +3,10 @@
|
||||||
*
|
*
|
||||||
* Overview:
|
* Overview:
|
||||||
* Bad block table support for the NAND driver
|
* Bad block table support for the NAND driver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
|
* Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
|
||||||
*
|
*
|
||||||
* $Id: nand_bbt.c,v 1.35 2005/07/15 13:53:47 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
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -14,23 +14,23 @@
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
*
|
*
|
||||||
* When nand_scan_bbt is called, then it tries to find the bad block table
|
* When nand_scan_bbt is called, then it tries to find the bad block table
|
||||||
* depending on the options in the bbt descriptor(s). If a bbt is found
|
* depending on the options in the bbt descriptor(s). If a bbt is found
|
||||||
* then the contents are read and the memory based bbt is created. If a
|
* then the contents are read and the memory based bbt is created. If a
|
||||||
* mirrored bbt is selected then the mirror is searched too and the
|
* mirrored bbt is selected then the mirror is searched too and the
|
||||||
* versions are compared. If the mirror has a greater version number
|
* versions are compared. If the mirror has a greater version number
|
||||||
* than the mirror bbt is used to build the memory based bbt.
|
* than the mirror bbt is used to build the memory based bbt.
|
||||||
* If the tables are not versioned, then we "or" the bad block information.
|
* If the tables are not versioned, then we "or" the bad block information.
|
||||||
* If one of the bbt's is out of date or does not exist it is (re)created.
|
* If one of the bbt's is out of date or does not exist it is (re)created.
|
||||||
* If no bbt exists at all then the device is scanned for factory marked
|
* If no bbt exists at all then the device is scanned for factory marked
|
||||||
* good / bad blocks and the bad block tables are created.
|
* good / bad blocks and the bad block tables are created.
|
||||||
*
|
*
|
||||||
* For manufacturer created bbts like the one found on M-SYS DOC devices
|
* For manufacturer created bbts like the one found on M-SYS DOC devices
|
||||||
* the bbt is searched and read but never created
|
* the bbt is searched and read but never created
|
||||||
*
|
*
|
||||||
* The autogenerated bad block table is located in the last good blocks
|
* The autogenerated bad block table is located in the last good blocks
|
||||||
* of the device. The table is mirrored, so it can be updated eventually.
|
* of the device. The table is mirrored, so it can be updated eventually.
|
||||||
* The table is marked in the oob area with an ident pattern and a version
|
* The table is marked in the oob area with an ident pattern and a version
|
||||||
* number which indicates which of both tables is more up to date.
|
* number which indicates which of both tables is more up to date.
|
||||||
*
|
*
|
||||||
* The table uses 2 bits per block
|
* The table uses 2 bits per block
|
||||||
|
@ -43,13 +43,13 @@
|
||||||
* 01b: block is marked bad due to wear
|
* 01b: block is marked bad due to wear
|
||||||
* 10b: block is reserved (to protect the bbt area)
|
* 10b: block is reserved (to protect the bbt area)
|
||||||
* 11b: block is factory marked bad
|
* 11b: block is factory marked bad
|
||||||
*
|
*
|
||||||
* Multichip devices like DOC store the bad block info per floor.
|
* Multichip devices like DOC store the bad block info per floor.
|
||||||
*
|
*
|
||||||
* Following assumptions are made:
|
* Following assumptions are made:
|
||||||
* - bbts start at a page boundary, if autolocated on a block boundary
|
* - 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 neccecary for a bbt in FLASH does not exceed a block boundary
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check_pattern - [GENERIC] check if a pattern is in the buffer
|
* check_pattern - [GENERIC] check if a pattern is in the buffer
|
||||||
* @buf: the buffer to search
|
* @buf: the buffer to search
|
||||||
* @len: the length of buffer to search
|
* @len: the length of buffer to search
|
||||||
|
@ -86,9 +86,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
|
||||||
if (p[i] != 0xff)
|
if (p[i] != 0xff)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p += end;
|
p += end;
|
||||||
|
|
||||||
/* Compare the pattern */
|
/* Compare the pattern */
|
||||||
for (i = 0; i < td->len; i++) {
|
for (i = 0; i < td->len; i++) {
|
||||||
if (p[i] != td->pattern[i])
|
if (p[i] != td->pattern[i])
|
||||||
|
@ -106,13 +106,13 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check_short_pattern - [GENERIC] check if a pattern is in the buffer
|
* check_short_pattern - [GENERIC] check if a pattern is in the buffer
|
||||||
* @buf: the buffer to search
|
* @buf: the buffer to search
|
||||||
* @td: search pattern descriptor
|
* @td: search pattern descriptor
|
||||||
*
|
*
|
||||||
* Check for a pattern at the given place. Used to search bad block
|
* Check for a pattern at the given place. Used to search bad block
|
||||||
* tables and good / bad block identifiers. Same as check_pattern, but
|
* tables and good / bad block identifiers. Same as check_pattern, but
|
||||||
* no optional empty check
|
* no optional empty check
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -142,7 +142,7 @@ static int check_short_pattern (uint8_t *buf, struct nand_bbt_descr *td)
|
||||||
* Read the bad block table starting from page.
|
* Read the bad block table starting from page.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
|
static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
|
||||||
int bits, int offs, int reserved_block_code)
|
int bits, int offs, int reserved_block_code)
|
||||||
{
|
{
|
||||||
int res, i, j, act = 0;
|
int res, i, j, act = 0;
|
||||||
|
@ -153,7 +153,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
|
||||||
|
|
||||||
totlen = (num * bits) >> 3;
|
totlen = (num * bits) >> 3;
|
||||||
from = ((loff_t)page) << this->page_shift;
|
from = ((loff_t)page) << this->page_shift;
|
||||||
|
|
||||||
while (totlen) {
|
while (totlen) {
|
||||||
len = min (totlen, (size_t) (1 << this->bbt_erase_shift));
|
len = min (totlen, (size_t) (1 << this->bbt_erase_shift));
|
||||||
res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob);
|
res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob);
|
||||||
|
@ -163,7 +163,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
|
||||||
return res;
|
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 */
|
/* Analyse data */
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
|
@ -183,12 +183,12 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
|
||||||
* message to MTD_DEBUG_LEVEL0 */
|
* message to MTD_DEBUG_LEVEL0 */
|
||||||
printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n",
|
printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n",
|
||||||
((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
|
((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
|
||||||
/* Factory marked bad or worn out ? */
|
/* Factory marked bad or worn out ? */
|
||||||
if (tmp == 0)
|
if (tmp == 0)
|
||||||
this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
|
this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
|
||||||
else
|
else
|
||||||
this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
|
this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
totlen -= len;
|
totlen -= len;
|
||||||
from += len;
|
from += len;
|
||||||
|
@ -200,7 +200,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
|
||||||
* read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
|
* read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @buf: temporary buffer
|
* @buf: temporary buffer
|
||||||
* @td: descriptor for the bad block table
|
* @td: descriptor for the bad block table
|
||||||
* @chip: read the table for a specific chip, -1 read all chips.
|
* @chip: read the table for a specific chip, -1 read all chips.
|
||||||
* Applies only if NAND_BBT_PERCHIP option is set
|
* Applies only if NAND_BBT_PERCHIP option is set
|
||||||
*
|
*
|
||||||
|
@ -235,7 +235,7 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
|
||||||
* read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
|
* read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @buf: temporary buffer
|
* @buf: temporary buffer
|
||||||
* @td: descriptor for the bad block table
|
* @td: descriptor for the bad block table
|
||||||
* @md: descriptor for the bad block table mirror
|
* @md: descriptor for the bad block table mirror
|
||||||
*
|
*
|
||||||
* Read the bad block table(s) for all chips starting at a given page
|
* Read the bad block table(s) for all chips starting at a given page
|
||||||
|
@ -247,16 +247,16 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
|
||||||
/* Read the primary version, if available */
|
/* Read the primary version, if available */
|
||||||
if (td->options & NAND_BBT_VERSION) {
|
if (td->options & NAND_BBT_VERSION) {
|
||||||
nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
|
nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
|
||||||
td->version[0] = buf[mtd->oobblock + td->veroffs];
|
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]);
|
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 */
|
/* Read the mirror version, if available */
|
||||||
if (md && (md->options & NAND_BBT_VERSION)) {
|
if (md && (md->options & NAND_BBT_VERSION)) {
|
||||||
nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
|
nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
|
||||||
md->version[0] = buf[mtd->oobblock + md->veroffs];
|
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]);
|
printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]);
|
||||||
}
|
}
|
||||||
|
@ -290,7 +290,7 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
|
||||||
else {
|
else {
|
||||||
if (bd->options & NAND_BBT_SCAN2NDPAGE)
|
if (bd->options & NAND_BBT_SCAN2NDPAGE)
|
||||||
len = 2;
|
len = 2;
|
||||||
else
|
else
|
||||||
len = 1;
|
len = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,10 +322,10 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
|
||||||
numblocks += startblock;
|
numblocks += startblock;
|
||||||
from = startblock << (this->bbt_erase_shift - 1);
|
from = startblock << (this->bbt_erase_shift - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = startblock; i < numblocks;) {
|
for (i = startblock; i < numblocks;) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (bd->options & NAND_BBT_SCANEMPTY)
|
if (bd->options & NAND_BBT_SCANEMPTY)
|
||||||
if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen)))
|
if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen)))
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -333,8 +333,8 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
|
||||||
for (j = 0; j < len; j++) {
|
for (j = 0; j < len; j++) {
|
||||||
if (!(bd->options & NAND_BBT_SCANEMPTY)) {
|
if (!(bd->options & NAND_BBT_SCANEMPTY)) {
|
||||||
size_t retlen;
|
size_t retlen;
|
||||||
|
|
||||||
/* Read the full oob until read_oob is fixed to
|
/* Read the full oob until read_oob is fixed to
|
||||||
* handle single byte reads for 16 bit buswidth */
|
* handle single byte reads for 16 bit buswidth */
|
||||||
ret = mtd->read_oob(mtd, from + j * mtd->oobblock,
|
ret = mtd->read_oob(mtd, from + j * mtd->oobblock,
|
||||||
mtd->oobsize, &retlen, buf);
|
mtd->oobsize, &retlen, buf);
|
||||||
|
@ -343,14 +343,14 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
|
||||||
|
|
||||||
if (check_short_pattern (buf, bd)) {
|
if (check_short_pattern (buf, bd)) {
|
||||||
this->bbt[i >> 3] |= 0x03 << (i & 0x6);
|
this->bbt[i >> 3] |= 0x03 << (i & 0x6);
|
||||||
printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
|
printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
|
||||||
i >> 1, (unsigned int) from);
|
i >> 1, (unsigned int) from);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
|
if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
|
||||||
this->bbt[i >> 3] |= 0x03 << (i & 0x6);
|
this->bbt[i >> 3] |= 0x03 << (i & 0x6);
|
||||||
printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
|
printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
|
||||||
i >> 1, (unsigned int) from);
|
i >> 1, (unsigned int) from);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -369,15 +369,15 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
|
||||||
* @td: descriptor for the bad block table
|
* @td: descriptor for the bad block table
|
||||||
*
|
*
|
||||||
* Read the bad block table by searching for a given ident pattern.
|
* Read the bad block table by searching for a given ident pattern.
|
||||||
* Search is preformed either from the beginning up or from the end of
|
* Search is preformed either from the beginning up or from the end of
|
||||||
* the device downwards. The search starts always at the start of a
|
* the device downwards. The search starts always at the start of a
|
||||||
* block.
|
* block.
|
||||||
* If the option NAND_BBT_PERCHIP is given, each chip is searched
|
* If the option NAND_BBT_PERCHIP is given, each chip is searched
|
||||||
* for a bbt, which contains the bad block information of this chip.
|
* for a bbt, which contains the bad block information of this chip.
|
||||||
* This is neccecary to provide support for certain DOC devices.
|
* This is neccecary to provide support for certain DOC devices.
|
||||||
*
|
*
|
||||||
* The bbt ident pattern resides in the oob area of the first page
|
* The bbt ident pattern resides in the oob area of the first page
|
||||||
* in a block.
|
* 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)
|
||||||
{
|
{
|
||||||
|
@ -392,10 +392,10 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
|
||||||
startblock = (mtd->size >> this->bbt_erase_shift) -1;
|
startblock = (mtd->size >> this->bbt_erase_shift) -1;
|
||||||
dir = -1;
|
dir = -1;
|
||||||
} else {
|
} else {
|
||||||
startblock = 0;
|
startblock = 0;
|
||||||
dir = 1;
|
dir = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do we have a bbt per chip ? */
|
/* Do we have a bbt per chip ? */
|
||||||
if (td->options & NAND_BBT_PERCHIP) {
|
if (td->options & NAND_BBT_PERCHIP) {
|
||||||
chips = this->numchips;
|
chips = this->numchips;
|
||||||
|
@ -405,19 +405,19 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
|
||||||
chips = 1;
|
chips = 1;
|
||||||
bbtblocks = mtd->size >> this->bbt_erase_shift;
|
bbtblocks = mtd->size >> this->bbt_erase_shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Number of bits for each erase block in the bbt */
|
/* Number of bits for each erase block in the bbt */
|
||||||
bits = td->options & NAND_BBT_NRBITS_MSK;
|
bits = td->options & NAND_BBT_NRBITS_MSK;
|
||||||
|
|
||||||
for (i = 0; i < chips; i++) {
|
for (i = 0; i < chips; i++) {
|
||||||
/* Reset version information */
|
/* Reset version information */
|
||||||
td->version[i] = 0;
|
td->version[i] = 0;
|
||||||
td->pages[i] = -1;
|
td->pages[i] = -1;
|
||||||
/* Scan the maximum number of blocks */
|
/* Scan the maximum number of blocks */
|
||||||
for (block = 0; block < td->maxblocks; block++) {
|
for (block = 0; block < td->maxblocks; block++) {
|
||||||
int actblock = startblock + dir * block;
|
int actblock = startblock + dir * block;
|
||||||
/* Read first page */
|
/* Read first page */
|
||||||
nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize);
|
nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize);
|
||||||
if (!check_pattern(buf, scanlen, mtd->oobblock, td)) {
|
if (!check_pattern(buf, scanlen, mtd->oobblock, td)) {
|
||||||
td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift);
|
td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift);
|
||||||
if (td->options & NAND_BBT_VERSION) {
|
if (td->options & NAND_BBT_VERSION) {
|
||||||
|
@ -435,46 +435,46 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
|
||||||
else
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* search_read_bbts - [GENERIC] scan the device for bad block table(s)
|
* search_read_bbts - [GENERIC] scan the device for bad block table(s)
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @buf: temporary buffer
|
* @buf: temporary buffer
|
||||||
* @td: descriptor for the bad block table
|
* @td: descriptor for the bad block table
|
||||||
* @md: descriptor for the bad block table mirror
|
* @md: descriptor for the bad block table mirror
|
||||||
*
|
*
|
||||||
* Search and read the bad block table(s)
|
* Search and read the bad block table(s)
|
||||||
*/
|
*/
|
||||||
static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf,
|
static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf,
|
||||||
struct nand_bbt_descr *td, struct nand_bbt_descr *md)
|
struct nand_bbt_descr *td, struct nand_bbt_descr *md)
|
||||||
{
|
{
|
||||||
/* Search the primary table */
|
/* Search the primary table */
|
||||||
search_bbt (mtd, buf, td);
|
search_bbt (mtd, buf, td);
|
||||||
|
|
||||||
/* Search the mirror table */
|
/* Search the mirror table */
|
||||||
if (md)
|
if (md)
|
||||||
search_bbt (mtd, buf, md);
|
search_bbt (mtd, buf, md);
|
||||||
|
|
||||||
/* Force result check */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/* Force result check */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
* write_bbt - [GENERIC] (Re)write the bad block table
|
* write_bbt - [GENERIC] (Re)write the bad block table
|
||||||
*
|
*
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @buf: temporary buffer
|
* @buf: temporary buffer
|
||||||
* @td: descriptor for the bad block table
|
* @td: descriptor for the bad block table
|
||||||
* @md: descriptor for the bad block table mirror
|
* @md: descriptor for the bad block table mirror
|
||||||
* @chipsel: selector for a specific chip, -1 for all
|
* @chipsel: selector for a specific chip, -1 for all
|
||||||
*
|
*
|
||||||
* (Re)write the bad block table
|
* (Re)write the bad block table
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
|
static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
|
||||||
struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel)
|
struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
@ -493,7 +493,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
|
||||||
/* Write bad block table per chip rather than per device ? */
|
/* Write bad block table per chip rather than per device ? */
|
||||||
if (td->options & NAND_BBT_PERCHIP) {
|
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 ? */
|
/* Full device write or specific chip ? */
|
||||||
if (chipsel == -1) {
|
if (chipsel == -1) {
|
||||||
nrchips = this->numchips;
|
nrchips = this->numchips;
|
||||||
} else {
|
} else {
|
||||||
|
@ -503,19 +503,19 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
|
||||||
} else {
|
} else {
|
||||||
numblocks = (int) (mtd->size >> this->bbt_erase_shift);
|
numblocks = (int) (mtd->size >> this->bbt_erase_shift);
|
||||||
nrchips = 1;
|
nrchips = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop through the chips */
|
/* Loop through the chips */
|
||||||
for (; chip < nrchips; chip++) {
|
for (; chip < nrchips; chip++) {
|
||||||
|
|
||||||
/* There was already a version of the table, reuse the page
|
/* There was already a version of the table, reuse the page
|
||||||
* This applies for absolute placement too, as we have the
|
* This applies for absolute placement too, as we have the
|
||||||
* page nr. in td->pages.
|
* page nr. in td->pages.
|
||||||
*/
|
*/
|
||||||
if (td->pages[chip] != -1) {
|
if (td->pages[chip] != -1) {
|
||||||
page = td->pages[chip];
|
page = td->pages[chip];
|
||||||
goto write;
|
goto write;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Automatic placement of the bad block table */
|
/* Automatic placement of the bad block table */
|
||||||
/* Search direction top -> down ? */
|
/* Search direction top -> down ? */
|
||||||
|
@ -525,7 +525,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
|
||||||
} else {
|
} else {
|
||||||
startblock = chip * numblocks;
|
startblock = chip * numblocks;
|
||||||
dir = 1;
|
dir = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < td->maxblocks; i++) {
|
for (i = 0; i < td->maxblocks; i++) {
|
||||||
int block = startblock + dir * i;
|
int block = startblock + dir * i;
|
||||||
|
@ -542,7 +542,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
|
||||||
}
|
}
|
||||||
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;
|
return -ENOSPC;
|
||||||
write:
|
write:
|
||||||
|
|
||||||
/* Set up shift count and masks for the flash table */
|
/* Set up shift count and masks for the flash table */
|
||||||
bits = td->options & NAND_BBT_NRBITS_MSK;
|
bits = td->options & NAND_BBT_NRBITS_MSK;
|
||||||
|
@ -553,14 +553,14 @@ write:
|
||||||
case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break;
|
case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break;
|
||||||
default: return -EINVAL;
|
default: return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bbtoffs = chip * (numblocks >> 2);
|
bbtoffs = chip * (numblocks >> 2);
|
||||||
|
|
||||||
to = ((loff_t) page) << this->page_shift;
|
to = ((loff_t) page) << this->page_shift;
|
||||||
|
|
||||||
memcpy (&oobinfo, this->autooob, sizeof(oobinfo));
|
memcpy (&oobinfo, this->autooob, sizeof(oobinfo));
|
||||||
oobinfo.useecc = MTD_NANDECC_PLACEONLY;
|
oobinfo.useecc = MTD_NANDECC_PLACEONLY;
|
||||||
|
|
||||||
/* Must we save the block contents ? */
|
/* Must we save the block contents ? */
|
||||||
if (td->options & NAND_BBT_SAVECONTENT) {
|
if (td->options & NAND_BBT_SAVECONTENT) {
|
||||||
/* Make it block aligned */
|
/* Make it block aligned */
|
||||||
|
@ -599,7 +599,7 @@ write:
|
||||||
buf[len + td->veroffs] = td->version[chip];
|
buf[len + td->veroffs] = td->version[chip];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* walk through the memory table */
|
/* walk through the memory table */
|
||||||
for (i = 0; i < numblocks; ) {
|
for (i = 0; i < numblocks; ) {
|
||||||
uint8_t dat;
|
uint8_t dat;
|
||||||
|
@ -611,7 +611,7 @@ write:
|
||||||
dat >>= 2;
|
dat >>= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memset (&einfo, 0, sizeof (einfo));
|
memset (&einfo, 0, sizeof (einfo));
|
||||||
einfo.mtd = mtd;
|
einfo.mtd = mtd;
|
||||||
einfo.addr = (unsigned long) to;
|
einfo.addr = (unsigned long) to;
|
||||||
|
@ -621,18 +621,18 @@ write:
|
||||||
printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res);
|
printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
|
res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res);
|
printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n",
|
printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n",
|
||||||
(unsigned int) to, td->version[chip]);
|
(unsigned int) to, td->version[chip]);
|
||||||
|
|
||||||
/* Mark it as used */
|
/* Mark it as used */
|
||||||
td->pages[chip] = page;
|
td->pages[chip] = page;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -641,7 +641,7 @@ write:
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @bd: descriptor for the good/bad block search pattern
|
* @bd: descriptor for the good/bad block search pattern
|
||||||
*
|
*
|
||||||
* The function creates a memory based bbt by scanning the device
|
* The function creates a memory based bbt by scanning the device
|
||||||
* for manufacturer / software marked good / bad blocks
|
* for manufacturer / software marked good / bad blocks
|
||||||
*/
|
*/
|
||||||
static inline 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)
|
||||||
|
@ -673,11 +673,11 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
|
||||||
struct nand_bbt_descr *rd, *rd2;
|
struct nand_bbt_descr *rd, *rd2;
|
||||||
|
|
||||||
/* Do we have a bbt per chip ? */
|
/* Do we have a bbt per chip ? */
|
||||||
if (td->options & NAND_BBT_PERCHIP)
|
if (td->options & NAND_BBT_PERCHIP)
|
||||||
chips = this->numchips;
|
chips = this->numchips;
|
||||||
else
|
else
|
||||||
chips = 1;
|
chips = 1;
|
||||||
|
|
||||||
for (i = 0; i < chips; i++) {
|
for (i = 0; i < chips; i++) {
|
||||||
writeops = 0;
|
writeops = 0;
|
||||||
rd = NULL;
|
rd = NULL;
|
||||||
|
@ -692,7 +692,7 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
|
||||||
}
|
}
|
||||||
|
|
||||||
if (td->pages[i] == -1) {
|
if (td->pages[i] == -1) {
|
||||||
rd = md;
|
rd = md;
|
||||||
td->version[i] = md->version[i];
|
td->version[i] = md->version[i];
|
||||||
writeops = 1;
|
writeops = 1;
|
||||||
goto writecheck;
|
goto writecheck;
|
||||||
|
@ -710,7 +710,7 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
|
||||||
if (!(td->options & NAND_BBT_VERSION))
|
if (!(td->options & NAND_BBT_VERSION))
|
||||||
rd2 = md;
|
rd2 = md;
|
||||||
goto writecheck;
|
goto writecheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((int8_t) (td->version[i] - md->version[i])) > 0) {
|
if (((int8_t) (td->version[i] - md->version[i])) > 0) {
|
||||||
rd = td;
|
rd = td;
|
||||||
|
@ -735,15 +735,15 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
|
||||||
create:
|
create:
|
||||||
/* Create the bad block table by scanning the device ? */
|
/* Create the bad block table by scanning the device ? */
|
||||||
if (!(td->options & NAND_BBT_CREATE))
|
if (!(td->options & NAND_BBT_CREATE))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Create the table in memory by scanning the chip(s) */
|
/* 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;
|
td->version[i] = 1;
|
||||||
if (md)
|
if (md)
|
||||||
md->version[i] = 1;
|
md->version[i] = 1;
|
||||||
writecheck:
|
writecheck:
|
||||||
/* read back first ? */
|
/* read back first ? */
|
||||||
if (rd)
|
if (rd)
|
||||||
read_abs_bbt (mtd, buf, rd, chipsel);
|
read_abs_bbt (mtd, buf, rd, chipsel);
|
||||||
|
@ -757,7 +757,7 @@ writecheck:
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the mirror bad block table to the device ? */
|
/* Write the mirror bad block table to the device ? */
|
||||||
if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
|
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);
|
||||||
|
@ -765,11 +765,11 @@ writecheck:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mark_bbt_regions - [GENERIC] mark the bad block table regions
|
* mark_bbt_regions - [GENERIC] mark the bad block table regions
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @td: bad block table descriptor
|
* @td: bad block table descriptor
|
||||||
*
|
*
|
||||||
|
@ -790,14 +790,14 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
|
||||||
} else {
|
} else {
|
||||||
chips = 1;
|
chips = 1;
|
||||||
nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
|
nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < chips; i++) {
|
for (i = 0; i < chips; i++) {
|
||||||
if ((td->options & NAND_BBT_ABSPAGE) ||
|
if ((td->options & NAND_BBT_ABSPAGE) ||
|
||||||
!(td->options & NAND_BBT_WRITE)) {
|
!(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 = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
|
||||||
block <<= 1;
|
block <<= 1;
|
||||||
oldval = this->bbt[(block >> 3)];
|
oldval = this->bbt[(block >> 3)];
|
||||||
newval = oldval | (0x2 << (block & 0x06));
|
newval = oldval | (0x2 << (block & 0x06));
|
||||||
this->bbt[(block >> 3)] = newval;
|
this->bbt[(block >> 3)] = newval;
|
||||||
|
@ -808,16 +808,16 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
|
||||||
update = 0;
|
update = 0;
|
||||||
if (td->options & NAND_BBT_LASTBLOCK)
|
if (td->options & NAND_BBT_LASTBLOCK)
|
||||||
block = ((i + 1) * nrblocks) - td->maxblocks;
|
block = ((i + 1) * nrblocks) - td->maxblocks;
|
||||||
else
|
else
|
||||||
block = i * nrblocks;
|
block = i * nrblocks;
|
||||||
block <<= 1;
|
block <<= 1;
|
||||||
for (j = 0; j < td->maxblocks; j++) {
|
for (j = 0; j < td->maxblocks; j++) {
|
||||||
oldval = this->bbt[(block >> 3)];
|
oldval = this->bbt[(block >> 3)];
|
||||||
newval = oldval | (0x2 << (block & 0x06));
|
newval = oldval | (0x2 << (block & 0x06));
|
||||||
this->bbt[(block >> 3)] = newval;
|
this->bbt[(block >> 3)] = newval;
|
||||||
if (oldval != newval) update = 1;
|
if (oldval != newval) update = 1;
|
||||||
block += 2;
|
block += 2;
|
||||||
}
|
}
|
||||||
/* If we want reserved blocks to be recorded to flash, and some
|
/* If we want reserved blocks to be recorded to flash, and some
|
||||||
new ones have been marked, then we need to update the stored
|
new ones have been marked, then we need to update the stored
|
||||||
bbts. This should only happen once. */
|
bbts. This should only happen once. */
|
||||||
|
@ -831,7 +831,7 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @bd: descriptor for the good/bad block search pattern
|
* @bd: descriptor for the good/bad block search pattern
|
||||||
*
|
*
|
||||||
* The function checks, if a bad block table(s) is/are already
|
* The function checks, if a bad block table(s) is/are already
|
||||||
* available. If not it scans the device for manufacturer
|
* available. If not it scans the device for manufacturer
|
||||||
* marked good / bad blocks and writes the bad block table(s) to
|
* marked good / bad blocks and writes the bad block table(s) to
|
||||||
* the selected place.
|
* the selected place.
|
||||||
|
@ -880,30 +880,30 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||||
this->bbt = NULL;
|
this->bbt = NULL;
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is the bbt at a given page ? */
|
/* Is the bbt at a given page ? */
|
||||||
if (td->options & NAND_BBT_ABSPAGE) {
|
if (td->options & NAND_BBT_ABSPAGE) {
|
||||||
res = read_abs_bbts (mtd, buf, td, md);
|
res = read_abs_bbts (mtd, buf, td, md);
|
||||||
} else {
|
} else {
|
||||||
/* Search the bad block table using a pattern in oob */
|
/* 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)
|
if (res)
|
||||||
res = check_create (mtd, buf, bd);
|
res = check_create (mtd, buf, bd);
|
||||||
|
|
||||||
/* Prevent the bbt regions from erasing / writing */
|
/* Prevent the bbt regions from erasing / writing */
|
||||||
mark_bbt_region (mtd, td);
|
mark_bbt_region (mtd, td);
|
||||||
if (md)
|
if (md)
|
||||||
mark_bbt_region (mtd, md);
|
mark_bbt_region (mtd, md);
|
||||||
|
|
||||||
kfree (buf);
|
kfree (buf);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_update_bbt - [NAND Interface] update bad block table(s)
|
* nand_update_bbt - [NAND Interface] update bad block table(s)
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @offs: the offset of the newly marked block
|
* @offs: the offset of the newly marked block
|
||||||
*
|
*
|
||||||
|
@ -930,7 +930,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
|
||||||
printk (KERN_ERR "nand_update_bbt: Out of memory\n");
|
printk (KERN_ERR "nand_update_bbt: Out of memory\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeops = md != NULL ? 0x03 : 0x01;
|
writeops = md != NULL ? 0x03 : 0x01;
|
||||||
|
|
||||||
/* Do we have a bbt per chip ? */
|
/* Do we have a bbt per chip ? */
|
||||||
|
@ -944,7 +944,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
|
||||||
|
|
||||||
td->version[chip]++;
|
td->version[chip]++;
|
||||||
if (md)
|
if (md)
|
||||||
md->version[chip]++;
|
md->version[chip]++;
|
||||||
|
|
||||||
/* Write the bad block table to the device ? */
|
/* Write the bad block table to the device ? */
|
||||||
if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
|
if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
|
||||||
|
@ -957,12 +957,12 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
|
||||||
res = write_bbt (mtd, buf, md, td, chipsel);
|
res = write_bbt (mtd, buf, md, td, chipsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree (buf);
|
kfree (buf);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Define some generic bad / good block scan pattern which are used
|
/* Define some generic bad / good block scan pattern which are used
|
||||||
* while scanning a device for factory marked good / bad blocks. */
|
* while scanning a device for factory marked good / bad blocks. */
|
||||||
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
|
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
|
||||||
|
|
||||||
|
@ -1009,7 +1009,7 @@ static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
|
||||||
static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
|
static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
|
||||||
|
|
||||||
static struct nand_bbt_descr bbt_main_descr = {
|
static struct nand_bbt_descr bbt_main_descr = {
|
||||||
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
|
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
|
||||||
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
|
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
|
||||||
.offs = 8,
|
.offs = 8,
|
||||||
.len = 4,
|
.len = 4,
|
||||||
|
@ -1019,7 +1019,7 @@ static struct nand_bbt_descr bbt_main_descr = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct nand_bbt_descr bbt_mirror_descr = {
|
static struct nand_bbt_descr bbt_mirror_descr = {
|
||||||
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
|
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
|
||||||
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
|
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
|
||||||
.offs = 8,
|
.offs = 8,
|
||||||
.len = 4,
|
.len = 4,
|
||||||
|
@ -1029,7 +1029,7 @@ static struct nand_bbt_descr bbt_mirror_descr = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_default_bbt - [NAND Interface] Select a default bad block table for the device
|
* nand_default_bbt - [NAND Interface] Select a default bad block table for the device
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
*
|
*
|
||||||
* This function selects the default bad block table
|
* This function selects the default bad block table
|
||||||
|
@ -1039,29 +1039,29 @@ static struct nand_bbt_descr bbt_mirror_descr = {
|
||||||
int nand_default_bbt (struct mtd_info *mtd)
|
int nand_default_bbt (struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
|
|
||||||
/* Default for AG-AND. We must use a flash based
|
/* Default for AG-AND. We must use a flash based
|
||||||
* bad block table as the devices have factory marked
|
* bad block table as the devices have factory marked
|
||||||
* _good_ blocks. Erasing those blocks leads to loss
|
* _good_ blocks. Erasing those blocks leads to loss
|
||||||
* of the good / bad information, so we _must_ store
|
* of the good / bad information, so we _must_ store
|
||||||
* this information in a good / bad table during
|
* this information in a good / bad table during
|
||||||
* startup
|
* startup
|
||||||
*/
|
*/
|
||||||
if (this->options & NAND_IS_AND) {
|
if (this->options & NAND_IS_AND) {
|
||||||
/* Use the default pattern descriptors */
|
/* Use the default pattern descriptors */
|
||||||
if (!this->bbt_td) {
|
if (!this->bbt_td) {
|
||||||
this->bbt_td = &bbt_main_descr;
|
this->bbt_td = &bbt_main_descr;
|
||||||
this->bbt_md = &bbt_mirror_descr;
|
this->bbt_md = &bbt_mirror_descr;
|
||||||
}
|
}
|
||||||
this->options |= NAND_USE_FLASH_BBT;
|
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 ? */
|
/* Is a flash based bad block table requested ? */
|
||||||
if (this->options & NAND_USE_FLASH_BBT) {
|
if (this->options & NAND_USE_FLASH_BBT) {
|
||||||
/* Use the default pattern descriptors */
|
/* Use the default pattern descriptors */
|
||||||
if (!this->bbt_td) {
|
if (!this->bbt_td) {
|
||||||
this->bbt_td = &bbt_main_descr;
|
this->bbt_td = &bbt_main_descr;
|
||||||
this->bbt_md = &bbt_mirror_descr;
|
this->bbt_md = &bbt_mirror_descr;
|
||||||
}
|
}
|
||||||
|
@ -1081,7 +1081,7 @@ int nand_default_bbt (struct mtd_info *mtd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_isbad_bbt - [NAND Interface] Check if a block is bad
|
* nand_isbad_bbt - [NAND Interface] Check if a block is bad
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @offs: offset in the device
|
* @offs: offset in the device
|
||||||
* @allowbbt: allow access to bad block table region
|
* @allowbbt: allow access to bad block table region
|
||||||
|
@ -1092,12 +1092,12 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
int block;
|
int block;
|
||||||
uint8_t res;
|
uint8_t res;
|
||||||
|
|
||||||
/* Get block number * 2 */
|
/* 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;
|
res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
|
||||||
|
|
||||||
DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
|
DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
|
||||||
(unsigned int)offs, block >> 1, res);
|
(unsigned int)offs, block >> 1, res);
|
||||||
|
|
||||||
switch ((int)res) {
|
switch ((int)res) {
|
||||||
|
|
|
@ -7,22 +7,22 @@
|
||||||
* Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
|
* Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
|
||||||
* Toshiba America Electronics Components, Inc.
|
* Toshiba America Electronics Components, Inc.
|
||||||
*
|
*
|
||||||
* $Id: nand_ecc.c,v 1.14 2004/06/16 15:34:37 gleixner Exp $
|
* $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
|
* 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
|
* under the terms of the GNU General Public License as published by the
|
||||||
* Free Software Foundation; either version 2 or (at your option) any
|
* Free Software Foundation; either version 2 or (at your option) any
|
||||||
* later version.
|
* later version.
|
||||||
*
|
*
|
||||||
* This file is distributed in the hope that it will be useful, but WITHOUT
|
* This file is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
* for more details.
|
* for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along
|
* You should have received a copy of the GNU General Public License along
|
||||||
* with this file; if not, write to the Free Software Foundation, Inc.,
|
* with this file; if not, write to the Free Software Foundation, Inc.,
|
||||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
*
|
*
|
||||||
* As a special exception, if other files instantiate templates or use
|
* As a special exception, if other files instantiate templates or use
|
||||||
* macros or inline functions from these files, or you compile these
|
* macros or inline functions from these files, or you compile these
|
||||||
* files and link them with other works to produce a work based on these
|
* files and link them with other works to produce a work based on these
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
* covered by the GNU General Public License. However the source code for
|
* covered by the GNU General Public License. However the source code for
|
||||||
* these files must still be made available in accordance with section (3)
|
* these files must still be made available in accordance with section (3)
|
||||||
* of the GNU General Public License.
|
* of the GNU General Public License.
|
||||||
*
|
*
|
||||||
* This exception does not invalidate any other reasons why a work based on
|
* This exception does not invalidate any other reasons why a work based on
|
||||||
* this file might be covered by the GNU General Public License.
|
* this file might be covered by the GNU General Public License.
|
||||||
*/
|
*/
|
||||||
|
@ -67,7 +67,7 @@ static const u_char nand_ecc_precalc_table[] = {
|
||||||
* nand_trans_result - [GENERIC] create non-inverted ECC
|
* nand_trans_result - [GENERIC] create non-inverted ECC
|
||||||
* @reg2: line parity reg 2
|
* @reg2: line parity reg 2
|
||||||
* @reg3: line parity reg 3
|
* @reg3: line parity reg 3
|
||||||
* @ecc_code: ecc
|
* @ecc_code: ecc
|
||||||
*
|
*
|
||||||
* Creates non-inverted ECC code from line parity
|
* Creates non-inverted ECC code from line parity
|
||||||
*/
|
*/
|
||||||
|
@ -75,11 +75,11 @@ static void nand_trans_result(u_char reg2, u_char reg3,
|
||||||
u_char *ecc_code)
|
u_char *ecc_code)
|
||||||
{
|
{
|
||||||
u_char a, b, i, tmp1, tmp2;
|
u_char a, b, i, tmp1, tmp2;
|
||||||
|
|
||||||
/* Initialize variables */
|
/* Initialize variables */
|
||||||
a = b = 0x80;
|
a = b = 0x80;
|
||||||
tmp1 = tmp2 = 0;
|
tmp1 = tmp2 = 0;
|
||||||
|
|
||||||
/* Calculate first ECC byte */
|
/* Calculate first ECC byte */
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */
|
if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */
|
||||||
|
@ -90,7 +90,7 @@ static void nand_trans_result(u_char reg2, u_char reg3,
|
||||||
b >>= 1;
|
b >>= 1;
|
||||||
a >>= 1;
|
a >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate second ECC byte */
|
/* Calculate second ECC byte */
|
||||||
b = 0x80;
|
b = 0x80;
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
|
@ -102,7 +102,7 @@ static void nand_trans_result(u_char reg2, u_char reg3,
|
||||||
b >>= 1;
|
b >>= 1;
|
||||||
a >>= 1;
|
a >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store two of the ECC bytes */
|
/* Store two of the ECC bytes */
|
||||||
ecc_code[0] = tmp1;
|
ecc_code[0] = tmp1;
|
||||||
ecc_code[1] = tmp2;
|
ecc_code[1] = tmp2;
|
||||||
|
@ -118,28 +118,28 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code
|
||||||
{
|
{
|
||||||
u_char idx, reg1, reg2, reg3;
|
u_char idx, reg1, reg2, reg3;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
/* Initialize variables */
|
/* Initialize variables */
|
||||||
reg1 = reg2 = reg3 = 0;
|
reg1 = reg2 = reg3 = 0;
|
||||||
ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
|
ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
|
||||||
|
|
||||||
/* Build up column parity */
|
/* Build up column parity */
|
||||||
for(j = 0; j < 256; j++) {
|
for(j = 0; j < 256; j++) {
|
||||||
|
|
||||||
/* Get CP0 - CP5 from table */
|
/* Get CP0 - CP5 from table */
|
||||||
idx = nand_ecc_precalc_table[dat[j]];
|
idx = nand_ecc_precalc_table[dat[j]];
|
||||||
reg1 ^= (idx & 0x3f);
|
reg1 ^= (idx & 0x3f);
|
||||||
|
|
||||||
/* All bit XOR = 1 ? */
|
/* All bit XOR = 1 ? */
|
||||||
if (idx & 0x40) {
|
if (idx & 0x40) {
|
||||||
reg3 ^= (u_char) j;
|
reg3 ^= (u_char) j;
|
||||||
reg2 ^= ~((u_char) j);
|
reg2 ^= ~((u_char) j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create non-inverted ECC code from line parity */
|
/* Create non-inverted ECC code from line parity */
|
||||||
nand_trans_result(reg2, reg3, ecc_code);
|
nand_trans_result(reg2, reg3, ecc_code);
|
||||||
|
|
||||||
/* Calculate final ECC code */
|
/* Calculate final ECC code */
|
||||||
ecc_code[0] = ~ecc_code[0];
|
ecc_code[0] = ~ecc_code[0];
|
||||||
ecc_code[1] = ~ecc_code[1];
|
ecc_code[1] = ~ecc_code[1];
|
||||||
|
@ -159,12 +159,12 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code
|
||||||
int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
|
int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
|
||||||
{
|
{
|
||||||
u_char a, b, c, d1, d2, d3, add, bit, i;
|
u_char a, b, c, d1, d2, d3, add, bit, i;
|
||||||
|
|
||||||
/* Do error detection */
|
/* Do error detection */
|
||||||
d1 = calc_ecc[0] ^ read_ecc[0];
|
d1 = calc_ecc[0] ^ read_ecc[0];
|
||||||
d2 = calc_ecc[1] ^ read_ecc[1];
|
d2 = calc_ecc[1] ^ read_ecc[1];
|
||||||
d3 = calc_ecc[2] ^ read_ecc[2];
|
d3 = calc_ecc[2] ^ read_ecc[2];
|
||||||
|
|
||||||
if ((d1 | d2 | d3) == 0) {
|
if ((d1 | d2 | d3) == 0) {
|
||||||
/* No errors */
|
/* No errors */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -173,7 +173,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha
|
||||||
a = (d1 ^ (d1 >> 1)) & 0x55;
|
a = (d1 ^ (d1 >> 1)) & 0x55;
|
||||||
b = (d2 ^ (d2 >> 1)) & 0x55;
|
b = (d2 ^ (d2 >> 1)) & 0x55;
|
||||||
c = (d3 ^ (d3 >> 1)) & 0x54;
|
c = (d3 ^ (d3 >> 1)) & 0x54;
|
||||||
|
|
||||||
/* Found and will correct single bit error in the data */
|
/* Found and will correct single bit error in the data */
|
||||||
if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
|
if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
|
||||||
c = 0x80;
|
c = 0x80;
|
||||||
|
@ -237,7 +237,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Should never happen */
|
/* Should never happen */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
|
* Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
|
||||||
*
|
*
|
||||||
* $Id: nand_ids.c,v 1.14 2005/06/23 09:38:50 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
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -14,14 +14,14 @@
|
||||||
#include <linux/mtd/nand.h>
|
#include <linux/mtd/nand.h>
|
||||||
/*
|
/*
|
||||||
* Chip ID list
|
* Chip ID list
|
||||||
*
|
*
|
||||||
* Name. ID code, pagesize, chipsize in MegaByte, eraseblock size,
|
* Name. ID code, pagesize, chipsize in MegaByte, eraseblock size,
|
||||||
* options
|
* options
|
||||||
*
|
*
|
||||||
* Pagesize; 0, 256, 512
|
* Pagesize; 0, 256, 512
|
||||||
* 0 get this information from the extended chip ID
|
* 0 get this information from the extended chip ID
|
||||||
+ 256 256 Byte page size
|
+ 256 256 Byte page size
|
||||||
* 512 512 Byte page size
|
* 512 512 Byte page size
|
||||||
*/
|
*/
|
||||||
struct nand_flash_dev nand_flash_ids[] = {
|
struct nand_flash_dev nand_flash_ids[] = {
|
||||||
{"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
|
{"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
|
||||||
|
@ -34,27 +34,27 @@ struct nand_flash_dev nand_flash_ids[] = {
|
||||||
{"NAND 4MiB 3,3V 8-bit", 0xe3, 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 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0},
|
||||||
{"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0},
|
{"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0},
|
||||||
|
|
||||||
{"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0},
|
{"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0},
|
||||||
{"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},
|
{"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 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
|
||||||
{"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
|
{"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
|
||||||
|
|
||||||
{"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
|
{"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
|
||||||
{"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
|
{"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
|
||||||
{"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
|
{"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
|
||||||
{"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
|
{"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
|
||||||
|
|
||||||
{"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0},
|
{"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0},
|
||||||
{"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0},
|
{"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0},
|
||||||
{"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
|
{"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
|
||||||
{"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
|
{"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
|
||||||
|
|
||||||
{"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0},
|
{"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0},
|
||||||
{"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},
|
{"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},
|
||||||
{"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
|
{"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
|
||||||
{"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
|
{"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", 0x78, 512, 128, 0x4000, 0},
|
||||||
{"NAND 128MiB 1,8V 8-bit", 0x39, 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 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0},
|
||||||
|
@ -62,7 +62,7 @@ struct nand_flash_dev nand_flash_ids[] = {
|
||||||
{"NAND 128MiB 1,8V 16-bit", 0x49, 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", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
|
||||||
{"NAND 128MiB 3,3V 16-bit", 0x59, 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},
|
{"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
|
||||||
|
|
||||||
/* These are the new chips with large page size. The pagesize
|
/* These are the new chips with large page size. The pagesize
|
||||||
|
@ -73,7 +73,7 @@ struct nand_flash_dev nand_flash_ids[] = {
|
||||||
{"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
|
{"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
|
||||||
{"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
|
{"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
|
||||||
{"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
|
{"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
|
||||||
|
|
||||||
/* 1 Gigabit */
|
/* 1 Gigabit */
|
||||||
{"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
|
{"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 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
|
||||||
|
@ -85,13 +85,13 @@ struct nand_flash_dev nand_flash_ids[] = {
|
||||||
{"NAND 256MiB 3,3V 8-bit", 0xDA, 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 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 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
|
||||||
|
|
||||||
/* 4 Gigabit */
|
/* 4 Gigabit */
|
||||||
{"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
|
{"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 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 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 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
|
||||||
|
|
||||||
/* 8 Gigabit */
|
/* 8 Gigabit */
|
||||||
{"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
|
{"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 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
|
||||||
|
@ -104,11 +104,11 @@ struct nand_flash_dev nand_flash_ids[] = {
|
||||||
{"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | 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 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
|
||||||
|
|
||||||
/* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout !
|
/* 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
|
* 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
|
* 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
|
* 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
|
* 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 | BBT_AUTO_REFRESH},
|
{"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org>
|
* Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org>
|
||||||
*
|
*
|
||||||
* Copyright (C) 2004 Nokia Corporation
|
* Copyright (C) 2004 Nokia Corporation
|
||||||
*
|
*
|
||||||
* Note: NS means "NAND Simulator".
|
* Note: NS means "NAND Simulator".
|
||||||
* Note: Input means input TO flash chip, output means output FROM chip.
|
* Note: Input means input TO flash chip, output means output FROM chip.
|
||||||
|
@ -126,7 +126,7 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero");
|
||||||
|
|
||||||
/* The largest possible page size */
|
/* The largest possible page size */
|
||||||
#define NS_LARGEST_PAGE_SIZE 2048
|
#define NS_LARGEST_PAGE_SIZE 2048
|
||||||
|
|
||||||
/* The prefix for simulator output */
|
/* The prefix for simulator output */
|
||||||
#define NS_OUTPUT_PREFIX "[nandsim]"
|
#define NS_OUTPUT_PREFIX "[nandsim]"
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero");
|
||||||
do { if (do_delays) udelay(us); } while(0)
|
do { if (do_delays) udelay(us); } while(0)
|
||||||
#define NS_MDELAY(us) \
|
#define NS_MDELAY(us) \
|
||||||
do { if (do_delays) mdelay(us); } while(0)
|
do { if (do_delays) mdelay(us); } while(0)
|
||||||
|
|
||||||
/* Is the nandsim structure initialized ? */
|
/* Is the nandsim structure initialized ? */
|
||||||
#define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0)
|
#define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0)
|
||||||
|
|
||||||
|
@ -153,12 +153,12 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero");
|
||||||
#define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0)))
|
#define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0)))
|
||||||
|
|
||||||
/* Operation failed completion status */
|
/* Operation failed completion status */
|
||||||
#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns))
|
#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns))
|
||||||
|
|
||||||
/* Calculate the page offset in flash RAM image by (row, column) address */
|
/* Calculate the page offset in flash RAM image by (row, column) address */
|
||||||
#define NS_RAW_OFFSET(ns) \
|
#define NS_RAW_OFFSET(ns) \
|
||||||
(((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column)
|
(((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column)
|
||||||
|
|
||||||
/* Calculate the OOB offset in flash RAM image by (row, column) address */
|
/* Calculate the OOB offset in flash RAM image by (row, column) address */
|
||||||
#define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
|
#define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
|
||||||
|
|
||||||
|
@ -223,15 +223,15 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero");
|
||||||
|
|
||||||
/* Remove action bits ftom state */
|
/* Remove action bits ftom state */
|
||||||
#define NS_STATE(x) ((x) & ~ACTION_MASK)
|
#define NS_STATE(x) ((x) & ~ACTION_MASK)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Maximum previous states which need to be saved. Currently saving is
|
* Maximum previous states which need to be saved. Currently saving is
|
||||||
* only needed for page programm operation with preceeded read command
|
* only needed for page programm operation with preceeded read command
|
||||||
* (which is only valid for 512-byte pages).
|
* (which is only valid for 512-byte pages).
|
||||||
*/
|
*/
|
||||||
#define NS_MAX_PREVSTATES 1
|
#define NS_MAX_PREVSTATES 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The structure which describes all the internal simulator data.
|
* The structure which describes all the internal simulator data.
|
||||||
*/
|
*/
|
||||||
struct nandsim {
|
struct nandsim {
|
||||||
|
@ -242,7 +242,7 @@ struct nandsim {
|
||||||
uint32_t options; /* chip's characteristic bits */
|
uint32_t options; /* chip's characteristic bits */
|
||||||
uint32_t state; /* current chip state */
|
uint32_t state; /* current chip state */
|
||||||
uint32_t nxstate; /* next expected state */
|
uint32_t nxstate; /* next expected state */
|
||||||
|
|
||||||
uint32_t *op; /* current operation, NULL operations isn't known yet */
|
uint32_t *op; /* current operation, NULL operations isn't known yet */
|
||||||
uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */
|
uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */
|
||||||
uint16_t npstates; /* number of previous states saved */
|
uint16_t npstates; /* number of previous states saved */
|
||||||
|
@ -413,7 +413,7 @@ init_nandsim(struct mtd_info *mtd)
|
||||||
ns->geom.secaddrbytes = 3;
|
ns->geom.secaddrbytes = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detect how many ID bytes the NAND chip outputs */
|
/* Detect how many ID bytes the NAND chip outputs */
|
||||||
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
|
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
|
||||||
if (second_id_byte != nand_flash_ids[i].id)
|
if (second_id_byte != nand_flash_ids[i].id)
|
||||||
|
@ -444,7 +444,7 @@ init_nandsim(struct mtd_info *mtd)
|
||||||
#ifdef CONFIG_NS_ABS_POS
|
#ifdef CONFIG_NS_ABS_POS
|
||||||
ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob);
|
ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob);
|
||||||
if (!ns->mem.byte) {
|
if (!ns->mem.byte) {
|
||||||
NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n",
|
NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n",
|
||||||
(void *)CONFIG_NS_ABS_POS);
|
(void *)CONFIG_NS_ABS_POS);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
@ -567,7 +567,7 @@ static int
|
||||||
check_command(int cmd)
|
check_command(int cmd)
|
||||||
{
|
{
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
|
||||||
case NAND_CMD_READ0:
|
case NAND_CMD_READ0:
|
||||||
case NAND_CMD_READSTART:
|
case NAND_CMD_READSTART:
|
||||||
case NAND_CMD_PAGEPROG:
|
case NAND_CMD_PAGEPROG:
|
||||||
|
@ -580,7 +580,7 @@ check_command(int cmd)
|
||||||
case NAND_CMD_RESET:
|
case NAND_CMD_RESET:
|
||||||
case NAND_CMD_READ1:
|
case NAND_CMD_READ1:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case NAND_CMD_STATUS_MULTI:
|
case NAND_CMD_STATUS_MULTI:
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -631,7 +631,7 @@ static inline void
|
||||||
accept_addr_byte(struct nandsim *ns, u_char bt)
|
accept_addr_byte(struct nandsim *ns, u_char bt)
|
||||||
{
|
{
|
||||||
uint byte = (uint)bt;
|
uint byte = (uint)bt;
|
||||||
|
|
||||||
if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes))
|
if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes))
|
||||||
ns->regs.column |= (byte << 8 * ns->regs.count);
|
ns->regs.column |= (byte << 8 * ns->regs.count);
|
||||||
else {
|
else {
|
||||||
|
@ -642,11 +642,11 @@ accept_addr_byte(struct nandsim *ns, u_char bt)
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Switch to STATE_READY state.
|
* Switch to STATE_READY state.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
switch_to_ready_state(struct nandsim *ns, u_char status)
|
switch_to_ready_state(struct nandsim *ns, u_char status)
|
||||||
{
|
{
|
||||||
NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
|
NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
|
||||||
|
@ -675,7 +675,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status)
|
||||||
* (for example program from the second half and read from the
|
* (for example program from the second half and read from the
|
||||||
* second half operations both begin with the READ1 command). In this
|
* second half operations both begin with the READ1 command). In this
|
||||||
* case the ns->pstates[] array contains previous states.
|
* case the ns->pstates[] array contains previous states.
|
||||||
*
|
*
|
||||||
* Thus, the function tries to find operation containing the following
|
* Thus, the function tries to find operation containing the following
|
||||||
* states (if the 'flag' parameter is 0):
|
* states (if the 'flag' parameter is 0):
|
||||||
* ns->pstates[0], ... ns->pstates[ns->npstates], ns->state
|
* ns->pstates[0], ... ns->pstates[ns->npstates], ns->state
|
||||||
|
@ -683,7 +683,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status)
|
||||||
* If (one and only one) matching operation is found, it is accepted (
|
* If (one and only one) matching operation is found, it is accepted (
|
||||||
* ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is
|
* ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is
|
||||||
* zeroed).
|
* zeroed).
|
||||||
*
|
*
|
||||||
* If there are several maches, the current state is pushed to the
|
* If there are several maches, the current state is pushed to the
|
||||||
* ns->pstates.
|
* ns->pstates.
|
||||||
*
|
*
|
||||||
|
@ -692,7 +692,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status)
|
||||||
* In such situation the function is called with 'flag' != 0, and the
|
* In such situation the function is called with 'flag' != 0, and the
|
||||||
* operation is searched using the following pattern:
|
* operation is searched using the following pattern:
|
||||||
* ns->pstates[0], ... ns->pstates[ns->npstates], <address input>
|
* ns->pstates[0], ... ns->pstates[ns->npstates], <address input>
|
||||||
*
|
*
|
||||||
* It is supposed that this pattern must either match one operation on
|
* It is supposed that this pattern must either match one operation on
|
||||||
* none. There can't be ambiguity in that case.
|
* none. There can't be ambiguity in that case.
|
||||||
*
|
*
|
||||||
|
@ -711,15 +711,15 @@ find_operation(struct nandsim *ns, uint32_t flag)
|
||||||
{
|
{
|
||||||
int opsfound = 0;
|
int opsfound = 0;
|
||||||
int i, j, idx = 0;
|
int i, j, idx = 0;
|
||||||
|
|
||||||
for (i = 0; i < NS_OPER_NUM; i++) {
|
for (i = 0; i < NS_OPER_NUM; i++) {
|
||||||
|
|
||||||
int found = 1;
|
int found = 1;
|
||||||
|
|
||||||
if (!(ns->options & ops[i].reqopts))
|
if (!(ns->options & ops[i].reqopts))
|
||||||
/* Ignore operations we can't perform */
|
/* Ignore operations we can't perform */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (flag) {
|
if (flag) {
|
||||||
if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK))
|
if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK))
|
||||||
continue;
|
continue;
|
||||||
|
@ -728,7 +728,7 @@ find_operation(struct nandsim *ns, uint32_t flag)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < ns->npstates; j++)
|
for (j = 0; j < ns->npstates; j++)
|
||||||
if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j])
|
if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j])
|
||||||
&& (ns->options & ops[idx].reqopts)) {
|
&& (ns->options & ops[idx].reqopts)) {
|
||||||
found = 0;
|
found = 0;
|
||||||
|
@ -745,7 +745,7 @@ find_operation(struct nandsim *ns, uint32_t flag)
|
||||||
/* Exact match */
|
/* Exact match */
|
||||||
ns->op = &ops[idx].states[0];
|
ns->op = &ops[idx].states[0];
|
||||||
if (flag) {
|
if (flag) {
|
||||||
/*
|
/*
|
||||||
* In this case the find_operation function was
|
* In this case the find_operation function was
|
||||||
* called when address has just began input. But it isn't
|
* called when address has just began input. But it isn't
|
||||||
* yet fully input and the current state must
|
* yet fully input and the current state must
|
||||||
|
@ -763,7 +763,7 @@ find_operation(struct nandsim *ns, uint32_t flag)
|
||||||
idx, get_state_name(ns->state), get_state_name(ns->nxstate));
|
idx, get_state_name(ns->state), get_state_name(ns->nxstate));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opsfound == 0) {
|
if (opsfound == 0) {
|
||||||
/* Nothing was found. Try to ignore previous commands (if any) and search again */
|
/* Nothing was found. Try to ignore previous commands (if any) and search again */
|
||||||
if (ns->npstates != 0) {
|
if (ns->npstates != 0) {
|
||||||
|
@ -777,13 +777,13 @@ find_operation(struct nandsim *ns, uint32_t flag)
|
||||||
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
|
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag) {
|
if (flag) {
|
||||||
/* This shouldn't happen */
|
/* This shouldn't happen */
|
||||||
NS_DBG("find_operation: BUG, operation must be known if address is input\n");
|
NS_DBG("find_operation: BUG, operation must be known if address is input\n");
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_DBG("find_operation: there is still ambiguity\n");
|
NS_DBG("find_operation: there is still ambiguity\n");
|
||||||
|
|
||||||
ns->pstates[ns->npstates++] = ns->state;
|
ns->pstates[ns->npstates++] = ns->state;
|
||||||
|
@ -803,7 +803,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
|
||||||
int busdiv = ns->busw == 8 ? 1 : 2;
|
int busdiv = ns->busw == 8 ? 1 : 2;
|
||||||
|
|
||||||
action &= ACTION_MASK;
|
action &= ACTION_MASK;
|
||||||
|
|
||||||
/* Check that page address input is correct */
|
/* Check that page address input is correct */
|
||||||
if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) {
|
if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) {
|
||||||
NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row);
|
NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row);
|
||||||
|
@ -827,14 +827,14 @@ do_state_action(struct nandsim *ns, uint32_t action)
|
||||||
|
|
||||||
NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
|
NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
|
||||||
num, NS_RAW_OFFSET(ns) + ns->regs.off);
|
num, NS_RAW_OFFSET(ns) + ns->regs.off);
|
||||||
|
|
||||||
if (ns->regs.off == 0)
|
if (ns->regs.off == 0)
|
||||||
NS_LOG("read page %d\n", ns->regs.row);
|
NS_LOG("read page %d\n", ns->regs.row);
|
||||||
else if (ns->regs.off < ns->geom.pgsz)
|
else if (ns->regs.off < ns->geom.pgsz)
|
||||||
NS_LOG("read page %d (second half)\n", ns->regs.row);
|
NS_LOG("read page %d (second half)\n", ns->regs.row);
|
||||||
else
|
else
|
||||||
NS_LOG("read OOB of page %d\n", ns->regs.row);
|
NS_LOG("read OOB of page %d\n", ns->regs.row);
|
||||||
|
|
||||||
NS_UDELAY(access_delay);
|
NS_UDELAY(access_delay);
|
||||||
NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv);
|
NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv);
|
||||||
|
|
||||||
|
@ -844,30 +844,30 @@ do_state_action(struct nandsim *ns, uint32_t action)
|
||||||
/*
|
/*
|
||||||
* Erase sector.
|
* Erase sector.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (ns->lines.wp) {
|
if (ns->lines.wp) {
|
||||||
NS_ERR("do_state_action: device is write-protected, ignore sector erase\n");
|
NS_ERR("do_state_action: device is write-protected, ignore sector erase\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec
|
if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec
|
||||||
|| (ns->regs.row & ~(ns->geom.secsz - 1))) {
|
|| (ns->regs.row & ~(ns->geom.secsz - 1))) {
|
||||||
NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row);
|
NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ns->regs.row = (ns->regs.row <<
|
ns->regs.row = (ns->regs.row <<
|
||||||
8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column;
|
8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column;
|
||||||
ns->regs.column = 0;
|
ns->regs.column = 0;
|
||||||
|
|
||||||
NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
|
NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
|
||||||
ns->regs.row, NS_RAW_OFFSET(ns));
|
ns->regs.row, NS_RAW_OFFSET(ns));
|
||||||
NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift));
|
NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift));
|
||||||
|
|
||||||
memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob);
|
memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob);
|
||||||
|
|
||||||
NS_MDELAY(erase_delay);
|
NS_MDELAY(erase_delay);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTION_PRGPAGE:
|
case ACTION_PRGPAGE:
|
||||||
|
@ -893,12 +893,12 @@ do_state_action(struct nandsim *ns, uint32_t action)
|
||||||
NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
|
NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
|
||||||
num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
|
num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
|
||||||
NS_LOG("programm page %d\n", ns->regs.row);
|
NS_LOG("programm page %d\n", ns->regs.row);
|
||||||
|
|
||||||
NS_UDELAY(programm_delay);
|
NS_UDELAY(programm_delay);
|
||||||
NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
|
NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTION_ZEROOFF:
|
case ACTION_ZEROOFF:
|
||||||
NS_DBG("do_state_action: set internal offset to 0\n");
|
NS_DBG("do_state_action: set internal offset to 0\n");
|
||||||
ns->regs.off = 0;
|
ns->regs.off = 0;
|
||||||
|
@ -918,7 +918,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
|
||||||
NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz);
|
NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz);
|
||||||
ns->regs.off = ns->geom.pgsz;
|
ns->regs.off = ns->geom.pgsz;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
NS_DBG("do_state_action: BUG! unknown action\n");
|
NS_DBG("do_state_action: BUG! unknown action\n");
|
||||||
}
|
}
|
||||||
|
@ -937,7 +937,7 @@ switch_state(struct nandsim *ns)
|
||||||
* The current operation have already been identified.
|
* The current operation have already been identified.
|
||||||
* Just follow the states chain.
|
* Just follow the states chain.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ns->stateidx += 1;
|
ns->stateidx += 1;
|
||||||
ns->state = ns->nxstate;
|
ns->state = ns->nxstate;
|
||||||
ns->nxstate = ns->op[ns->stateidx + 1];
|
ns->nxstate = ns->op[ns->stateidx + 1];
|
||||||
|
@ -951,14 +951,14 @@ switch_state(struct nandsim *ns)
|
||||||
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
|
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* We don't yet know which operation we perform.
|
* We don't yet know which operation we perform.
|
||||||
* Try to identify it.
|
* Try to identify it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The only event causing the switch_state function to
|
* The only event causing the switch_state function to
|
||||||
* be called with yet unknown operation is new command.
|
* be called with yet unknown operation is new command.
|
||||||
*/
|
*/
|
||||||
|
@ -987,7 +987,7 @@ switch_state(struct nandsim *ns)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
u_char status = NS_STATUS_OK(ns);
|
u_char status = NS_STATUS_OK(ns);
|
||||||
|
|
||||||
/* In case of data states, see if all bytes were input/output */
|
/* In case of data states, see if all bytes were input/output */
|
||||||
if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK))
|
if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK))
|
||||||
&& ns->regs.count != ns->regs.num) {
|
&& ns->regs.count != ns->regs.num) {
|
||||||
|
@ -995,17 +995,17 @@ switch_state(struct nandsim *ns)
|
||||||
ns->regs.num - ns->regs.count);
|
ns->regs.num - ns->regs.count);
|
||||||
status = NS_STATUS_FAILED(ns);
|
status = NS_STATUS_FAILED(ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_DBG("switch_state: operation complete, switch to STATE_READY state\n");
|
NS_DBG("switch_state: operation complete, switch to STATE_READY state\n");
|
||||||
|
|
||||||
switch_to_ready_state(ns, status);
|
switch_to_ready_state(ns, status);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) {
|
} else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) {
|
||||||
/*
|
/*
|
||||||
* If the next state is data input/output, switch to it now
|
* If the next state is data input/output, switch to it now
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ns->state = ns->nxstate;
|
ns->state = ns->nxstate;
|
||||||
ns->nxstate = ns->op[++ns->stateidx + 1];
|
ns->nxstate = ns->op[++ns->stateidx + 1];
|
||||||
ns->regs.num = ns->regs.count = 0;
|
ns->regs.num = ns->regs.count = 0;
|
||||||
|
@ -1023,16 +1023,16 @@ switch_state(struct nandsim *ns)
|
||||||
case STATE_DATAOUT:
|
case STATE_DATAOUT:
|
||||||
ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
|
ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATE_DATAOUT_ID:
|
case STATE_DATAOUT_ID:
|
||||||
ns->regs.num = ns->geom.idbytes;
|
ns->regs.num = ns->geom.idbytes;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATE_DATAOUT_STATUS:
|
case STATE_DATAOUT_STATUS:
|
||||||
case STATE_DATAOUT_STATUS_M:
|
case STATE_DATAOUT_STATUS_M:
|
||||||
ns->regs.count = ns->regs.num = 0;
|
ns->regs.count = ns->regs.num = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
NS_ERR("switch_state: BUG! unknown data state\n");
|
NS_ERR("switch_state: BUG! unknown data state\n");
|
||||||
}
|
}
|
||||||
|
@ -1044,16 +1044,16 @@ switch_state(struct nandsim *ns)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ns->regs.count = 0;
|
ns->regs.count = 0;
|
||||||
|
|
||||||
switch (NS_STATE(ns->nxstate)) {
|
switch (NS_STATE(ns->nxstate)) {
|
||||||
case STATE_ADDR_PAGE:
|
case STATE_ADDR_PAGE:
|
||||||
ns->regs.num = ns->geom.pgaddrbytes;
|
ns->regs.num = ns->geom.pgaddrbytes;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case STATE_ADDR_SEC:
|
case STATE_ADDR_SEC:
|
||||||
ns->regs.num = ns->geom.secaddrbytes;
|
ns->regs.num = ns->geom.secaddrbytes;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATE_ADDR_ZERO:
|
case STATE_ADDR_ZERO:
|
||||||
ns->regs.num = 1;
|
ns->regs.num = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -1062,7 +1062,7 @@ switch_state(struct nandsim *ns)
|
||||||
NS_ERR("switch_state: BUG! unknown address state\n");
|
NS_ERR("switch_state: BUG! unknown address state\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Just reset internal counters.
|
* Just reset internal counters.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -1184,7 +1184,7 @@ ns_nand_read_byte(struct mtd_info *mtd)
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns->regs.count == ns->regs.num) {
|
if (ns->regs.count == ns->regs.num) {
|
||||||
NS_DBG("read_byte: all bytes were read\n");
|
NS_DBG("read_byte: all bytes were read\n");
|
||||||
|
|
||||||
|
@ -1201,9 +1201,9 @@ ns_nand_read_byte(struct mtd_info *mtd)
|
||||||
}
|
}
|
||||||
else if (NS_STATE(ns->nxstate) == STATE_READY)
|
else if (NS_STATE(ns->nxstate) == STATE_READY)
|
||||||
switch_state(ns);
|
switch_state(ns);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return outb;
|
return outb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1211,7 +1211,7 @@ static void
|
||||||
ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
|
ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
|
||||||
{
|
{
|
||||||
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
|
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
|
||||||
|
|
||||||
/* Sanity and correctness checks */
|
/* Sanity and correctness checks */
|
||||||
if (!ns->lines.ce) {
|
if (!ns->lines.ce) {
|
||||||
NS_ERR("write_byte: chip is disabled, ignore write\n");
|
NS_ERR("write_byte: chip is disabled, ignore write\n");
|
||||||
|
@ -1221,7 +1221,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
|
||||||
NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n");
|
NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns->lines.cle == 1) {
|
if (ns->lines.cle == 1) {
|
||||||
/*
|
/*
|
||||||
* The byte written is a command.
|
* The byte written is a command.
|
||||||
|
@ -1233,7 +1233,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Chip might still be in STATE_DATAOUT
|
* Chip might still be in STATE_DATAOUT
|
||||||
* (if OPT_AUTOINCR feature is supported), STATE_DATAOUT_STATUS or
|
* (if OPT_AUTOINCR feature is supported), STATE_DATAOUT_STATUS or
|
||||||
* STATE_DATAOUT_STATUS_M state. If so, switch state.
|
* STATE_DATAOUT_STATUS_M state. If so, switch state.
|
||||||
|
@ -1254,13 +1254,13 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
|
||||||
"ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
|
"ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
|
||||||
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
|
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the command byte is correct */
|
/* Check that the command byte is correct */
|
||||||
if (check_command(byte)) {
|
if (check_command(byte)) {
|
||||||
NS_ERR("write_byte: unknown command %#x\n", (uint)byte);
|
NS_ERR("write_byte: unknown command %#x\n", (uint)byte);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_DBG("command byte corresponding to %s state accepted\n",
|
NS_DBG("command byte corresponding to %s state accepted\n",
|
||||||
get_state_name(get_state_by_command(byte)));
|
get_state_name(get_state_by_command(byte)));
|
||||||
ns->regs.command = byte;
|
ns->regs.command = byte;
|
||||||
|
@ -1277,12 +1277,12 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
|
||||||
|
|
||||||
if (find_operation(ns, 1) < 0)
|
if (find_operation(ns, 1) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
|
if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
|
||||||
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
|
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ns->regs.count = 0;
|
ns->regs.count = 0;
|
||||||
switch (NS_STATE(ns->nxstate)) {
|
switch (NS_STATE(ns->nxstate)) {
|
||||||
case STATE_ADDR_PAGE:
|
case STATE_ADDR_PAGE:
|
||||||
|
@ -1306,7 +1306,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
|
||||||
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
|
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if this is expected byte */
|
/* Check if this is expected byte */
|
||||||
if (ns->regs.count == ns->regs.num) {
|
if (ns->regs.count == ns->regs.num) {
|
||||||
NS_ERR("write_byte: no more address bytes expected\n");
|
NS_ERR("write_byte: no more address bytes expected\n");
|
||||||
|
@ -1325,12 +1325,12 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
|
||||||
NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column);
|
NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column);
|
||||||
switch_state(ns);
|
switch_state(ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* The byte written is an input data.
|
* The byte written is an input data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Check that chip is expecting data input */
|
/* Check that chip is expecting data input */
|
||||||
if (!(ns->state & STATE_DATAIN_MASK)) {
|
if (!(ns->state & STATE_DATAIN_MASK)) {
|
||||||
NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, "
|
NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, "
|
||||||
|
@ -1372,7 +1372,7 @@ ns_nand_read_word(struct mtd_info *mtd)
|
||||||
struct nand_chip *chip = (struct nand_chip *)mtd->priv;
|
struct nand_chip *chip = (struct nand_chip *)mtd->priv;
|
||||||
|
|
||||||
NS_DBG("read_word\n");
|
NS_DBG("read_word\n");
|
||||||
|
|
||||||
return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
|
return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1380,14 +1380,14 @@ static void
|
||||||
ns_nand_write_word(struct mtd_info *mtd, uint16_t word)
|
ns_nand_write_word(struct mtd_info *mtd, uint16_t word)
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = (struct nand_chip *)mtd->priv;
|
struct nand_chip *chip = (struct nand_chip *)mtd->priv;
|
||||||
|
|
||||||
NS_DBG("write_word\n");
|
NS_DBG("write_word\n");
|
||||||
|
|
||||||
chip->write_byte(mtd, word & 0xFF);
|
chip->write_byte(mtd, word & 0xFF);
|
||||||
chip->write_byte(mtd, word >> 8);
|
chip->write_byte(mtd, word >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||||
{
|
{
|
||||||
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
|
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
|
||||||
|
@ -1409,13 +1409,13 @@ ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||||
|
|
||||||
memcpy(ns->buf.byte + ns->regs.count, buf, len);
|
memcpy(ns->buf.byte + ns->regs.count, buf, len);
|
||||||
ns->regs.count += len;
|
ns->regs.count += len;
|
||||||
|
|
||||||
if (ns->regs.count == ns->regs.num) {
|
if (ns->regs.count == ns->regs.num) {
|
||||||
NS_DBG("write_buf: %d bytes were written\n", ns->regs.count);
|
NS_DBG("write_buf: %d bytes were written\n", ns->regs.count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||||
{
|
{
|
||||||
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
|
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
|
||||||
|
@ -1453,7 +1453,7 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||||
|
|
||||||
memcpy(buf, ns->buf.byte + ns->regs.count, len);
|
memcpy(buf, ns->buf.byte + ns->regs.count, len);
|
||||||
ns->regs.count += len;
|
ns->regs.count += len;
|
||||||
|
|
||||||
if (ns->regs.count == ns->regs.num) {
|
if (ns->regs.count == ns->regs.num) {
|
||||||
if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) {
|
if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) {
|
||||||
ns->regs.count = 0;
|
ns->regs.count = 0;
|
||||||
|
@ -1465,11 +1465,11 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||||
else if (NS_STATE(ns->nxstate) == STATE_READY)
|
else if (NS_STATE(ns->nxstate) == STATE_READY)
|
||||||
switch_state(ns);
|
switch_state(ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||||
{
|
{
|
||||||
ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len);
|
ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len);
|
||||||
|
@ -1496,7 +1496,7 @@ int __init ns_init_module(void)
|
||||||
NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
|
NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate and initialize mtd_info, nand_chip and nandsim structures */
|
/* Allocate and initialize mtd_info, nand_chip and nandsim structures */
|
||||||
nsmtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)
|
nsmtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)
|
||||||
+ sizeof(struct nandsim), GFP_KERNEL);
|
+ sizeof(struct nandsim), GFP_KERNEL);
|
||||||
|
@ -1509,7 +1509,7 @@ int __init ns_init_module(void)
|
||||||
chip = (struct nand_chip *)(nsmtd + 1);
|
chip = (struct nand_chip *)(nsmtd + 1);
|
||||||
nsmtd->priv = (void *)chip;
|
nsmtd->priv = (void *)chip;
|
||||||
nand = (struct nandsim *)(chip + 1);
|
nand = (struct nandsim *)(chip + 1);
|
||||||
chip->priv = (void *)nand;
|
chip->priv = (void *)nand;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register simulator's callbacks.
|
* Register simulator's callbacks.
|
||||||
|
@ -1526,9 +1526,9 @@ int __init ns_init_module(void)
|
||||||
chip->eccmode = NAND_ECC_SOFT;
|
chip->eccmode = NAND_ECC_SOFT;
|
||||||
chip->options |= NAND_SKIP_BBTSCAN;
|
chip->options |= NAND_SKIP_BBTSCAN;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform minimum nandsim structure initialization to handle
|
* Perform minimum nandsim structure initialization to handle
|
||||||
* the initial ID read command correctly
|
* the initial ID read command correctly
|
||||||
*/
|
*/
|
||||||
if (third_id_byte != 0xFF || fourth_id_byte != 0xFF)
|
if (third_id_byte != 0xFF || fourth_id_byte != 0xFF)
|
||||||
nand->geom.idbytes = 4;
|
nand->geom.idbytes = 4;
|
||||||
|
@ -1557,7 +1557,7 @@ int __init ns_init_module(void)
|
||||||
NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
|
NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((retval = nand_default_bbt(nsmtd)) != 0) {
|
if ((retval = nand_default_bbt(nsmtd)) != 0) {
|
||||||
free_nandsim(nand);
|
free_nandsim(nand);
|
||||||
goto error;
|
goto error;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Derived from drivers/mtd/nand/edb7312.c
|
* Derived from drivers/mtd/nand/edb7312.c
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* $Id: ppchameleonevb.c,v 1.6 2004/11/05 16:07:16 kalev Exp $
|
* $Id: ppchameleonevb.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -338,7 +338,7 @@ nand_evb_init:
|
||||||
out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0);
|
out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0);
|
||||||
out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF);
|
out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF);
|
||||||
/* enable output driver */
|
/* enable output driver */
|
||||||
out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN |
|
out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN |
|
||||||
NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN);
|
NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN);
|
||||||
#ifdef USE_READY_BUSY_PIN
|
#ifdef USE_READY_BUSY_PIN
|
||||||
/* three-state select */
|
/* three-state select */
|
||||||
|
@ -402,7 +402,7 @@ static void __exit ppchameleonevb_cleanup (void)
|
||||||
/* Release resources, unregister device(s) */
|
/* Release resources, unregister device(s) */
|
||||||
nand_release (ppchameleon_mtd);
|
nand_release (ppchameleon_mtd);
|
||||||
nand_release (ppchameleonevb_mtd);
|
nand_release (ppchameleonevb_mtd);
|
||||||
|
|
||||||
/* Release iomaps */
|
/* Release iomaps */
|
||||||
this = (struct nand_chip *) &ppchameleon_mtd[1];
|
this = (struct nand_chip *) &ppchameleon_mtd[1];
|
||||||
iounmap((void *) this->IO_ADDR_R;
|
iounmap((void *) this->IO_ADDR_R;
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
* drivers/mtd/nand/rtc_from4.c
|
* drivers/mtd/nand/rtc_from4.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2004 Red Hat, Inc.
|
* Copyright (C) 2004 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* Derived from drivers/mtd/nand/spia.c
|
* Derived from drivers/mtd/nand/spia.c
|
||||||
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
|
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
|
||||||
*
|
*
|
||||||
* $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $
|
* $Id: rtc_from4.c,v 1.10 2005/11/07 11:14:31 gleixner Exp $
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -14,8 +14,8 @@
|
||||||
*
|
*
|
||||||
* Overview:
|
* Overview:
|
||||||
* This is a device driver for the AG-AND flash device found on the
|
* This is a device driver for the AG-AND flash device found on the
|
||||||
* Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4),
|
* Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4),
|
||||||
* which utilizes the Renesas HN29V1G91T-30 part.
|
* which utilizes the Renesas HN29V1G91T-30 part.
|
||||||
* This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device.
|
* This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -105,9 +105,9 @@ const static struct mtd_partition partition_info[] = {
|
||||||
};
|
};
|
||||||
#define NUM_PARTITIONS 1
|
#define NUM_PARTITIONS 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hardware specific flash bbt decriptors
|
* hardware specific flash bbt decriptors
|
||||||
* Note: this is to allow debugging by disabling
|
* Note: this is to allow debugging by disabling
|
||||||
* NAND_BBT_CREATE and/or NAND_BBT_WRITE
|
* NAND_BBT_CREATE and/or NAND_BBT_WRITE
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -141,7 +141,7 @@ static struct nand_bbt_descr rtc_from4_bbt_mirror_descr = {
|
||||||
/* the Reed Solomon control structure */
|
/* the Reed Solomon control structure */
|
||||||
static struct rs_control *rs_decoder;
|
static struct rs_control *rs_decoder;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hardware specific Out Of Band information
|
* hardware specific Out Of Band information
|
||||||
*/
|
*/
|
||||||
static struct nand_oobinfo rtc_from4_nand_oobinfo = {
|
static struct nand_oobinfo rtc_from4_nand_oobinfo = {
|
||||||
|
@ -200,38 +200,38 @@ static uint8_t revbits[256] = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* rtc_from4_hwcontrol - hardware specific access to control-lines
|
* rtc_from4_hwcontrol - hardware specific access to control-lines
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @cmd: hardware control command
|
* @cmd: hardware control command
|
||||||
*
|
*
|
||||||
* Address lines (A5 and A4) are used to control Command and Address Latch
|
* Address lines (A5 and A4) are used to control Command and Address Latch
|
||||||
* Enable on this board, so set the read/write address appropriately.
|
* Enable on this board, so set the read/write address appropriately.
|
||||||
*
|
*
|
||||||
* Chip Enable is also controlled by the Chip Select (CS5) and
|
* Chip Enable is also controlled by the Chip Select (CS5) and
|
||||||
* Address lines (A24-A22), so no action is required here.
|
* Address lines (A24-A22), so no action is required here.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd)
|
static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd)
|
||||||
{
|
{
|
||||||
struct nand_chip* this = (struct nand_chip *) (mtd->priv);
|
struct nand_chip* this = (struct nand_chip *) (mtd->priv);
|
||||||
|
|
||||||
switch(cmd) {
|
switch(cmd) {
|
||||||
|
|
||||||
case NAND_CTL_SETCLE:
|
case NAND_CTL_SETCLE:
|
||||||
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE);
|
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE);
|
||||||
break;
|
break;
|
||||||
case NAND_CTL_CLRCLE:
|
case NAND_CTL_CLRCLE:
|
||||||
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE);
|
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_CTL_SETALE:
|
case NAND_CTL_SETALE:
|
||||||
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE);
|
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE);
|
||||||
break;
|
break;
|
||||||
case NAND_CTL_CLRALE:
|
case NAND_CTL_CLRALE:
|
||||||
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE);
|
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_CTL_SETNCE:
|
case NAND_CTL_SETNCE:
|
||||||
break;
|
break;
|
||||||
case NAND_CTL_CLRNCE:
|
case NAND_CTL_CLRNCE:
|
||||||
|
@ -296,7 +296,7 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd)
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @chip: Chip to select (0 == slot 3, 1 == slot 4)
|
* @chip: Chip to select (0 == slot 3, 1 == slot 4)
|
||||||
*
|
*
|
||||||
* If there was a sudden loss of power during an erase operation, a
|
* If there was a sudden loss of power during an erase operation, a
|
||||||
* "device recovery" operation must be performed when power is restored
|
* "device recovery" operation must be performed when power is restored
|
||||||
* to ensure correct operation. This routine performs the required steps
|
* to ensure correct operation. This routine performs the required steps
|
||||||
* for the requested chip.
|
* for the requested chip.
|
||||||
|
@ -312,7 +312,7 @@ static void deplete(struct mtd_info *mtd, int chip)
|
||||||
while (!this->dev_ready(mtd));
|
while (!this->dev_ready(mtd));
|
||||||
|
|
||||||
this->select_chip(mtd, chip);
|
this->select_chip(mtd, chip);
|
||||||
|
|
||||||
/* Send the commands for device recovery, phase 1 */
|
/* Send the commands for device recovery, phase 1 */
|
||||||
this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000);
|
this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000);
|
||||||
this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1);
|
this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1);
|
||||||
|
@ -330,7 +330,7 @@ static void deplete(struct mtd_info *mtd, int chip)
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @mode: I/O mode; read or write
|
* @mode: I/O mode; read or write
|
||||||
*
|
*
|
||||||
* enable hardware ECC for data read or write
|
* enable hardware ECC for data read or write
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
|
static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||||
|
@ -340,7 +340,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case NAND_ECC_READ :
|
case NAND_ECC_READ :
|
||||||
status = RTC_FROM4_RS_ECC_CTL_CLR
|
status = RTC_FROM4_RS_ECC_CTL_CLR
|
||||||
| RTC_FROM4_RS_ECC_CTL_FD_E;
|
| RTC_FROM4_RS_ECC_CTL_FD_E;
|
||||||
|
|
||||||
*rs_ecc_ctl = status;
|
*rs_ecc_ctl = status;
|
||||||
|
@ -353,8 +353,8 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_ECC_WRITE :
|
case NAND_ECC_WRITE :
|
||||||
status = RTC_FROM4_RS_ECC_CTL_CLR
|
status = RTC_FROM4_RS_ECC_CTL_CLR
|
||||||
| RTC_FROM4_RS_ECC_CTL_GEN
|
| RTC_FROM4_RS_ECC_CTL_GEN
|
||||||
| RTC_FROM4_RS_ECC_CTL_FD_E;
|
| RTC_FROM4_RS_ECC_CTL_FD_E;
|
||||||
|
|
||||||
*rs_ecc_ctl = status;
|
*rs_ecc_ctl = status;
|
||||||
|
@ -411,7 +411,7 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c
|
||||||
static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2)
|
static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2)
|
||||||
{
|
{
|
||||||
int i, j, res;
|
int i, j, res;
|
||||||
unsigned short status;
|
unsigned short status;
|
||||||
uint16_t par[6], syn[6];
|
uint16_t par[6], syn[6];
|
||||||
uint8_t ecc[8];
|
uint8_t ecc[8];
|
||||||
volatile unsigned short *rs_ecc;
|
volatile unsigned short *rs_ecc;
|
||||||
|
@ -430,7 +430,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert into 6 10bit syndrome fields */
|
/* convert into 6 10bit syndrome fields */
|
||||||
par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) |
|
par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) |
|
||||||
(((uint16_t)ecc[1] << 8) & 0x300)];
|
(((uint16_t)ecc[1] << 8) & 0x300)];
|
||||||
par[4] = rs_decoder->index_of[(((uint16_t)ecc[1] >> 2) & 0x03f) |
|
par[4] = rs_decoder->index_of[(((uint16_t)ecc[1] >> 2) & 0x03f) |
|
||||||
(((uint16_t)ecc[2] << 6) & 0x3c0)];
|
(((uint16_t)ecc[2] << 6) & 0x3c0)];
|
||||||
|
@ -456,7 +456,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
|
||||||
/* Let the library code do its magic.*/
|
/* Let the library code do its magic.*/
|
||||||
res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL);
|
res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL);
|
||||||
if (res > 0) {
|
if (res > 0) {
|
||||||
DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: "
|
DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: "
|
||||||
"ECC corrected %d errors on read\n", res);
|
"ECC corrected %d errors on read\n", res);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -470,9 +470,9 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
|
||||||
* @state: state or the operation
|
* @state: state or the operation
|
||||||
* @status: status code returned from read status
|
* @status: status code returned from read status
|
||||||
* @page: startpage inside the chip, must be called with (page & this->pagemask)
|
* @page: startpage inside the chip, must be called with (page & this->pagemask)
|
||||||
*
|
*
|
||||||
* Perform additional error status checks on erase and write failures
|
* Perform additional error status checks on erase and write failures
|
||||||
* to determine if errors are correctable. For this device, correctable
|
* to determine if errors are correctable. For this device, correctable
|
||||||
* 1-bit errors on erase and write are considered acceptable.
|
* 1-bit errors on erase and write are considered acceptable.
|
||||||
*
|
*
|
||||||
* note: see pages 34..37 of data sheet for details.
|
* note: see pages 34..37 of data sheet for details.
|
||||||
|
@ -633,7 +633,7 @@ int __init rtc_from4_init (void)
|
||||||
|
|
||||||
#ifdef RTC_FROM4_HWECC
|
#ifdef RTC_FROM4_HWECC
|
||||||
/* We could create the decoder on demand, if memory is a concern.
|
/* We could create the decoder on demand, if memory is a concern.
|
||||||
* This way we have it handy, if an error happens
|
* This way we have it handy, if an error happens
|
||||||
*
|
*
|
||||||
* Symbolsize is 10 (bits)
|
* Symbolsize is 10 (bits)
|
||||||
* Primitve polynomial is x^10+x^3+1
|
* Primitve polynomial is x^10+x^3+1
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
* 08-Jul-2005 BJD Fix OOPS when no platform data supplied
|
* 08-Jul-2005 BJD Fix OOPS when no platform data supplied
|
||||||
* 20-Oct-2005 BJD Fix timing calculation bug
|
* 20-Oct-2005 BJD Fix timing calculation bug
|
||||||
*
|
*
|
||||||
* $Id: s3c2410.c,v 1.18 2005/10/20 21:22:55 bjd Exp $
|
* $Id: s3c2410.c,v 1.20 2005/11/07 11:14:31 gleixner Exp $
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -164,7 +164,7 @@ static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
|
||||||
|
|
||||||
/* controller setup */
|
/* controller setup */
|
||||||
|
|
||||||
static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
|
static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
|
||||||
struct device *dev)
|
struct device *dev)
|
||||||
{
|
{
|
||||||
struct s3c2410_platform_nand *plat = to_nand_plat(dev);
|
struct s3c2410_platform_nand *plat = to_nand_plat(dev);
|
||||||
|
@ -186,7 +186,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
|
||||||
twrph0 = 8;
|
twrph0 = 8;
|
||||||
twrph1 = 8;
|
twrph1 = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
|
if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
|
||||||
printk(KERN_ERR PFX "cannot get timings suitable for board\n");
|
printk(KERN_ERR PFX "cannot get timings suitable for board\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -194,7 +194,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
|
||||||
|
|
||||||
printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
|
printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
|
||||||
tacls, to_ns(tacls, clkrate),
|
tacls, to_ns(tacls, clkrate),
|
||||||
twrph0, to_ns(twrph0, clkrate),
|
twrph0, to_ns(twrph0, clkrate),
|
||||||
twrph1, to_ns(twrph1, clkrate));
|
twrph1, to_ns(twrph1, clkrate));
|
||||||
|
|
||||||
if (!info->is_s3c2440) {
|
if (!info->is_s3c2440) {
|
||||||
|
@ -219,7 +219,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
|
||||||
static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
|
static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
|
||||||
{
|
{
|
||||||
struct s3c2410_nand_info *info;
|
struct s3c2410_nand_info *info;
|
||||||
struct s3c2410_nand_mtd *nmtd;
|
struct s3c2410_nand_mtd *nmtd;
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
void __iomem *reg;
|
void __iomem *reg;
|
||||||
unsigned long cur;
|
unsigned long cur;
|
||||||
|
@ -252,7 +252,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
|
||||||
writel(cur, reg);
|
writel(cur, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* command and control functions
|
/* command and control functions
|
||||||
*
|
*
|
||||||
* Note, these all use tglx's method of changing the IO_ADDR_W field
|
* Note, these all use tglx's method of changing the IO_ADDR_W field
|
||||||
* to make the code simpler, and use the nand layer's code to issue the
|
* to make the code simpler, and use the nand layer's code to issue the
|
||||||
|
@ -324,7 +324,7 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd)
|
||||||
static int s3c2410_nand_devready(struct mtd_info *mtd)
|
static int s3c2410_nand_devready(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||||
|
|
||||||
if (info->is_s3c2440)
|
if (info->is_s3c2440)
|
||||||
return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
|
return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
|
||||||
return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
|
return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
|
||||||
|
@ -345,7 +345,7 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||||
|
|
||||||
if (read_ecc[0] == calc_ecc[0] &&
|
if (read_ecc[0] == calc_ecc[0] &&
|
||||||
read_ecc[1] == calc_ecc[1] &&
|
read_ecc[1] == calc_ecc[1] &&
|
||||||
read_ecc[2] == calc_ecc[2])
|
read_ecc[2] == calc_ecc[2])
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* we curently have no method for correcting the error */
|
/* we curently have no method for correcting the error */
|
||||||
|
@ -436,14 +436,14 @@ static int s3c2410_nand_remove(struct device *dev)
|
||||||
|
|
||||||
dev_set_drvdata(dev, NULL);
|
dev_set_drvdata(dev, NULL);
|
||||||
|
|
||||||
if (info == NULL)
|
if (info == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* first thing we need to do is release all our mtds
|
/* first thing we need to do is release all our mtds
|
||||||
* and their partitions, then go through freeing the
|
* and their partitions, then go through freeing the
|
||||||
* resources used
|
* resources used
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (info->mtds != NULL) {
|
if (info->mtds != NULL) {
|
||||||
struct s3c2410_nand_mtd *ptr = info->mtds;
|
struct s3c2410_nand_mtd *ptr = info->mtds;
|
||||||
int mtdno;
|
int mtdno;
|
||||||
|
@ -507,7 +507,7 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
|
||||||
|
|
||||||
/* s3c2410_nand_init_chip
|
/* s3c2410_nand_init_chip
|
||||||
*
|
*
|
||||||
* init a single instance of an chip
|
* init a single instance of an chip
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
|
static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
|
||||||
|
@ -625,7 +625,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440)
|
||||||
dev_err(dev, "cannot reserve register region\n");
|
dev_err(dev, "cannot reserve register region\n");
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto exit_error;
|
goto exit_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(dev, "mapped registers at %p\n", info->regs);
|
dev_dbg(dev, "mapped registers at %p\n", info->regs);
|
||||||
|
|
||||||
|
@ -659,7 +659,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440)
|
||||||
for (setno = 0; setno < nr_sets; setno++, nmtd++) {
|
for (setno = 0; setno < nr_sets; setno++, nmtd++) {
|
||||||
pr_debug("initialising set %d (%p, info %p)\n",
|
pr_debug("initialising set %d (%p, info %p)\n",
|
||||||
setno, nmtd, info);
|
setno, nmtd, info);
|
||||||
|
|
||||||
s3c2410_nand_init_chip(info, nmtd, sets);
|
s3c2410_nand_init_chip(info, nmtd, sets);
|
||||||
|
|
||||||
nmtd->scan_res = nand_scan(&nmtd->mtd,
|
nmtd->scan_res = nand_scan(&nmtd->mtd,
|
||||||
|
@ -672,7 +672,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440)
|
||||||
if (sets != NULL)
|
if (sets != NULL)
|
||||||
sets++;
|
sets++;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("initialised ok\n");
|
pr_debug("initialised ok\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2004 Richard Purdie
|
* Copyright (C) 2004 Richard Purdie
|
||||||
*
|
*
|
||||||
* $Id: sharpsl.c,v 1.6 2005/11/03 11:36:42 rpurdie Exp $
|
* $Id: sharpsl.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $
|
||||||
*
|
*
|
||||||
* Based on Sharp's NAND driver sharp_sl.c
|
* Based on Sharp's NAND driver sharp_sl.c
|
||||||
*
|
*
|
||||||
|
@ -76,14 +76,14 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hardware specific access to control-lines
|
* hardware specific access to control-lines
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd)
|
sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd)
|
||||||
{
|
{
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case NAND_CTL_SETCLE:
|
case NAND_CTL_SETCLE:
|
||||||
writeb(readb(FLASHCTL) | FLCLE, FLASHCTL);
|
writeb(readb(FLASHCTL) | FLCLE, FLASHCTL);
|
||||||
break;
|
break;
|
||||||
case NAND_CTL_CLRCLE:
|
case NAND_CTL_CLRCLE:
|
||||||
|
@ -97,10 +97,10 @@ sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd)
|
||||||
writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL);
|
writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_CTL_SETNCE:
|
case NAND_CTL_SETNCE:
|
||||||
writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL);
|
writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL);
|
||||||
break;
|
break;
|
||||||
case NAND_CTL_CLRNCE:
|
case NAND_CTL_CLRNCE:
|
||||||
writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL);
|
writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -126,8 +126,8 @@ static struct nand_oobinfo akita_oobinfo = {
|
||||||
.useecc = MTD_NANDECC_AUTOPLACE,
|
.useecc = MTD_NANDECC_AUTOPLACE,
|
||||||
.eccbytes = 24,
|
.eccbytes = 24,
|
||||||
.eccpos = {
|
.eccpos = {
|
||||||
0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11,
|
0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11,
|
||||||
0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
|
0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
|
||||||
0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37},
|
0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37},
|
||||||
.oobfree = { {0x08, 0x09} }
|
.oobfree = { {0x08, 0x09} }
|
||||||
};
|
};
|
||||||
|
@ -177,7 +177,7 @@ sharpsl_nand_init(void)
|
||||||
printk ("Unable to allocate SharpSL NAND MTD device structure.\n");
|
printk ("Unable to allocate SharpSL NAND MTD device structure.\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* map physical adress */
|
/* map physical adress */
|
||||||
sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000);
|
sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000);
|
||||||
if(!sharpsl_io_base){
|
if(!sharpsl_io_base){
|
||||||
|
@ -185,7 +185,7 @@ sharpsl_nand_init(void)
|
||||||
kfree(sharpsl_mtd);
|
kfree(sharpsl_mtd);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get pointer to private data */
|
/* Get pointer to private data */
|
||||||
this = (struct nand_chip *) (&sharpsl_mtd[1]);
|
this = (struct nand_chip *) (&sharpsl_mtd[1]);
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ sharpsl_nand_init(void)
|
||||||
this->chip_delay = 15;
|
this->chip_delay = 15;
|
||||||
/* set eccmode using hardware ECC */
|
/* set eccmode using hardware ECC */
|
||||||
this->eccmode = NAND_ECC_HW3_256;
|
this->eccmode = NAND_ECC_HW3_256;
|
||||||
this->badblock_pattern = &sharpsl_bbt;
|
this->badblock_pattern = &sharpsl_bbt;
|
||||||
if (machine_is_akita() || machine_is_borzoi()) {
|
if (machine_is_akita() || machine_is_borzoi()) {
|
||||||
this->badblock_pattern = &sharpsl_akita_bbt;
|
this->badblock_pattern = &sharpsl_akita_bbt;
|
||||||
this->autooob = &akita_oobinfo;
|
this->autooob = &akita_oobinfo;
|
||||||
|
@ -232,7 +232,7 @@ sharpsl_nand_init(void)
|
||||||
sharpsl_mtd->name = "sharpsl-nand";
|
sharpsl_mtd->name = "sharpsl-nand";
|
||||||
nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes,
|
nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes,
|
||||||
&sharpsl_partition_info, 0);
|
&sharpsl_partition_info, 0);
|
||||||
|
|
||||||
if (nr_partitions <= 0) {
|
if (nr_partitions <= 0) {
|
||||||
nr_partitions = DEFAULT_NUM_PARTITIONS;
|
nr_partitions = DEFAULT_NUM_PARTITIONS;
|
||||||
sharpsl_partition_info = sharpsl_nand_default_partition_info;
|
sharpsl_partition_info = sharpsl_nand_default_partition_info;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* to controllines (due to change in nand.c)
|
* to controllines (due to change in nand.c)
|
||||||
* page_cache added
|
* page_cache added
|
||||||
*
|
*
|
||||||
* $Id: spia.c,v 1.24 2004/11/04 12:53:10 gleixner Exp $
|
* $Id: spia.c,v 1.25 2005/11/07 11:14:31 gleixner Exp $
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -82,7 +82,7 @@ const static struct mtd_partition partition_info[] = {
|
||||||
#define NUM_PARTITIONS 2
|
#define NUM_PARTITIONS 2
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hardware specific access to control-lines
|
* hardware specific access to control-lines
|
||||||
*/
|
*/
|
||||||
static void spia_hwcontrol(struct mtd_info *mtd, int cmd){
|
static void spia_hwcontrol(struct mtd_info *mtd, int cmd){
|
||||||
|
@ -137,7 +137,7 @@ int __init spia_init (void)
|
||||||
/* Set address of hardware control function */
|
/* Set address of hardware control function */
|
||||||
this->hwcontrol = spia_hwcontrol;
|
this->hwcontrol = spia_hwcontrol;
|
||||||
/* 15 us command delay time */
|
/* 15 us command delay time */
|
||||||
this->chip_delay = 15;
|
this->chip_delay = 15;
|
||||||
|
|
||||||
/* Scan to find existence of the device */
|
/* Scan to find existence of the device */
|
||||||
if (nand_scan (spia_mtd, 1)) {
|
if (nand_scan (spia_mtd, 1)) {
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* This is a device driver for the NAND flash device found on the
|
* This is a device driver for the NAND flash device found on the
|
||||||
* TI fido board. It supports 32MiB and 64MiB cards
|
* TI fido board. It supports 32MiB and 64MiB cards
|
||||||
*
|
*
|
||||||
* $Id: toto.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $
|
* $Id: toto.c,v 1.5 2005/11/07 11:14:31 gleixner Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
@ -57,7 +57,7 @@ static unsigned long toto_io_base = OMAP_FLASH_1_BASE;
|
||||||
#endif
|
#endif
|
||||||
#define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0)
|
#define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0)
|
||||||
#define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE)
|
#define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define partitions for flash devices
|
* Define partitions for flash devices
|
||||||
*/
|
*/
|
||||||
|
@ -91,7 +91,7 @@ static struct mtd_partition partition_info32M[] = {
|
||||||
|
|
||||||
#define NUM_PARTITIONS32M 3
|
#define NUM_PARTITIONS32M 3
|
||||||
#define NUM_PARTITIONS64M 4
|
#define NUM_PARTITIONS64M 4
|
||||||
/*
|
/*
|
||||||
* hardware specific access to control-lines
|
* hardware specific access to control-lines
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ int __init toto_init (void)
|
||||||
this->hwcontrol = toto_hwcontrol;
|
this->hwcontrol = toto_hwcontrol;
|
||||||
this->dev_ready = NULL;
|
this->dev_ready = NULL;
|
||||||
/* 25 us command delay time */
|
/* 25 us command delay time */
|
||||||
this->chip_delay = 30;
|
this->chip_delay = 30;
|
||||||
this->eccmode = NAND_ECC_SOFT;
|
this->eccmode = NAND_ECC_SOFT;
|
||||||
|
|
||||||
/* Scan to find existance of the device */
|
/* Scan to find existance of the device */
|
||||||
|
@ -157,10 +157,10 @@ int __init toto_init (void)
|
||||||
|
|
||||||
/* Register the partitions */
|
/* Register the partitions */
|
||||||
switch(toto_mtd->size){
|
switch(toto_mtd->size){
|
||||||
case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break;
|
case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break;
|
||||||
case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break;
|
case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break;
|
||||||
default: {
|
default: {
|
||||||
printk (KERN_WARNING "Unsupported Nand device\n");
|
printk (KERN_WARNING "Unsupported Nand device\n");
|
||||||
err = -ENXIO;
|
err = -ENXIO;
|
||||||
goto out_buf;
|
goto out_buf;
|
||||||
}
|
}
|
||||||
|
@ -170,9 +170,9 @@ int __init toto_init (void)
|
||||||
archflashwp(0,0); /* open up flash for writing */
|
archflashwp(0,0); /* open up flash for writing */
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
out_buf:
|
out_buf:
|
||||||
kfree (this->data_buf);
|
kfree (this->data_buf);
|
||||||
out_mtd:
|
out_mtd:
|
||||||
kfree (toto_mtd);
|
kfree (toto_mtd);
|
||||||
out:
|
out:
|
||||||
|
@ -194,7 +194,7 @@ static void __exit toto_cleanup (void)
|
||||||
|
|
||||||
/* stop flash writes */
|
/* stop flash writes */
|
||||||
archflashwp(0,1);
|
archflashwp(0,1);
|
||||||
|
|
||||||
/* release gpios to system */
|
/* release gpios to system */
|
||||||
gpiorelease(NAND_MASK);
|
gpiorelease(NAND_MASK);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue