Commit 60d9aa75 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.infradead.org/mtd-2.6

* git://git.infradead.org/mtd-2.6: (90 commits)
  jffs2: Fix long-standing bug with symlink garbage collection.
  mtd: OneNAND: Fix test of unsigned in onenand_otp_walk()
  mtd: cfi_cmdset_0002, fix lock imbalance
  Revert "mtd: move mxcnd_remove to .exit.text"
  mtd: m25p80: add support for Macronix MX25L4005A
  kmsg_dump: fix build for CONFIG_PRINTK=n
  mtd: nandsim: add support for 4KiB pages
  mtd: mtdoops: refactor as a kmsg_dumper
  mtd: mtdoops: make record size configurable
  mtd: mtdoops: limit the maximum mtd partition size
  mtd: mtdoops: keep track of used/unused pages in an array
  mtd: mtdoops: several minor cleanups
  core: Add kernel message dumper to call on oopses and panics
  mtd: add ARM pismo support
  mtd: pxa3xx_nand: Fix PIO data transfer
  mtd: nand: fix multi-chip suspend problem
  mtd: add support for switching old SST chips into QRY mode
  mtd: fix M29W800D dev_id and uaddr
  mtd: don't use PF_MEMALLOC
  mtd: Add bad block table overrides to Davinci NAND driver
  ...

Fixed up conflicts (mostly trivial) in
	drivers/mtd/devices/m25p80.c
	drivers/mtd/maps/pcmciamtd.c
	drivers/mtd/nand/pxa3xx_nand.c
	kernel/printk.c
parents b2adf0cb 2e16cfca
......@@ -70,9 +70,19 @@ static struct ctl_table bcmring_sysctl_reboot[] = {
{}
};
static struct resource nand_resource[] = {
[0] = {
.start = MM_ADDR_IO_NAND,
.end = MM_ADDR_IO_NAND + 0x1000 - 1,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device nand_device = {
.name = "bcm-nand",
.id = -1,
.resource = nand_resource,
.num_resources = ARRAY_SIZE(nand_resource),
};
static struct platform_device *devices[] __initdata = {
......
/*****************************************************************************
* Copyright 2001 - 2008 Broadcom Corporation. All rights reserved.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2, available at
* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a
* license other than the GPL, without Broadcom's express prior written
* consent.
*****************************************************************************/
/*
*
*****************************************************************************
*
* REG_NAND.h
*
* PURPOSE:
*
* This file contains definitions for the nand registers:
*
* NOTES:
*
*****************************************************************************/
#if !defined(__ASM_ARCH_REG_NAND_H)
#define __ASM_ARCH_REG_NAND_H
/* ---- Include Files ---------------------------------------------------- */
#include <csp/reg.h>
#include <mach/reg_umi.h>
/* ---- Constants and Types ---------------------------------------------- */
#define HW_NAND_BASE MM_IO_BASE_NAND /* NAND Flash */
/* DMA accesses by the bootstrap need hard nonvirtual addresses */
#define REG_NAND_CMD __REG16(HW_NAND_BASE + 0)
#define REG_NAND_ADDR __REG16(HW_NAND_BASE + 4)
#define REG_NAND_PHYS_DATA16 (HW_NAND_BASE + 8)
#define REG_NAND_PHYS_DATA8 (HW_NAND_BASE + 8)
#define REG_NAND_DATA16 __REG16(REG_NAND_PHYS_DATA16)
#define REG_NAND_DATA8 __REG8(REG_NAND_PHYS_DATA8)
/* use appropriate offset to make sure it start at the 1K boundary */
#define REG_NAND_PHYS_DATA_DMA (HW_NAND_BASE + 0x400)
#define REG_NAND_DATA_DMA __REG32(REG_NAND_PHYS_DATA_DMA)
/* Linux DMA requires physical address of the data register */
#define REG_NAND_DATA16_PADDR HW_IO_VIRT_TO_PHYS(REG_NAND_PHYS_DATA16)
#define REG_NAND_DATA8_PADDR HW_IO_VIRT_TO_PHYS(REG_NAND_PHYS_DATA8)
#define REG_NAND_DATA_PADDR HW_IO_VIRT_TO_PHYS(REG_NAND_PHYS_DATA_DMA)
#define NAND_BUS_16BIT() (0)
#define NAND_BUS_8BIT() (!NAND_BUS_16BIT())
/* Register offsets */
#define REG_NAND_CMD_OFFSET (0)
#define REG_NAND_ADDR_OFFSET (4)
#define REG_NAND_DATA8_OFFSET (8)
#endif
This diff is collapsed.
......@@ -79,6 +79,10 @@ struct davinci_nand_pdata { /* platform_data */
/* e.g. NAND_BUSWIDTH_16 or NAND_USE_FLASH_BBT */
unsigned options;
/* Main and mirror bbt descriptor overrides */
struct nand_bbt_descr *bbt_td;
struct nand_bbt_descr *bbt_md;
};
#endif /* __ARCH_ARM_DAVINCI_NAND_H */
......@@ -18,6 +18,7 @@
#include <linux/gpio.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/onenand.h>
#include <linux/mtd/partitions.h>
#include <linux/io.h>
#include <asm/sizes.h>
......@@ -149,7 +150,7 @@ static struct mtd_partition nhk8815_onenand_partitions[] = {
}
};
static struct flash_platform_data nhk8815_onenand_data = {
static struct onenand_platform_data nhk8815_onenand_data = {
.parts = nhk8815_onenand_partitions,
.nr_parts = ARRAY_SIZE(nhk8815_onenand_partitions),
};
......@@ -163,7 +164,7 @@ static struct resource nhk8815_onenand_resource[] = {
};
static struct platform_device nhk8815_onenand_device = {
.name = "onenand",
.name = "onenand-flash",
.id = -1,
.dev = {
.platform_data = &nhk8815_onenand_data,
......@@ -174,10 +175,10 @@ static struct platform_device nhk8815_onenand_device = {
static void __init nhk8815_onenand_init(void)
{
#ifdef CONFIG_ONENAND
#ifdef CONFIG_MTD_ONENAND
/* Set up SMCS0 for OneNand */
writel(0x000030db, FSMC_BCR0);
writel(0x02100551, FSMC_BTR0);
writel(0x000030db, FSMC_BCR(0));
writel(0x02100551, FSMC_BTR(0));
#endif
}
......
......@@ -22,6 +22,7 @@
struct mxc_nand_platform_data {
int width; /* data bus width in bytes */
int hw_ecc; /* 0 if supress hardware ECC */
int hw_ecc:1; /* 0 if supress hardware ECC */
int flash_bbt:1; /* set to 1 to use a flash based bbt */
};
#endif /* __ASM_ARCH_NAND_H */
......@@ -17,6 +17,7 @@
* Setting this flag will allow the kernel to
* look for it at boot time and also skip the NAND
* scan.
* @options: Default value to set into 'struct nand_chip' options.
* @nr_chips: Number of chips in this set
* @nr_partitions: Number of partitions pointed to by @partitions
* @name: Name of set (optional)
......@@ -31,6 +32,7 @@ struct s3c2410_nand_set {
unsigned int disable_ecc:1;
unsigned int flash_bbt:1;
unsigned int options;
int nr_chips;
int nr_partitions;
char *name;
......
......@@ -43,15 +43,17 @@
// debugging, turns off buffer write mode if set to 1
#define FORCE_WORD_WRITE 0
#define MANUFACTURER_INTEL 0x0089
/* Intel chips */
#define I82802AB 0x00ad
#define I82802AC 0x00ac
#define PF38F4476 0x881c
#define MANUFACTURER_ST 0x0020
/* STMicroelectronics chips */
#define M50LPW080 0x002F
#define M50FLW080A 0x0080
#define M50FLW080B 0x0081
/* Atmel chips */
#define AT49BV640D 0x02de
#define AT49BV640DT 0x02db
static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
......@@ -199,6 +201,16 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
cfi->cfiq->BufWriteTimeoutMax = 0;
}
static void fixup_at49bv640dx_lock(struct mtd_info *mtd, void *param)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
cfip->FeatureSupport |= (1 << 5);
mtd->flags |= MTD_POWERUP_LOCK;
}
#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
......@@ -283,6 +295,8 @@ static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param)
static struct cfi_fixup cfi_fixup_table[] = {
{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
{ CFI_MFR_ATMEL, AT49BV640D, fixup_at49bv640dx_lock, NULL },
{ CFI_MFR_ATMEL, AT49BV640DT, fixup_at49bv640dx_lock, NULL },
#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
#endif
......@@ -294,16 +308,16 @@ static struct cfi_fixup cfi_fixup_table[] = {
#endif
{ CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
{ CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
{ MANUFACTURER_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, },
{ CFI_MFR_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, },
{ 0, 0, NULL, NULL }
};
static struct cfi_fixup jedec_fixup_table[] = {
{ MANUFACTURER_INTEL, I82802AB, fixup_use_fwh_lock, NULL, },
{ MANUFACTURER_INTEL, I82802AC, fixup_use_fwh_lock, NULL, },
{ MANUFACTURER_ST, M50LPW080, fixup_use_fwh_lock, NULL, },
{ MANUFACTURER_ST, M50FLW080A, fixup_use_fwh_lock, NULL, },
{ MANUFACTURER_ST, M50FLW080B, fixup_use_fwh_lock, NULL, },
{ CFI_MFR_INTEL, I82802AB, fixup_use_fwh_lock, NULL, },
{ CFI_MFR_INTEL, I82802AC, fixup_use_fwh_lock, NULL, },
{ CFI_MFR_ST, M50LPW080, fixup_use_fwh_lock, NULL, },
{ CFI_MFR_ST, M50FLW080A, fixup_use_fwh_lock, NULL, },
{ CFI_MFR_ST, M50FLW080B, fixup_use_fwh_lock, NULL, },
{ 0, 0, NULL, NULL }
};
static struct cfi_fixup fixup_table[] = {
......@@ -319,7 +333,7 @@ static struct cfi_fixup fixup_table[] = {
static void cfi_fixup_major_minor(struct cfi_private *cfi,
struct cfi_pri_intelext *extp)
{
if (cfi->mfr == MANUFACTURER_INTEL &&
if (cfi->mfr == CFI_MFR_INTEL &&
cfi->id == PF38F4476 && extp->MinorVersion == '3')
extp->MinorVersion = '1';
}
......@@ -2235,7 +2249,7 @@ static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
/* Some chips have OTP located in the _top_ partition only.
For example: Intel 28F256L18T (T means top-parameter device) */
if (cfi->mfr == MANUFACTURER_INTEL) {
if (cfi->mfr == CFI_MFR_INTEL) {
switch (cfi->id) {
case 0x880b:
case 0x880c:
......@@ -2564,6 +2578,7 @@ static int cfi_intelext_reset(struct mtd_info *mtd)
if (!ret) {
map_write(map, CMD(0xff), chip->start);
chip->state = FL_SHUTDOWN;
put_chip(map, chip, chip->start);
}
spin_unlock(chip->mutex);
}
......
......@@ -490,10 +490,6 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
}
#endif
/* FIXME: erase-suspend-program is broken. See
http://lists.infradead.org/pipermail/linux-mtd/2003-December/009001.html */
printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n");
__module_get(THIS_MODULE);
return mtd;
......@@ -573,7 +569,6 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
if (time_after(jiffies, timeo)) {
printk(KERN_ERR "Waiting for chip to be ready timed out.\n");
spin_unlock(chip->mutex);
return -EIO;
}
spin_unlock(chip->mutex);
......@@ -589,15 +584,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
return 0;
case FL_ERASING:
if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */
goto sleep;
if (!( mode == FL_READY
|| mode == FL_POINT
|| !cfip
|| (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))
|| (mode == FL_WRITING && (cfip->EraseSuspend & 0x1)
)))
if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
!(mode == FL_READY || mode == FL_POINT ||
(mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
goto sleep;
/* We could check to see if we're trying to access the sector
......
......@@ -69,6 +69,13 @@ int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map,
/* ST M29DW chips */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL);
if (cfi_qry_present(map, base, cfi))
return 1;
/* some old SST chips, e.g. 39VF160x/39VF320x */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
if (cfi_qry_present(map, base, cfi))
return 1;
/* QRY not found */
......
......@@ -142,8 +142,8 @@
/* ST - www.st.com */
#define M29F800AB 0x0058
#define M29W800DT 0x00D7
#define M29W800DB 0x005B
#define M29W800DT 0x22D7
#define M29W800DB 0x225B
#define M29W400DT 0x00EE
#define M29W400DB 0x00EF
#define M29W160DT 0x22C4
......@@ -1575,7 +1575,7 @@ static const struct amd_flash_info jedec_table[] = {
.dev_id = M29W800DT,
.name = "ST M29W800DT",
.devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
.uaddr = MTD_UADDR_0x5555_0x2AAA, /* ???? */
.uaddr = MTD_UADDR_0x0AAA_0x0555,
.dev_size = SIZE_1MiB,
.cmd_set = P_ID_AMD_STD,
.nr_regions = 4,
......@@ -1590,7 +1590,7 @@ static const struct amd_flash_info jedec_table[] = {
.dev_id = M29W800DB,
.name = "ST M29W800DB",
.devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
.uaddr = MTD_UADDR_0x5555_0x2AAA, /* ???? */
.uaddr = MTD_UADDR_0x0AAA_0x0555,
.dev_size = SIZE_1MiB,
.cmd_set = P_ID_AMD_STD,
.nr_regions = 4,
......
This diff is collapsed.
......@@ -636,6 +636,7 @@ add_dataflash_otp(struct spi_device *spi, char *name,
struct mtd_info *device;
struct flash_platform_data *pdata = spi->dev.platform_data;
char *otp_tag = "";
int err = 0;
priv = kzalloc(sizeof *priv, GFP_KERNEL);
if (!priv)
......@@ -693,13 +694,23 @@ add_dataflash_otp(struct spi_device *spi, char *name,
if (nr_parts > 0) {
priv->partitioned = 1;
return add_mtd_partitions(device, parts, nr_parts);
err = add_mtd_partitions(device, parts, nr_parts);
goto out;
}
} else if (pdata && pdata->nr_parts)
dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
pdata->nr_parts, device->name);
return add_mtd_device(device) == 1 ? -ENODEV : 0;
if (add_mtd_device(device) == 1)
err = -ENODEV;
out:
if (!err)
return 0;
dev_set_drvdata(&spi->dev, NULL);
kfree(priv);
return err;
}
static inline int __devinit
......@@ -932,8 +943,10 @@ static int __devexit dataflash_remove(struct spi_device *spi)
status = del_mtd_partitions(&flash->mtd);
else
status = del_mtd_device(&flash->mtd);
if (status == 0)
if (status == 0) {
dev_set_drvdata(&spi->dev, NULL);
kfree(flash);
}
return status;
}
......
......@@ -359,12 +359,6 @@ config MTD_SA1100
the SA1100 and SA1110, including the Assabet and the Compaq iPAQ.
If you have such a board, say 'Y'.
config MTD_IPAQ
tristate "CFI Flash device mapped on Compaq/HP iPAQ"
depends on IPAQ_HANDHELD && MTD_CFI
help
This provides a driver for the on-board flash of the iPAQ.
config MTD_DC21285
tristate "CFI Flash device mapped on DC21285 Footbridge"
depends on MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS
......
......@@ -24,12 +24,12 @@ obj-$(CONFIG_MTD_CEIVA) += ceiva.o
obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o
obj-$(CONFIG_MTD_PISMO) += pismo.o
obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o
obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
obj-$(CONFIG_MTD_IPAQ) += ipaq-flash.o
obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o
obj-$(CONFIG_MTD_NETSC520) += netsc520.o
......
This diff is collapsed.
......@@ -210,7 +210,7 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
* not attempt to do a direct access on us.
*/
info->map.phys = NO_XIP;
info->map.size = dev->resource->end - dev->resource->start + 1;
info->map.size = resource_size(dev->resource);
/*
* We only support 16-bit accesses for now. If and when
......@@ -224,7 +224,7 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
info->map.copy_from = ixp4xx_copy_from,
info->res = request_mem_region(dev->resource->start,
dev->resource->end - dev->resource->start + 1,
resource_size(dev->resource),
"IXP4XXFlash");
if (!info->res) {
printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n");
......@@ -233,7 +233,7 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
}
info->map.virt = ioremap(dev->resource->start,
dev->resource->end - dev->resource->start + 1);
resource_size(dev->resource));
if (!info->map.virt) {
printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n");
err = -EIO;
......
......@@ -48,23 +48,22 @@ static int physmap_flash_remove(struct platform_device *dev)
if (info->cmtd) {
#ifdef CONFIG_MTD_PARTITIONS
if (info->nr_parts || physmap_data->nr_parts)
if (info->nr_parts || physmap_data->nr_parts) {
del_mtd_partitions(info->cmtd);
else
if (info->nr_parts)
kfree(info->parts);
} else {
del_mtd_device(info->cmtd);
}
#else
del_mtd_device(info->cmtd);
#endif
}
#ifdef CONFIG_MTD_PARTITIONS
if (info->nr_parts)
kfree(info->parts);
#endif
#ifdef CONFIG_MTD_CONCAT
if (info->cmtd != info->mtd[0])
mtd_concat_destroy(info->cmtd);
#endif
}
for (i = 0; i < MAX_RESOURCES; i++) {
if (info->mtd[i] != NULL)
......@@ -130,7 +129,7 @@ static int physmap_flash_probe(struct platform_device *dev)
info->map[i].size);
if (info->map[i].virt == NULL) {
dev_err(&dev->dev, "Failed to ioremap flash region\n");
err = EIO;
err = -EIO;
goto err_out;
}
......
......@@ -248,7 +248,7 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla
plat->exit();
}
static struct sa_info *__init
static struct sa_info *__devinit
sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
{
struct sa_info *info;
......
......@@ -612,16 +612,15 @@ static int __devinit vmu_connect(struct maple_device *mdev)
test_flash_data = be32_to_cpu(mdev->devinfo.function);
/* Need to count how many bits are set - to find out which
* function_data element has details of the memory card:
* using Brian Kernighan's/Peter Wegner's method */
for (c = 0; test_flash_data; c++)
test_flash_data &= test_flash_data - 1;
* function_data element has details of the memory card
*/
c = hweight_long(test_flash_data);
basic_flash_data = be32_to_cpu(mdev->devinfo.function_data[c - 1]);
card = kmalloc(sizeof(struct memcard), GFP_KERNEL);
if (!card) {
error = ENOMEM;
error = -ENOMEM;
goto fail_nomem;
}
......
......@@ -84,9 +84,6 @@ static int mtd_blktrans_thread(void *arg)
struct request_queue *rq = tr->blkcore_priv->rq;
struct request *req = NULL;
/* we might get involved when memory gets low, so use PF_MEMALLOC */
current->flags |= PF_MEMALLOC;
spin_lock_irq(rq->queue_lock);
while (!kthread_should_stop()) {
......@@ -381,7 +378,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr,
"%sd", tr->name);
if (IS_ERR(tr->blkcore_priv->thread)) {
int ret = PTR_ERR(tr->blkcore_priv->thread);
ret = PTR_ERR(tr->blkcore_priv->thread);
blk_cleanup_queue(tr->blkcore_priv->rq);
unregister_blkdev(tr->major, tr->name);
kfree(tr->blkcore_priv);
......
......@@ -447,7 +447,7 @@ struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
for (i=0; i< MAX_MTD_DEVICES; i++)
if (mtd_table[i] == mtd)
ret = mtd_table[i];
} else if (num < MAX_MTD_DEVICES) {
} else if (num >= 0 && num < MAX_MTD_DEVICES) {
ret = mtd_table[num];
if (mtd && mtd != ret)
ret = NULL;
......
This diff is collapsed.
......@@ -201,6 +201,22 @@ config MTD_NAND_S3C2410_CLKSTOP
when the is NAND chip selected or released, but will save
approximately 5mA of power when there is nothing happening.
config MTD_NAND_BCM_UMI
tristate "NAND Flash support for BCM Reference Boards"
depends on ARCH_BCMRING && MTD_NAND
help
This enables the NAND flash controller on the BCM UMI block.
No board specfic support is done by this driver, each board
must advertise a platform_device for the driver to attach.
config MTD_NAND_BCM_UMI_HWCS
bool "BCM UMI NAND Hardware CS"
depends on MTD_NAND_BCM_UMI
help
Enable the use of the BCM UMI block's internal CS using NAND.
This should only be used if you know the external NAND CS can toggle.
config MTD_NAND_DISKONCHIP
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
depends on EXPERIMENTAL
......
......@@ -42,5 +42,6 @@ obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
obj-$(CONFIG_MTD_NAND_W90P910) += w90p910_nand.o
obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o
obj-$(CONFIG_MTD_NAND_BCM_UMI) += bcm_umi_nand.o nand_bcm_umi.o
nand-objs := nand_base.o nand_bbt.o
......@@ -372,15 +372,6 @@ static int alauda_read_oob(struct mtd_info *mtd, loff_t from, void *oob)
return __alauda_read_page(mtd, from, ignore_buf, oob);
}
static int popcount8(u8 c)
{
int ret = 0;
for ( ; c; c>>=1)
ret += c & 1;
return ret;
}
static int alauda_isbad(struct mtd_info *mtd, loff_t ofs)
{
u8 oob[16];
......@@ -391,7 +382,7 @@ static int alauda_isbad(struct mtd_info *mtd, loff_t ofs)
return err;
/* A block is marked bad if two or more bits are zero */
return popcount8(oob[5]) >= 7 ? 0 : 1;
return hweight8(oob[5]) >= 7 ? 0 : 1;
}
static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len,
......
......@@ -192,7 +192,6 @@ static int atmel_nand_calculate(struct mtd_info *mtd,
{
struct nand_chip *nand_chip = mtd->priv;
struct atmel_nand_host *host = nand_chip->priv;
uint32_t *eccpos = nand_chip->ecc.layout->eccpos;
unsigned int ecc_value;
/* get the first 2 ECC bytes */
......@@ -464,7 +463,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
if (host->board->det_pin) {
if (gpio_get_value(host->board->det_pin)) {
printk(KERN_INFO "No SmartMedia card inserted.\n");
res = ENXIO;
res = -ENXIO;
goto err_no_card;
}
}
......@@ -535,7 +534,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
if ((!partitions) || (num_partitions == 0)) {
printk(KERN_ERR "atmel_nand: No partitions defined, or unsupported device.\n");
res = ENXIO;
res = -ENXIO;
goto err_no_partitions;
}
......
/*****************************************************************************
* Copyright 2004 - 2009 Broadcom Corporation. All rights reserved.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2, available at
* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a
* license other than the GPL, without Broadcom's express prior written
* consent.
*****************************************************************************/
/* ---- Include Files ---------------------------------------------------- */
#include "nand_bcm_umi.h"
/* ---- External Variable Declarations ----------------------------------- */
/* ---- External Function Prototypes ------------------------------------- */
/* ---- Public Variables ------------------------------------------------- */
/* ---- Private Constants and Types -------------------------------------- */
/* ---- Private Function Prototypes -------------------------------------- */
static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int page);
static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf);
/* ---- Private Variables ------------------------------------------------ */
/*
** nand_hw_eccoob
** New oob placement block for use with hardware ecc generation.
*/
static struct nand_ecclayout nand_hw_eccoob_512 = {
/* Reserve 5 for BI indicator */
.oobfree = {
#if (NAND_ECC_NUM_BYTES > 3)
{.offset = 0, .length = 2}
#else
{.offset = 0, .length = 5},
{.offset = 6, .length = 7}
#endif
}
};
/*
** We treat the OOB for a 2K page as if it were 4 512 byte oobs,
** except the BI is at byte 0.
*/
static struct nand_ecclayout nand_hw_eccoob_2048 = {
/* Reserve 0 as BI indicator */
.oobfree = {
#if (NAND_ECC_NUM_BYTES > 10)
{.offset = 1, .length = 2},
#elif (NAND_ECC_NUM_BYTES > 7)
{.offset = 1, .length = 5},
{.offset = 16, .length = 6},
{.offset = 32, .length = 6},
{.offset = 48, .length = 6}
#else
{.offset = 1, .length = 8},
{.offset = 16, .length = 9},
{.offset = 32, .length = 9},
{.offset = 48, .length = 9}
#endif
}
};
/* We treat the OOB for a 4K page as if it were 8 512 byte oobs,
* except the BI is at byte 0. */
static struct nand_ecclayout nand_hw_eccoob_4096 = {
/* Reserve 0 as BI indicator */
.oobfree = {
#if (NAND_ECC_NUM_BYTES > 10)
{.offset = 1, .length = 2},
{.offset = 16, .length = 3},
{.offset = 32, .length = 3},
{.offset = 48, .length = 3},
{.offset = 64, .length = 3},
{.offset = 80, .length = 3},
{.offset = 96, .length = 3},
{.offset = 112, .length = 3}
#else
{.offset = 1, .length = 5},
{.offset = 16, .length = 6},
{.offset = 32, .length = 6},
{.offset = 48, .length = 6},
{.offset = 64, .length = 6},
{.offset = 80, .length = 6},
{.offset = 96, .length = 6},
{.offset = 112, .length = 6}
#endif
}
};
/* ---- Private Functions ------------------------------------------------ */
/* ==== Public Functions ================================================= */
/****************************************************************************
*
* bcm_umi_bch_read_page_hwecc - hardware ecc based page read function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
*
***************************************************************************/
static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t * buf,
int page)
{
int sectorIdx = 0;
int eccsize = chip->ecc.size;
int eccsteps = chip->ecc.steps;
uint8_t *datap = buf;
uint8_t eccCalc[NAND_ECC_NUM_BYTES];
int sectorOobSize = mtd->oobsize / eccsteps;
int stat;
for (sectorIdx = 0; sectorIdx < eccsteps;
sectorIdx++, datap += eccsize) {
if (sectorIdx > 0) {
/* Seek to page location within sector */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, sectorIdx * eccsize,
-1);
}
/* Enable hardware ECC before reading the buf */
nand_bcm_umi_bch_enable_read_hwecc();
/* Read in data */
bcm_umi_nand_read_buf(mtd, datap, eccsize);
/* Pause hardware ECC after reading the buf */
nand_bcm_umi_bch_pause_read_ecc_calc();
/* Read the OOB ECC */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
mtd->writesize + sectorIdx * sectorOobSize, -1);
nand_bcm_umi_bch_read_oobEcc(mtd->writesize, eccCalc,
NAND_ECC_NUM_BYTES,
chip->oob_poi +
sectorIdx * sectorOobSize);
/* Correct any ECC detected errors */
stat =
nand_bcm_umi_bch_correct_page(datap, eccCalc,
NAND_ECC_NUM_BYTES);
/* Update Stats */
if (stat < 0) {
#if defined(NAND_BCM_UMI_DEBUG)
printk(KERN_WARNING "%s uncorr_err sectorIdx=%d\n",
__func__, sectorIdx);
printk(KERN_WARNING
"%s data %02x %02x %02x %02x "
"%02x %02x %02x %02x\n",
__func__, datap[0], datap[1], datap[2], datap[3],
datap[4], datap[5], datap[6], datap[7]);
printk(KERN_WARNING
"%s ecc %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x "
"%02x %02x %02x\n",
__func__, eccCalc[0], eccCalc[1], eccCalc[2],
eccCalc[3], eccCalc[4], eccCalc[5], eccCalc[6],
eccCalc[7], eccCalc[8], eccCalc[9], eccCalc[10],
eccCalc[11], eccCalc[12]);
BUG();
#endif
mtd->ecc_stats.failed++;
} else {
#if defined(NAND_BCM_UMI_DEBUG)
if (stat > 0) {
printk(KERN_INFO
"%s %d correctable_errors detected\n",
__func__, stat);
}
#endif
mtd->ecc_stats.corrected += stat;
}
}
return 0;
}
/****************************************************************************
*
* bcm_umi_bch_write_page_hwecc - hardware ecc based page write function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
*
***************************************************************************/
static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf)
{
int sectorIdx = 0;
int eccsize = chip->ecc.size;
int eccsteps = chip->ecc.steps;
const uint8_t *datap = buf;
uint8_t *oobp = chip->oob_poi;
int sectorOobSize = mtd->oobsize / eccsteps;
for (sectorIdx = 0; sectorIdx < eccsteps;
sectorIdx++, datap += eccsize, oobp += sectorOobSize) {
/* Enable hardware ECC before writing the buf */
nand_bcm_umi_bch_enable_write_hwecc();
bcm_umi_nand_write_buf(mtd, datap, eccsize);
nand_bcm_umi_bch_write_oobEcc(mtd->writesize, oobp,
NAND_ECC_NUM_BYTES);
}
bcm_umi_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
}
This diff is collapsed.
......@@ -591,6 +591,8 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
/* options such as NAND_USE_FLASH_BBT or 16-bit widths */
info->chip.options = pdata->options;
info->chip.bbt_td = pdata->bbt_td;
info->chip.bbt_md = pdata->bbt_md;
info->ioaddr = (uint32_t __force) vaddr;
......@@ -599,7 +601,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
info->mask_chipsel = pdata->mask_chipsel;
/* use nandboot-capable ALE/CLE masks by default */
info->mask_ale = pdata->mask_cle ? : MASK_ALE;
info->mask_ale = pdata->mask_ale ? : MASK_ALE;
info->mask_cle = pdata->mask_cle ? : MASK_CLE;
/* Set address of hardware control function */
......
......@@ -128,7 +128,7 @@ static int excite_nand_devready(struct mtd_info *mtd)
* The binding to the mtd and all allocated
* resources are released.
*/
static int __exit excite_nand_remove(struct platform_device *dev)
static int __devexit excite_nand_remove(struct platform_device *dev)
{
struct excite_nand_drvdata * const this = platform_get_drvdata(dev);
......
......@@ -237,12 +237,15 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
ctrl->use_mdr = 0;
dev_vdbg(ctrl->dev,
"fsl_elbc_run_command: stat=%08x mdr=%08x fmr=%08x\n",
ctrl->status, ctrl->mdr, in_be32(&lbc->fmr));
if (ctrl->status != LTESR_CC) {
dev_info(ctrl->dev,
"command failed: fir %x fcr %x status %x mdr %x\n",
in_be32(&lbc->fir), in_be32(&lbc->fcr),
ctrl->status, ctrl->mdr);
return -EIO;
}
/* returns 0 on success otherwise non-zero) */
return ctrl->status == LTESR_CC ? 0 : -EIO;
return 0;
}
static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
......@@ -253,17 +256,17 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
if (priv->page_size) {
out_be32(&lbc->fir,
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
(FIR_OP_CM0 << FIR_OP0_SHIFT) |
(FIR_OP_CA << FIR_OP1_SHIFT) |
(FIR_OP_PA << FIR_OP2_SHIFT) |
(FIR_OP_CW1 << FIR_OP3_SHIFT) |
(FIR_OP_CM1 << FIR_OP3_SHIFT) |
(FIR_OP_RBW << FIR_OP4_SHIFT));
out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
(NAND_CMD_READSTART << FCR_CMD1_SHIFT));
} else {
out_be32(&lbc->fir,
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
(FIR_OP_CM0 << FIR_OP0_SHIFT) |
(FIR_OP_CA << FIR_OP1_SHIFT) |
(FIR_OP_PA << FIR_OP2_SHIFT) |
(FIR_OP_RBW << FIR_OP3_SHIFT));
......@@ -332,7 +335,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
case NAND_CMD_READID:
dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) |
out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) |
(FIR_OP_UA << FIR_OP1_SHIFT) |
(FIR_OP_RBW << FIR_OP2_SHIFT));
out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
......@@ -359,16 +362,20 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
out_be32(&lbc->fir,
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
(FIR_OP_CM0 << FIR_OP0_SHIFT) |
(FIR_OP_PA << FIR_OP1_SHIFT) |
(FIR_OP_CM1 << FIR_OP2_SHIFT));
(FIR_OP_CM2 << FIR_OP2_SHIFT) |
(FIR_OP_CW1 << FIR_OP3_SHIFT) |
(FIR_OP_RS << FIR_OP4_SHIFT));
out_be32(&lbc->fcr,
(NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
(NAND_CMD_ERASE2 << FCR_CMD1_SHIFT));
(NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
(NAND_CMD_ERASE2 << FCR_CMD2_SHIFT));
out_be32(&lbc->fbcr, 0);
ctrl->read_bytes = 0;
ctrl->use_mdr = 1;
fsl_elbc_run_command(mtd);
return;
......@@ -383,40 +390,41 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
ctrl->column = column;
ctrl->oob = 0;
ctrl->use_mdr = 1;
if (priv->page_size) {
fcr = (NAND_CMD_SEQIN << FCR_CMD0_SHIFT) |
(NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT);
fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
(NAND_CMD_SEQIN << FCR_CMD2_SHIFT) |
(NAND_CMD_PAGEPROG << FCR_CMD3_SHIFT);
if (priv->page_size) {
out_be32(&lbc->fir,
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
(FIR_OP_CM2 << FIR_OP0_SHIFT) |
(FIR_OP_CA << FIR_OP1_SHIFT) |
(FIR_OP_PA << FIR_OP2_SHIFT) |
(FIR_OP_WB << FIR_OP3_SHIFT) |
(FIR_OP_CW1 << FIR_OP4_SHIFT));
(FIR_OP_CM3 << FIR_OP4_SHIFT) |
(FIR_OP_CW1 << FIR_OP5_SHIFT) |
(FIR_OP_RS << FIR_OP6_SHIFT));
} else {
fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) |
(NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
out_be32(&lbc->fir,
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
(FIR_OP_CM0 << FIR_OP0_SHIFT) |
(FIR_OP_CM2 << FIR_OP1_SHIFT) |
(FIR_OP_CA << FIR_OP2_SHIFT) |
(FIR_OP_PA << FIR_OP3_SHIFT) |
(FIR_OP_WB << FIR_OP4_SHIFT) |
(FIR_OP_CW1 << FIR_OP5_SHIFT));
(FIR_OP_CM3 << FIR_OP5_SHIFT) |
(FIR_OP_CW1 << FIR_OP6_SHIFT) |
(FIR_OP_RS << FIR_OP7_SHIFT));
if (column >= mtd->writesize) {
/* OOB area --> READOOB */
column -= mtd->writesize;
fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
ctrl->oob = 1;
} else if (column < 256) {
} else {
WARN_ON(column != 0);
/* First 256 bytes --> READ0 */
fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
} else {
/* Second 256 bytes --> READ1 */
fcr |= NAND_CMD_READ1 << FCR_CMD0_SHIFT;
}
}
......@@ -628,22 +636,6 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
{
struct fsl_elbc_mtd *priv = chip->priv;
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
if (ctrl->status != LTESR_CC)
return NAND_STATUS_FAIL;
/* Use READ_STATUS command, but wait for the device to be ready */
ctrl->use_mdr = 0;
out_be32(&lbc->fir,
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
(FIR_OP_RBW << FIR_OP1_SHIFT));
out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
out_be32(&lbc->fbcr, 1);
set_addr(mtd, 0, 0, 0);
ctrl->read_bytes = 1;
fsl_elbc_run_command(mtd);
if (ctrl->status != LTESR_CC)
return NAND_STATUS_FAIL;
......@@ -651,8 +643,7 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
/* The chip always seems to report that it is
* write-protected, even when it is not.
*/
setbits8(ctrl->addr, NAND_STATUS_WP);
return fsl_elbc_read_byte(mtd);
return (ctrl->mdr & 0xff) | NAND_STATUS_WP;
}
static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
......@@ -946,6 +937,13 @@ static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl)
{
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
/*
* NAND transactions can tie up the bus for a long time, so set the
* bus timeout to max by clearing LBCR[BMT] (highest base counter
* value) and setting LBCR[BMTPS] to the highest prescaler value.
*/
clrsetbits_be32(&lbc->lbcr, LBCR_BMT, 15);
/* clear event registers */
setbits32(&lbc->ltesr, LTESR_NAND_MASK);
out_be32(&lbc->lteatr, 0);
......
......@@ -112,7 +112,7 @@ static void fun_select_chip(struct mtd_info *mtd, int mchip_nr)
if (mchip_nr == -1) {
chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
} else if (mchip_nr >= 0) {
} else if (mchip_nr >= 0 && mchip_nr < NAND_MAX_CHIPS) {
fun->mchip_number = mchip_nr;
chip->IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
chip->IO_ADDR_W = chip->IO_ADDR_R;
......
This diff is collapsed.
......@@ -428,6 +428,28 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
return nand_isbad_bbt(mtd, ofs, allowbbt);
}
/**
* panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
* @mtd: MTD device structure
* @timeo: Timeout
*
* Helper function for nand_wait_ready used when needing to wait in interrupt
* context.
*/
static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
{
struct nand_chip *chip = mtd->priv;
int i;
/* Wait for the device to get ready */
for (i = 0; i < timeo; i++) {
if (chip->dev_ready(mtd))
break;
touch_softlockup_watchdog();
mdelay(1);
}
}
/*
* Wait for the ready pin, after a command
* The timeout is catched later.
......@@ -437,6 +459,10 @@ void nand_wait_ready(struct mtd_info *mtd)
struct nand_chip *chip = mtd->priv;
unsigned long timeo = jiffies + 2;
/* 400ms timeout */
if (in_interrupt() || oops_in_progress)
return panic_nand_wait_ready(mtd, 400);
led_trigger_event(nand_led_trigger, LED_FULL);
/* wait until command is processed or timeout occures */
do {
......@@ -671,6 +697,22 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
nand_wait_ready(mtd);
}
/**
* panic_nand_get_device - [GENERIC] Get chip for selected access
* @chip: the nand chip descriptor
* @mtd: MTD device structure
* @new_state: the state which is requested
*
* Used when in panic, no locks are taken.
*/
static void panic_nand_get_device(struct nand_chip *chip,
struct mtd_info *mtd, int new_state)
{
/* Hardware controller shared among independend devices */
chip->controller->active = chip;
chip->state = new_state;
}
/**
* nand_get_device - [GENERIC] Get chip for selected access
* @chip: the nand chip descriptor
......@@ -698,8 +740,14 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
return 0;
}
if (new_state == FL_PM_SUSPENDED) {
if (chip->controller->active->state == FL_PM_SUSPENDED) {
chip->state = FL_PM_SUSPENDED;
spin_unlock(lock);
return (chip->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
return 0;
} else {
spin_unlock(lock);
return -EAGAIN;
}
}
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(wq, &wait);
......@@ -709,6 +757,32 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
goto retry;
}
/**
* panic_nand_wait - [GENERIC] wait until the command is done
* @mtd: MTD device structure
* @chip: NAND chip structure
* @timeo: Timeout
*
* Wait for command done. This is a helper function for nand_wait used when
* we are in interrupt context. May happen when in panic and trying to write
* an oops trough mtdoops.
*/
static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
unsigned long timeo)
{
int i;
for (i = 0; i < timeo; i++) {
if (chip->dev_ready) {
if (chip->dev_ready(mtd))
break;
} else {
if (chip->read_byte(mtd) & NAND_STATUS_READY)
break;
}
mdelay(1);
}
}
/**
* nand_wait - [DEFAULT] wait until the command is done
* @mtd: MTD device structure
......@@ -740,6 +814,9 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
else
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
if (in_interrupt() || oops_in_progress)
panic_nand_wait(mtd, chip, timeo);
else {
while (time_before(jiffies, timeo)) {
if (chip->dev_ready) {
if (chip->dev_ready(mtd))
......@@ -750,6 +827,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
}
cond_resched();
}
}
led_trigger_event(nand_led_trigger, LED_OFF);
status = (int)chip->read_byte(mtd);
......@@ -1948,6 +2026,45 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
return ret;
}
/**
* panic_nand_write - [MTD Interface] NAND write with ECC
* @mtd: MTD device structure
* @to: offset to write to
* @len: number of bytes to write
* @retlen: pointer to variable to store the number of written bytes
* @buf: the data to write
*
* NAND write with ECC. Used when performing writes in interrupt context, this
* may for example be called by mtdoops when writing an oops while in panic.
*/
static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
int ret;
/* Do not allow reads past end of device */
if ((to + len) > mtd->size)
return -EINVAL;
if (!len)
return 0;
/* Wait for the device to get ready. */
panic_nand_wait(mtd, chip, 400);
/* Grab the device. */
panic_nand_get_device(chip, mtd, FL_WRITING);
chip->ops.len = len;
chip->ops.datbuf = (uint8_t *)buf;
chip->ops.oobbuf = NULL;
ret = nand_do_write_ops(mtd, to, &chip->ops);
*retlen = chip->ops.retlen;
return ret;
}
/**
* nand_write - [MTD Interface] NAND write with ECC
* @mtd: MTD device structure
......@@ -2645,7 +2762,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
if (IS_ERR(type)) {
printk(KERN_WARNING "No NAND device found!!!\n");
if (!(chip->options & NAND_SCAN_SILENT_NODEV))
printk(KERN_WARNING "No NAND device found.\n");
chip->select_chip(mtd, -1);
return PTR_ERR(type);
}
......@@ -2877,6 +2995,7 @@ int nand_scan_tail(struct mtd_info *mtd)
mtd->unpoint = NULL;
mtd->read = nand_read;
mtd->write = nand_write;
mtd->panic_write = panic_nand_write;
mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob;
mtd->sync = nand_sync;
......
/*****************************************************************************
* Copyright 2004 - 2009 Broadcom Corporation. All rights reserved.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2, available at
* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a
* license other than the GPL, without Broadcom's express prior written
* consent.
*****************************************************************************/
/* ---- Include Files ---------------------------------------------------- */
#include <mach/reg_umi.h>
#include "nand_bcm_umi.h"
#ifdef BOOT0_BUILD
#include <uart.h>
#endif
/* ---- External Variable Declarations ----------------------------------- */
/* ---- External Function Prototypes ------------------------------------- */
/* ---- Public Variables ------------------------------------------------- */
/* ---- Private Constants and Types -------------------------------------- */
/* ---- Private Function Prototypes -------------------------------------- */
/* ---- Private Variables ------------------------------------------------ */
/* ---- Private Functions ------------------------------------------------ */
#if NAND_ECC_BCH
/****************************************************************************
* nand_bch_ecc_flip_bit - Routine to flip an errored bit
*
* PURPOSE:
* This is a helper routine that flips the bit (0 -> 1 or 1 -> 0) of the
* errored bit specified
*
* PARAMETERS:
* datap - Container that holds the 512 byte data
* errorLocation - Location of the bit that needs to be flipped
*
* RETURNS:
* None
****************************************************************************/
static void nand_bcm_umi_bch_ecc_flip_bit(uint8_t *datap, int errorLocation)
{
int locWithinAByte = (errorLocation & REG_UMI_BCH_ERR_LOC_BYTE) >> 0;
int locWithinAWord = (errorLocation & REG_UMI_BCH_ERR_LOC_WORD) >> 3;
int locWithinAPage = (errorLocation & REG_UMI_BCH_ERR_LOC_PAGE) >> 5;
uint8_t errorByte = 0;
uint8_t byteMask = 1 << locWithinAByte;
/* BCH uses big endian, need to change the location
* bits to little endian */
locWithinAWord = 3 - locWithinAWord;
errorByte = datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord];
#ifdef BOOT0_BUILD
puthexs("\nECC Correct Offset: ",
locWithinAPage * sizeof(uint32_t) + locWithinAWord);
puthexs(" errorByte:", errorByte);
puthex8(" Bit: ", locWithinAByte);
#endif
if (errorByte & byteMask) {
/* bit needs to be cleared */
errorByte &= ~byteMask;
} else {
/* bit needs to be set */
errorByte |= byteMask;
}
/* write back the value with the fixed bit */
datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord] = errorByte;
}
/****************************************************************************
* nand_correct_page_bch - Routine to correct bit errors when reading NAND
*
* PURPOSE:
* This routine reads the BCH registers to determine if there are any bit
* errors during the read of the last 512 bytes of data + ECC bytes. If
* errors exists, the routine fixes it.
*
* PARAMETERS:
* datap - Container that holds the 512 byte data
*
* RETURNS:
* 0 or greater = Number of errors corrected
* (No errors are found or errors have been fixed)
* -1 = Error(s) cannot be fixed
****************************************************************************/
int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData,
int numEccBytes)
{
int numErrors;
int errorLocation;
int idx;
uint32_t regValue;
/* wait for read ECC to be valid */
regValue = nand_bcm_umi_bch_poll_read_ecc_calc();
/*
* read the control status register to determine if there
* are error'ed bits
* see if errors are correctible
*/
if ((regValue & REG_UMI_BCH_CTRL_STATUS_UNCORR_ERR) > 0) {
int i;
for (i = 0; i < numEccBytes; i++) {
if (readEccData[i] != 0xff) {
/* errors cannot be fixed, return -1 */
return -1;
}
}
/* If ECC is unprogrammed then we can't correct,
* assume everything OK */
return 0;
}
if ((regValue & REG_UMI_BCH_CTRL_STATUS_CORR_ERR) == 0) {
/* no errors */
return 0;
}
/*
* Fix errored bits by doing the following:
* 1. Read the number of errors in the control and status register
* 2. Read the error location registers that corresponds to the number
* of errors reported
* 3. Invert the bit in the data
*/
numErrors = (regValue & REG_UMI_BCH_CTRL_STATUS_NB_CORR_ERROR) >> 20;
for (idx = 0; idx < numErrors; idx++) {
errorLocation =
REG_UMI_BCH_ERR_LOC_ADDR(idx) & REG_UMI_BCH_ERR_LOC_MASK;
/* Flip bit */
nand_bcm_umi_bch_ecc_flip_bit(datap, errorLocation);
}
/* Errors corrected */
return numErrors;
}
#endif
This diff is collapsed.
......@@ -150,20 +150,19 @@ static const char addressbits[256] = {
};
/**
* nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
* __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
* block
* @mtd: MTD block structure
* @buf: input buffer with raw data
* @eccsize: data bytes per ecc step (256 or 512)
* @code: output buffer with ECC
*/
int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
unsigned char *code)
{
int i;
const uint32_t *bp = (uint32_t *)buf;
/* 256 or 512 bytes/ecc */
const uint32_t eccsize_mult =
(((struct nand_chip *)mtd->priv)->ecc.size) >> 8;
const uint32_t eccsize_mult = eccsize >> 8;
uint32_t cur; /* current value in buffer */
/* rp0..rp15..rp17 are the various accumulated parities (per byte) */
uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
......@@ -412,6 +411,22 @@ int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
(invparity[par & 0x55] << 2) |
(invparity[rp17] << 1) |
(invparity[rp16] << 0);
}
EXPORT_SYMBOL(__nand_calculate_ecc);
/**
* nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
* block
* @mtd: MTD block structure
* @buf: input buffer with raw data
* @code: output buffer with ECC
*/
int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
unsigned char *code)
{
__nand_calculate_ecc(buf,
((struct nand_chip *)mtd->priv)->ecc.size, code);
return 0;
}
EXPORT_SYMBOL(nand_calculate_ecc);
......
......@@ -161,7 +161,7 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I
MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory");
/* The largest possible page size */
#define NS_LARGEST_PAGE_SIZE 2048
#define NS_LARGEST_PAGE_SIZE 4096
/* The prefix for simulator output */
#define NS_OUTPUT_PREFIX "[nandsim]"
......@@ -259,7 +259,8 @@ MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of mem
#define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */
#define OPT_AUTOINCR 0x00000020 /* page number auto inctimentation is possible */
#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
#define OPT_LARGEPAGE (OPT_PAGE2048) /* 2048-byte page chips */
#define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */
#define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */
#define OPT_SMALLPAGE (OPT_PAGE256 | OPT_PAGE512) /* 256 and 512-byte page chips */
/* Remove action bits ftom state */
......@@ -588,6 +589,8 @@ static int init_nandsim(struct mtd_info *mtd)
ns->options |= OPT_PAGE512_8BIT;
} else if (ns->geom.pgsz == 2048) {
ns->options |= OPT_PAGE2048;
} else if (ns->geom.pgsz == 4096) {
ns->options |= OPT_PAGE4096;
} else {
NS_ERR("init_nandsim: unknown page size %u\n", ns->geom.pgsz);
return -EIO;
......
......@@ -34,7 +34,12 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
{
struct platform_nand_data *pdata = pdev->dev.platform_data;
struct plat_nand_data *data;
int res = 0;
struct resource *res;
int err = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENXIO;
/* Allocate memory for the device structure (and zero it) */
data = kzalloc(sizeof(struct plat_nand_data), GFP_KERNEL);
......@@ -43,12 +48,18 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
return -ENOMEM;
}
data->io_base = ioremap(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1);
if (!request_mem_region(res->start, resource_size(res),
dev_name(&pdev->dev))) {
dev_err(&pdev->dev, "request_mem_region failed\n");
err = -EBUSY;
goto out_free;
}
data->io_base = ioremap(res->start, resource_size(res));
if (data->io_base == NULL) {
dev_err(&pdev->dev, "ioremap failed\n");
kfree(data);
return -EIO;
err = -EIO;
goto out_release_io;
}
data->chip.priv = &data;
......@@ -74,24 +85,24 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
/* Handle any platform specific setup */
if (pdata->ctrl.probe) {
res = pdata->ctrl.probe(pdev);
if (res)
err = pdata->ctrl.probe(pdev);
if (err)
goto out;
}
/* Scan to find existance of the device */
if (nand_scan(&data->mtd, 1)) {
res = -ENXIO;
err = -ENXIO;
goto out;
}
#ifdef CONFIG_MTD_PARTITIONS
if (pdata->chip.part_probe_types) {
res = parse_mtd_partitions(&data->mtd,
err = parse_mtd_partitions(&data->mtd,
pdata->chip.part_probe_types,
&data->parts, 0);
if (res > 0) {
add_mtd_partitions(&data->mtd, data->parts, res);
if (err > 0) {
add_mtd_partitions(&data->mtd, data->parts, err);
return 0;
}
}
......@@ -99,14 +110,14 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
pdata->chip.set_parts(data->mtd.size, &pdata->chip);
if (pdata->chip.partitions) {
data->parts = pdata->chip.partitions;
res = add_mtd_partitions(&data->mtd, data->parts,
err = add_mtd_partitions(&data->mtd, data->parts,
pdata->chip.nr_partitions);
} else
#endif
res = add_mtd_device(&data->mtd);
err = add_mtd_device(&data->mtd);
if (!res)
return res;
if (!err)
return err;
nand_release(&data->mtd);
out:
......@@ -114,8 +125,11 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
pdata->ctrl.remove(pdev);
platform_set_drvdata(pdev, NULL);
iounmap(data->io_base);
out_release_io:
release_mem_region(res->start, resource_size(res));
out_free:
kfree(data);
return res;
return err;
}
/*
......@@ -125,6 +139,9 @@ static int __devexit plat_nand_remove(struct platform_device *pdev)
{
struct plat_nand_data *data = platform_get_drvdata(pdev);
struct platform_nand_data *pdata = pdev->dev.platform_data;
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nand_release(&data->mtd);
#ifdef CONFIG_MTD_PARTITIONS
......@@ -134,6 +151,7 @@ static int __devexit plat_nand_remove(struct platform_device *pdev)
if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev);
iounmap(data->io_base);
release_mem_region(res->start, resource_size(res));
kfree(data);
return 0;
......
......@@ -774,7 +774,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->select_chip = s3c2410_nand_select_chip;
chip->chip_delay = 50;
chip->priv = nmtd;
chip->options = 0;
chip->options = set->options;
chip->controller = &info->controller;
switch (info->cpu_type) {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -5,3 +5,4 @@ obj-$(CONFIG_MTD_TESTS) += mtd_speedtest.o
obj-$(CONFIG_MTD_TESTS) += mtd_stresstest.o
obj-$(CONFIG_MTD_TESTS) += mtd_subpagetest.o
obj-$(CONFIG_MTD_TESTS) += mtd_torturetest.o
obj-$(CONFIG_MTD_TESTS) += mtd_nandecctest.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment