提交 49353617 编写于 作者: L Linus Torvalds

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

* git://git.infradead.org/mtd-2.6: (49 commits)
  [MTD] [NAND] S3C2412 fix hw ecc
  [MTD] [NAND] Work around false compiler warning in CAFÉ driver
  [JFFS2] printk warning fixes
  [MTD] [MAPS] ichxrom warning fix
  [MTD] [MAPS] amd76xrom warning fix
  [MTD] [MAPS] esb2rom warning fixes
  [MTD] [MAPS] ck804xrom warning fix
  [MTD] [MAPS] netsc520 warning fix
  [MTD] [MAPS] sc520cdp warning fix
  [MTD] [ONENAND] onenand_base warning fix
  [MTD] [NAND] eXcite nand flash driver
  [MTD] Improve heuristic for detecting wrong-endian RedBoot partition table
  [MTD] Fix RedBoot partition parsing regression harder.
  [MTD] [NAND] S3C2410: Hardware ECC correction code
  [JFFS2] Use MTD_OOB_AUTO to automatically place cleanmarker on NAND
  [MTD] Clarify OOB-operation interface comments
  [MTD] remove unused ecctype,eccsize fields from struct mtd_info
  [MTD] [NOR] Intel: remove ugly PROGREGION macros
  [MTD] [NOR] STAA: use writesize instead off eccsize to represent ECC block
  [MTD] OneNAND: Invalidate bufferRAM after erase
  ...
......@@ -397,9 +397,23 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
cfi_fixup(mtd, fixup_table);
for (i=0; i< cfi->numchips; i++) {
cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
cfi->chips[i].erase_time = 1000<<cfi->cfiq->BlockEraseTimeoutTyp;
if (cfi->cfiq->WordWriteTimeoutTyp)
cfi->chips[i].word_write_time =
1<<cfi->cfiq->WordWriteTimeoutTyp;
else
cfi->chips[i].word_write_time = 50000;
if (cfi->cfiq->BufWriteTimeoutTyp)
cfi->chips[i].buffer_write_time =
1<<cfi->cfiq->BufWriteTimeoutTyp;
/* No default; if it isn't specified, we won't use it */
if (cfi->cfiq->BlockEraseTimeoutTyp)
cfi->chips[i].erase_time =
1000<<cfi->cfiq->BlockEraseTimeoutTyp;
else
cfi->chips[i].erase_time = 2000000;
cfi->chips[i].ref_point_counter = 0;
init_waitqueue_head(&(cfi->chips[i].wq));
}
......@@ -546,13 +560,11 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
struct cfi_intelext_programming_regioninfo *prinfo;
prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs];
mtd->writesize = cfi->interleave << prinfo->ProgRegShift;
MTD_PROGREGION_CTRLMODE_VALID(mtd) = cfi->interleave * prinfo->ControlValid;
MTD_PROGREGION_CTRLMODE_INVALID(mtd) = cfi->interleave * prinfo->ControlInvalid;
mtd->flags &= ~MTD_BIT_WRITEABLE;
printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n",
map->name, mtd->writesize,
MTD_PROGREGION_CTRLMODE_VALID(mtd),
MTD_PROGREGION_CTRLMODE_INVALID(mtd));
cfi->interleave * prinfo->ControlValid,
cfi->interleave * prinfo->ControlInvalid);
}
/*
......
......@@ -662,7 +662,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to,
* a small buffer for this.
* XXX: If the buffer size is not a multiple of 2, this will break
*/
#define ECCBUF_SIZE (mtd->eccsize)
#define ECCBUF_SIZE (mtd->writesize)
#define ECCBUF_DIV(x) ((x) & ~(ECCBUF_SIZE - 1))
#define ECCBUF_MOD(x) ((x) & (ECCBUF_SIZE - 1))
static int
......
......@@ -569,7 +569,6 @@ void DoC2k_init(struct mtd_info *mtd)
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
mtd->ecctype = MTD_ECC_RS_DiskOnChip;
mtd->size = 0;
mtd->erasesize = 0;
mtd->writesize = 512;
......
......@@ -348,7 +348,6 @@ void DoCMil_init(struct mtd_info *mtd)
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
mtd->ecctype = MTD_ECC_RS_DiskOnChip;
mtd->size = 0;
/* FIXME: erase size is not always 8KiB */
......
......@@ -472,7 +472,6 @@ void DoCMilPlus_init(struct mtd_info *mtd)
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
mtd->ecctype = MTD_ECC_RS_DiskOnChip;
mtd->size = 0;
mtd->erasesize = 0;
......
......@@ -204,7 +204,7 @@ config MTD_ESB2ROM
config MTD_CK804XROM
tristate "BIOS flash chip on Nvidia CK804"
depends on X86 && MTD_JEDECPROBE
depends on X86 && MTD_JEDECPROBE && PCI
help
Support for treating the BIOS flash chip on nvidia motherboards
as an MTD device - with this you can reprogram your BIOS.
......
......@@ -205,8 +205,8 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
(((unsigned long)(window->virt)) + offset);
map->map.size = 0xffffffffUL - map_top + 1UL;
/* Set the name of the map to the address I am trying */
sprintf(map->map_name, "%s @%08lx",
MOD_NAME, map->map.phys);
sprintf(map->map_name, "%s @%08Lx",
MOD_NAME, (unsigned long long)map->map.phys);
/* There is no generic VPP support */
for(map->map.bankwidth = 32; map->map.bankwidth;
......
......@@ -207,8 +207,8 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
(((unsigned long)(window->virt)) + offset);
map->map.size = 0xffffffffUL - map_top + 1UL;
/* Set the name of the map to the address I am trying */
sprintf(map->map_name, "%s @%08lx",
MOD_NAME, map->map.phys);
sprintf(map->map_name, "%s @%08Lx",
MOD_NAME, (unsigned long long)map->map.phys);
/* There is no generic VPP support */
for(map->map.bankwidth = 32; map->map.bankwidth;
......@@ -327,7 +327,7 @@ static int __init init_ck804xrom(void)
pdev = NULL;
for(id = ck804xrom_pci_tbl; id->vendor; id++) {
pdev = pci_find_device(id->vendor, id->device, NULL);
pdev = pci_get_device(id->vendor, id->device, NULL);
if (pdev)
break;
}
......
......@@ -289,8 +289,8 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev,
(((unsigned long)(window->virt)) + offset);
map->map.size = 0xffffffffUL - map_top + 1UL;
/* Set the name of the map to the address I am trying */
sprintf(map->map_name, "%s @%08lx",
MOD_NAME, map->map.phys);
sprintf(map->map_name, "%s @%08Lx",
MOD_NAME, (unsigned long long)map->map.phys);
/* Firmware hubs only use vpp when being programmed
* in a factory setting. So in-place programming
......
......@@ -227,8 +227,8 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
(((unsigned long)(window->virt)) + offset);
map->map.size = 0xffffffffUL - map_top + 1UL;
/* Set the name of the map to the address I am trying */
sprintf(map->map_name, "%s @%08lx",
MOD_NAME, map->map.phys);
sprintf(map->map_name, "%s @%08Lx",
MOD_NAME, (unsigned long long)map->map.phys);
/* Firmware hubs only use vpp when being programmed
* in a factory setting. So in-place programming
......
......@@ -94,7 +94,9 @@ static struct mtd_info *mymtd;
static int __init init_netsc520(void)
{
printk(KERN_NOTICE "NetSc520 flash device: 0x%lx at 0x%lx\n", netsc520_map.size, netsc520_map.phys);
printk(KERN_NOTICE "NetSc520 flash device: 0x%Lx at 0x%Lx\n",
(unsigned long long)netsc520_map.size,
(unsigned long long)netsc520_map.phys);
netsc520_map.virt = ioremap_nocache(netsc520_map.phys, netsc520_map.size);
if (!netsc520_map.virt) {
......
......@@ -237,8 +237,9 @@ static int __init init_sc520cdp(void)
#endif
for (i = 0; i < NUM_FLASH_BANKS; i++) {
printk(KERN_NOTICE "SC520 CDP flash device: 0x%lx at 0x%lx\n",
sc520cdp_map[i].size, sc520cdp_map[i].phys);
printk(KERN_NOTICE "SC520 CDP flash device: 0x%Lx at 0x%Lx\n",
(unsigned long long)sc520cdp_map[i].size,
(unsigned long long)sc520cdp_map[i].phys);
sc520cdp_map[i].virt = ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size);
......
......@@ -419,8 +419,9 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
info.erasesize = mtd->erasesize;
info.writesize = mtd->writesize;
info.oobsize = mtd->oobsize;
info.ecctype = mtd->ecctype;
info.eccsize = mtd->eccsize;
/* The below fields are obsolete */
info.ecctype = -1;
info.eccsize = 0;
if (copy_to_user(argp, &info, sizeof(struct mtd_info_user)))
return -EFAULT;
break;
......
......@@ -727,8 +727,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.erasesize = subdev[0]->erasesize;
concat->mtd.writesize = subdev[0]->writesize;
concat->mtd.oobsize = subdev[0]->oobsize;
concat->mtd.ecctype = subdev[0]->ecctype;
concat->mtd.eccsize = subdev[0]->eccsize;
if (subdev[0]->writev)
concat->mtd.writev = concat_writev;
if (subdev[0]->read_oob)
......@@ -774,8 +772,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
if (concat->mtd.writesize != subdev[i]->writesize ||
concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
concat->mtd.oobsize != subdev[i]->oobsize ||
concat->mtd.ecctype != subdev[i]->ecctype ||
concat->mtd.eccsize != subdev[i]->eccsize ||
!concat->mtd.read_oob != !subdev[i]->read_oob ||
!concat->mtd.write_oob != !subdev[i]->write_oob) {
kfree(concat);
......
......@@ -338,8 +338,6 @@ int add_mtd_partitions(struct mtd_info *master,
slave->mtd.size = parts[i].size;
slave->mtd.writesize = master->writesize;
slave->mtd.oobsize = master->oobsize;
slave->mtd.ecctype = master->ecctype;
slave->mtd.eccsize = master->eccsize;
slave->mtd.subpage_sft = master->subpage_sft;
slave->mtd.name = parts[i].name;
......
......@@ -126,10 +126,6 @@ config MTD_NAND_S3C2410_HWECC
incorrect ECC generation, and if using these, the default of
software ECC is preferable.
If you lay down a device with the hardware ECC, then you will
currently not be able to switch to software, as there is no
implementation for ECC method used by the S3C2410
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
depends on MTD_NAND && 44x
......@@ -221,9 +217,17 @@ config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on MTD_NAND && ARCH_PXA
config MTD_NAND_BASLER_EXCITE
tristate "Support for NAND Flash on Basler eXcite"
depends on MTD_NAND && BASLER_EXCITE
help
This enables the driver for the NAND flash device found on the
Basler eXcite Smart Camera. If built as a module, the driver
will be named "excite_nandflash.ko".
config MTD_NAND_CAFE
tristate "NAND support for OLPC CAFÉ chip"
depends on PCI
depends on MTD_NAND && PCI
help
Use NAND flash attached to the CAFÉ chip designed for the $100
laptop.
......
......@@ -24,6 +24,7 @@ obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
nand-objs := nand_base.o nand_bbt.o
cafe_nand-objs := cafe.o cafe_ecc.o
......@@ -78,8 +78,9 @@ module_param(regdebug, int, 0644);
static int checkecc = 1;
module_param(checkecc, int, 0644);
static int slowtiming = 0;
module_param(slowtiming, int, 0644);
static int numtimings;
static int timing[3];
module_param_array(timing, int, &numtimings, 0644);
/* Hrm. Why isn't this already conditional on something in the struct device? */
#define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
......@@ -264,10 +265,10 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
ndelay(100);
if (1) {
int c = 500000;
int c;
uint32_t irqs;
while (c--) {
for (c = 500000; c != 0; c--) {
irqs = cafe_readl(cafe, NAND_IRQ);
if (irqs & doneint)
break;
......@@ -529,6 +530,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
{
struct mtd_info *mtd;
struct cafe_priv *cafe;
uint32_t timing1, timing2, timing3;
uint32_t ctrl;
int err = 0;
......@@ -580,31 +582,45 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
cafe->nand.block_bad = cafe_nand_block_bad;
}
if (numtimings && numtimings != 3) {
dev_warn(&cafe->pdev->dev, "%d timing register values ignored; precisely three are required\n", numtimings);
}
if (numtimings == 3) {
timing1 = timing[0];
timing2 = timing[1];
timing3 = timing[2];
cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n",
timing1, timing2, timing3);
} else {
timing1 = cafe_readl(cafe, NAND_TIMING1);
timing2 = cafe_readl(cafe, NAND_TIMING2);
timing3 = cafe_readl(cafe, NAND_TIMING3);
if (timing1 | timing2 | timing3) {
cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n", timing1, timing2, timing3);
} else {
dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n");
timing1 = timing2 = timing3 = 0xffffffff;
}
}
/* Start off by resetting the NAND controller completely */
cafe_writel(cafe, 1, NAND_RESET);
cafe_writel(cafe, 0, NAND_RESET);
cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
cafe_writel(cafe, timing1, NAND_TIMING1);
cafe_writel(cafe, timing2, NAND_TIMING2);
cafe_writel(cafe, timing3, NAND_TIMING3);
/* Timings from Marvell's test code (not verified or calculated by us) */
if (!slowtiming) {
cafe_writel(cafe, 0x01010a0a, NAND_TIMING1);
cafe_writel(cafe, 0x24121212, NAND_TIMING2);
cafe_writel(cafe, 0x11000000, NAND_TIMING3);
} else {
cafe_writel(cafe, 0xffffffff, NAND_TIMING1);
cafe_writel(cafe, 0xffffffff, NAND_TIMING2);
cafe_writel(cafe, 0xffffffff, NAND_TIMING3);
}
cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED,
"CAFE NAND", mtd);
if (err) {
dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
goto out_free_dma;
}
#if 1
/* Disable master reset, enable NAND clock */
ctrl = cafe_readl(cafe, GLOBAL_CTRL);
ctrl &= 0xffffeff0;
......@@ -631,32 +647,8 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK));
#endif
#if 1
mtd->writesize=2048;
mtd->oobsize = 0x40;
memset(cafe->dmabuf, 0x5a, 2112);
cafe->nand.cmdfunc(mtd, NAND_CMD_READID, 0, -1);
cafe->nand.read_byte(mtd);
cafe->nand.read_byte(mtd);
cafe->nand.read_byte(mtd);
cafe->nand.read_byte(mtd);
cafe->nand.read_byte(mtd);
#endif
#if 0
cafe->nand.cmdfunc(mtd, NAND_CMD_READ0, 0, 0);
// nand_wait_ready(mtd);
cafe->nand.read_byte(mtd);
cafe->nand.read_byte(mtd);
cafe->nand.read_byte(mtd);
cafe->nand.read_byte(mtd);
#endif
#if 0
writel(0x84600070, cafe->mmio);
udelay(10);
cafe_dev_dbg(&cafe->pdev->dev, "Status %x\n", cafe_readl(cafe, NAND_NONMEM));
#endif
/* Scan to find existance of the device */
/* Scan to find existence of the device */
if (nand_scan_ident(mtd, 1)) {
err = -ENXIO;
goto out_irq;
......@@ -760,13 +752,4 @@ module_exit(cafe_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("NAND flash driver for OLPC CAFE chip");
/* Correct ECC for 2048 bytes of 0xff:
41 a0 71 65 54 27 f3 93 ec a9 be ed 0b a1 */
/* dwmw2's B-test board, in case of completely screwing it:
Bad eraseblock 2394 at 0x12b40000
Bad eraseblock 2627 at 0x14860000
Bad eraseblock 3349 at 0x1a2a0000
*/
MODULE_DESCRIPTION("NAND flash driver for OLPC CAFÉ chip");
......@@ -1045,7 +1045,7 @@ static unsigned short err_pos_lut[4096] = {
static unsigned short err_pos(unsigned short din)
{
BUG_ON(din > 4096);
BUG_ON(din >= ARRAY_SIZE(err_pos_lut));
return err_pos_lut[din];
}
static int chk_no_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
......
/*
* Copyright (C) 2005 - 2007 by Basler Vision Technologies AG
* Author: Thomas Koeller <thomas.koeller.qbaslerweb.com>
* Original code by Thies Moeller <thies.moeller@baslerweb.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
#include <asm/rm9k-ocd.h>
#include <excite_nandflash.h>
#define EXCITE_NANDFLASH_VERSION "0.1"
/* I/O register offsets */
#define EXCITE_NANDFLASH_DATA_BYTE 0x00
#define EXCITE_NANDFLASH_STATUS_BYTE 0x0c
#define EXCITE_NANDFLASH_ADDR_BYTE 0x10
#define EXCITE_NANDFLASH_CMD_BYTE 0x14
/* prefix for debug output */
static const char module_id[] = "excite_nandflash";
/*
* partition definition
*/
static const struct mtd_partition partition_info[] = {
{
.name = "eXcite RootFS",
.offset = 0,
.size = MTDPART_SIZ_FULL
}
};
static inline const struct resource *
excite_nand_get_resource(struct platform_device *d, unsigned long flags,
const char *basename)
{
char buf[80];
if (snprintf(buf, sizeof buf, "%s_%u", basename, d->id) >= sizeof buf)
return NULL;
return platform_get_resource_byname(d, flags, buf);
}
static inline void __iomem *
excite_nand_map_regs(struct platform_device *d, const char *basename)
{
void *result = NULL;
const struct resource *const r =
excite_nand_get_resource(d, IORESOURCE_MEM, basename);
if (r)
result = ioremap_nocache(r->start, r->end + 1 - r->start);
return result;
}
/* controller and mtd information */
struct excite_nand_drvdata {
struct mtd_info board_mtd;
struct nand_chip board_chip;
void __iomem *regs;
void __iomem *tgt;
};
/* Control function */
static void excite_nand_control(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct excite_nand_drvdata * const d =
container_of(mtd, struct excite_nand_drvdata, board_mtd);
switch (ctrl) {
case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
d->tgt = d->regs + EXCITE_NANDFLASH_CMD_BYTE;
break;
case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
d->tgt = d->regs + EXCITE_NANDFLASH_ADDR_BYTE;
break;
case NAND_CTRL_CHANGE | NAND_NCE:
d->tgt = d->regs + EXCITE_NANDFLASH_DATA_BYTE;
break;
}
if (cmd != NAND_CMD_NONE)
__raw_writeb(cmd, d->tgt);
}
/* Return 0 if flash is busy, 1 if ready */
static int excite_nand_devready(struct mtd_info *mtd)
{
struct excite_nand_drvdata * const drvdata =
container_of(mtd, struct excite_nand_drvdata, board_mtd);
return __raw_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS_BYTE);
}
/*
* Called by device layer to remove the driver.
* The binding to the mtd and all allocated
* resources are released.
*/
static int __exit excite_nand_remove(struct device *dev)
{
struct excite_nand_drvdata * const this = dev_get_drvdata(dev);
dev_set_drvdata(dev, NULL);
if (unlikely(!this)) {
printk(KERN_ERR "%s: called %s without private data!!",
module_id, __func__);
return -EINVAL;
}
/* first thing we need to do is release our mtd
* then go through freeing the resource used
*/
nand_release(&this->board_mtd);
/* free the common resources */
iounmap(this->regs);
kfree(this);
DEBUG(MTD_DEBUG_LEVEL1, "%s: removed\n", module_id);
return 0;
}
/*
* Called by device layer when it finds a device matching
* one our driver can handle. This code checks to see if
* it can allocate all necessary resources then calls the
* nand layer to look for devices.
*/
static int __init excite_nand_probe(struct device *dev)
{
struct platform_device * const pdev = to_platform_device(dev);
struct excite_nand_drvdata *drvdata; /* private driver data */
struct nand_chip *board_chip; /* private flash chip data */
struct mtd_info *board_mtd; /* mtd info for this board */
int scan_res;
drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
if (unlikely(!drvdata)) {
printk(KERN_ERR "%s: no memory for drvdata\n",
module_id);
return -ENOMEM;
}
/* bind private data into driver */
dev_set_drvdata(dev, drvdata);
/* allocate and map the resource */
drvdata->regs =
excite_nand_map_regs(pdev, EXCITE_NANDFLASH_RESOURCE_REGS);
if (unlikely(!drvdata->regs)) {
printk(KERN_ERR "%s: cannot reserve register region\n",
module_id);
kfree(drvdata);
return -ENXIO;
}
drvdata->tgt = drvdata->regs + EXCITE_NANDFLASH_DATA_BYTE;
/* initialise our chip */
board_chip = &drvdata->board_chip;
board_chip->IO_ADDR_R = board_chip->IO_ADDR_W =
drvdata->regs + EXCITE_NANDFLASH_DATA_BYTE;
board_chip->cmd_ctrl = excite_nand_control;
board_chip->dev_ready = excite_nand_devready;
board_chip->chip_delay = 25;
board_chip->ecc.mode = NAND_ECC_SOFT;
/* link chip to mtd */
board_mtd = &drvdata->board_mtd;
board_mtd->priv = board_chip;
DEBUG(MTD_DEBUG_LEVEL2, "%s: device scan\n", module_id);
scan_res = nand_scan(&drvdata->board_mtd, 1);
if (likely(!scan_res)) {
DEBUG(MTD_DEBUG_LEVEL2, "%s: register partitions\n", module_id);
add_mtd_partitions(&drvdata->board_mtd, partition_info,
sizeof partition_info / sizeof partition_info[0]);
} else {
iounmap(drvdata->regs);
kfree(drvdata);
printk(KERN_ERR "%s: device scan failed\n", module_id);
return -EIO;
}
return 0;
}
static struct device_driver excite_nand_driver = {
.name = "excite_nand",
.bus = &platform_bus_type,
.probe = excite_nand_probe,
.remove = __exit_p(excite_nand_remove)
};
static int __init excite_nand_init(void)
{
pr_info("Basler eXcite nand flash driver Version "
EXCITE_NANDFLASH_VERSION "\n");
return driver_register(&excite_nand_driver);
}
static void __exit excite_nand_exit(void)
{
driver_unregister(&excite_nand_driver);
}
module_init(excite_nand_init);
module_exit(excite_nand_exit);
MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>");
MODULE_DESCRIPTION("Basler eXcite NAND-Flash driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(EXCITE_NANDFLASH_VERSION)
......@@ -1272,10 +1272,25 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
(unsigned long long)from, readlen);
if (ops->mode == MTD_OOB_RAW)
len = mtd->oobsize;
else
if (ops->mode == MTD_OOB_AUTO)
len = chip->ecc.layout->oobavail;
else
len = mtd->oobsize;
if (unlikely(ops->ooboffs >= len)) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
"Attempt to start read outside oob\n");
return -EINVAL;
}
/* Do not allow reads past end of device */
if (unlikely(from >= mtd->size ||
ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -
(from >> chip->page_shift)) * len)) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
"Attempt read beyond end of device\n");
return -EINVAL;
}
chipnr = (int)(from >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
......@@ -1742,19 +1757,40 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
int chipnr, page, status;
int chipnr, page, status, len;
struct nand_chip *chip = mtd->priv;
DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
(unsigned int)to, (int)ops->ooblen);
if (ops->mode == MTD_OOB_AUTO)
len = chip->ecc.layout->oobavail;
else
len = mtd->oobsize;
/* Do not allow write past end of page */
if ((ops->ooboffs + ops->ooblen) > mtd->oobsize) {
if ((ops->ooboffs + ops->ooblen) > len) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
"Attempt to write past end of page\n");
return -EINVAL;
}
if (unlikely(ops->ooboffs >= len)) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
"Attempt to start write outside oob\n");
return -EINVAL;
}
/* Do not allow reads past end of device */
if (unlikely(to >= mtd->size ||
ops->ooboffs + ops->ooblen >
((mtd->size >> chip->page_shift) -
(to >> chip->page_shift)) * len)) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
"Attempt write beyond end of device\n");
return -EINVAL;
}
chipnr = (int)(to >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
......@@ -2530,7 +2566,6 @@ int nand_scan_tail(struct mtd_info *mtd)
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
mtd->ecctype = MTD_ECC_SW;
mtd->erase = nand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
......
......@@ -337,17 +337,69 @@ static int s3c2412_nand_devready(struct mtd_info *mtd)
static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n", mtd, dat, read_ecc, calc_ecc);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned int diff0, diff1, diff2;
unsigned int bit, byte;
pr_debug("eccs: read %02x,%02x,%02x vs calc %02x,%02x,%02x\n",
read_ecc[0], read_ecc[1], read_ecc[2], calc_ecc[0], calc_ecc[1], calc_ecc[2]);
pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);
if (read_ecc[0] == calc_ecc[0] && read_ecc[1] == calc_ecc[1] && read_ecc[2] == calc_ecc[2])
return 0;
diff0 = read_ecc[0] ^ calc_ecc[0];
diff1 = read_ecc[1] ^ calc_ecc[1];
diff2 = read_ecc[2] ^ calc_ecc[2];
pr_debug("%s: rd %02x%02x%02x calc %02x%02x%02x diff %02x%02x%02x\n",
__func__,
read_ecc[0], read_ecc[1], read_ecc[2],
calc_ecc[0], calc_ecc[1], calc_ecc[2],
diff0, diff1, diff2);
if (diff0 == 0 && diff1 == 0 && diff2 == 0)
return 0; /* ECC is ok */
/* Can we correct this ECC (ie, one row and column change).
* Note, this is similar to the 256 error code on smartmedia */
if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&
((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&
((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
/* calculate the bit position of the error */
bit = (diff2 >> 2) & 1;
bit |= (diff2 >> 3) & 2;
bit |= (diff2 >> 4) & 4;
/* calculate the byte position of the error */
byte = (diff1 << 1) & 0x80;
byte |= (diff1 << 2) & 0x40;
byte |= (diff1 << 3) & 0x20;
byte |= (diff1 << 4) & 0x10;
byte |= (diff0 >> 3) & 0x08;
byte |= (diff0 >> 2) & 0x04;
byte |= (diff0 >> 1) & 0x02;
byte |= (diff0 >> 0) & 0x01;
/* we curently have no method for correcting the error */
byte |= (diff2 << 8) & 0x100;
return -1;
dev_dbg(info->device, "correcting error bit %d, byte %d\n",
bit, byte);
dat[byte] ^= (1 << bit);
return 1;
}
/* if there is only one bit difference in the ECC, then
* one of only a row or column parity has changed, which
* means the error is most probably in the ECC itself */
diff0 |= (diff1 << 8);
diff0 |= (diff2 << 16);
if ((diff0 & ~(1<<fls(diff0))) == 0)
return 1;
return 0;
}
/* ECC functions
......@@ -366,6 +418,15 @@ static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
writel(ctrl, info->regs + S3C2410_NFCONF);
}
static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned long ctrl;
ctrl = readl(info->regs + S3C2440_NFCONT);
writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC, info->regs + S3C2440_NFCONT);
}
static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
......@@ -383,6 +444,21 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
pr_debug("%s: returning ecc %02x%02x%02x\n", __func__,
ecc_code[0], ecc_code[1], ecc_code[2]);
return 0;
}
static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
ecc_code[0] = ecc;
ecc_code[1] = ecc >> 8;
ecc_code[2] = ecc >> 16;
pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]);
return 0;
......@@ -397,7 +473,7 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
ecc_code[1] = ecc >> 8;
ecc_code[2] = ecc >> 16;
pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]);
pr_debug("%s: returning ecc %06x\n", __func__, ecc);
return 0;
}
......@@ -565,6 +641,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
break;
case TYPE_S3C2412:
chip->ecc.hwctl = s3c2412_nand_enable_hwecc;
chip->ecc.calculate = s3c2412_nand_calculate_ecc;
break;
case TYPE_S3C2440:
chip->ecc.hwctl = s3c2440_nand_enable_hwecc;
chip->ecc.calculate = s3c2440_nand_calculate_ecc;
......
此差异已折叠。
......@@ -17,8 +17,8 @@
#include <linux/mtd/onenand.h>
#include <linux/mtd/compatmac.h>
extern int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
extern int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops);
/**
* check_short_pattern - [GENERIC] check if a pattern is in the buffer
......@@ -65,10 +65,11 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
int startblock;
loff_t from;
size_t readlen, ooblen;
struct mtd_oob_ops ops;
printk(KERN_INFO "Scanning device for bad blocks\n");
len = 1;
len = 2;
/* We need only read few bytes from the OOB area */
scanlen = ooblen = 0;
......@@ -82,22 +83,24 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
startblock = 0;
from = 0;
ops.mode = MTD_OOB_PLACE;
ops.ooblen = readlen;
ops.oobbuf = buf;
ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
for (i = startblock; i < numblocks; ) {
int ret;
for (j = 0; j < len; j++) {
size_t retlen;
/* No need to read pages fully,
* just read required OOB bytes */
ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs,
readlen, &retlen, &buf[0]);
ret = onenand_bbt_read_oob(mtd, from + j * mtd->writesize + bd->offs, &ops);
/* If it is a initial bad block, just ignore it */
if (ret && !(ret & ONENAND_CTRL_LOAD))
return ret;
if (ret == ONENAND_BBT_READ_FATAL_ERROR)
return -EIO;
if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
if (ret || check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
i >> 1, (unsigned int) from);
......@@ -168,8 +171,8 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
* marked good / bad blocks and writes the bad block table(s) to
* the selected place.
*
* The bad block table memory is allocated here. It must be freed
* by calling the onenand_free_bbt function.
* The bad block table memory is allocated here. It is freed
* by the onenand_release function.
*
*/
int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
......
......@@ -94,8 +94,19 @@ static int parse_redboot_partitions(struct mtd_info *master,
* (NOTE: this is 'size' not 'data_length'; size is
* the full size of the entry.)
*/
if (swab32(buf[i].size) == master->erasesize) {
/* RedBoot can combine the FIS directory and
config partitions into a single eraseblock;
we assume wrong-endian if either the swapped
'size' matches the eraseblock size precisely,
or if the swapped size actually fits in an
eraseblock while the unswapped size doesn't. */
if (swab32(buf[i].size) == master->erasesize ||
(buf[i].size > master->erasesize
&& swab32(buf[i].size) < master->erasesize)) {
int j;
/* Update numslots based on actual FIS directory size */
numslots = swab32(buf[i].size) / sizeof (struct fis_image_desc);
for (j = 0; j < numslots; ++j) {
/* A single 0xff denotes a deleted entry.
......@@ -120,11 +131,11 @@ static int parse_redboot_partitions(struct mtd_info *master,
swab32s(&buf[j].desc_cksum);
swab32s(&buf[j].file_cksum);
}
} else if (buf[i].size < master->erasesize) {
/* Update numslots based on actual FIS directory size */
numslots = buf[i].size / sizeof(struct fis_image_desc);
}
break;
} else {
/* re-calculate of real numslots */
numslots = buf[i].size / sizeof(struct fis_image_desc);
}
}
if (i == numslots) {
......
......@@ -348,23 +348,27 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
ret = jffs2_sum_init(c);
if (ret)
return ret;
goto out_free;
if (jffs2_build_filesystem(c)) {
dbg_fsbuild("build_fs failed\n");
jffs2_free_ino_caches(c);
jffs2_free_raw_node_refs(c);
#ifndef __ECOS
if (jffs2_blocks_use_vmalloc(c))
vfree(c->blocks);
else
#endif
kfree(c->blocks);
return -EIO;
ret = -EIO;
goto out_free;
}
jffs2_calc_trigger_levels(c);
return 0;
out_free:
#ifndef __ECOS
if (jffs2_blocks_use_vmalloc(c))
vfree(c->blocks);
else
#endif
kfree(c->blocks);
return ret;
}
......@@ -98,20 +98,14 @@ struct jffs2_sb_info {
uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
/* Write-behind buffer for NAND flash */
unsigned char *wbuf;
unsigned char *oobbuf;
unsigned char *wbuf; /* Write-behind buffer for NAND flash */
uint32_t wbuf_ofs;
uint32_t wbuf_len;
struct jffs2_inodirty *wbuf_inodes;
struct rw_semaphore wbuf_sem; /* Protects the write buffer */
/* Information about out-of-band area usage... */
struct nand_ecclayout *ecclayout;
uint32_t badblock_pos;
uint32_t fsdata_pos;
uint32_t fsdata_len;
unsigned char *oobbuf;
int oobavail; /* How many bytes are available for JFFS2 in OOB */
#endif
struct jffs2_summary *summary; /* Summary information */
......
......@@ -450,16 +450,20 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
if (jffs2_cleanmarker_oob(c)) {
int ret = jffs2_check_nand_cleanmarker(c, jeb);
int ret;
if (c->mtd->block_isbad(c->mtd, jeb->offset))
return BLK_STATE_BADBLOCK;
ret = jffs2_check_nand_cleanmarker(c, jeb);
D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret));
/* Even if it's not found, we still scan to see
if the block is empty. We use this information
to decide whether to erase it or not. */
switch (ret) {
case 0: cleanmarkerfound = 1; break;
case 1: break;
case 2: return BLK_STATE_BADBLOCK;
case 3: return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */
default: return ret;
}
}
......
......@@ -957,43 +957,48 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
return ret;
}
#define NR_OOB_SCAN_PAGES 4
#define NR_OOB_SCAN_PAGES 4
/* For historical reasons we use only 12 bytes for OOB clean marker */
#define OOB_CM_SIZE 12
static const struct jffs2_unknown_node oob_cleanmarker =
{
.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK),
.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
.totlen = cpu_to_je32(8)
};
/*
* Check, if the out of band area is empty
* Check, if the out of band area is empty. This function knows about the clean
* marker and if it is present in OOB, treats the OOB as empty anyway.
*/
int jffs2_check_oob_empty(struct jffs2_sb_info *c,
struct jffs2_eraseblock *jeb, int mode)
{
int i, page, ret;
int oobsize = c->mtd->oobsize;
int i, ret;
int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);
struct mtd_oob_ops ops;
ops.ooblen = NR_OOB_SCAN_PAGES * oobsize;
ops.mode = MTD_OOB_AUTO;
ops.ooblen = NR_OOB_SCAN_PAGES * c->oobavail;
ops.oobbuf = c->oobbuf;
ops.ooboffs = 0;
ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
ops.datbuf = NULL;
ops.mode = MTD_OOB_PLACE;
ret = c->mtd->read_oob(c->mtd, jeb->offset, &ops);
if (ret) {
D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB "
"failed %d for block at %08x\n", ret, jeb->offset));
if (ret || ops.oobretlen != ops.ooblen) {
printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"
" bytes, read %zd bytes, error %d\n",
jeb->offset, ops.ooblen, ops.oobretlen, ret);
if (!ret)
ret = -EIO;
return ret;
}
if (ops.oobretlen < ops.ooblen) {
D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB "
"returned short read (%zd bytes not %d) for block "
"at %08x\n", ops.oobretlen, ops.ooblen, jeb->offset));
return -EIO;
}
/* Special check for first page */
for(i = 0; i < oobsize ; i++) {
/* Yeah, we know about the cleanmarker. */
if (mode && i >= c->fsdata_pos &&
i < c->fsdata_pos + c->fsdata_len)
for(i = 0; i < ops.ooblen; i++) {
if (mode && i < cmlen)
/* Yeah, we know about the cleanmarker */
continue;
if (ops.oobbuf[i] != 0xFF) {
......@@ -1003,111 +1008,63 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c,
}
}
/* we know, we are aligned :) */
for (page = oobsize; page < ops.ooblen; page += sizeof(long)) {
long dat = *(long *)(&ops.oobbuf[page]);
if(dat != -1)
return 1;
}
return 0;
}
/*
* Scan for a valid cleanmarker and for bad blocks
* Check for a valid cleanmarker.
* Returns: 0 if a valid cleanmarker was found
* 1 if no cleanmarker was found
* negative error code if an error occurred
*/
int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c,
struct jffs2_eraseblock *jeb)
int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c,
struct jffs2_eraseblock *jeb)
{
struct jffs2_unknown_node n;
struct mtd_oob_ops ops;
int oobsize = c->mtd->oobsize;
unsigned char *p,*b;
int i, ret;
size_t offset = jeb->offset;
/* Check first if the block is bad. */
if (c->mtd->block_isbad(c->mtd, offset)) {
D1 (printk(KERN_WARNING "jffs2_check_nand_cleanmarker()"
": Bad block at %08x\n", jeb->offset));
return 2;
}
int ret, cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);
ops.ooblen = oobsize;
ops.mode = MTD_OOB_AUTO;
ops.ooblen = cmlen;
ops.oobbuf = c->oobbuf;
ops.ooboffs = 0;
ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
ops.datbuf = NULL;
ops.mode = MTD_OOB_PLACE;
ret = c->mtd->read_oob(c->mtd, offset, &ops);
if (ret) {
D1 (printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): "
"Read OOB failed %d for block at %08x\n",
ret, jeb->offset));
ret = c->mtd->read_oob(c->mtd, jeb->offset, &ops);
if (ret || ops.oobretlen != ops.ooblen) {
printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"
" bytes, read %zd bytes, error %d\n",
jeb->offset, ops.ooblen, ops.oobretlen, ret);
if (!ret)
ret = -EIO;
return ret;
}
if (ops.oobretlen < ops.ooblen) {
D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): "
"Read OOB return short read (%zd bytes not %d) "
"for block at %08x\n", ops.oobretlen, ops.ooblen,
jeb->offset));
return -EIO;
}
n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
n.totlen = cpu_to_je32 (8);
p = (unsigned char *) &n;
b = c->oobbuf + c->fsdata_pos;
for (i = c->fsdata_len; i; i--) {
if (*b++ != *p++)
ret = 1;
}
D1(if (ret == 1) {
printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): "
"Cleanmarker node not detected in block at %08x\n",
offset);
printk(KERN_WARNING "OOB at %08zx was ", offset);
for (i=0; i < oobsize; i++)
printk("%02x ", c->oobbuf[i]);
printk("\n");
});
return ret;
return !!memcmp(&oob_cleanmarker, c->oobbuf, cmlen);
}
int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c,
struct jffs2_eraseblock *jeb)
{
struct jffs2_unknown_node n;
int ret;
int ret;
struct mtd_oob_ops ops;
int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);
n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
n.totlen = cpu_to_je32(8);
ops.ooblen = c->fsdata_len;
ops.oobbuf = (uint8_t *)&n;
ops.ooboffs = c->fsdata_pos;
ops.mode = MTD_OOB_AUTO;
ops.ooblen = cmlen;
ops.oobbuf = (uint8_t *)&oob_cleanmarker;
ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
ops.datbuf = NULL;
ops.mode = MTD_OOB_PLACE;
ret = c->mtd->write_oob(c->mtd, jeb->offset, &ops);
if (ret) {
D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): "
"Write failed for block at %08x: error %d\n",
jeb->offset, ret));
if (ret || ops.oobretlen != ops.ooblen) {
printk(KERN_ERR "cannot write OOB for EB at %08x, requested %zd"
" bytes, read %zd bytes, error %d\n",
jeb->offset, ops.ooblen, ops.oobretlen, ret);
if (!ret)
ret = -EIO;
return ret;
}
if (ops.oobretlen != ops.ooblen) {
D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): "
"Short write for block at %08x: %zd not %d\n",
jeb->offset, ops.oobretlen, ops.ooblen));
return -EIO;
}
return 0;
}
......@@ -1140,41 +1097,24 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *
return 1;
}
static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c)
int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
{
struct nand_ecclayout *oinfo = c->mtd->ecclayout;
/* Do this only, if we have an oob buffer */
if (!c->mtd->oobsize)
return 0;
/* Cleanmarker is out-of-band, so inline size zero */
c->cleanmarker_size = 0;
/* Should we use autoplacement ? */
if (!oinfo) {
D1(printk(KERN_DEBUG "JFFS2 on NAND. No autoplacment info found\n"));
if (!oinfo || oinfo->oobavail == 0) {
printk(KERN_ERR "inconsistent device description\n");
return -EINVAL;
}
D1(printk(KERN_DEBUG "JFFS2 using autoplace on NAND\n"));
/* Get the position of the free bytes */
if (!oinfo->oobfree[0].length) {
printk (KERN_WARNING "jffs2_nand_set_oobinfo(): Eeep."
" Autoplacement selected and no empty space in oob\n");
return -ENOSPC;
}
c->fsdata_pos = oinfo->oobfree[0].offset;
c->fsdata_len = oinfo->oobfree[0].length;
if (c->fsdata_len > 8)
c->fsdata_len = 8;
D1(printk(KERN_DEBUG "JFFS2 using OOB on NAND\n"));
return 0;
}
int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
{
int res;
c->oobavail = oinfo->oobavail;
/* Initialise write buffer */
init_rwsem(&c->wbuf_sem);
......@@ -1185,22 +1125,13 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
if (!c->wbuf)
return -ENOMEM;
c->oobbuf = kmalloc(NR_OOB_SCAN_PAGES * c->mtd->oobsize, GFP_KERNEL);
if (!c->oobbuf)
return -ENOMEM;
res = jffs2_nand_set_oobinfo(c);
#ifdef BREAKME
if (!brokenbuf)
brokenbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
if (!brokenbuf) {
c->oobbuf = kmalloc(NR_OOB_SCAN_PAGES * c->oobavail, GFP_KERNEL);
if (!c->oobbuf) {
kfree(c->wbuf);
return -ENOMEM;
}
memset(brokenbuf, 0xdb, c->wbuf_pagesize);
#endif
return res;
return 0;
}
void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
......
......@@ -92,6 +92,13 @@ struct nand_bbt_descr {
*/
#define ONENAND_BADBLOCK_POS 0
/*
* Bad block scanning errors
*/
#define ONENAND_BBT_READ_ERROR 1
#define ONENAND_BBT_READ_ECC_ERROR 2
#define ONENAND_BBT_READ_FATAL_ERROR 4
/**
* struct bbm_info - [GENERIC] Bad Block Table data structure
* @bbt_erase_shift: [INTERN] number of address bits in a bbt entry
......
......@@ -183,7 +183,7 @@ typedef union {
struct map_info {
char *name;
unsigned long size;
unsigned long phys;
resource_size_t phys;
#define NO_XIP (-1UL)
void __iomem *virt;
......
......@@ -85,6 +85,10 @@ typedef enum {
* mode = MTD_OOB_PLACE)
* @datbuf: data buffer - if NULL only oob data are read/written
* @oobbuf: oob data buffer
*
* Note, it is allowed to read more then one OOB area at one go, but not write.
* The interface assumes that the OOB write requests program only one page's
* OOB area.
*/
struct mtd_oob_ops {
mtd_oob_mode_t mode;
......@@ -117,18 +121,6 @@ struct mtd_info {
u_int32_t writesize;
u_int32_t oobsize; // Amount of OOB data per block (e.g. 16)
u_int32_t ecctype;
u_int32_t eccsize;
/*
* Reuse some of the above unused fields in the case of NOR flash
* with configurable programming regions to avoid modifying the
* user visible structure layout/size. Only valid when the
* MTD_PROGRAM_REGIONS flag is set.
* (Maybe we should have an union for those?)
*/
#define MTD_PROGREGION_CTRLMODE_VALID(mtd) (mtd)->oobsize
#define MTD_PROGREGION_CTRLMODE_INVALID(mtd) (mtd)->ecctype
// Kernel-only stuff starts here.
char *name;
......
......@@ -343,6 +343,7 @@ struct nand_buffers {
* @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about
* special functionality. See the defines for further explanation
* @badblockpos: [INTERN] position of the bad block marker in the oob area
* @cellinfo: [INTERN] MLC/multichip data from chip ident
* @numchips: [INTERN] number of physical chips
* @chipsize: [INTERN] the size of one chip for multichip arrays
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
......
/*
* linux/include/linux/mtd/onenand.h
*
* Copyright (C) 2005-2006 Samsung Electronics
* Copyright (C) 2005-2007 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
......@@ -42,14 +42,10 @@ typedef enum {
/**
* struct onenand_bufferram - OneNAND BufferRAM Data
* @block: block address in BufferRAM
* @page: page address in BufferRAM
* @valid: valid flag
* @blockpage: block & page address in BufferRAM
*/
struct onenand_bufferram {
int block;
int page;
int valid;
int blockpage;
};
/**
......@@ -63,7 +59,6 @@ struct onenand_bufferram {
* partly be set to inform onenand_scan about
* @erase_shift: [INTERN] number of address bits in a block
* @page_shift: [INTERN] number of address bits in a page
* @ppb_shift: [INTERN] number of address bits in a pages per block
* @page_mask: [INTERN] a page per block mask
* @bufferram_index: [INTERN] BufferRAM index
* @bufferram: [INTERN] BufferRAM info
......@@ -103,7 +98,6 @@ struct onenand_chip {
unsigned int erase_shift;
unsigned int page_shift;
unsigned int ppb_shift; /* Pages per block shift */
unsigned int page_mask;
unsigned int bufferram_index;
......@@ -150,6 +144,9 @@ struct onenand_chip {
#define ONENAND_SET_SYS_CFG1(v, this) \
(this->write_word(v, this->base + ONENAND_REG_SYS_CFG1))
#define ONENAND_IS_DDP(this) \
(this->device_id & ONENAND_DEVICE_IS_DDP)
/* Check byte access in OneNAND */
#define ONENAND_CHECK_BYTE_ACCESS(addr) (addr & 0x1)
......
......@@ -3,7 +3,8 @@
*
* OneNAND Register header file
*
* Copyright (C) 2005-2006 Samsung Electronics
* Copyright (C) 2005-2007 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
......@@ -80,9 +81,11 @@
#define ONENAND_VERSION_PROCESS_SHIFT (8)
/*
* Start Address 1 F100h (R/W)
* Start Address 1 F100h (R/W) & Start Address 2 F101h (R/W)
*/
#define ONENAND_DDP_SHIFT (15)
#define ONENAND_DDP_CHIP0 (0)
#define ONENAND_DDP_CHIP1 (1 << ONENAND_DDP_SHIFT)
/*
* Start Address 8 F107h (R/W)
......
......@@ -18,9 +18,10 @@
#define __LINUX_MTD_PHYSMAP__
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
struct map_info;
struct physmap_flash_data {
unsigned int width;
void (*set_vpp)(struct map_info *, int);
......
......@@ -36,12 +36,6 @@ struct mtd_oob_buf {
#define MTD_CAP_NORFLASH (MTD_WRITEABLE | MTD_BIT_WRITEABLE)
#define MTD_CAP_NANDFLASH (MTD_WRITEABLE)
// Types of automatic ECC/Checksum available
#define MTD_ECC_NONE 0 // No automatic ECC available
#define MTD_ECC_RS_DiskOnChip 1 // Automatic ECC on DiskOnChip
#define MTD_ECC_SW 2 // SW ECC for Toshiba & Samsung devices
/* ECC byte placement */
#define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended)
#define MTD_NANDECC_PLACE 1 // Use the given placement in the structure (YAFFS1 legacy mode)
......@@ -61,6 +55,8 @@ struct mtd_info_user {
uint32_t erasesize;
uint32_t writesize;
uint32_t oobsize; // Amount of OOB data per block (e.g. 16)
/* The below two fields are obsolete and broken, do not use them
* (TODO: remove at some point) */
uint32_t ecctype;
uint32_t eccsize;
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册