From: Mason <slash.tmp@free.fr>
To: linux-mtd <linux-mtd@lists.infradead.org>
Cc: David Woodhouse <dwmw2@infradead.org>,
Brian Norris <computersforpeace@gmail.com>,
Sebastian Frias <sf84@laposte.net>
Subject: RFC on large number of hacks in mtd core files
Date: Fri, 22 Jan 2016 16:34:58 +0100 [thread overview]
Message-ID: <56A24C22.2050607@free.fr> (raw)
Hello everyone,
As I've mentioned in a previous thread, I'm supposed to port a NAND
controller driver from 3.4 to 4.4. But this is complicated by the
fact that several core files have been modified along the way.
Here's the full picture:
$ git diff --stat v3.4.39 custom-3.4 drivers/mtd
drivers/mtd/Kconfig | 15 +-
drivers/mtd/chips/cfi_cmdset_0002.c | 129 ++-
drivers/mtd/devices/Kconfig | 6 +
drivers/mtd/devices/Makefile | 3 +-
drivers/mtd/devices/m25p80.c | 100 +-
drivers/mtd/devices/spiflash.c | 2131 +++++++++++++++++++++++++++++++++++
drivers/mtd/maps/Kconfig | 11 +-
drivers/mtd/maps/physmap.c | 202 +++-
drivers/mtd/mtdchar.c | 54 +
drivers/mtd/mtdcore.c | 63 +-
drivers/mtd/mtdpart.c | 9 +
drivers/mtd/nand/Kconfig | 46 +-
drivers/mtd/nand/Makefile | 11 +-
drivers/mtd/nand/monza_nand.c | 614 ++++++++++
drivers/mtd/nand/nand_base.c | 1226 +++++++++++++++++++-
drivers/mtd/nand/nand_bch_ecc.c | 311 +++++
drivers/mtd/nand/nand_bch_ecc.h | 11 +
drivers/mtd/nand/nand_ids.c | 253 ++++-
drivers/mtd/nand/nandsim.c | 2 +-
drivers/mtd/nand/smp8xxx_nand.c | 2009 +++++++++++++++++++++++++++++++++
drivers/mtd/ubi/misc.c | 7 +
21 files changed, 7164 insertions(+), 49 deletions(-)
Here's the actual diff, with non-core changes omitted.
I have also deleted two irrelevant large diff blocks in nand_base.c
CONFIG_VENDOR_DTV can be ignored, it's an unrelated project.
AFAICT, most of this code should not be in core files.
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 27143e042af5..f50826842364 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -1,6 +1,7 @@
menuconfig MTD
tristate "Memory Technology Device (MTD) support"
depends on GENERIC_IO
+ depends on (!VENDOR_DTV || (VENDOR_DTV_ROM_SLC || VENDOR_DTV_ROM_MLC))
help
Memory Technology Devices are flash, RAM and similar chips, often
used for solid state file systems on embedded devices. This option
@@ -22,9 +23,21 @@ config MTD_TESTS
WARNING: some of the tests will ERASE entire MTD device which they
test. Do not use these tests unless you really know what you do.
+config MTD_PARTITIONS
+ bool "MTD partitioning support"
+ help
+ If you have a device which needs to divide its flash chip(s) up
+ into multiple 'partitions', each of which appears to the user as
+ a separate MTD device, you require this option to be enabled. If
+ unsure, say 'Y'.
+
+ Note, however, that you don't need this option for the DiskOnChip
+ devices. Partitioning on NFTL 'devices' is a different - that's the
+ 'normal' form of partitioning used on a block device.
config MTD_REDBOOT_PARTS
tristate "RedBoot partition table parsing"
+ depends on !TANGOX
---help---
RedBoot is a ROM monitor and bootloader which deals with multiple
'images' in flash devices by putting a table one of the erase
@@ -75,7 +88,7 @@ endif # MTD_REDBOOT_PARTS
config MTD_CMDLINE_PARTS
bool "Command line partition table parsing"
- depends on MTD = "y"
+ depends on MTD = "y" && !XENV_PARTITION
---help---
Allow generic configuration of the MTD partition tables via the kernel
command line. Multiple flash resources are supported for hardware where
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index d02592e6a0f0..eb70d2eca02d 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -345,6 +345,16 @@ static struct cfi_fixup cfi_nopri_fixup_table[] = {
{ 0, 0, NULL }
};
+static void fixup_M29W128G_write_buffer(struct mtd_info *mtd)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ if (cfi->cfiq->BufWriteTimeoutTyp) {
+ pr_warning("Don't use write buffer on ST flash M29W128G\n");
+ cfi->cfiq->BufWriteTimeoutTyp = 0;
+ }
+}
+
static struct cfi_fixup cfi_fixup_table[] = {
{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri },
#ifdef AMD_BOOTLOC_BUG
@@ -362,6 +372,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
{ CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors },
{ CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors },
{ CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors },
+ { CFI_MFR_ST, 0x227E, fixup_M29W128G_write_buffer },
{ CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */
{ CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */
{ CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */
@@ -616,6 +627,22 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
* correctly and is therefore not done (particularly with interleaved chips
* as each chip must be checked independently of the others).
*/
+#ifdef CONFIG_TANGOX
+/* For TANGOX, verify content in start address as well */
+static int __xipram chip_ready(struct map_info *map, unsigned long addr, unsigned long start, map_word z_val)
+{
+ map_word d, t, z;
+
+ d = map_read(map, addr);
+ mb();
+ t = map_read(map, addr);
+ mb();
+ z = map_read(map, start);
+ mb();
+
+ return map_word_equal(map, d, t) && map_word_equal(map, z, z_val);
+}
+#else
static int __xipram chip_ready(struct map_info *map, unsigned long addr)
{
map_word d, t;
@@ -625,6 +652,7 @@ static int __xipram chip_ready(struct map_info *map, unsigned long addr)
return map_word_equal(map, d, t);
}
+#endif
/*
* Return true if the chip is ready and has the correct value.
@@ -658,6 +686,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
struct cfi_private *cfi = map->fldrv_priv;
unsigned long timeo;
struct cfi_pri_amdstd *cfip = (struct cfi_pri_amdstd *)cfi->cmdset_priv;
+#ifdef CONFIG_TANGOX
+ map_word z_val = map_read(map, chip->start);
+#endif
resettime:
timeo = jiffies + HZ;
@@ -666,8 +697,13 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
case FL_STATUS:
for (;;) {
+#ifdef CONFIG_TANGOX
+ if (chip_ready(map, adr, chip->start, z_val))
+ break;
+#else
if (chip_ready(map, adr))
break;
+#endif
if (time_after(jiffies, timeo)) {
printk(KERN_ERR "Waiting for chip to be ready timed out.\n");
@@ -691,6 +727,12 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
(mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
goto sleep;
+ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Sentivision FIX: map_write here whole flash operation freeze on VIP1216 STB.
+ * So we just will sleep waitting for state change: */
+ goto sleep;
+ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
/* We could check to see if we're trying to access the sector
* that is currently being erased. However, no user will try
* anything like that so we just wait for the timeout. */
@@ -703,8 +745,13 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
chip->state = FL_ERASE_SUSPENDING;
chip->erase_suspended = 1;
for (;;) {
+#ifdef CONFIG_TANGOX
+ if (chip_ready(map, adr, chip->start, z_val))
+ break;
+#else
if (chip_ready(map, adr))
break;
+#endif
if (time_after(jiffies, timeo)) {
/* Should have suspended the erase by now.
@@ -1143,6 +1190,9 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
int ret = 0;
map_word oldd;
int retry_cnt = 0;
+#ifdef CONFIG_TANGOX
+ map_word z_val;
+#endif
adr += chip->start;
@@ -1162,6 +1212,9 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
* data at other locations when 0xff is written to a location that
* already contains 0xff.
*/
+#ifdef CONFIG_TANGOX
+ z_val = ((adr == chip->start) ? datum : map_read(map, chip->start));
+#endif
oldd = map_read(map, adr);
if (map_word_equal(map, oldd, datum)) {
pr_debug("MTD %s(): NOP\n",
@@ -1200,15 +1253,25 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
continue;
}
- if (time_after(jiffies, timeo) && !chip_ready(map, adr)){
+#ifdef CONFIG_TANGOX
+ if (time_after(jiffies, timeo) && !chip_ready(map, adr, chip->start, z_val))
+#else
+ if (time_after(jiffies, timeo) && !chip_ready(map, adr))
+#endif
+ {
xip_enable(map, chip, adr);
printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
xip_disable(map, chip, adr);
break;
}
+#ifdef CONFIG_TANGOX
+ if (chip_ready(map, adr, chip->start, z_val))
+ break;
+#else
if (chip_ready(map, adr))
break;
+#endif
/* Latency issues. Drop the lock, wait a while and retry */
UDELAY(map, chip, adr, 1);
@@ -1374,6 +1437,9 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
unsigned long cmd_adr;
int z, words;
map_word datum;
+#ifdef CONFIG_TANGOX
+ map_word z_val;
+#endif
adr += chip->start;
cmd_adr = adr;
@@ -1394,6 +1460,9 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
ENABLE_VPP(map);
xip_disable(map, chip, cmd_adr);
+#ifdef CONFIG_TANGOX
+ z_val = ((adr == chip->start) ? datum : map_read(map, chip->start));
+#endif
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
@@ -1443,10 +1512,20 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
continue;
}
+#ifdef CONFIG_TANGOX
+ if (time_after(jiffies, timeo) && !chip_ready(map, adr, chip->start, z_val))
+ break;
+#else
if (time_after(jiffies, timeo) && !chip_ready(map, adr))
break;
+#endif
- if (chip_ready(map, adr)) {
+#ifdef CONFIG_TANGOX
+ if (chip_ready(map, adr, chip->start, z_val))
+#else
+ if (chip_ready(map, adr))
+#endif
+ {
xip_enable(map, chip, adr);
goto op_done;
}
@@ -1563,12 +1642,19 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
struct cfi_private *cfi = map->fldrv_priv;
int retries = 10;
int i;
+#ifdef CONFIG_TANGOX
+ map_word z_val = map_read(map, chip->start);
+#endif
/*
* If the driver thinks the chip is idle, and no toggle bits
* are changing, then the chip is actually idle for sure.
*/
+#ifdef CONFIG_TANGOX
+ if (chip->state == FL_READY && chip_ready(map, adr, chip->start, z_val))
+#else
if (chip->state == FL_READY && chip_ready(map, adr))
+#endif
return 0;
/*
@@ -1585,7 +1671,11 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
/* wait for the chip to become ready */
for (i = 0; i < jiffies_to_usecs(timeo); i++) {
+#ifdef CONFIG_TANGOX
+ if (chip_ready(map, adr, chip->start, z_val))
+#else
if (chip_ready(map, adr))
+#endif
return 0;
udelay(1);
@@ -1616,6 +1706,9 @@ static int do_panic_write_oneword(struct map_info *map, struct flchip *chip,
map_word oldd;
int ret = 0;
int i;
+#ifdef CONFIG_TANGOX
+ map_word z_val = map_read(map, chip->start);
+#endif
adr += chip->start;
@@ -1647,7 +1740,11 @@ retry:
map_write(map, datum, adr);
for (i = 0; i < jiffies_to_usecs(uWriteTimeout); i++) {
+#ifdef CONFIG_TANGOX
+ if (chip_ready(map, adr, chip->start, z_val))
+#else
if (chip_ready(map, adr))
+#endif
break;
udelay(1);
@@ -1793,6 +1890,10 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
unsigned long int adr;
DECLARE_WAITQUEUE(wait, current);
int ret = 0;
+#ifdef CONFIG_TANGOX
+ map_word z_val;
+ z_val.x[0] = ((map->bankwidth == 1) ? 0xff : 0xffff);
+#endif
adr = cfi->addr_unlock1;
@@ -1845,8 +1946,13 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
chip->erase_suspended = 0;
}
+#ifdef CONFIG_TANGOX
+ if (chip_ready(map, adr, chip->start, z_val))
+ break;
+#else
if (chip_ready(map, adr))
break;
+#endif
if (time_after(jiffies, timeo)) {
printk(KERN_WARNING "MTD %s(): software timeout\n",
@@ -1882,6 +1988,9 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
unsigned long timeo = jiffies + HZ;
DECLARE_WAITQUEUE(wait, current);
int ret = 0;
+#ifdef CONFIG_TANGOX
+ map_word z_val;
+#endif
adr += chip->start;
@@ -1895,6 +2004,13 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
pr_debug("MTD %s(): ERASE 0x%.8lx\n",
__func__, adr );
+#ifdef CONFIG_TANGOX
+ if (adr == chip->start)
+ z_val.x[0] = ((map->bankwidth == 1) ? 0xff : 0xffff);
+ else
+ z_val = map_read(map, chip->start);
+#endif
+
XIP_INVAL_CACHED_RANGE(map, adr, len);
ENABLE_VPP(map);
xip_disable(map, chip, adr);
@@ -1928,13 +2044,18 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
continue;
}
if (chip->erase_suspended) {
- /* This erase was suspended and resumed.
+ /* This erase was suspended and resumed.
Adjust the timeout */
timeo = jiffies + (HZ*20); /* FIXME */
chip->erase_suspended = 0;
}
- if (chip_ready(map, adr)) {
+#ifdef CONFIG_TANGOX
+ if (chip_ready(map, adr, chip->start, z_val))
+#else
+ if (chip_ready(map, adr))
+#endif
+ {
xip_enable(map, chip, adr);
break;
}
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 1924d247c1cb..077105f0996d 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -56,6 +56,9 @@
/* Used for Macronix flashes only. */
#define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */
#define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */
+#if defined(CONFIG_SPI_TANGOX) || defined (CONFIG_SPI_TANGOX_MODULE)
+#define OPCODE_RDP 0xab /* Release from deep power down */
+#endif
/* Used for Spansion flashes only. */
#define OPCODE_BRWR 0x17 /* Bank register write */
@@ -388,6 +391,80 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
return 0;
}
+ /*
+ * Read an address range from the flash chip page by page.
+ * Some controller has transaction length limitation such as the
+ * Freescale's eSPI controller can only trasmit 0xFFFF bytes one
+ * time, so we have to read page by page if the len is more than
+ * the limitation.
+ */
+static int m25p80_page_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct m25p *flash = mtd_to_m25p(mtd);
+ struct spi_transfer t[2];
+ struct spi_message m;
+ u32 i, page_size = 0;
+
+ pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
+ __func__, (u32)from, len);
+
+ /* sanity checks */
+ if (!len)
+ return 0;
+
+ if (from + len > flash->mtd.size)
+ return -EINVAL;
+
+ spi_message_init(&m);
+ memset(t, 0, (sizeof t));
+
+ /* NOTE:
+ * OPCODE_FAST_READ (if available) is faster.
+ * Should add 1 byte DUMMY_BYTE.
+ */
+ t[0].tx_buf = flash->command;
+ t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].rx_buf = buf;
+ spi_message_add_tail(&t[1], &m);
+
+ /* Byte count starts at zero. */
+ if (retlen)
+ *retlen = 0;
+
+ mutex_lock(&flash->lock);
+
+ /* Wait till previous write/erase is done. */
+ if (wait_till_ready(flash)) {
+ /* REVISIT status return?? */
+ mutex_unlock(&flash->lock);
+ return 1;
+ }
+
+ /* Set up the write data buffer. */
+ flash->command[0] = OPCODE_READ;
+
+ for (i = page_size; i < len; i += page_size) {
+ page_size = len - i;
+ if (page_size > flash->page_size)
+ page_size = flash->page_size;
+ m25p_addr2cmd(flash, from + i, flash->command);
+ t[1].len = page_size;
+ t[1].rx_buf = buf + i;
+
+ spi_sync(flash->spi, &m);
+
+ *retlen += m.actual_length - m25p_cmdsz(flash)
+ - FAST_READ_DUMMY_BYTE;
+ }
+
+ mutex_unlock(&flash->lock);
+
+ return 0;
+}
+
/*
* Write an address range to the flash chip. Data must be written in
* FLASH_PAGESIZE chunks. The address range may be any size provided
@@ -820,6 +897,22 @@ static int __devinit m25p_probe(struct spi_device *spi)
dev_warn(&spi->dev, "unrecognized id %s\n", data->type);
}
+#if defined(CONFIG_SPI_TANGOX) || defined (CONFIG_SPI_TANGOX_MODULE)
+ /*
+ * - we need to send wake up command before probing id. this is because
+ * the macronix device will not return correct id in sleep mode.
+ *
+ * - the wake up command is only for macronix device and we check it with
+ * the id string from platform device info.
+ */
+ if ( !strncmp(id->name, "mx", 2) ) {
+ /* wake up device for the case flash in deep power down mode */
+ u8 code = OPCODE_RDP;
+ u8 dummy;
+ spi_write_then_read(spi, &code, 1, &dummy, 1);
+ }
+#endif
+
info = (void *)id->driver_data;
if (info->jedec_id) {
@@ -880,6 +973,12 @@ static int __devinit m25p_probe(struct spi_device *spi)
flash->mtd._erase = m25p80_erase;
flash->mtd._read = m25p80_read;
+#if defined(CONFIG_SPI_TANGOX) || defined (CONFIG_SPI_TANGOX_MODULE)
+ /* overwrite read for page size read */
+ if (spi->master->quirks & SPI_QUIRK_TRANS_LEN_LIMIT)
+ flash->mtd._read = m25p80_page_read;
+#endif
+
/* sst flash chips use AAI word program */
if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST)
flash->mtd._write = sst_write;
@@ -934,7 +1033,6 @@ static int __devinit m25p_probe(struct spi_device *spi)
flash->mtd.eraseregions[i].erasesize / 1024,
flash->mtd.eraseregions[i].numblocks);
-
/* partitions should match sector boundaries; and it may be good to
* use readonly partitions for writeprotected sectors (BP2..BP0).
*/
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 8af67cfd671a..7354f465b430 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -4,6 +4,7 @@ menu "Mapping drivers for chip access"
config MTD_COMPLEX_MAPPINGS
bool "Support non-linear mappings of flash chips"
+ depends on MTD && !TANGOX_XENV_READ
help
This causes the chip drivers to allow for complicated
paged mappings of flash chips.
@@ -24,7 +25,7 @@ config MTD_PHYSMAP
config MTD_PHYSMAP_COMPAT
bool "Physmap compat support"
- depends on MTD_PHYSMAP
+ depends on MTD_PHYSMAP && !TANGOX_XENV_READ
default n
help
Setup a simple mapping via the Kconfig options. Normally the
@@ -35,7 +36,7 @@ config MTD_PHYSMAP_COMPAT
config MTD_PHYSMAP_START
hex "Physical start address of flash mapping"
- depends on MTD_PHYSMAP_COMPAT
+ depends on MTD_PHYSMAP_COMPAT && !TANGOX_XENV_READ
default "0x8000000"
help
This is the physical memory location at which the flash chips
@@ -45,8 +46,8 @@ config MTD_PHYSMAP_START
config MTD_PHYSMAP_LEN
hex "Physical length of flash mapping"
- depends on MTD_PHYSMAP_COMPAT
- default "0"
+ depends on MTD_PHYSMAP_COMPAT && !TANGOX_XENV_READ
+ default "0x4000000"
help
This is the total length of the mapping of the flash chips on
your particular board. If there is space, or aliases, in the
@@ -57,7 +58,7 @@ config MTD_PHYSMAP_LEN
config MTD_PHYSMAP_BANKWIDTH
int "Bank width in octets"
- depends on MTD_PHYSMAP_COMPAT
+ depends on MTD_PHYSMAP_COMPAT && !TANGOX_XENV_READ
default "2"
help
This is the total width of the data bus of the flash devices
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index 21b0b713cacb..3b682502988d 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -21,6 +21,53 @@
#include <linux/mtd/concat.h>
#include <linux/io.h>
+#if defined(CONFIG_TANGOX) && defined(CONFIG_TANGOX_XENV_READ)
+
+#ifdef CONFIG_TANGO2
+#include <asm/tango2/emhwlib_registers_tango2.h>
+#include <asm/tango2/tango2_gbus.h>
+#elif defined(CONFIG_TANGO3)
+#include <asm/tango3/emhwlib_registers_tango3.h>
+#include <asm/tango3/tango3_gbus.h>
+#endif
+
+#define XENV_MAX_FLASH 4
+#define XENV_MAX_FLASH_PARTITIONS 16
+static struct mtd_info *mymtds[XENV_MAX_FLASH] = { NULL, NULL, NULL, NULL };
+static struct mtd_partition *mtd_parts[XENV_MAX_FLASH] = { NULL, NULL, NULL, NULL };
+static unsigned int p_cnts[XENV_MAX_FLASH] = { 0, 0, 0, 0 };
+static u64 f_sizes[XENV_MAX_FLASH] = { 0, 0, 0, 0 };
+
+struct map_info physmap_maps[XENV_MAX_FLASH] = {
+ {
+ .name = "CS0: Physically mapped flash",
+ .phys = 0x40000000,
+ .size = 0, /* To be filled by XENV */
+ .bankwidth = 2, /* To be checked by PBI registers */
+ },
+ {
+ .name = "CS1: Physically mapped flash",
+ .phys = 0x44000000,
+ .size = 0, /* To be filled by XENV */
+ .bankwidth = 2, /* To be checked by PBI registers */
+ },
+ {
+ .name = "CS2: Physically mapped flash",
+ .phys = 0x48000000,
+ .size = 0, /* To be filled by XENV */
+ .bankwidth = 2, /* To be checked by PBI registers */
+ },
+ {
+ .name = "CS3: Physically mapped flash",
+ .phys = 0x4c000000,
+ .size = 0, /* To be filled by XENV */
+ .bankwidth = 2, /* To be checked by PBI registers */
+ },
+};
+int tangox_flash_get_info(int cs, u64 *size, unsigned int *part_count);
+int tangox_flash_get_parts(int cs, u64 offset[], u64 size[]);
+#endif
+
#define MAX_RESOURCES 4
struct physmap_flash_info {
@@ -33,6 +80,29 @@ struct physmap_flash_info {
static int physmap_flash_remove(struct platform_device *dev)
{
+#if defined(CONFIG_TANGOX) && defined(CONFIG_TANGOX_XENV_READ)
+ int cs, p;
+ struct mtd_partition *part_ptr;
+
+ for (cs = 0; cs < XENV_MAX_FLASH; cs++) {
+ if (f_sizes[cs] != 0) {
+ if (p_cnts[cs] != 0) {
+ for (part_ptr = mtd_parts[cs], p = 0; p < p_cnts[cs]; p++, part_ptr++) {
+ if (part_ptr->name) {
+ kfree(part_ptr->name);
+ part_ptr->name = NULL;
+ }
+ }
+ }
+ mtd_device_unregister(mymtds[cs]);
+ map_destroy(mymtds[cs]);
+ kfree(mtd_parts[cs]);
+ mtd_parts[cs] = NULL;
+ iounmap(physmap_maps[cs].virt);
+ physmap_maps[cs].virt = NULL;
+ }
+ }
+#else
struct physmap_flash_info *info;
struct physmap_flash_data *physmap_data;
int i;
@@ -57,7 +127,7 @@ static int physmap_flash_remove(struct platform_device *dev)
if (physmap_data->exit)
physmap_data->exit(dev);
-
+#endif
return 0;
}
@@ -93,14 +163,128 @@ static const char *rom_probe_types[] = {
"qinfo_probe",
"map_rom",
NULL };
+
+#ifndef CONFIG_TANGOX
static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", "afs",
NULL };
+#endif
static int physmap_flash_probe(struct platform_device *dev)
{
+ const char **probe_type;
+
+#if defined(CONFIG_TANGOX) && defined(CONFIG_TANGOX_XENV_READ)
+ int cs;
+ int part_num = 0;
+ unsigned long csconfig = gbus_read_reg32(REG_BASE_host_interface + PB_CS_config) & 0xf;
+
+ for (cs = 0; cs < XENV_MAX_FLASH; cs++) {
+
+ /* Check XENV for availability */
+ f_sizes[cs] = p_cnts[cs] = 0;
+
+ tangox_flash_get_info(cs, &f_sizes[cs], &p_cnts[cs]);
+ if (f_sizes[cs] == 0)
+ continue;
+ else {
+ physmap_maps[cs].size = f_sizes[cs];
+ physmap_maps[cs].bankwidth = ((csconfig >> cs) & 0x1) ? 1 : 2;
+ }
+
+ printk(KERN_NOTICE "physmap flash device CS%d: 0x%x at 0x%x\n",
+ cs, (u32)physmap_maps[cs].size, (u32)physmap_maps[cs].phys);
+ physmap_maps[cs].virt = ioremap(physmap_maps[cs].phys, physmap_maps[cs].size);
+
+ if (!physmap_maps[cs].virt) {
+ printk("Failed to ioremap\n");
+ continue;
+ }
+
+ simple_map_init(&physmap_maps[cs]);
+
+ mymtds[cs] = NULL;
+ probe_type = rom_probe_types;
+ for(; !mymtds[cs] && *probe_type; probe_type++) {
+ mymtds[cs] = do_map_probe(*probe_type, &physmap_maps[cs]);
+ }
+
+ if (mymtds[cs] && (mymtds[cs]->size != f_sizes[cs])) {
+ /* Redo ioremap if size specified is not the same as detected */
+ iounmap((void *)physmap_maps[cs].virt);
+ physmap_maps[cs].size = mymtds[cs]->size;
+ physmap_maps[cs].virt = ioremap(physmap_maps[cs].phys, physmap_maps[cs].size);
+ physmap_maps[cs].set_vpp = physmap_set_vpp;
+
+ if (!physmap_maps[cs].virt) {
+ printk(KERN_NOTICE "Failed to ioremap at 0x%08x, size 0x%08x\n",
+ (u32)physmap_maps[cs].phys, (u32)physmap_maps[cs].size);
+ continue;
+ }
+ printk(KERN_NOTICE "CS%d: flash size mismatched, re-do probing/initialization.\n", cs);
+ printk(KERN_NOTICE "physmap flash device CS%d: 0x%x at 0x%x (remapped 0x%x)\n",
+ cs, (u32)physmap_maps[cs].size, (u32)physmap_maps[cs].phys, (u32)physmap_maps[cs].virt);
+
+ /* Re-do initialization */
+ simple_map_init(&physmap_maps[cs]);
+ mymtds[cs] = NULL;
+ probe_type = rom_probe_types;
+ for(; !mymtds[cs] && *probe_type; probe_type++) {
+ mymtds[cs] = do_map_probe(*probe_type, &physmap_maps[cs]);
+ }
+ }
+
+ if (mymtds[cs]) {
+ mymtds[cs]->owner = THIS_MODULE;
+ mtd_device_register(mymtds[cs], NULL, 0);
+ part_num++;
+
+ if (p_cnts[cs] > 0) {
+ int p, pcnt;
+ struct mtd_partition *part_ptr;
+ u64 offsets[XENV_MAX_FLASH_PARTITIONS];
+ u64 szs[XENV_MAX_FLASH_PARTITIONS];
+
+ if ((mtd_parts[cs] = (struct mtd_partition *)kmalloc(
+ sizeof(struct mtd_partition) * p_cnts[cs], GFP_KERNEL)) == NULL) {
+ printk(KERN_NOTICE "Out of memory.\n");
+ return -ENOMEM;
+ }
+ memset(mtd_parts[cs], 0, sizeof(struct mtd_partition) * p_cnts[cs]);
+ tangox_flash_get_parts(cs, offsets, szs);
+
+ printk(KERN_NOTICE "Using physmap partition definition\n");
+
+ /* Initialize each partition */
+ for (pcnt = 0, part_ptr = mtd_parts[cs], p = 0; p < p_cnts[cs]; p++) {
+ if (((szs[p] & 0x7fffffff) + offsets[p]) > physmap_maps[cs].size) {
+ printk(KERN_NOTICE "CS%d-Part%d (offset:0x%llx, size:0x%llx) outside physical map, removed.\n",
+ cs, p + 1, offsets[p], szs[p] & 0x7fffffffffffffffULL);
+ continue;
+ }
+ part_ptr->size = szs[p] & 0x7fffffffffffffffULL;
+ part_ptr->offset = offsets[p];
+ if (part_ptr->size & 0x8000000000000000ULL)
+ part_ptr->mask_flags = MTD_WRITEABLE;
+ part_ptr->name = (char *)kmalloc(16, GFP_KERNEL);
+ if (part_ptr->name != NULL)
+ sprintf(part_ptr->name, "CS%d-Part%d", cs, p + 1);
+ pcnt++;
+ part_ptr++;
+ }
+ p_cnts[cs] = pcnt;
+
+ if (p_cnts[cs] > 0) {
+ printk(KERN_NOTICE "Adding partition #%d-#%d\n", part_num, part_num + p_cnts[cs] - 1);
+ mtd_device_register(mymtds[cs], mtd_parts[cs], p_cnts[cs]);
+ part_num += p_cnts[cs];
+ }
+ }
+ }
+ }
+ return 0;
+#else
struct physmap_flash_data *physmap_data;
struct physmap_flash_info *info;
- const char **probe_type;
const char **part_types;
int err = 0;
int i;
@@ -199,6 +383,7 @@ static int physmap_flash_probe(struct platform_device *dev)
err_out:
physmap_flash_remove(dev);
return err;
+#endif /* CONFIG_TANGOX && CONFIG_TANGOX_XENV_READ */
}
#ifdef CONFIG_PM
@@ -218,7 +403,9 @@ static void physmap_flash_shutdown(struct platform_device *dev)
static struct platform_driver physmap_flash_driver = {
.probe = physmap_flash_probe,
.remove = physmap_flash_remove,
- .shutdown = physmap_flash_shutdown,
+#ifdef CONFIG_PM
+ .shutdown = physmap_flash_shutdown,
+#endif
.driver = {
.name = "physmap-flash",
.owner = THIS_MODULE,
@@ -261,11 +448,20 @@ static int __init physmap_init(void)
}
#endif
+#ifdef CONFIG_TANGOX
+ /* a hack to force probing here */
+ err = physmap_flash_probe(NULL);
+#endif
+
return err;
}
static void __exit physmap_exit(void)
{
+#ifdef CONFIG_TANGOX
+ physmap_flash_remove(NULL);
+#endif
+
#ifdef CONFIG_MTD_PHYSMAP_COMPAT
platform_device_unregister(&physmap_flash);
#endif
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index f2f482bec573..8219c1ce0f6b 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -620,6 +620,8 @@ static int mtdchar_write_ioctl(struct mtd_info *mtd,
return ret;
}
+#define MEMERASEFORCE _IOW('M', 20, struct erase_info_user)
+
static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
{
struct mtd_file_info *mfi = file->private_data;
@@ -751,6 +753,58 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
break;
}
+ case MEMERASEFORCE:
+ {
+ struct erase_info *erase;
+
+ if(!(file->f_mode & 2))
+ return -EPERM;
+
+ erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL);
+ if (!erase)
+ ret = -ENOMEM;
+ else {
+ wait_queue_head_t waitq;
+ DECLARE_WAITQUEUE(wait, current);
+
+ init_waitqueue_head(&waitq);
+
+ if (copy_from_user(&erase->addr, argp,
+ sizeof(struct erase_info_user))) {
+ kfree(erase);
+ return -EFAULT;
+ }
+ erase->mtd = mtd;
+ erase->callback = mtdchar_erase_callback;
+ erase->priv = (unsigned long)&waitq;
+ erase->retries = 0x73092215;
+
+ /*
+ FIXME: Allow INTERRUPTIBLE. Which means
+ not having the wait_queue head on the stack.
+
+ If the wq_head is on the stack, and we
+ leave because we got interrupted, then the
+ wq_head is no longer there when the
+ callback routine tries to wake us up.
+ */
+ ret = mtd_erase(mtd, erase);
+ if (!ret) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&waitq, &wait);
+ if (erase->state != MTD_ERASE_DONE &&
+ erase->state != MTD_ERASE_FAILED)
+ schedule();
+ remove_wait_queue(&waitq, &wait);
+ set_current_state(TASK_RUNNING);
+
+ ret = (erase->state == MTD_ERASE_FAILED)?-EIO:0;
+ }
+ kfree(erase);
+ }
+ break;
+ }
+
case MEMWRITEOOB:
{
struct mtd_oob_buf buf;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index c837507dfb1c..3a3d5062456e 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -3,7 +3,7 @@
* drivers and users.
*
* Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org>
- * Copyright © 2006 Red Hat UK Limited
+ * Copyright © 2006 Red Hat UK Limited
*
* 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
@@ -80,6 +80,10 @@ static struct class mtd_class = {
.resume = mtd_cls_resume,
};
+#if defined(CONFIG_ARCH_VENDOR_SX6) && defined(CONFIG_MTD_UBI) && !defined(CONFIG_BLK_DEV_INITRD)
+extern char saved_root_name[64];
+#endif
+
static DEFINE_IDR(mtd_idr);
/* These are exported solely for the purpose of mtd_blkdevs.c. You
@@ -250,6 +254,49 @@ static ssize_t mtd_name_show(struct device *dev,
}
static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL);
+static ssize_t mtd_nand_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mtd_info *mtd = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", mtd->nand_type);
+}
+static DEVICE_ATTR(nand_type, S_IRUGO, mtd_nand_type_show, NULL);
+
+static ssize_t mtd_nand_manufacturer_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mtd_info *mtd = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", mtd->nand_manufacturer);
+}
+static DEVICE_ATTR(nand_manufacturer, S_IRUGO, mtd_nand_manufacturer_show, NULL);
+
+static ssize_t mtd_nand_onfi_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mtd_info *mtd = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", mtd->onfi_version);
+}
+static DEVICE_ATTR(onfi_version, S_IRUGO, mtd_nand_onfi_version_show, NULL);
+
+static ssize_t mtd_nand_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mtd_info *mtd = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", mtd->id_data[0]
+ , mtd->id_data[1]
+ , mtd->id_data[2]
+ , mtd->id_data[3]
+ , mtd->id_data[4]
+ , mtd->id_data[5]
+ , mtd->id_data[6]
+ , mtd->id_data[7]);
+}
+static DEVICE_ATTR(nand_id, S_IRUGO, mtd_nand_id_show, NULL);
+
static struct attribute *mtd_attrs[] = {
&dev_attr_type.attr,
&dev_attr_flags.attr,
@@ -260,6 +307,10 @@ static struct attribute *mtd_attrs[] = {
&dev_attr_oobsize.attr,
&dev_attr_numeraseregions.attr,
&dev_attr_name.attr,
+ &dev_attr_nand_type.attr,
+ &dev_attr_nand_manufacturer.attr,
+ &dev_attr_nand_id.attr,
+ &dev_attr_onfi_version.attr,
NULL,
};
@@ -321,7 +372,15 @@ int add_mtd_device(struct mtd_info *mtd)
mtd->index = i;
mtd->usecount = 0;
-
+#if defined(CONFIG_ARCH_VENDOR_SX6) && defined(CONFIG_MTD_UBI) && !defined(CONFIG_BLK_DEV_INITRD)
+ if(0 == strncmp(mtd->name,"Rootfs",6))
+ {
+ char rootname[16];
+ sprintf(rootname,"/dev/mtdblock%d",i);
+ strlcpy(saved_root_name, rootname, sizeof(rootname));
+ printk("UBI root=%s\n",saved_root_name);
+ }
+#endif
if (is_power_of_2(mtd->erasesize))
mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
else
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index bf24aa77175d..148cfefa045d 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -345,6 +345,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
{
struct mtd_part *slave;
char *name;
+ int i;
/* allocate the partition structure */
slave = kzalloc(sizeof(*slave), GFP_KERNEL);
@@ -366,6 +367,11 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd.oobsize = master->oobsize;
slave->mtd.oobavail = master->oobavail;
slave->mtd.subpage_sft = master->subpage_sft;
+ slave->mtd.nand_type = master->nand_type;
+ slave->mtd.nand_manufacturer = master->nand_manufacturer;
+ slave->mtd.onfi_version = master->onfi_version;
+ for (i = 0; i < 8; i++)
+ slave->mtd.id_data[i] = master->id_data[i];
slave->mtd.name = name;
slave->mtd.owner = master->owner;
@@ -646,6 +652,9 @@ int add_mtd_partitions(struct mtd_info *master,
return 0;
}
+#ifdef CONFIG_VENDOR_DTV
+EXPORT_SYMBOL(add_mtd_partitions);
+#endif
static DEFINE_SPINLOCK(part_parser_lock);
static LIST_HEAD(part_parsers);
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7d17cecad69d..241410eee873 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -1,3 +1,10 @@
+config MTD_NAND_IDS
+ tristate "Include chip ids for known NAND devices."
+ depends on MTD
+ help
+ Useful for NAND drivers that do not use the NAND subsystem but
+ still like to take advantage of the known chip information.
+
config MTD_NAND_ECC
tristate
@@ -83,6 +90,14 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
scratch register here to enable this feature. On Intel Moorestown
boards, the scratch register is at 0xFF108018.
+config MTD_NAND_TANGOX
+ tristate "TANGOX NAND Device Support"
+ depends on TANGO3 || TANGO4
+ select MTD_PARTITIONS
+ default m
+ help
+ Support TANGOX NAND Flash in the NAND flash reserved zone.
+
config MTD_NAND_H1900
tristate "iPAQ H1900 flash"
depends on ARCH_PXA && BROKEN
@@ -115,9 +130,6 @@ config MTD_NAND_OMAP2
Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
platforms.
-config MTD_NAND_IDS
- tristate
-
config MTD_NAND_RICOH
tristate "Ricoh xD card reader"
default n
@@ -566,5 +578,33 @@ config MTD_NAND_FSMC
help
Enables support for NAND Flash chips on the ST Microelectronics
Flexible Static Memory Controller (FSMC)
+choice
+ prompt "NAND ECC mode"
+ depends on MTD_NAND && ARCH_VENDOR_SX6
+ default MTD_NAND_MLC_BCH if (VENDOR_DTV_ROM_SLC || VENDOR_DTV_ROM_MLC)
+config MTD_NAND_ECC_HW
+ bool "Hardware ECC"
+config MTD_NAND_ECC_SW
+ bool "Soft ECC"
+config MTD_NAND_MLC_BCH
+ bool "MLC BCH "
+config MTD_NAND_ECC_NONE
+ bool "None ECC"
+endchoice
+
+choice
+ prompt "NAND ECC calc size"
+ depends on MTD_NAND && ARCH_VENDOR_SX6
+ default MTD_NAND_ECC_512 if VENDOR_DTV_ROM_SLC
+ default MTD_NAND_ECC_1024 if VENDOR_DTV_ROM_MLC
+config MTD_NAND_ECC_512
+ bool "512 bytes"
+config MTD_NAND_ECC_1024
+ bool "1024 bytes"
+endchoice
+config MTD_NAND_DMA
+ bool "DMA enable"
+ depends on MTD_NAND_PHYSMAP
+default y
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index d4b4d8739bd8..696b8ddfd8f4 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -7,12 +7,15 @@ obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
-
+ifdef CONFIG_MTD_NAND
+obj-$(CONFIG_ARCH_VENDOR_SX6) += monza_nand.o
+endif
obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
obj-$(CONFIG_MTD_NAND_DENALI) += denali.o
+obj-$(CONFIG_MTD_NAND_TANGOX) += smp8xxx_nand.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
@@ -53,3 +56,9 @@ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
nand-objs := nand_base.o nand_bbt.o
+
+ifeq ($(CONFIG_VENDOR_DTV),y)
+ifdef CONFIG_MTD_NAND_MLC_BCH
+nand-objs += nand_bch_ecc.o
+endif
+endif
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index eb9f5fb02eef..4f05253bdc26 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -47,7 +47,22 @@
#include <linux/bitops.h>
#include <linux/leds.h>
#include <linux/io.h>
+#ifdef CONFIG_VENDOR_DTV
+#include <linux/semaphore.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#endif
+
+#ifdef CONFIG_MTD_PARTITIONS
#include <linux/mtd/partitions.h>
+#endif
+#ifdef CONFIG_MTD_NAND_MLC_BCH
+#define CONFIG_NAND_MODE 1
+#endif
/* Define default oob placement schemes for large and small page devices */
static struct nand_ecclayout nand_oob_8 = {
@@ -64,8 +79,11 @@ static struct nand_ecclayout nand_oob_16 = {
.eccbytes = 6,
.eccpos = {0, 1, 2, 3, 6, 7},
.oobfree = {
- {.offset = 8,
- . length = 8} }
+#ifdef CONFIG_MTD_NAND_BBM
+ {.offset = 9, . length = 7}} //nand bbm config
+#else
+ {.offset = 8, . length = 8}}
+#endif
};
static struct nand_ecclayout nand_oob_64 = {
@@ -75,8 +93,112 @@ static struct nand_ecclayout nand_oob_64 = {
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63},
.oobfree = {
- {.offset = 2,
- .length = 38} }
+#ifdef CONFIG_MTD_NAND_BBM
+ {.offset = 3,.length = 37}} //nand bbm config
+#else
+ {.offset = 2,.length = 38}}
+#endif
+};
+
+/*For BCH code*/
+static struct nand_ecclayout nand_oob_mlcbch_16 = {
+ .eccbytes = 7,
+ .eccpos = {0, 1, 2, 3, 6, 7, 9},
+ .oobfree = {
+ {.offset = 10,
+ .length = 6}}
+};
+
+#ifdef CONFIG_MTD_NAND_ECC_512
+//change for 8bit 512 byte ecc
+static struct nand_ecclayout nand_oob_mlcbch_64 = {
+ .eccbytes = 56,
+ .eccpos = {
+ 8,9,10,11,12,13,14,15,16,17,18,19,20,21,
+ 22,23,24,25,26,27,28,29,30,31,32,33,34,35,
+ 36,37,38,39,40,41,42,43,44,45,46,47,48,49,
+ 50,51,52,53,54,55,56,57,58,59,60,61,62,63 },
+ .oobfree = {
+ {.offset = 3,
+ .length = 5}}
+};
+#else
+//change for 8bit 1024 byte ecc
+static struct nand_ecclayout nand_oob_mlcbch_64 = {
+ .eccbytes = 28,
+ .eccpos = {
+ 36,37,38,39,40,41,42,43,44,45,46,47,48,49,
+ 50,51,52,53,54,55,56,57,58,59,60,61,62,63 },
+ .oobfree = {
+ {.offset = 3,
+ .length = 33}}
+};
+
+static struct nand_ecclayout nand_oob_mlcbch_448 = {
+ .eccbytes = 336,//24*7/4 *8,
+ .eccpos = {
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
+ 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
+ 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
+ 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
+ 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
+ 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
+ 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
+ 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
+ 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
+ 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243,
+ 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
+ 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265,
+ 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276,
+ 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287,
+ 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298,
+ 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309,
+ 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320,
+ 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331,
+ 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342,
+ 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353,
+ 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364,
+ 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375,
+ 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386,
+ 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397,
+ 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408,
+ 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419,
+ 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430,
+ 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441,
+ 442, 443, 444, 445, 446, 447 },
+ .oobfree = {
+ {.offset = 3,
+ .length = 109}}
+};
+
+#endif
+
+/*2013.4.2 add for Micron MT29F16G08CBACA*/
+static struct nand_ecclayout nand_oob_mlcbch_224 = {
+ .eccbytes = 168,
+ .eccpos = {
+ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
+ 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
+ 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
+ 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
+ 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
+ 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
+ 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
+ 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
+ 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
+ 222, 223},
+ .oobfree = {
+ {.offset = 3,
+ .length = 53}}
};
static struct nand_ecclayout nand_oob_128 = {
@@ -93,6 +215,86 @@ static struct nand_ecclayout nand_oob_128 = {
.length = 78} }
};
+#ifdef CONFIG_MIPS_TRIDENT_FUSION_ANDROID
+/*
+ read 1`b1 , access permission, 0`b1 permission denied. it should be write
+ 1 after finish access, then others can access
+ warning: the SPI_lock will change when read the register each time,so don`t
+ use unnecessary ReadRegWord operation
+*/
+
+static int DMA_flag_reset = 1;
+#define SPIN_REG_ADDR 0xf5024068
+
+#define SPINID 0x1
+static void NAND_spin_lock_hw(volatile void * reg)
+{
+ u32 value ;
+ do {
+ value = ReadRegWord(reg) ;
+ } while((value & SPINID) == 0 ); //get 0 permission denied
+
+ //now we get the SPI_lock, value should be 1`b1
+ //printk(KERN_INFO "[%s] reg = 0x%x\t value = 0x%x \n",__func__,reg,value);
+
+ return ;
+}
+
+//fail return 1, 0 success & get the SPIN lock
+u32 NAND_try_spinlock_hw(volatile void * reg)
+{
+ u32 val;
+ val = ReadRegWord(reg);
+ if((val&SPINID)==0x0) //0 is permission denied
+ {
+ //printk(KERN_INFO "NAND: try to get hw SPIN lock fail \n");
+ return 1;
+ }
+ else
+ {
+ //printk(KERN_INFO "NAND: try to get hw SPIN lock success \n");
+ return 0;
+ }
+}
+
+void NAND_spin_lock_hw_dump(volatile void * reg)
+{
+ int try_time = 0;
+ int print_once = 1;
+ while( NAND_try_spinlock_hw(reg) )
+ {
+ schedule();
+
+ //debug
+ #if 0
+ try_time++;
+ if(unlikely(try_time > 20000))
+ {
+ if(print_once)
+ {
+ print_once = 0;
+ dump_stack();
+ }
+ }
+ #endif
+ }
+}
+
+void NAND_spin_unlock_hw(volatile void * reg)
+{
+ u32 val;
+ val = ReadRegWord(reg);
+ WriteRegWord(reg,(val |SPINID));
+
+ //printk(KERN_INFO "[%s] reg = 0x%x\t value = 0x%x \n",__func__,reg,val);
+}
+
+#endif
+
+#ifdef CONFIG_TRIDENT_FLASH_MULTI
+DECLARE_MUTEX(flash_multi_sem);
+#endif
+
static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
int new_state);
@@ -123,6 +325,14 @@ static int check_offs_len(struct mtd_info *mtd,
ret = -EINVAL;
}
+//#ifdef CONFIG_VENDOR_DTV
+ /* Do not allow past end of device */
+ if (ofs + len > mtd->size) {
+ pr_debug( "%s: Past end of device\n",__func__);
+ ret = -EINVAL;
+ }
+//#endif
+
return ret;
}
@@ -145,6 +355,14 @@ static void nand_release_device(struct mtd_info *mtd)
chip->state = FL_READY;
wake_up(&chip->controller->wq);
spin_unlock(&chip->controller->lock);
+
+#ifdef CONFIG_TRIDENT_FLASH_MULTI
+ up(&flash_multi_sem);
+#endif
+
+#ifdef CONFIG_MIPS_TRIDENT_FUSION_ANDROID
+ NAND_spin_unlock_hw(SPIN_REG_ADDR);
+#endif
}
/**
@@ -156,7 +374,11 @@ static void nand_release_device(struct mtd_info *mtd)
static uint8_t nand_read_byte(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
+#ifdef CONFIG_VENDOR_DTV
+ return ReadRegByte(chip->IO_ADDR_R);
+#else
return readb(chip->IO_ADDR_R);
+#endif
}
/**
@@ -182,7 +404,11 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd)
static u16 nand_read_word(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
+#ifdef CONFIG_VENDOR_DTV
+ return ReadRegWord(chip->IO_ADDR_R);
+#else
return readw(chip->IO_ADDR_R);
+#endif
}
/**
@@ -322,6 +548,51 @@ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
return 0;
}
+#ifdef CONFIG_VENDOR_DTV
+static void nand_write_buf32(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+// int i;
+ struct nand_chip *chip = mtd->priv;
+ register volatile void* hwaddr = chip->IO_ADDR_W;
+ register u32 *p = (u32 *) buf;
+
+ len >>= 2;
+ if (len == 0)
+ return;
+ do {
+ WriteRegWord(hwaddr,*p++);
+ } while(--len);
+
+// for (i = 0; i < len; i++)
+// WriteRegWord(chip->IO_ADDR_W,p[i]);
+}
+
+static void nand_read_buf32(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ int i;
+ struct nand_chip *chip = mtd->priv;
+ u32 *p = (u32 *) buf;
+
+ len >>= 2;
+ for (i = 0; i < len; i++)
+ p[i] = ReadRegWord(chip->IO_ADDR_R);
+}
+
+static int nand_verify_buf32(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ int i;
+ struct nand_chip *chip = mtd->priv;
+ u32 *p = (u32 *) buf;
+
+ len >>= 2;
+ for (i = 0; i < len; i++)
+ if (p[i] != ReadRegWord(chip->IO_ADDR_R))
+ return -EFAULT;
+
+ return 0;
+}
+#endif
+
/**
* nand_block_bad - [DEFAULT] Read bad block marker from the chip
* @mtd: MTD device structure
@@ -646,7 +917,13 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine.
*/
+#ifdef CONFIG_TANGOX
+ udelay(1); /* needs to make it much longer than tWB */
+#elif defined(CONFIG_VENDOR_DTV)
+ //ndelay(100);
+#else
ndelay(100);
+#endif
nand_wait_ready(mtd);
}
@@ -768,7 +1045,13 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine.
*/
+#ifdef CONFIG_TANGOX
+ udelay(1); /* needs to make it much longer than tWB */
+#elif defined(CONFIG_VENDOR_DTV)
+ //ndelay(100);
+#else
ndelay(100);
+#endif
nand_wait_ready(mtd);
}
@@ -800,9 +1083,59 @@ static void panic_nand_get_device(struct nand_chip *chip,
static int
nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
{
+#ifdef CONFIG_MIPS_TRIDENT_FUSION_ANDROID
+ /*for share NAND control between PLF and APP, we use HW SPIN_LOCK to
+ protect */
+ NAND_spin_lock_hw_dump(SPIN_REG_ADDR);
+#endif
+
spinlock_t *lock = &chip->controller->lock;
wait_queue_head_t *wq = &chip->controller->wq;
DECLARE_WAITQUEUE(wait, current);
+
+#ifdef CONFIG_TRIDENT_FLASH_MULTI
+ unsigned int val;
+ if(new_state != FL_PM_SUSPENDED){
+ down(&flash_multi_sem);
+ }
+
+ /*switch to nand*/
+ val = ReadRegWord((void*)0xfB002008);
+ if(val != 0x2)
+ {
+ WriteRegWord((void*)0xfb002008,0x2);
+ ReadRegWord((void*)0xfb002008);
+ }
+
+ #ifdef CONFIG_NAND_MODE
+ /* switch the nand source clock from 100Hz to 200Hz for this version of NAND mode setting
+ if the souce clock is not match the NAND mode, will cause the DMA read time out error */
+ unsigned char nand_clock = ReadRegByte((void*)0xf500e849);
+ nand_clock &= 0xcf;
+ nand_clock |= 0x20;
+ WriteRegByte((void*)0xf500e849,nand_clock);
+
+ /* switch the nand source clock 200Hz clock for write,
+ if the clock is not match the NAND init setting such like 1b002004 = 0x21, will cause WP*/
+ WriteRegWord((void*)0xfb002004, 0x00000067);
+
+ unsigned int write_clock = ReadRegWord((void*)0xfb002070);
+ write_clock |= 0x100;
+ WriteRegWord((void*)0xfb002070,write_clock);
+
+ write_clock = ReadRegWord((void*)0xfb002020);
+ write_clock &= 0xffff3f3f;
+ WriteRegWord((void*)0xfb002020,write_clock);
+
+ /*we set 205c only here,it changed in UXL*/
+ #ifdef CONFIG_MIPS_TRIDENT_UXL
+ WriteRegWord((void*)0xfb00205c, 0x40193333);
+ #else
+ WriteRegWord((void*)0xfb00205c, 0x40193333);
+ #endif
+ #endif
+#endif
+
retry:
spin_lock(lock);
@@ -874,7 +1207,11 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
if (state == FL_ERASING)
timeo += (HZ * 400) / 1000;
else
+#ifdef CONFIG_VENDOR_DTV
+ timeo += (HZ * 100) / 1000;
+#else
timeo += (HZ * 20) / 1000;
+#endif
led_trigger_event(nand_led_trigger, LED_FULL);
@@ -882,7 +1219,11 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
* Apply this short delay always to ensure that we do wait tWB in any
* case on any machine.
*/
+#ifdef CONFIG_TANGOX
+ udelay(1); /* needs to make it much longer than tWB */
+#else
ndelay(100);
+#endif
if ((state == FL_ERASING) && (chip->options & NAND_IS_AND))
chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
@@ -903,6 +1244,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
cond_resched();
}
}
+#ifdef CONFIG_VENDOR_DTV
+ if(!time_before(jiffies, timeo)&& state == FL_ERASING)
+ printk("%s eraseing? %d not ready\n",__func__,state == FL_ERASING);
+#endif
led_trigger_event(nand_led_trigger, LED_OFF);
status = (int)chip->read_byte(mtd);
@@ -939,6 +1284,11 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,
/* Call wait ready function */
status = chip->waitfunc(mtd, chip);
+
+#ifdef CONFIG_VENDOR_DTV
+ udelay(1000);
+#endif
+
/* See if device thinks it succeeded */
if (status & 0x01) {
pr_debug("%s: error status = 0x%08x\n",
@@ -991,6 +1341,10 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
ret = __nand_unlock(mtd, ofs, len, 0);
out:
+#ifdef CONFIG_VENDOR_DTV
+ /* de-select the NAND device */
+ chip->select_chip(mtd, -1);
+#endif
nand_release_device(mtd);
return ret;
@@ -1272,6 +1626,76 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *ecc_code = chip->buffers->ecccode;
uint32_t *eccpos = chip->ecc.layout->eccpos;
+#ifdef CONFIG_VENDOR_DTV
+ unsigned int reg;
+ unsigned int status;
+ //unsigned char soft_ecc_code[3];
+ int timeo = 1000;
+
+ //printk("%s\n",__func__);
+
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);//read oob first to get ECC code
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+// enable_nce(0); //make ce invalid for a while
+ //ndelay(100); //ce high
+ nand_wait_ready(mtd);
+
+ for (i = 0; i < chip->ecc.total; i++)
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
+
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ //enable read ecc, size 256 bytes
+ WriteRegWord((u32 __iomem *)0xfb002044, 0);
+
+ //write ecc code to register need by caculate
+ reg = ReadRegWord((u32 __iomem *)0xfb002044);
+ reg |= (0x2000000 | ecc_code[i+2]<<16 | ecc_code[i+1] | ecc_code[i+0]<<8 );//0x12000000; only supprot 3 byte ecc code by SX
+ WriteRegWord((u32 __iomem *)0xfb002044, reg);
+
+#ifdef CONFIG_MTD_NAND_DMA
+ nand_dma_read(p, chip->IO_ADDR_R, eccsize);
+#else
+ chip->read_buf(mtd, p, eccsize);
+#endif
+ //chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+ status = ReadRegWord((u32 __iomem *)0xfb002048);
+ while(timeo&&(status&0x8000)!=0x8000){
+ udelay(1);
+ timeo--;
+ status = ReadRegWord((u32 __iomem *)0xfb002048);
+ }
+ if(timeo<=0)
+ printk("Error: NAND ECC ready timeout\n");
+
+ //check status
+ if((status&0x2000)==0x2000){
+ mtd->ecc_stats.failed++;
+ printk("Error:Hardware ECC error at page:%d\n",page);
+ }
+ else if((status&0x1000)!=0x1000){
+ // no ecc error
+ //return 0;
+ }
+ else{
+ int byte_position;
+ int bit_position;
+ //printk("Hardware ECC correct one bit error at page:%d\n",page);
+ byte_position = status>>3 &0x1ff;
+ bit_position = status&0x7;
+
+ p[byte_position] ^= 1<<bit_position;
+
+ mtd->ecc_stats.corrected ++;
+ }
+
+ }
+ return 0;
+
+#else
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize);
@@ -1295,6 +1719,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
mtd->ecc_stats.corrected += stat;
}
return 0;
+#endif
}
/**
@@ -1448,6 +1873,12 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
return NULL;
}
+#ifdef CONFIG_VENDOR_DTV
+static int nand_read_page_onek(struct mtd_info *mtd, struct nand_chip *chip, u_char *buf,u_int page_addr);
+#ifdef CONFIG_UBI_SCAN_OPTIMIZE
+static int ubi_scan_finished = 0;
+#endif
+#endif
/**
* nand_do_read_ops - [INTERN] Read data with ECC
* @mtd: MTD device structure
@@ -1485,6 +1916,18 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
buf = ops->datbuf;
oob = ops->oobbuf;
+#if defined(CONFIG_UBI_SCAN_OPTIMIZE) && defined(CONFIG_VENDOR_DTV)
+ //optimize ubi attach speed
+ if(!ubi_scan_finished && col == 0 && readlen <= 1024 && !oob )
+ {
+ //printk("%s %08x\n",__func__,readlen);
+ ret = nand_read_page_onek(mtd, chip, buf, page);
+
+ readlen = 0;
+ }
+ else
+ {
+#endif
while (1) {
bytes = min(mtd->writesize - col, readlen);
aligned = (bytes == mtd->writesize);
@@ -1493,15 +1936,21 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
if (realpage != chip->pagebuf || oob) {
bufpoi = aligned ? buf : chip->buffers->databuf;
+#if defined(CONFIG_TANGOX) || (!defined(CONFIG_MTD_NAND_MLC_BCH) && !defined(CONFIG_MTD_NAND_ECC_HW) && defined(CONFIG_VENDOR_DTV))
if (likely(sndcmd)) {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
sndcmd = 0;
}
+#endif
/* Now read the page into the buffer */
- if (unlikely(ops->mode == MTD_OPS_RAW))
+ if (unlikely(ops->mode == MTD_OPS_RAW)){
+#ifdef CONFIG_VENDOR_DTV
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+#endif
ret = chip->ecc.read_page_raw(mtd, chip,
bufpoi, page);
+ }
else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)
ret = chip->ecc.read_subpage(mtd, chip,
col, bytes, bufpoi);
@@ -1583,6 +2032,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))
sndcmd = 1;
}
+#if defined(CONFIG_UBI_SCAN_OPTIMIZE) && defined(CONFIG_VENDOR_DTV)
+ }
+#endif
ops->retlen = ops->len - (size_t) readlen;
if (oob)
@@ -1614,6 +2066,14 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
struct mtd_oob_ops ops;
int ret;
+//#ifdef CONFIG_VENDOR_DTV
+ /* Do not allow reads past end of device */
+ if ((from + len) > mtd->size)
+ return -EINVAL;
+ if (!len)
+ return 0;
+//#endif
+
nand_get_device(chip, mtd, FL_READING);
ops.len = len;
ops.datbuf = buf;
@@ -2010,18 +2470,91 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *p = buf;
uint32_t *eccpos = chip->ecc.layout->eccpos;
+#ifdef CONFIG_VENDOR_DTV
+ unsigned int reg;
+ unsigned int status;
+ //unsigned char soft_ecc_code[3];
+ int timeo = 1000;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ //enable read ecc, size 256 bytes
+ WriteRegWord((u32 __iomem *)0xfb002044, 0);
+
+ reg = ReadRegWord((u32 __iomem *)0xfb002044);
+ reg |= 0x1000000 ;
+ WriteRegWord((u32 __iomem *)0xfb002044, reg);
+
+ chip->write_buf(mtd, p, eccsize);
+
+ status = ReadRegWord((u32 __iomem *)0xfb002048);
+ while(timeo&&(status&0x8000)!=0x8000){
+ udelay(1);
+ timeo--;
+ status = ReadRegWord((u32 __iomem *)0xfb002048);
+ }
+ if(timeo<=0)
+ printk("Error: NAND ECC ready timeout\n");
+
+ ecc_calc[i+2] = ReadRegWord((u32 __iomem *)0xfb00204c)&0xff;
+ ecc_calc[i+1] = (ReadRegWord((u32 __iomem *)0xfb002048)&0x00ff0000)>>16;
+ ecc_calc[i+0] = (ReadRegWord((u32 __iomem *)0xfb002048)&0xff000000)>>24;
+
+ //nand_calc_ecc_word_256((unsigned int *)(p),soft_ecc_code);
+
+ //printk(" hardware ECC code:%02x,%02x,%02x\n",ecc_calc[i+0],ecc_calc[i+1],ecc_calc[i+2]);
+ //printf(" soft ECC code:%02x,%02x,%02x\n",soft_ecc_code[0],soft_ecc_code[1],soft_ecc_code[2]);
+
+ }
+#else
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
chip->write_buf(mtd, p, eccsize);
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
}
+#endif
+
+ for (i = 0; i < chip->ecc.total; i++)
+ chip->oob_poi[eccpos[i]] = ecc_calc[i];
+
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+}
+
+#if defined(CONFIG_MTD_NAND_MLC_BCH) && defined(CONFIG_VENDOR_DTV)
+
+char ecc_tmp_write[250] __attribute__ ((aligned (4)));
+static int nand_write_page_mlcbch(struct mtd_info *mtd, struct nand_chip *chip,
+ u_char *buf,u_int page_addr)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ u_char *p = buf;
+ u_char *ecc_calc = chip->buffers->ecccalc;
+ int *eccpos = chip->ecc.layout->eccpos;
+ unsigned int ret;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ BCH_ECC_enc_start(chip);
+ chip->write_buf(mtd, p, eccsize);
+ ret = BCH_ECC_enc_end((unsigned int*)ecc_tmp_write,chip);
+ if(ret)
+ {
+ printk("BCH: write page error %d at page addr %d \n",ret,page_addr);
+ return ret;
+ }
+
+ memcpy(&ecc_calc[i] ,ecc_tmp_write,eccbytes);
+ }
for (i = 0; i < chip->ecc.total; i++)
chip->oob_poi[eccpos[i]] = ecc_calc[i];
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ return 0;
}
+#endif
+
/**
* nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write
* @mtd: mtd info structure
@@ -2541,6 +3074,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
struct nand_chip *chip = mtd->priv;
loff_t rewrite_bbt[NAND_MAX_CHIPS] = {0};
unsigned int bbt_masked_page = 0xffffffff;
+ int force_erase = 0;
loff_t len;
pr_debug("%s: start = 0x%012llx, len = %llu\n",
@@ -2550,6 +3084,9 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
if (check_offs_len(mtd, instr->addr, instr->len))
return -EINVAL;
+ if (instr->retries == 0x73092215)
+ force_erase = 1;
+
/* Grab the lock and see if the device is available */
nand_get_device(chip, mtd, FL_ERASING);
@@ -2586,14 +3123,16 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
instr->state = MTD_ERASING;
while (len) {
+#ifndef CONFIG_MTD_NAND_BBM
/* Check if we have a bad block, we do not erase bad blocks! */
- if (nand_block_checkbad(mtd, ((loff_t) page) <<
+ if (!force_erase && nand_block_checkbad(mtd, ((loff_t) page) <<
chip->page_shift, 0, allowbbt)) {
pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
__func__, page);
instr->state = MTD_ERASE_FAILED;
goto erase_exit;
}
+#endif
/*
* Invalidate the page cache, if we erase the block which
@@ -2713,6 +3252,11 @@ static void nand_sync(struct mtd_info *mtd)
*/
static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
{
+//#ifdef CONFIG_VENDOR_DTV
+ /* Check for invalid offset */
+ if (offs > mtd->size)
+ return -EINVAL;
+//#endif
return nand_block_checkbad(mtd, offs, 1, 0);
}
@@ -2788,12 +3332,23 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
chip->block_bad = nand_block_bad;
if (!chip->block_markbad)
chip->block_markbad = nand_default_block_markbad;
+#ifdef CONFIG_VENDOR_DTV
+ //speed up
+ if (!chip->write_buf)
+ chip->write_buf = nand_write_buf32;
+ if (!chip->read_buf)
+ chip->read_buf = nand_read_buf32;
+ if (!chip->verify_buf)
+ chip->verify_buf = nand_verify_buf32;
+#else
if (!chip->write_buf)
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
if (!chip->read_buf)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
if (!chip->verify_buf)
chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
+#endif
+
if (!chip->scan_bbt)
chip->scan_bbt = nand_default_bbt;
@@ -2851,6 +3406,22 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
return 0;
+#ifdef CONFIG_TANGOX
+ chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
+ for (i = 0; i < 3; i++) {
+ int j = 0;
+
+ for ( j = 0; j < sizeof(*p); j++ ) {
+ *(((uint8_t *)p)+j) = chip->read_byte(mtd);
+ }
+
+ if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
+ le16_to_cpu(p->crc)) {
+ pr_info("ONFI param page %d valid\n", i);
+ break;
+ }
+ }
+#else
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
for (i = 0; i < 3; i++) {
chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
@@ -2860,6 +3431,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
break;
}
}
+#endif
if (i == 3)
return 0;
@@ -2888,16 +3460,29 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
sanitize_string(p->model, sizeof(p->model));
if (!mtd->name)
mtd->name = p->model;
+
mtd->writesize = le32_to_cpu(p->byte_per_page);
- mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
+
+ /*
+ * pages_per_block and blocks_per_lun may not be a power-of-2 size
+ * (don't ask me who thought of this...). MTD assumes that these
+ * dimensions will be power-of-2, so just truncate the remaining area.
+ */
+ mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+ mtd->erasesize *= mtd->writesize;
+
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
- chip->chipsize = le32_to_cpu(p->blocks_per_lun);
+
+ /* See erasesize comment */
+ chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
*busw = 0;
if (le16_to_cpu(p->features) & 1)
*busw = NAND_BUSWIDTH_16;
- chip->options |= NAND_NO_READRDY | NAND_NO_AUTOINCR;
+ chip->options &= ~NAND_CHIPOPTIONS_MSK;
+ chip->options |= (NAND_NO_READRDY |
+ NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK;
pr_info("ONFI flash detected\n");
return 1;
@@ -2915,6 +3500,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
int i, maf_idx;
u8 id_data[8];
int ret;
+ char onfi_version[3];
/* Select the device */
chip->select_chip(mtd, 0);
@@ -2941,7 +3527,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
- for (i = 0; i < 2; i++)
+ for (i = 0; i < 8; i++)
id_data[i] = chip->read_byte(mtd);
if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
@@ -2954,12 +3540,12 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
if (!type)
type = nand_flash_ids;
- for (; type->name != NULL; type++)
+ for (; (type->name != NULL) && (type->id != 0); type++)
if (*dev_id == type->id)
break;
chip->onfi_version = 0;
- if (!type->name || !type->pagesize) {
+ if (!type->name || !type->id || !type->pagesize) {
/* Check is chip is ONFI compliant */
ret = nand_flash_detect_onfi(mtd, chip, &busw);
if (ret)
@@ -2973,7 +3559,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
for (i = 0; i < 8; i++)
id_data[i] = chip->read_byte(mtd);
- if (!type->name)
+ if ((!type->name) || (!type->id))
return ERR_PTR(-ENODEV);
if (!mtd->name)
@@ -2981,7 +3567,32 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
chip->chipsize = (uint64_t)type->chipsize << 20;
- if (!type->pagesize && chip->init_size) {
+#ifdef CONFIG_VENDOR_DTV
+ chip->ecc.bytes = type->eccbits;
+
+ /* Newer devices have all the information in additional id bytes */
+ /* add judgment for support Micron flash, or you can fix it use ONFI to get the chip info */
+
+ if(*maf_id ==0x2c )
+ {
+ busw = type->options & NAND_BUSWIDTH_16;
+
+ mtd->oobsize = 224;
+ mtd->writesize = 4096;
+
+ if(*dev_id == 0x38)
+ mtd->erasesize = 0x80000;
+ else if(*dev_id == 0xd3)
+ mtd->erasesize = 0x40000;
+ else if(*dev_id == 0x48)
+ mtd->erasesize = 0x100000;
+ else
+ printk("%s[%d] ERROR: unknown dev_id!\n", __func__, __LINE__);
+ }
+#else
+ if (0);
+#endif
+ else if (!type->pagesize && chip->init_size) {
/* Set the pagesize, oobsize, erasesize by the driver */
busw = chip->init_size(mtd, chip, id_data);
} else if (!type->pagesize) {
@@ -2995,14 +3606,17 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
* Field definitions are in the following datasheets:
* Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
* New style (6 byte ID): Samsung K9GBG08U0M (p.40)
+ * Micron (5 byte ID): Micron MT29F16G08MAA (p.24)
+ * Note: Micron rule is based on heuristics for
+ * newer chips
*
* Check for wraparound + Samsung ID + nonzero 6th byte
* to decide what to do.
*/
- if (id_data[0] == id_data[6] && id_data[1] == id_data[7] &&
+ if ((id_data[0] == id_data[6] && id_data[1] == id_data[7] &&
id_data[0] == NAND_MFR_SAMSUNG &&
(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
- id_data[5] != 0x00) {
+ id_data[5] != 0x00) || (id_data[0] == NAND_MFR_MIRA)) {
/* Calc pagesize */
mtd->writesize = 2048 << (extid & 0x03);
extid >>= 2;
@@ -3026,27 +3640,71 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
mtd->erasesize = (128 * 1024) <<
(((extid >> 1) & 0x04) | (extid & 0x03));
busw = 0;
- } else {
+ } else if (id_data[0] == NAND_MFR_ESMT) {
/* Calc pagesize */
mtd->writesize = 1024 << (extid & 0x03);
extid >>= 2;
/* Calc oobsize */
- mtd->oobsize = (8 << (extid & 0x01)) *
- (mtd->writesize >> 9);
+ mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize / 512) ;
extid >>= 2;
- /* Calc blocksize. Blocksize is multiples of 64KiB */
+ /* Calc blocksize */
mtd->erasesize = (64 * 1024) << (extid & 0x03);
+ busw = 0;
+ } else {
+ /* Calc pagesize */
+ mtd->writesize = 1024 << (extid & 0x03);
extid >>= 2;
- /* Get buswidth information */
- busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+
+ /* Check for 5 byte ID + Micron + read more 0x00 */
+ if (id_data[0] == NAND_MFR_MICRON && id_data[4] != 0x00
+ && mtd->writesize >= 4096
+ && id_data[5] == 0x00
+ && id_data[6] == 0x00) {
+ /* OOB is 218B/224B per 4KiB pagesize */
+ mtd->oobsize = ((extid & 0x03) == 0x03 ? 218 :
+ 224) << (mtd->writesize >> 13);
+ extid >>= 3;
+ /* Blocksize is multiple of 64KiB */
+ mtd->erasesize = mtd->writesize <<
+ (extid & 0x03) << 6;
+ /* All Micron have busw x8? */
+ printk("[%s] All Micron : %d\n", __func__, extid);
+ busw = 0;
+ } else {
+ /* Calc oobsize */
+ mtd->oobsize = (8 << (extid & 0x01)) *
+ (mtd->writesize >> 9);
+ extid >>= 2;
+ /* Calc blocksize (multiples of 64KiB) */
+ mtd->erasesize = (64 * 1024) << (extid & 0x03);
+ extid >>= 2;
+ /* Get buswidth information */
+ busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+ }
}
+#ifdef CONFIG_VENDOR_DTV
+ } else if (*maf_id == 0xad && dev_id == 0xd5 ){ //hynix
+ busw = type->options & NAND_BUSWIDTH_16;
+ mtd->oobsize = 448;
+ mtd->writesize = 8192;
+ mtd->erasesize = 0x200000;
+ chip->ecc.bytes = type->eccbits;
+ printk(KERN_DEBUG "chip->ecc.bytes is 0x%x\n",chip->ecc.bytes);
+#endif
} else {
/*
* Old devices have chip data hardcoded in the device id table.
*/
mtd->erasesize = type->erasesize;
mtd->writesize = type->pagesize;
+#ifdef CONFIG_VENDOR_DTV
+ if(type->oobsize)
+ mtd->oobsize = type->oobsize;
+ else
+ mtd->oobsize = mtd->writesize / 32;
+#else
mtd->oobsize = mtd->writesize / 32;
+#endif
busw = type->options & NAND_BUSWIDTH_16;
/*
@@ -3062,8 +3720,9 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
}
}
- /* Get chip options */
- chip->options |= type->options;
+ /* Get chip options, preserve non chip based options */
+ chip->options &= ~NAND_CHIPOPTIONS_MSK;
+ chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
/*
* Check if chip is not a Samsung device. Do not clear the
@@ -3129,10 +3788,14 @@ ident_done:
*/
if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
(*maf_id == NAND_MFR_SAMSUNG ||
+ *maf_id == NAND_MFR_MIRA ||
+ *maf_id == NAND_MFR_ESMT ||
*maf_id == NAND_MFR_HYNIX))
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
(*maf_id == NAND_MFR_SAMSUNG ||
+ *maf_id == NAND_MFR_MIRA ||
+ *maf_id == NAND_MFR_ESMT ||
*maf_id == NAND_MFR_HYNIX ||
*maf_id == NAND_MFR_TOSHIBA ||
*maf_id == NAND_MFR_AMD ||
@@ -3141,6 +3804,7 @@ ident_done:
*maf_id == NAND_MFR_MICRON))
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+
/* Check for AND chips with 4 page planes */
if (chip->options & NAND_4PAGE_ARRAY)
chip->erase_cmd = multi_erase_cmd;
@@ -3156,7 +3820,42 @@ ident_done:
nand_manuf_ids[maf_idx].name,
chip->onfi_version ? chip->onfi_params.model : type->name);
+ if (chip->onfi_version)
+ snprintf(onfi_version, sizeof(onfi_version), "%d.%d",
+ chip->onfi_version / 10,
+ chip->onfi_version % 10);
+ else
+ snprintf(onfi_version, sizeof(onfi_version), "%s", "0");
+
+ /* ID Data Mapping */
+ for (i = 0; i < 8; i++)
+ {
+ mtd->id_data[i] = id_data[i];
+ }
+
+ mtd->onfi_version = kstrdup(onfi_version, GFP_KERNEL);
+ if (!mtd->onfi_version)
+ return ERR_PTR(-ENOMEM);
+
+ mtd->nand_manufacturer = kstrdup(nand_manuf_ids[maf_idx].name, GFP_KERNEL);
+ if (!mtd->nand_manufacturer) {
+ ret = -ENOMEM;
+ goto out_onfi_version;
+ }
+
+ mtd->nand_type = kstrdup(type->name, GFP_KERNEL);
+ if (!mtd->nand_type) {
+ ret = -ENOMEM;
+ goto out_nand_type;
+ }
+
return type;
+
+out_nand_type:
+ kfree(mtd->nand_type);
+out_onfi_version:
+ kfree(mtd->onfi_version);
+ return ERR_PTR(ret);
}
/**
@@ -3176,6 +3875,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
int i, busw, nand_maf_id, nand_dev_id;
struct nand_chip *chip = mtd->priv;
struct nand_flash_dev *type;
+ int err;
/* Get buswidth to select the correct functions */
busw = chip->options & NAND_BUSWIDTH_16;
@@ -3190,7 +3890,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
if (!(chip->options & NAND_SCAN_SILENT_NODEV))
pr_warn("No NAND device found\n");
chip->select_chip(mtd, -1);
- return PTR_ERR(type);
+ err = PTR_ERR(type);
+ goto out_error;
}
/* Check for a chip array */
@@ -3212,7 +3913,20 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
chip->numchips = i;
mtd->size = i * chip->chipsize;
+ chip->maf_id = nand_maf_id;
+ chip->dev_id = type->id;
+
return 0;
+
+out_error:
+ if (mtd->nand_type)
+ kfree(mtd->nand_type);
+ if (mtd->nand_manufacturer)
+ kfree(mtd->nand_manufacturer);
+ if (mtd->onfi_version)
+ kfree(mtd->onfi_version);
+
+ return err;
}
EXPORT_SYMBOL(nand_scan_ident);
@@ -3254,11 +3968,28 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.layout = &nand_oob_16;
break;
case 64:
+#if defined(CONFIG_MTD_NAND_MLC_BCH) && defined(CONFIG_VENDOR_DTV)
+ chip->ecc.layout = &nand_oob_mlcbch_64;
+#else
chip->ecc.layout = &nand_oob_64;
+#endif
break;
case 128:
chip->ecc.layout = &nand_oob_128;
break;
+ case 224:
+ chip->ecc.layout = &nand_oob_mlcbch_224;
+ //8 bit bch ecc for Micron 1G flash, 224 oobsize use 128 for ecc
+ //for(i=224-112,k=0;i<224;k++,i++)
+ // chip->ecc.layout->eccpos[k]=i;
+ //chip->ecc.layout->oobfree[0].offset=3;
+ //chip->ecc.layout->oobfree[0].length=(224-112-3);
+ break;
+#ifndef CONFIG_MTD_NAND_ECC_512
+ case 448:
+ chip->ecc.layout = &nand_oob_mlcbch_448;
+ break;
+#endif
default:
pr_warn("No oob scheme defined for oobsize %d\n",
mtd->oobsize);
@@ -3300,6 +4031,37 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.read_oob = nand_read_oob_std;
if (!chip->ecc.write_oob)
chip->ecc.write_oob = nand_write_oob_std;
+#ifdef CONFIG_VENDOR_DTV
+ chip->ecc.size = 256;
+ chip->ecc.bytes = 3;
+ break;
+
+#ifdef CONFIG_MTD_NAND_MLC_BCH
+ case NAND_MLC_BCH:
+ chip->ecc.read_page = nand_read_page_mlcbch;
+ chip->ecc.write_page = nand_write_page_mlcbch;
+ chip->ecc.read_oob = nand_read_oob_std;
+ chip->ecc.read_page_raw = nand_read_page_raw;
+ chip->ecc.write_page_raw = nand_write_page_raw;
+ chip->ecc.write_oob = nand_write_oob_std;
+
+ // do ECC control reset. REG_BCH_ECC_CONTROL = 0xfb002200
+ WriteRegWord((u32 __iomem *)0xfb002200, (ReadRegWord((u32 __iomem *)0xfb002200)&(~0x4)));
+ WriteRegWord((u32 __iomem *)0xfb002200, 0x1000);
+ while(ReadRegWord((u32 __iomem *)0xfb002200)&0x1000!=0)
+ ;
+ WriteRegWord((u32 __iomem *)0xfb002200, 0x02);
+
+ #ifdef CONFIG_MTD_NAND_ECC_512
+ printk(KERN_DEBUG "NAND: BCH ECC,size 512B.\n");
+ chip->ecc.size = 512;
+ #else
+ printk(KERN_DEBUG "NAND: BCH ECC,size 1024B.\n");
+ chip->ecc.size = 1024;
+ #endif
+ break;
+#endif
+#endif //ifdef CONFIG_VENDOR_DTV
case NAND_ECC_HW_SYNDROME:
if ((!chip->ecc.calculate || !chip->ecc.correct ||
@@ -3437,12 +4199,20 @@ int nand_scan_tail(struct mtd_info *mtd)
!(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
switch (chip->ecc.steps) {
case 2:
+#if defined(CONFIG_MTD_UBI) && defined(CONFIG_VENDOR_DTV)
+ mtd->subpage_sft = 0; //fix me, to simplify ubi config
+#else
mtd->subpage_sft = 1;
+#endif
break;
case 4:
case 8:
case 16:
+#if defined(CONFIG_MTD_UBI) && defined(CONFIG_VENDOR_DTV)
+ mtd->subpage_sft = 0; //fix me, to simplify ubi config
+#else
mtd->subpage_sft = 2;
+#endif
break;
}
}
@@ -3517,6 +4287,44 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
{
int ret;
+#ifdef CONFIG_VENDOR_DTV
+ struct nand_chip *chip;
+#ifdef CONFIG_MIPS_TRIDENT_FUSION_ANDROID
+ //protect NAND init
+ NAND_spin_lock_hw_dump(SPIN_REG_ADDR);
+#endif
+
+#ifdef CONFIG_NAND_MODE
+ /* switch the nand source clock from 100Hz to 200Hz for this version of NAND mode setting
+ * if the souce clock is not match the NAND mode, will cause the DMA read time out error */
+
+ unsigned char nand_clock = ReadRegByte((void*)0xf500e849);
+ nand_clock &= 0xcf;
+ nand_clock |= 0x20;
+ WriteRegByte((void*)0xf500e849,nand_clock);
+
+ /* switch the nand source clock 200Hz clock for write,
+ if the clock is not match the NAND init setting such like 1b002004 = 0x21, will cause WP*/
+ WriteRegWord((void*)0xfb002004, 0x00000067);
+
+ unsigned int write_clock = ReadRegWord((void*)0xfb002070);
+ write_clock |= 0x100;
+ WriteRegWord((void*)0xfb002070,write_clock);
+
+ write_clock = ReadRegWord((void*)0xfb002020);
+ write_clock &= 0xffff3f3f;
+ WriteRegWord((void*)0xfb002020,write_clock);
+
+ /*we set 205c only here,it changed in UXL*/
+#ifdef CONFIG_MIPS_TRIDENT_UXL
+ WriteRegWord((void*)0xfb00205c, 0x40193333);
+#else
+ WriteRegWord((void*)0xfb00205c, 0x40193333);
+#endif
+
+#endif //ifdef CONFIG_NAND_MODE
+#endif //ifdef CONFIG_VENDOR_DTV
+
/* Many callers got this wrong, so check for it for a while... */
if (!mtd->owner && caller_is_module()) {
pr_crit("%s called with NULL mtd->owner!\n", __func__);
@@ -3526,7 +4334,25 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
ret = nand_scan_ident(mtd, maxchips, NULL);
if (!ret)
ret = nand_scan_tail(mtd);
+
+#ifdef CONFIG_MIPS_TRIDENT_FUSION_ANDROID
+ NAND_spin_unlock_hw(SPIN_REG_ADDR);
+#endif
+
+#ifdef CONFIG_VENDOR_DTV
+ chip = mtd->priv;
+
+ if (chip->options & NAND_SKIP_BBTSCAN)
+ return ret;
+/*scan_bbt will be processed in nand_scan_tail*/
+//#ifdef CONFIG_MTD_UBI
+// return chip->scan_bbt(mtd);
+//#else
return ret;
+//#endif
+#else
+ return ret;
+#endif
}
EXPORT_SYMBOL(nand_scan);
@@ -3541,7 +4367,9 @@ void nand_release(struct mtd_info *mtd)
if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
+#ifndef CONFIG_VENDOR_DTV
mtd_device_unregister(mtd);
+#endif
/* Free bad block table memory */
kfree(chip->bbt);
@@ -3552,6 +4380,10 @@ void nand_release(struct mtd_info *mtd)
if (chip->badblock_pattern && chip->badblock_pattern->options
& NAND_BBT_DYNAMICSTRUCT)
kfree(chip->badblock_pattern);
+
+ kfree(mtd->nand_type);
+ kfree(mtd->nand_manufacturer);
+ kfree(mtd->onfi_version);
}
EXPORT_SYMBOL_GPL(nand_release);
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index af4fe8ca7b5e..03c687c3b8a4 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -23,6 +23,232 @@
*/
struct nand_flash_dev nand_flash_ids[] = {
+#ifdef CONFIG_VENDOR_DTV
+#ifdef CONFIG_MTD_NAND_MLC_BCH
+#ifdef CONFIG_MTD_NAND_MUSEUM_IDS
+// unsigned long eccbits;
+ {"NAND 1MiB 5V 8-bit", 0x0,0x6e, 256, 1, 0x1000, 0x0,0,14},
+ {"NAND 2MiB 5V 8-bit", 0x0,0x64, 256, 2, 0x1000, 0x0,0,14},
+ {"NAND 4MiB 5V 8-bit", 0x0,0x6b, 512, 4, 0x2000, 0x0,0,14},
+ {"NAND 1MiB 3,3V 8-bit", 0x0,0xe8, 256, 1, 0x1000, 0x0,0,14},
+ {"NAND 1MiB 3,3V 8-bit", 0x0,0xec, 256, 1, 0x1000, 0x0,0,14},
+ {"NAND 2MiB 3,3V 8-bit", 0x0,0xea, 256, 2, 0x1000, 0x0,0,14},
+ {"NAND 4MiB 3,3V 8-bit", 0xff,0xd5, 512, 4, 0x2000, 0x0,0,14},
+ {"NAND 4MiB 3,3V 8-bit", 0x0,0xe3, 512, 4, 0x2000, 0x0,0,14},
+ {"NAND 4MiB 3,3V 8-bit", 0x0,0xe5, 512, 4, 0x2000, 0x0,0,14},
+ {"NAND 8MiB 3,3V 8-bit", 0x0,0xd6, 512, 8, 0x2000, 0x0,0,14},
+
+ {"NAND 8MiB 1,8V 8-bit", 0x0,0x39, 512, 8, 0x2000, 0x0,0,14},
+ {"NAND 8MiB 3,3V 8-bit", 0x0,0xe6, 512, 8, 0x2000, 0x0,0,14},
+ {"NAND 8MiB 1,8V 16-bit", 0x0,0x49, 512, 8, 0x2000, 0x0,NAND_BUSWIDTH_16,14},
+ {"NAND 8MiB 3,3V 16-bit", 0x0,0x59, 512, 8, 0x2000, 0x0,NAND_BUSWIDTH_16,14},
+#endif
+
+ {"NAND 16MiB 1,8V 8-bit", 0x0,0x33, 512, 16, 0x4000, 0x0,0,14},
+ {"NAND 16MiB 3,3V 8-bit", 0x0,0x73, 512, 16, 0x4000, 0x0,0,14},
+ {"NAND 16MiB 1,8V 16-bit", 0x0,0x43, 512, 16, 0x4000, 0x0,NAND_BUSWIDTH_16,14},
+ {"NAND 16MiB 3,3V 16-bit", 0x0,0x53, 512, 16, 0x4000, 0x0,NAND_BUSWIDTH_16,14},
+
+ {"NAND 32MiB 1,8V 8-bit", 0x0,0x35, 512, 32, 0x4000, 0x0,0,14},
+ {"NAND 32MiB 3,3V 8-bit", 0x0,0x75, 512, 32, 0x4000, 0x0,0,14},
+ {"NAND 32MiB 1,8V 16-bit", 0x0,0x45, 512, 32, 0x4000, 0x0,NAND_BUSWIDTH_16,14},
+ {"NAND 32MiB 3,3V 16-bit", 0x0,0x55, 512, 32, 0x4000, 0x0,NAND_BUSWIDTH_16,14},
+
+ {"NAND 64MiB 1,8V 8-bit", 0x0,0x36, 512, 64, 0x4000, 0x0,0,14},
+ {"NAND 64MiB 3,3V 8-bit", 0x0,0x76, 512, 64, 0x4000, 0x0,0,14},
+ {"NAND 64MiB 1,8V 16-bit", 0x0,0x46, 512, 64, 0x4000, 0x0,NAND_BUSWIDTH_16,14},
+ {"NAND 64MiB 3,3V 16-bit", 0x0,0x56, 512, 64, 0x4000, 0x0,NAND_BUSWIDTH_16,14},
+
+ {"NAND 128MiB 1,8V 8-bit", 0x0,0x78, 512, 128, 0x4000, 0x0,0,14},
+ {"NAND 128MiB 1,8V 8-bit", 0x0,0x39, 512, 128, 0x4000, 0x0,0,14},
+ {"NAND 128MiB 3,3V 8-bit", 0x0,0x79, 512, 128, 0x4000, 0x0,0,14},
+ {"NAND 128MiB 1,8V 16-bit", 0x0,0x72, 512, 128, 0x4000, 0x0,NAND_BUSWIDTH_16,14},
+ {"NAND 128MiB 1,8V 16-bit", 0x0,0x49, 512, 128, 0x4000, 0x0,NAND_BUSWIDTH_16,14},
+ {"NAND 128MiB 3,3V 16-bit", 0x0,0x74, 512, 128, 0x4000, 0x0,NAND_BUSWIDTH_16,14},
+ {"NAND 128MiB 3,3V 16-bit", 0x0,0x59, 512, 128, 0x4000, 0x0,NAND_BUSWIDTH_16,14},
+
+ {"NAND 256MiB 3,3V 8-bit", 0x0,0x71, 512, 256, 0x4000, 0x0,0,14},
+
+ /*
+ * These are the new chips with large page size. The pagesize and the
+ * erasesize is determined from the extended id bytes
+ */
+#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR)
+#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
+
+ /*512 Megabit */
+ {"NAND 64MiB 1,8V 8-bit", 0x0,0xA2, 0, 64, 0, 0x0,LP_OPTIONS,14},
+ {"NAND 64MiB 3,3V 8-bit", 0x0,0xF2, 0, 64, 0, 0x0,LP_OPTIONS,14},
+ {"NAND 64MiB 1,8V 16-bit", 0x0,0xB2, 0, 64, 0, 0x0,LP_OPTIONS16,14},
+ {"NAND 64MiB 3,3V 16-bit", 0x0,0xC2, 0, 64, 0, 0x0,LP_OPTIONS16,14},
+
+ /* 1 Gigabit */
+ {"NAND 128MiB 1,8V 8-bit", 0x0,0xA1, 0, 128, 0, 0x0,LP_OPTIONS,14},
+ {"NAND 128MiB 3,3V 8-bit", 0x0,0xF1, 2048, 128, 0x20000,0x0, LP_OPTIONS,14},
+ {"NAND 128MiB 1,8V 16-bit", 0x0,0xB1, 0, 128, 0, 0x0,LP_OPTIONS16,14},
+ {"NAND 128MiB 3,3V 16-bit", 0x0,0xC1, 0, 128, 0, 0x0,LP_OPTIONS16,14},
+
+ /* 2 Gigabit */
+ {"NAND 256MiB 1,8V 8-bit", 0x0,0xAA, 0, 256, 0, 0x0,LP_OPTIONS,14},
+ {"NAND 256MiB 3,3V 8-bit", 0x0,0xDA, 0, 256, 0, 0x0,LP_OPTIONS,14},
+ {"NAND 256MiB 1,8V 16-bit", 0x0,0xBA, 0, 256, 0, 0x0,LP_OPTIONS16,14},
+ {"NAND 256MiB 3,3V 16-bit", 0x0,0xCA, 0, 256, 0, 0x0,LP_OPTIONS16,14},
+
+ /* 4 Gigabit */
+ {"NAND 512MiB 1,8V 8-bit", 0x0,0xAC, 0, 512, 0, 0x0,LP_OPTIONS,14},
+ {"NAND 512MiB 3,3V 8-bit", 0xff,0xDC, 0, 512, 0, 0x0,LP_OPTIONS,14},
+ {"NAND 512MiB 1,8V 16-bit", 0x0,0xBC, 0, 512, 0, 0x0,LP_OPTIONS16,14},
+ {"NAND 512MiB 3,3V 16-bit", 0x0,0xCC, 0, 512, 0, 0x0,LP_OPTIONS16,14},
+
+ /* 8 Gigabit */
+ {"NAND 1GiB 1,8V 8-bit", 0x0,0xA3, 0, 1024, 0, 0x0,LP_OPTIONS,14},
+ {"NAND 1GiB 3,3V 8-bit", 0x2c,0xD3, 4096, 1024, 0x80000, 224,LP_OPTIONS,14},
+ {"NAND 1GiB 3,3V 8-bit", 0x2c,0x38,4096, 1024, 0x80000,224,LP_OPTIONS,14},
+ {"NAND 1GiB 3,3V 8-bit", 0x0,0x38,4096, 1024, 0x80000,0x0,LP_OPTIONS,14},
+
+ {"NAND 1GiB 1,8V 16-bit", 0x0,0xB3, 0, 1024, 0, 0x0,LP_OPTIONS16,14},
+ {"NAND 1GiB 3,3V 16-bit", 0x0,0xC3, 0, 1024, 0, 0x0,LP_OPTIONS16,14},
+
+ //samsung chip, same dev id , different chip size
+ {"NAND 1GiB/2GiB 3,3V 8-bit", 0xec,0xD3, 0, 0, 0, 0,LP_OPTIONS,14},
+
+ /* 16 Gigabit */
+ {"NAND 2GiB 1,8V 8-bit", 0x0,0xA5, 0, 2048, 0, 0x0,LP_OPTIONS,42},
+ {"NAND 2GiB 3,3V 8-bit", 0xec,0xD5, 8192, 2048, 0x100000, 512,LP_OPTIONS,42},
+ {"NAND 2GiB 3,3V 8-bit", 0xad,0xD5, 8192, 2048, 0x200000, 448,LP_OPTIONS|NAND_MLC,42},
+ {"NAND 2GiB 1,8V 16-bit", 0x0,0xB5, 0, 2048, 0, 0x0,LP_OPTIONS16,42},
+ {"NAND 2GiB 3,3V 16-bit", 0x0,0xC5, 0, 2048, 0, 0x0,LP_OPTIONS16,42},
+
+ /*2013.4.2 add for Micron MT29F16G*/
+ {"NAND 2GiB 3,3V 8-bit", 0x2c, 0x48, 4096, 2048, 0x100000,224, LP_OPTIONS|NAND_MLC,42},
+ /*
+ * Renesas AND 1 Gigabit. Those chips do not support extended id and
+ * have a strange page/block layout ! The chosen minimum erasesize is
+ * 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page
+ * planes 1 block = 2 pages, but due to plane arrangement the blocks
+ * 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would
+ * increase the eraseblock size so we chose a combined one which can be
+ * erased in one go There are more speed improvements for reads and
+ * writes possible, but not implemented now
+ */
+
+ {"AND 128MiB 3,3V 8-bit", 0x0,0x01, 2048, 128, 0x4000,0x0,
+ NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY |
+ BBT_AUTO_REFRESH,14},
+
+#else /*not define CONFIG_MTD_NAND_MLC_BCH*/
+#ifdef CONFIG_MTD_NAND_MUSEUM_IDS
+ {"NAND 1MiB 5V 8-bit", 0x0,0x6e, 256, 1, 0x1000, 0x0,0},
+ {"NAND 2MiB 5V 8-bit", 0x0,0x64, 256, 2, 0x1000, 0x0,0},
+ {"NAND 4MiB 5V 8-bit", 0x0,0x6b, 512, 4, 0x2000, 0x0,0},
+ {"NAND 1MiB 3,3V 8-bit", 0x0,0xe8, 256, 1, 0x1000, 0x0,0},
+ {"NAND 1MiB 3,3V 8-bit", 0x0,0xec, 256, 1, 0x1000, 0x0,0},
+ {"NAND 2MiB 3,3V 8-bit", 0x0,0xea, 256, 2, 0x1000, 0x0,0},
+ {"NAND 4MiB 3,3V 8-bit", 0xff,0xd5, 512, 4, 0x2000, 0x0,0},
+ {"NAND 4MiB 3,3V 8-bit", 0x0,0xe3, 512, 4, 0x2000, 0x0,0},
+ {"NAND 4MiB 3,3V 8-bit", 0x0,0xe5, 512, 4, 0x2000, 0x0,0},
+ {"NAND 8MiB 3,3V 8-bit", 0x0,0xd6, 512, 8, 0x2000, 0x0,0},
+
+ {"NAND 8MiB 1,8V 8-bit", 0x0,0x39, 512, 8, 0x2000, 0x0,0},
+ {"NAND 8MiB 3,3V 8-bit", 0x0,0xe6, 512, 8, 0x2000, 0x0,0},
+ {"NAND 8MiB 1,8V 16-bit", 0x0,0x49, 512, 8, 0x2000, 0x0,NAND_BUSWIDTH_16},
+ {"NAND 8MiB 3,3V 16-bit", 0x0,0x59, 512, 8, 0x2000, 0x0,NAND_BUSWIDTH_16},
+#endif
+
+ {"NAND 16MiB 1,8V 8-bit", 0x0,0x33, 512, 16, 0x4000, 0x0,0},
+ {"NAND 16MiB 3,3V 8-bit", 0x0,0x73, 512, 16, 0x4000, 0x0,0},
+ {"NAND 16MiB 1,8V 16-bit", 0x0,0x43, 512, 16, 0x4000, 0x0,NAND_BUSWIDTH_16},
+ {"NAND 16MiB 3,3V 16-bit", 0x0,0x53, 512, 16, 0x4000, 0x0,NAND_BUSWIDTH_16},
+
+ {"NAND 32MiB 1,8V 8-bit", 0x0,0x35, 512, 32, 0x4000, 0x0,0},
+ {"NAND 32MiB 3,3V 8-bit", 0x0,0x75, 512, 32, 0x4000, 0x0,0},
+ {"NAND 32MiB 1,8V 16-bit", 0x0,0x45, 512, 32, 0x4000, 0x0,NAND_BUSWIDTH_16},
+ {"NAND 32MiB 3,3V 16-bit", 0x0,0x55, 512, 32, 0x4000, 0x0,NAND_BUSWIDTH_16},
+
+ {"NAND 64MiB 1,8V 8-bit", 0x0,0x36, 512, 64, 0x4000, 0x0,0},
+ {"NAND 64MiB 3,3V 8-bit", 0x0,0x76, 512, 64, 0x4000, 0x0,0},
+ {"NAND 64MiB 1,8V 16-bit", 0x0,0x46, 512, 64, 0x4000, 0x0,NAND_BUSWIDTH_16},
+ {"NAND 64MiB 3,3V 16-bit", 0x0,0x56, 512, 64, 0x4000, 0x0,NAND_BUSWIDTH_16},
+
+ {"NAND 128MiB 1,8V 8-bit", 0x0,0x78, 512, 128, 0x4000, 0x0,0},
+ {"NAND 128MiB 1,8V 8-bit", 0x0,0x39, 512, 128, 0x4000, 0x0,0},
+ {"NAND 128MiB 3,3V 8-bit", 0x0,0x79, 512, 128, 0x4000, 0x0,0},
+ {"NAND 128MiB 1,8V 16-bit", 0x0,0x72, 512, 128, 0x4000, 0x0,NAND_BUSWIDTH_16},
+ {"NAND 128MiB 1,8V 16-bit", 0x0,0x49, 512, 128, 0x4000, 0x0,NAND_BUSWIDTH_16},
+ {"NAND 128MiB 3,3V 16-bit", 0x0,0x74, 512, 128, 0x4000, 0x0,NAND_BUSWIDTH_16},
+ {"NAND 128MiB 3,3V 16-bit", 0x0,0x59, 512, 128, 0x4000, 0x0,NAND_BUSWIDTH_16},
+
+ {"NAND 256MiB 3,3V 8-bit", 0x0,0x71, 512, 256, 0x4000, 0x0,0},
+
+ /*
+ * These are the new chips with large page size. The pagesize and the
+ * erasesize is determined from the extended id bytes
+ */
+#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR)
+#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
+
+ /*512 Megabit */
+ {"NAND 64MiB 1,8V 8-bit", 0x0,0xA2, 0, 64, 0, 0x0,LP_OPTIONS},
+ {"NAND 64MiB 3,3V 8-bit", 0x0,0xF2, 0, 64, 0, 0x0,LP_OPTIONS},
+ {"NAND 64MiB 1,8V 16-bit", 0x0,0xB2, 0, 64, 0, 0x0,LP_OPTIONS16},
+ {"NAND 64MiB 3,3V 16-bit", 0x0,0xC2, 0, 64, 0, 0x0,LP_OPTIONS16},
+
+ /* 1 Gigabit */
+ {"NAND 128MiB 1,8V 8-bit", 0x0,0xA1, 0, 128, 0, 0x0,LP_OPTIONS},
+ {"NAND 128MiB 3,3V 8-bit", 0x0,0xF1, 2048, 128, 0x20000,0x0, LP_OPTIONS},
+ {"NAND 128MiB 1,8V 16-bit", 0x0,0xB1, 0, 128, 0, 0x0,LP_OPTIONS16},
+ {"NAND 128MiB 3,3V 16-bit", 0x0,0xC1, 0, 128, 0, 0x0,LP_OPTIONS16},
+
+ /* 2 Gigabit */
+ {"NAND 256MiB 1,8V 8-bit", 0x0,0xAA, 0, 256, 0, 0x0,LP_OPTIONS},
+ {"NAND 256MiB 3,3V 8-bit", 0x0,0xDA, 0, 256, 0, 0x0,LP_OPTIONS},
+ {"NAND 256MiB 1,8V 16-bit", 0x0,0xBA, 0, 256, 0, 0x0,LP_OPTIONS16},
+ {"NAND 256MiB 3,3V 16-bit", 0x0,0xCA, 0, 256, 0, 0x0,LP_OPTIONS16},
+
+ /* 4 Gigabit */
+ {"NAND 512MiB 1,8V 8-bit", 0x0,0xAC, 0, 512, 0, 0x0,LP_OPTIONS},
+ {"NAND 512MiB 3,3V 8-bit", 0xff,0xDC, 0, 512, 0, 0x0,LP_OPTIONS},
+ {"NAND 512MiB 1,8V 16-bit", 0x0,0xBC, 0, 512, 0, 0x0,LP_OPTIONS16},
+ {"NAND 512MiB 3,3V 16-bit", 0x0,0xCC, 0, 512, 0, 0x0,LP_OPTIONS16},
+
+ /* 8 Gigabit */
+ {"NAND 1GiB 1,8V 8-bit", 0x0,0xA3, 0, 1024, 0, 0x0,LP_OPTIONS},
+ {"NAND 1GiB 3,3V 8-bit", 0x2c,0xD3, 4096, 1024, 0x80000, 224,LP_OPTIONS},
+ {"NAND 1GiB 3,3V 8-bit", 0x2c,0x38,4096, 1024, 0x80000,224,LP_OPTIONS},
+ {"NAND 1GiB 3,3V 8-bit", 0x0,0x38,4096, 1024, 0x80000,0x0,LP_OPTIONS},
+
+ {"NAND 1GiB 1,8V 16-bit", 0x0,0xB3, 0, 1024, 0, 0x0,LP_OPTIONS16},
+ {"NAND 1GiB 3,3V 16-bit", 0x0,0xC3, 0, 1024, 0, 0x0,LP_OPTIONS16},
+
+ //samsung chip, same dev id , different chip size
+ {"NAND 1GiB/2GiB 3,3V 8-bit", 0xec,0xD3, 0, 0, 0, 0,LP_OPTIONS},
+
+ /* 16 Gigabit */
+ {"NAND 2GiB 1,8V 8-bit", 0x0,0xA5, 0, 2048, 0, 0x0,LP_OPTIONS},
+ {"NAND 2GiB 3,3V 8-bit", 0xec,0xD5, 8192, 2048, 0x100000, 512,LP_OPTIONS},
+ {"NAND 2GiB 3,3V 8-bit", 0xad,0xD5, 8192, 2048, 0x200000, 448,LP_OPTIONS},
+ {"NAND 2GiB 1,8V 16-bit", 0x0,0xB5, 0, 2048, 0, 0x0,LP_OPTIONS16},
+ {"NAND 2GiB 3,3V 16-bit", 0x0,0xC5, 0, 2048, 0, 0x0,LP_OPTIONS16},
+
+ /*
+ * Renesas AND 1 Gigabit. Those chips do not support extended id and
+ * have a strange page/block layout ! The chosen minimum erasesize is
+ * 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page
+ * planes 1 block = 2 pages, but due to plane arrangement the blocks
+ * 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would
+ * increase the eraseblock size so we chose a combined one which can be
+ * erased in one go There are more speed improvements for reads and
+ * writes possible, but not implemented now
+ */
+
+ {"AND 128MiB 3,3V 8-bit", 0x0,0x01, 2048, 128, 0x4000,0x0,
+ NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY |
+ BBT_AUTO_REFRESH
+ },
+
+#endif /* not define CONFIG_MTD_NAND_MLC_BCH */
+
+#else /* not define CONFIG_VENDOR_DTV */
#ifdef CONFIG_MTD_NAND_MUSEUM_IDS
{"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
{"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},
@@ -90,7 +316,7 @@ struct nand_flash_dev nand_flash_ids[] = {
{"NAND 128MiB 3,3V 8-bit", 0xD1, 0, 128, 0, LP_OPTIONS},
{"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16},
{"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16},
- {"NAND 128MiB 1,8V 16-bit", 0xAD, 0, 128, 0, LP_OPTIONS16},
+ {"NAND 128MiB 1,8V 16-bit", 0xAD, 0, 128, 0, LP_OPTIONS16},
/* 2 Gigabit */
{"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS},
@@ -107,22 +333,26 @@ struct nand_flash_dev nand_flash_ids[] = {
/* 8 Gigabit */
{"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},
+ {"NAND 1GiB 3,3V 8-bit", 0x38, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16},
{"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16},
/* 16 Gigabit */
{"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, LP_OPTIONS},
{"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS},
+ {"NAND 2GiB 3,3V 8-bit", 0x48, 0, 2048, 0, LP_OPTIONS},
{"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16},
{"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},
/* 32 Gigabit */
+ {"NAND 4GiB 3,3V 8-bit", 0x68, 0, 4096, 0, LP_OPTIONS},
{"NAND 4GiB 1,8V 8-bit", 0xA7, 0, 4096, 0, LP_OPTIONS},
{"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS},
{"NAND 4GiB 1,8V 16-bit", 0xB7, 0, 4096, 0, LP_OPTIONS16},
{"NAND 4GiB 3,3V 16-bit", 0xC7, 0, 4096, 0, LP_OPTIONS16},
/* 64 Gigabit */
+ {"NAND 8GiB 3,3V 8-bit", 0x88, 0, 8192, 0, LP_OPTIONS},
{"NAND 8GiB 1,8V 8-bit", 0xAE, 0, 8192, 0, LP_OPTIONS},
{"NAND 8GiB 3,3V 8-bit", 0xDE, 0, 8192, 0, LP_OPTIONS},
{"NAND 8GiB 1,8V 16-bit", 0xBE, 0, 8192, 0, LP_OPTIONS16},
@@ -135,6 +365,7 @@ struct nand_flash_dev nand_flash_ids[] = {
{"NAND 16GiB 3,3V 16-bit", 0x4A, 0, 16384, 0, LP_OPTIONS16},
/* 256 Gigabit */
+ {"NAND 32GiB 3,3V 8-bit", 0xA8, 0, 32768, 0, LP_OPTIONS},
{"NAND 32GiB 1,8V 8-bit", 0x1C, 0, 32768, 0, LP_OPTIONS},
{"NAND 32GiB 3,3V 8-bit", 0x3C, 0, 32768, 0, LP_OPTIONS},
{"NAND 32GiB 1,8V 16-bit", 0x2C, 0, 32768, 0, LP_OPTIONS16},
@@ -161,7 +392,23 @@ struct nand_flash_dev nand_flash_ids[] = {
BBT_AUTO_REFRESH
},
- {NULL,}
+ /*
+ * Fill-in gaps, may be refilled at the runtime
+ */
+ {" ", 0, },
+ {" ", 0, },
+ {" ", 0, },
+ {" ", 0, },
+ {" ", 0, },
+ {" ", 0, },
+ {" ", 0, },
+ {" ", 0, },
+#endif /* not define CONFIG_VENDOR_DTV */
+
+ /*
+ * Terminates the table
+ */
+ {NULL, },
};
/*
@@ -178,6 +425,8 @@ struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_MICRON, "Micron"},
{NAND_MFR_AMD, "AMD"},
{NAND_MFR_MACRONIX, "Macronix"},
+ {NAND_MFR_ESMT, "ESMT"},
+ {NAND_MFR_MIRA, "MIRA"},
{0x0, "Unknown"}
};
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index b9cbd65f49b5..a3b0336dc374 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -654,7 +654,7 @@ static int init_nandsim(struct mtd_info *mtd)
}
/* 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) && (nand_flash_ids[i].id != 0); i++) {
if (second_id_byte != nand_flash_ids[i].id)
continue;
if (!(nand_flash_ids[i].options & NAND_NO_AUTOINCR))
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
old mode 100644
new mode 100755
index f6a7d7ac4b98..475fd0063b12
--- a/drivers/mtd/ubi/misc.c
+++ b/drivers/mtd/ubi/misc.c
@@ -63,6 +63,13 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
void *buf;
int err = 0, i;
struct ubi_volume *vol = ubi->volumes[vol_id];
+#ifdef CONFIG_VENDOR_DTV
+ /*
+ Do not check the volume when the volume is static,in order to reduce the
+ time of attach mtd device when the device include big static volume
+ */
+ return 0;
+#endif
if (vol->vol_type != UBI_STATIC_VOLUME)
return 0;
next reply other threads:[~2016-01-22 15:35 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-01-22 15:34 Mason [this message]
2016-01-23 3:16 ` RFC on large number of hacks in mtd core files Brian Norris
2016-01-23 10:53 ` Mason
2016-01-25 17:34 ` Mason
2016-01-28 18:05 ` Geert Uytterhoeven
2016-01-28 21:05 ` Mason
2016-01-29 7:50 ` Geert Uytterhoeven
2016-01-29 16:27 ` Boris Brezillon
2016-01-29 18:14 ` Brian Norris
2016-01-30 11:37 ` Boris Brezillon
2016-01-29 23:25 ` Mason
2016-01-30 11:22 ` Boris Brezillon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=56A24C22.2050607@free.fr \
--to=slash.tmp@free.fr \
--cc=computersforpeace@gmail.com \
--cc=dwmw2@infradead.org \
--cc=linux-mtd@lists.infradead.org \
--cc=sf84@laposte.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.