diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-30 08:31:35 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-30 08:31:35 -0700 |
commit | 79346507ad48895f41b438fa562b1965721f36b9 (patch) | |
tree | 5c115ce87f1fbc0b530f30db56cecf824e9f6e05 /drivers/mtd/nand | |
parent | 706d4b12f8d7edd28d7e879a77235472da393edb (diff) | |
parent | 40847437f15221b5822ba70550e8b9fcccfb9bb3 (diff) |
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (82 commits)
mtd: fix build error in m25p80.c
mtd: Remove redundant mutex from mtd_blkdevs.c
MTD: Fix wrong check register_blkdev return value
Revert "mtd: cleanup Kconfig dependencies"
mtd: cfi_cmdset_0002: make sector erase command variable
mtd: cfi_cmdset_0002: add CFI detection for SST 38VF640x chips
mtd: cfi_util: add support for switching SST 39VF640xB chips into QRY mode
mtd: cfi_cmdset_0001: use defined value of P_ID_INTEL_PERFORMANCE instead of hardcoded one
block2mtd: dubious assignment
P4080/mtd: Fix the freescale lbc issue with 36bit mode
P4080/eLBC: Make Freescale elbc interrupt common to elbc devices
mtd: phram: use KBUILD_MODNAME
mtd: OneNAND: S5PC110: Fix double call suspend & resume function
mtd: nand: fix MTD_MODE_RAW writes
jffs2: use kmemdup
mtd: sm_ftl: cosmetic, use bool when possible
mtd: r852: remove useless pci powerup/down from suspend/resume routines
mtd: blktrans: fix a race vs kthread_stop
mtd: blktrans: kill BKL
mtd: allow to unload the mtdtrans module if its block devices aren't open
...
Fix up trivial whitespace-introduced conflict in drivers/mtd/mtdchar.c
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/Kconfig | 15 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/bf5xx_nand.c | 14 | ||||
-rw-r--r-- | drivers/mtd/nand/davinci_nand.c | 11 | ||||
-rw-r--r-- | drivers/mtd/nand/denali.c | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_elbc_nand.c | 484 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_upm.c | 10 | ||||
-rw-r--r-- | drivers/mtd/nand/fsmc_nand.c | 866 | ||||
-rw-r--r-- | drivers/mtd/nand/mpc5121_nfc.c | 11 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 338 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 250 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_ids.c | 31 | ||||
-rw-r--r-- | drivers/mtd/nand/nandsim.c | 19 | ||||
-rw-r--r-- | drivers/mtd/nand/ndfc.c | 8 | ||||
-rw-r--r-- | drivers/mtd/nand/omap2.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/pxa3xx_nand.c | 348 | ||||
-rw-r--r-- | drivers/mtd/nand/r852.c | 30 | ||||
-rw-r--r-- | drivers/mtd/nand/r852.h | 2 |
18 files changed, 1710 insertions, 733 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 8b4b67c8a39..8229802b434 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -400,13 +400,6 @@ config MTD_NAND_PXA3xx This enables the driver for the NAND flash device found on PXA3xx processors -config MTD_NAND_PXA3xx_BUILTIN - bool "Use builtin definitions for some NAND chips (deprecated)" - depends on MTD_NAND_PXA3xx - help - This enables builtin definitions for some NAND chips. This - is deprecated in favor of platform specific data. - config MTD_NAND_CM_X270 tristate "Support for NAND Flash on CM-X270 modules" depends on MACH_ARMCORE @@ -458,6 +451,7 @@ config MTD_NAND_ORION config MTD_NAND_FSL_ELBC tristate "NAND support for Freescale eLBC controllers" depends on PPC_OF + select FSL_LBC help Various Freescale chips, including the 8313, include a NAND Flash Controller Module with built-in hardware ECC capabilities. @@ -531,4 +525,11 @@ config MTD_NAND_JZ4740 help Enables support for NAND Flash on JZ4740 SoC based boards. +config MTD_NAND_FSMC + tristate "Support for NAND on ST Micros FSMC" + depends on PLAT_SPEAR || PLAT_NOMADIK || MACH_U300 + help + Enables support for NAND Flash chips on the ST Microelectronics + Flexible Static Memory Controller (FSMC) + endif # MTD_NAND diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index ac83dcdac5d..8ad6faec72c 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o +obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o obj-$(CONFIG_MTD_NAND_H1900) += h1910.o obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 6fbeefa3a76..79947bea4d5 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -110,15 +110,6 @@ static const unsigned short bfin_nfc_pin_req[] = 0}; #ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC -static uint8_t bbt_pattern[] = { 0xff }; - -static struct nand_bbt_descr bootrom_bbt = { - .options = 0, - .offs = 63, - .len = 1, - .pattern = bbt_pattern, -}; - static struct nand_ecclayout bootrom_ecclayout = { .eccbytes = 24, .eccpos = { @@ -809,7 +800,6 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) /* setup hardware ECC data struct */ if (hardware_ecc) { #ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC - chip->badblock_pattern = &bootrom_bbt; chip->ecc.layout = &bootrom_ecclayout; #endif chip->read_buf = bf5xx_nand_dma_read_buf; @@ -830,6 +820,10 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) goto out_err_nand_scan; } +#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC + chip->badblockpos = 63; +#endif + /* add NAND partition */ bf5xx_nand_add_partition(info); diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 8beb0d0233b..a90fde3ede2 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -316,7 +316,7 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd, u32 syndrome[4]; u32 ecc_state; unsigned num_errors, corrected; - unsigned long timeo = jiffies + msecs_to_jiffies(100); + unsigned long timeo; /* All bytes 0xff? It's an erased page; ignore its ECC. */ for (i = 0; i < 10; i++) { @@ -372,9 +372,11 @@ compare: * after setting the 4BITECC_ADD_CALC_START bit. So if you immediately * begin trying to poll for the state, you may fall right out of your * loop without any of the correction calculations having taken place. - * The recommendation from the hardware team is to wait till ECC_STATE - * reads less than 4, which means ECC HW has entered correction state. + * The recommendation from the hardware team is to initially delay as + * long as ECC_STATE reads less than 4. After that, ECC HW has entered + * correction state. */ + timeo = jiffies + usecs_to_jiffies(100); do { ecc_state = (davinci_nand_readl(info, NANDFSR_OFFSET) >> 8) & 0x0f; @@ -733,6 +735,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev) * breaks userspace ioctl interface with mtd-utils. Once we * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used * for the 4KiB page chips. + * + * TODO: Note that nand_ecclayout has now been expanded and can + * hold plenty of OOB entries. */ dev_warn(&pdev->dev, "no 4-bit ECC support yet " "for 4KiB-page NAND\n"); diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 532fe07cf88..8c8d3c86c0e 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1292,6 +1292,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, read_status(denali); break; case NAND_CMD_READID: + case NAND_CMD_PARAM: reset_buf(denali); /*sometimes ManufactureId read from register is not right * e.g. some of Micron MT29F32G08QAA MLC NAND chips diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 80de0bff6c3..c141b07b25d 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -1,9 +1,11 @@ /* Freescale Enhanced Local Bus Controller NAND driver * - * Copyright (c) 2006-2007 Freescale Semiconductor + * Copyright © 2006-2007, 2010 Freescale Semiconductor * * Authors: Nick Spence <nick.spence@freescale.com>, * Scott Wood <scottwood@freescale.com> + * Jack Lan <jack.lan@freescale.com> + * Roy Zang <tie-fei.zang@freescale.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 @@ -27,6 +29,7 @@ #include <linux/string.h> #include <linux/ioport.h> #include <linux/of_platform.h> +#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/interrupt.h> @@ -42,14 +45,12 @@ #define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */ #define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */ -struct fsl_elbc_ctrl; - /* mtd information per set */ struct fsl_elbc_mtd { struct mtd_info mtd; struct nand_chip chip; - struct fsl_elbc_ctrl *ctrl; + struct fsl_lbc_ctrl *ctrl; struct device *dev; int bank; /* Chip select bank number */ @@ -58,18 +59,12 @@ struct fsl_elbc_mtd { unsigned int fmr; /* FCM Flash Mode Register value */ }; -/* overview of the fsl elbc controller */ +/* Freescale eLBC FCM controller infomation */ -struct fsl_elbc_ctrl { +struct fsl_elbc_fcm_ctrl { struct nand_hw_control controller; struct fsl_elbc_mtd *chips[MAX_BANKS]; - /* device info */ - struct device *dev; - struct fsl_lbc_regs __iomem *regs; - int irq; - wait_queue_head_t irq_wait; - unsigned int irq_status; /* status read from LTESR by irq handler */ u8 __iomem *addr; /* Address of assigned FCM buffer */ unsigned int page; /* Last page written to / read from */ unsigned int read_bytes; /* Number of bytes read during command */ @@ -79,6 +74,7 @@ struct fsl_elbc_ctrl { unsigned int mdr; /* UPM/FCM Data Register value */ unsigned int use_mdr; /* Non zero if the MDR is to be set */ unsigned int oob; /* Non zero if operating on OOB data */ + unsigned int counter; /* counter for the initializations */ char *oob_poi; /* Place to write ECC after read back */ }; @@ -164,11 +160,12 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_lbc_ctrl *ctrl = priv->ctrl; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; int buf_num; - ctrl->page = page_addr; + elbc_fcm_ctrl->page = page_addr; out_be32(&lbc->fbar, page_addr >> (chip->phys_erase_shift - chip->page_shift)); @@ -185,16 +182,18 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) buf_num = page_addr & 7; } - ctrl->addr = priv->vbase + buf_num * 1024; - ctrl->index = column; + elbc_fcm_ctrl->addr = priv->vbase + buf_num * 1024; + elbc_fcm_ctrl->index = column; /* for OOB data point to the second half of the buffer */ if (oob) - ctrl->index += priv->page_size ? 2048 : 512; + elbc_fcm_ctrl->index += priv->page_size ? 2048 : 512; - dev_vdbg(ctrl->dev, "set_addr: bank=%d, ctrl->addr=0x%p (0x%p), " + dev_vdbg(priv->dev, "set_addr: bank=%d, " + "elbc_fcm_ctrl->addr=0x%p (0x%p), " "index %x, pes %d ps %d\n", - buf_num, ctrl->addr, priv->vbase, ctrl->index, + buf_num, elbc_fcm_ctrl->addr, priv->vbase, + elbc_fcm_ctrl->index, chip->phys_erase_shift, chip->page_shift); } @@ -205,18 +204,19 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_lbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; /* Setup the FMR[OP] to execute without write protection */ out_be32(&lbc->fmr, priv->fmr | 3); - if (ctrl->use_mdr) - out_be32(&lbc->mdr, ctrl->mdr); + if (elbc_fcm_ctrl->use_mdr) + out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr); - dev_vdbg(ctrl->dev, + dev_vdbg(priv->dev, "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n", in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr)); - dev_vdbg(ctrl->dev, + dev_vdbg(priv->dev, "fsl_elbc_run_command: fbar=%08x fpar=%08x " "fbcr=%08x bank=%d\n", in_be32(&lbc->fbar), in_be32(&lbc->fpar), @@ -229,19 +229,18 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) /* wait for FCM complete flag or timeout */ wait_event_timeout(ctrl->irq_wait, ctrl->irq_status, FCM_TIMEOUT_MSECS * HZ/1000); - ctrl->status = ctrl->irq_status; - + elbc_fcm_ctrl->status = ctrl->irq_status; /* store mdr value in case it was needed */ - if (ctrl->use_mdr) - ctrl->mdr = in_be32(&lbc->mdr); + if (elbc_fcm_ctrl->use_mdr) + elbc_fcm_ctrl->mdr = in_be32(&lbc->mdr); - ctrl->use_mdr = 0; + elbc_fcm_ctrl->use_mdr = 0; - if (ctrl->status != LTESR_CC) { - dev_info(ctrl->dev, + if (elbc_fcm_ctrl->status != LTESR_CC) { + dev_info(priv->dev, "command failed: fir %x fcr %x status %x mdr %x\n", in_be32(&lbc->fir), in_be32(&lbc->fcr), - ctrl->status, ctrl->mdr); + elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr); return -EIO; } @@ -251,7 +250,7 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) static void fsl_elbc_do_read(struct nand_chip *chip, int oob) { struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_lbc_ctrl *ctrl = priv->ctrl; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; if (priv->page_size) { @@ -284,15 +283,16 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_lbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; - ctrl->use_mdr = 0; + elbc_fcm_ctrl->use_mdr = 0; /* clear the read buffer */ - ctrl->read_bytes = 0; + elbc_fcm_ctrl->read_bytes = 0; if (command != NAND_CMD_PAGEPROG) - ctrl->index = 0; + elbc_fcm_ctrl->index = 0; switch (command) { /* READ0 and READ1 read the entire buffer to use hardware ECC. */ @@ -301,7 +301,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* fall-through */ case NAND_CMD_READ0: - dev_dbg(ctrl->dev, + dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:" " 0x%x, column: 0x%x.\n", page_addr, column); @@ -309,8 +309,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */ set_addr(mtd, 0, page_addr, 0); - ctrl->read_bytes = mtd->writesize + mtd->oobsize; - ctrl->index += column; + elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize; + elbc_fcm_ctrl->index += column; fsl_elbc_do_read(chip, 0); fsl_elbc_run_command(mtd); @@ -318,14 +318,14 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* READOOB reads only the OOB because no ECC is performed. */ case NAND_CMD_READOOB: - dev_vdbg(ctrl->dev, + dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:" " 0x%x, column: 0x%x.\n", page_addr, column); out_be32(&lbc->fbcr, mtd->oobsize - column); set_addr(mtd, column, page_addr, 1); - ctrl->read_bytes = mtd->writesize + mtd->oobsize; + elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize; fsl_elbc_do_read(chip, 1); fsl_elbc_run_command(mtd); @@ -333,7 +333,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* READID must read all 5 possible bytes while CEB is active */ case NAND_CMD_READID: - dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n"); + dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n"); out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) | (FIR_OP_UA << FIR_OP1_SHIFT) | @@ -341,9 +341,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT); /* 5 bytes for manuf, device and exts */ out_be32(&lbc->fbcr, 5); - ctrl->read_bytes = 5; - ctrl->use_mdr = 1; - ctrl->mdr = 0; + elbc_fcm_ctrl->read_bytes = 5; + elbc_fcm_ctrl->use_mdr = 1; + elbc_fcm_ctrl->mdr = 0; set_addr(mtd, 0, 0, 0); fsl_elbc_run_command(mtd); @@ -351,7 +351,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* ERASE1 stores the block and page address */ case NAND_CMD_ERASE1: - dev_vdbg(ctrl->dev, + dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, " "page_addr: 0x%x.\n", page_addr); set_addr(mtd, 0, page_addr, 0); @@ -359,7 +359,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* ERASE2 uses the block and page address from ERASE1 */ case NAND_CMD_ERASE2: - dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n"); + dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n"); out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) | @@ -374,8 +374,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, (NAND_CMD_ERASE2 << FCR_CMD2_SHIFT)); out_be32(&lbc->fbcr, 0); - ctrl->read_bytes = 0; - ctrl->use_mdr = 1; + elbc_fcm_ctrl->read_bytes = 0; + elbc_fcm_ctrl->use_mdr = 1; fsl_elbc_run_command(mtd); return; @@ -383,14 +383,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* SEQIN sets up the addr buffer and all registers except the length */ case NAND_CMD_SEQIN: { __be32 fcr; - dev_vdbg(ctrl->dev, - "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, " + dev_vdbg(priv->dev, + "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, " "page_addr: 0x%x, column: 0x%x.\n", page_addr, column); - ctrl->column = column; - ctrl->oob = 0; - ctrl->use_mdr = 1; + elbc_fcm_ctrl->use_mdr = 1; fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT) | @@ -420,7 +418,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* OOB area --> READOOB */ column -= mtd->writesize; fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT; - ctrl->oob = 1; + elbc_fcm_ctrl->oob = 1; } else { WARN_ON(column != 0); /* First 256 bytes --> READ0 */ @@ -429,24 +427,24 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, } out_be32(&lbc->fcr, fcr); - set_addr(mtd, column, page_addr, ctrl->oob); + set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob); return; } /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ case NAND_CMD_PAGEPROG: { int full_page; - dev_vdbg(ctrl->dev, + dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " - "writing %d bytes.\n", ctrl->index); + "writing %d bytes.\n", elbc_fcm_ctrl->index); /* if the write did not start at 0 or is not a full page * then set the exact length, otherwise use a full page * write so the HW generates the ECC. */ - if (ctrl->oob || ctrl->column != 0 || - ctrl->index != mtd->writesize + mtd->oobsize) { - out_be32(&lbc->fbcr, ctrl->index); + if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 || + elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) { + out_be32(&lbc->fbcr, elbc_fcm_ctrl->index); full_page = 0; } else { out_be32(&lbc->fbcr, 0); @@ -458,21 +456,21 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* Read back the page in order to fill in the ECC for the * caller. Is this really needed? */ - if (full_page && ctrl->oob_poi) { + if (full_page && elbc_fcm_ctrl->oob_poi) { out_be32(&lbc->fbcr, 3); set_addr(mtd, 6, page_addr, 1); - ctrl->read_bytes = mtd->writesize + 9; + elbc_fcm_ctrl->read_bytes = mtd->writesize + 9; fsl_elbc_do_read(chip, 1); fsl_elbc_run_command(mtd); - memcpy_fromio(ctrl->oob_poi + 6, - &ctrl->addr[ctrl->index], 3); - ctrl->index += 3; + memcpy_fromio(elbc_fcm_ctrl->oob_poi + 6, + &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], 3); + elbc_fcm_ctrl->index += 3; } - ctrl->oob_poi = NULL; + elbc_fcm_ctrl->oob_poi = NULL; return; } @@ -485,26 +483,26 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, 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; + elbc_fcm_ctrl->read_bytes = 1; fsl_elbc_run_command(mtd); /* The chip always seems to report that it is * write-protected, even when it is not. */ - setbits8(ctrl->addr, NAND_STATUS_WP); + setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP); return; /* RESET without waiting for the ready line */ case NAND_CMD_RESET: - dev_dbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n"); + dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n"); out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT); out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT); fsl_elbc_run_command(mtd); return; default: - dev_err(ctrl->dev, + dev_err(priv->dev, "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n", command); } @@ -524,24 +522,24 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; unsigned int bufsize = mtd->writesize + mtd->oobsize; if (len <= 0) { - dev_err(ctrl->dev, "write_buf of %d bytes", len); - ctrl->status = 0; + dev_err(priv->dev, "write_buf of %d bytes", len); + elbc_fcm_ctrl->status = 0; return; } - if ((unsigned int)len > bufsize - ctrl->index) { - dev_err(ctrl->dev, + if ((unsigned int)len > bufsize - elbc_fcm_ctrl->index) { + dev_err(priv->dev, "write_buf beyond end of buffer " "(%d requested, %u available)\n", - len, bufsize - ctrl->index); - len = bufsize - ctrl->index; + len, bufsize - elbc_fcm_ctrl->index); + len = bufsize - elbc_fcm_ctrl->index; } - memcpy_toio(&ctrl->addr[ctrl->index], buf, len); + memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len); /* * This is workaround for the weird elbc hangs during nand write, * Scott Wood says: "...perhaps difference in how long it takes a @@ -549,9 +547,9 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) * is causing problems, and sync isn't helping for some reason." * Reading back the last byte helps though. */ - in_8(&ctrl->addr[ctrl->index] + len - 1); + in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index] + len - 1); - ctrl->index += len; + elbc_fcm_ctrl->index += len; } /* @@ -562,13 +560,13 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; /* If there are still bytes in the FCM, then use the next byte. */ - if (ctrl->index < ctrl->read_bytes) - return in_8(&ctrl->addr[ctrl->index++]); + if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes) + return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]); - dev_err(ctrl->dev, "read_byte beyond end of buffer\n"); + dev_err(priv->dev, "read_byte beyond end of buffer\n"); return ERR_BYTE; } @@ -579,18 +577,19 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; int avail; if (len < 0) return; - avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index); - memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail); - ctrl->index += avail; + avail = min((unsigned int)len, + elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index); + memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], avail); + elbc_fcm_ctrl->index += avail; if (len > avail) - dev_err(ctrl->dev, + dev_err(priv->dev, "read_buf beyond end of buffer " "(%d requested, %d available)\n", len, avail); @@ -603,30 +602,32 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; int i; if (len < 0) { - dev_err(ctrl->dev, "write_buf of %d bytes", len); + dev_err(priv->dev, "write_buf of %d bytes", len); return -EINVAL; } - if ((unsigned int)len > ctrl->read_bytes - ctrl->index) { - dev_err(ctrl->dev, - "verify_buf beyond end of buffer " - "(%d requested, %u available)\n", - len, ctrl->read_bytes - ctrl->index); + if ((unsigned int)len > + elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index) { + dev_err(priv->dev, + "verify_buf beyond end of buffer " + "(%d requested, %u available)\n", + len, elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index); - ctrl->index = ctrl->read_bytes; + elbc_fcm_ctrl->index = elbc_fcm_ctrl->read_bytes; return -EINVAL; } for (i = 0; i < len; i++) - if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i]) + if (in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index + i]) + != buf[i]) break; - ctrl->index += len; - return i == len && ctrl->status == LTESR_CC ? 0 : -EIO; + elbc_fcm_ctrl->index += len; + return i == len && elbc_fcm_ctrl->status == LTESR_CC ? 0 : -EIO; } /* This function is called after Program and Erase Operations to @@ -635,22 +636,22 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) 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_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; - if (ctrl->status != LTESR_CC) + if (elbc_fcm_ctrl->status != LTESR_CC) return NAND_STATUS_FAIL; /* The chip always seems to report that it is * write-protected, even when it is not. */ - return (ctrl->mdr & 0xff) | NAND_STATUS_WP; + return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP; } static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_lbc_ctrl *ctrl = priv->ctrl; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; unsigned int al; @@ -665,41 +666,41 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) priv->fmr |= (12 << FMR_CWTO_SHIFT) | /* Timeout > 12 ms */ (al << FMR_AL_SHIFT); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->numchips = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n", chip->numchips); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chipsize = %lld\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n", chip->chipsize); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->pagemask = %8x\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n", chip->pagemask); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_delay = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n", chip->chip_delay); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->badblockpos = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n", chip->badblockpos); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_shift = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n", chip->chip_shift); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->page_shift = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n", chip->page_shift); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n", chip->phys_erase_shift); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecclayout = %p\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecclayout = %p\n", chip->ecclayout); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.mode = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n", chip->ecc.mode); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.steps = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n", chip->ecc.steps); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n", chip->ecc.bytes); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.total = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n", chip->ecc.total); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.layout = %p\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.layout = %p\n", chip->ecc.layout); - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags); - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size); - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->erasesize = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags); + dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size); + dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n", mtd->erasesize); - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->writesize = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n", mtd->writesize); - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->oobsize = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n", mtd->oobsize); /* adjust Option Register and ECC to match Flash page size */ @@ -719,7 +720,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) chip->badblock_pattern = &largepage_memorybased; } } else { - dev_err(ctrl->dev, + dev_err(priv->dev, "fsl_elbc_init: page size %d is not supported\n", mtd->writesize); return -1; @@ -750,18 +751,19 @@ static void fsl_elbc_write_page(struct mtd_info *mtd, const uint8_t *buf) { struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; fsl_elbc_write_buf(mtd, buf, mtd->writesize); fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); - ctrl->oob_poi = chip->oob_poi; + elbc_fcm_ctrl->oob_poi = chip->oob_poi; } static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) { - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_lbc_ctrl *ctrl = priv->ctrl; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; struct nand_chip *chip = &priv->chip; dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank); @@ -790,7 +792,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT; - chip->controller = &ctrl->controller; + chip->controller = &elbc_fcm_ctrl->controller; chip->priv = priv; chip->ecc.read_page = fsl_elbc_read_page; @@ -815,8 +817,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) { - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; nand_release(&priv->mtd); kfree(priv->mtd.name); @@ -824,18 +825,21 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) if (priv->vbase) iounmap(priv->vbase); - ctrl->chips[priv->bank] = NULL; + elbc_fcm_ctrl->chips[priv->bank] = NULL; kfree(priv); - + kfree(elbc_fcm_ctrl); return 0; } -static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, - struct device_node *node) +static DEFINE_MUTEX(fsl_elbc_nand_mutex); + +static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) { - struct fsl_lbc_regs __iomem *lbc = ctrl->regs; + struct fsl_lbc_regs __iomem *lbc; struct fsl_elbc_mtd *priv; struct resource res; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl; + #ifdef CONFIG_MTD_PARTITIONS static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; @@ -843,11 +847,18 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, #endif int ret; int bank; + struct device *dev; + struct device_node *node = pdev->dev.of_node; + + if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) + return -ENODEV; + lbc = fsl_lbc_ctrl_dev->regs; + dev = fsl_lbc_ctrl_dev->dev; /* get, allocate and map the memory resource */ ret = of_address_to_resource(node, 0, &res); if (ret) { - dev_err(ctrl->dev, "failed to get resource\n"); + dev_err(dev, "failed to get resource\n"); return ret; } @@ -857,11 +868,11 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM && (in_be32(&lbc->bank[bank].br) & in_be32(&lbc->bank[bank].or) & BR_BA) - == res.start) + == fsl_lbc_addr(res.start)) break; if (bank >= MAX_BANKS) { - dev_err(ctrl->dev, "address did not match any chip selects\n"); + dev_err(dev, "address did not match any chip selects\n"); return -ENODEV; } @@ -869,14 +880,33 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, if (!priv) return -ENOMEM; - ctrl->chips[bank] = priv; + mutex_lock(&fsl_elbc_nand_mutex); + if (!fsl_lbc_ctrl_dev->nand) { + elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL); + if (!elbc_fcm_ctrl) { + dev_err(dev, "failed to allocate memory\n"); + mutex_unlock(&fsl_elbc_nand_mutex); + ret = -ENOMEM; + goto err; + } + elbc_fcm_ctrl->counter++; + + spin_lock_init(&elbc_fcm_ctrl->controller.lock); + init_waitqueue_head(&elbc_fcm_ctrl->controller.wq); + fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl; + } else { + elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand; + } + mutex_unlock(&fsl_elbc_nand_mutex); + + elbc_fcm_ctrl->chips[bank] = priv; priv->bank = bank; - priv->ctrl = ctrl; - priv->dev = ctrl->dev; + priv->ctrl = fsl_lbc_ctrl_dev; + priv->dev = dev; priv->vbase = ioremap(res.start, resource_size(&res)); if (!priv->vbase) { - dev_err(ctrl->dev, "failed to map chip region\n"); + dev_err(dev, "failed to map chip region\n"); ret = -ENOMEM; goto err; } @@ -933,171 +963,53 @@ err: return ret; } -static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl) +static int fsl_elbc_nand_remove(struct platform_device *pdev) { - 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); - - /* Enable interrupts for any detected events */ - out_be32(&lbc->lteir, LTESR_NAND_MASK); - - ctrl->read_bytes = 0; - ctrl->index = 0; - ctrl->addr = NULL; - - return 0; -} - -static int fsl_elbc_ctrl_remove(struct platform_device *ofdev) -{ - struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev); int i; - + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand; for (i = 0; i < MAX_BANKS; i++) - if (ctrl->chips[i]) - fsl_elbc_chip_remove(ctrl->chips[i]); - - if (ctrl->irq) - free_irq(ctrl->irq, ctrl); - - if (ctrl->regs) - iounmap(ctrl->regs); - - dev_set_drvdata(&ofdev->dev, NULL); - kfree(ctrl); - return 0; -} - -/* NOTE: This interrupt is also used to report other localbus events, - * such as transaction errors on other chipselects. If we want to - * capture those, we'll need to move the IRQ code into a shared - * LBC driver. - */ - -static irqreturn_t fsl_elbc_ctrl_irq(int irqno, void *data) -{ - struct fsl_elbc_ctrl *ctrl = data; - struct fsl_lbc_regs __iomem *lbc = ctrl->regs; - __be32 status = in_be32(&lbc->ltesr) & LTESR_NAND_MASK; - - if (status) { - out_be32(&lbc->ltesr, status); - out_be32(&lbc->lteatr, 0); - - ctrl->irq_status = status; - smp_wmb(); - wake_up(&ctrl->irq_wait); - - return IRQ_HANDLED; + if (elbc_fcm_ctrl->chips[i]) + fsl_elbc_chip_remove(elbc_fcm_ctrl->chips[i]); + + mutex_lock(&fsl_elbc_nand_mutex); + elbc_fcm_ctrl->counter--; + if (!elbc_fcm_ctrl->counter) { + fsl_lbc_ctrl_dev->nand = NULL; + kfree(elbc_fcm_ctrl); } - - return IRQ_NONE; -} - -/* fsl_elbc_ctrl_probe - * - * called by device layer when it finds a device matching - * one our driver can handled. This code allocates all of - * the resources needed for the controller only. The - * resources for the NAND banks themselves are allocated - * in the chip probe function. -*/ - -static int __devinit fsl_elbc_ctrl_probe(struct platform_device *ofdev, - const struct of_device_id *match) -{ - struct device_node *child; - struct fsl_elbc_ctrl *ctrl; - int ret; - - ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); - if (!ctrl) - return -ENOMEM; - - dev_set_drvdata(&ofdev->dev, ctrl); - - spin_lock_init(&ctrl->controller.lock); - init_waitqueue_head(&ctrl->controller.wq); - init_waitqueue_head(&ctrl->irq_wait); - - ctrl->regs = of_iomap(ofdev->dev.of_node, 0); - if (!ctrl->regs) { - dev_err(&ofdev->dev, "failed to get memory region\n"); - ret = -ENODEV; - goto err; - } - - ctrl->irq = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); - if (ctrl->irq == NO_IRQ) { - dev_err(&ofdev->dev, "failed to get irq resource\n"); - ret = -ENODEV; - goto err; - } - - ctrl->dev = &ofdev->dev; - - ret = fsl_elbc_ctrl_init(ctrl); - if (ret < 0) - goto err; - - ret = request_irq(ctrl->irq, fsl_elbc_ctrl_irq, 0, "fsl-elbc", ctrl); - if (ret != 0) { - dev_err(&ofdev->dev, "failed to install irq (%d)\n", - ctrl->irq); - ret = ctrl->irq; - goto err; - } - - for_each_child_of_node(ofdev->dev.of_node, child) - if (of_device_is_compatible(child, "fsl,elbc-fcm-nand")) - fsl_elbc_chip_probe(ctrl, child); + mutex_unlock(&fsl_elbc_nand_mutex); return 0; -err: - fsl_elbc_ctrl_remove(ofdev); - return ret; } -static const struct of_device_id fsl_elbc_match[] = { - { - .compatible = "fsl,elbc", - }, +static const struct of_device_id fsl_elbc_nand_match[] = { + { .compatible = "fsl,elbc-fcm-nand", }, {} }; -static struct of_platform_driver fsl_elbc_ctrl_driver = { +static struct platform_driver fsl_elbc_nand_driver = { .driver = { - .name = "fsl-elbc", + .name = "fsl,elbc-fcm-nand", .owner = THIS_MODULE, - .of_match_table = fsl_elbc_match, + .of_match_table = fsl_elbc_nand_match, }, - .probe = fsl_elbc_ctrl_probe, - .remove = fsl_elbc_ctrl_remove, + .probe = fsl_elbc_nand_probe, + .remove = fsl_elbc_nand_remove, }; -static int __init fsl_elbc_init(void) +static int __init fsl_elbc_nand_init(void) { - return of_register_platform_driver(&fsl_elbc_ctrl_driver); + return platform_driver_register(&fsl_elbc_nand_driver); } -static void __exit fsl_elbc_exit(void) +static void __exit fsl_elbc_nand_exit(void) { - of_unregister_platform_driver(&fsl_elbc_ctrl_driver); + platform_driver_unregister(&fsl_elbc_nand_driver); } -module_init(fsl_elbc_init); -module_exit(fsl_elbc_exit); +module_init(fsl_elbc_nand_init); +module_exit(fsl_elbc_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Freescale"); diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 4eff8b25e5a..efdcca94ce5 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -186,7 +186,7 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, if (!flash_np) return -ENODEV; - fun->mtd.name = kasprintf(GFP_KERNEL, "%x.%s", io_res->start, + fun->mtd.name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start, flash_np->name); if (!fun->mtd.name) { ret = -ENOMEM; @@ -222,7 +222,7 @@ static int __devinit fun_probe(struct platform_device *ofdev, { struct fsl_upm_nand *fun; struct resource io_res; - const uint32_t *prop; + const __be32 *prop; int rnb_gpio; int ret; int size; @@ -270,7 +270,7 @@ static int __devinit fun_probe(struct platform_device *ofdev, goto err1; } for (i = 0; i < fun->mchip_count; i++) - fun->mchip_offsets[i] = prop[i]; + fun->mchip_offsets[i] = be32_to_cpu(prop[i]); } else { fun->mchip_count = 1; } @@ -295,13 +295,13 @@ static int __devinit fun_probe(struct platform_device *ofdev, prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL); if (prop) - fun->chip_delay = *prop; + fun->chip_delay = be32_to_cpup(prop); else fun->chip_delay = 50; prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size); if (prop && size == sizeof(uint32_t)) - fun->wait_flags = *prop; + fun->wait_flags = be32_to_cpup(prop); else fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN | FSL_UPM_WAIT_WRITE_BYTE; diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c new file mode 100644 index 00000000000..02edfba25b0 --- /dev/null +++ b/drivers/mtd/nand/fsmc_nand.c @@ -0,0 +1,866 @@ +/* + * drivers/mtd/nand/fsmc_nand.c + * + * ST Microelectronics + * Flexible Static Memory Controller (FSMC) + * Driver for NAND portions + * + * Copyright © 2010 ST Microelectronics + * Vipin Kumar <vipin.kumar@st.com> + * Ashish Priyadarshi + * + * Based on drivers/mtd/nand/nomadik_nand.c + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/resource.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/platform_device.h> +#include <linux/mtd/partitions.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/mtd/fsmc.h> +#include <mtd/mtd-abi.h> + +static struct nand_ecclayout fsmc_ecc1_layout = { + .eccbytes = 24, + .eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52, + 66, 67, 68, 82, 83, 84, 98, 99, 100, 114, 115, 116}, + .oobfree = { + {.offset = 8, .length = 8}, + {.offset = 24, .length = 8}, + {.offset = 40, .length = 8}, + {.offset = 56, .length = 8}, + {.offset = 72, .length = 8}, + {.offset = 88, .length = 8}, + {.offset = 104, .length = 8}, + {.offset = 120, .length = 8} + } +}; + +static struct nand_ecclayout fsmc_ecc4_lp_layout = { + .eccbytes = 104, + .eccpos = { 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, + 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, + 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, + 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, + 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, + 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, + 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126 + }, + .oobfree = { + {.offset = 15, .length = 3}, + {.offset = 31, .length = 3}, + {.offset = 47, .length = 3}, + {.offset = 63, .length = 3}, + {.offset = 79, .length = 3}, + {.offset = 95, .length = 3}, + {.offset = 111, .length = 3}, + {.offset = 127, .length = 1} + } +}; + +/* + * ECC placement definitions in oobfree type format. + * There are 13 bytes of ecc for every 512 byte block and it has to be read + * consecutively and immediately after the 512 byte data block for hardware to + * generate the error bit offsets in 512 byte data. + * Managing the ecc bytes in the following way makes it easier for software to + * read ecc bytes consecutive to data bytes. This way is similar to + * oobfree structure maintained already in generic nand driver + */ +static struct fsmc_eccplace fsmc_ecc4_lp_place = { + .eccplace = { + {.offset = 2, .length = 13}, + {.offset = 18, .length = 13}, + {.offset = 34, .length = 13}, + {.offset = 50, .length = 13}, + {.offset = 66, .length = 13}, + {.offset = 82, .length = 13}, + {.offset = 98, .length = 13}, + {.offset = 114, .length = 13} + } +}; + +static struct nand_ecclayout fsmc_ecc4_sp_layout = { + .eccbytes = 13, + .eccpos = { 0, 1, 2, 3, 6, 7, 8, + 9, 10, 11, 12, 13, 14 + }, + .oobfree = { + {.offset = 15, .length = 1}, + } +}; + +static struct fsmc_eccplace fsmc_ecc4_sp_place = { + .eccplace = { + {.offset = 0, .length = 4}, + {.offset = 6, .length = 9} + } +}; + +/* + * Default partition tables to be used if the partition information not + * provided through platform data + */ +#define PARTITION(n, off, sz) {.name = n, .offset = off, .size = sz} + +/* + * Default partition layout for small page(= 512 bytes) devices + * Size for "Root file system" is updated in driver based on actual device size + */ +static struct mtd_partition partition_info_16KB_blk[] = { + PARTITION("X-loader", 0, 4 * 0x4000), + PARTITION("U-Boot", 0x10000, 20 * 0x4000), + PARTITION("Kernel", 0x60000, 256 * 0x4000), + PARTITION("Root File System", 0x460000, 0), +}; + +/* + * Default partition layout for large page(> 512 bytes) devices + * Size for "Root file system" is updated in driver based on actual device size + */ +static struct mtd_partition partition_info_128KB_blk[] = { + PARTITION("X-loader", 0, 4 * 0x20000), + PARTITION("U-Boot", 0x80000, 12 * 0x20000), + PARTITION("Kernel", 0x200000, 48 * 0x20000), + PARTITION("Root File System", 0x800000, 0), +}; + +#ifdef CONFIG_MTD_CMDLINE_PARTS +const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + +/** + * struct fsmc_nand_data - atructure for FSMC NAND device state + * + * @mtd: MTD info for a NAND flash. + * @nand: Chip related info for a NAND flash. + * @partitions: Partition info for a NAND Flash. + * @nr_partitions: Total number of partition of a NAND flash. + * + * @ecc_place: ECC placing locations in oobfree type format. + * @bank: Bank number for probed device. + * @clk: Clock structure for FSMC. + * + * @data_va: NAND port for Data. + * @cmd_va: NAND port for Command. + * @addr_va: NAND port for Address. + * @regs_va: FSMC regs base address. + */ +struct fsmc_nand_data { + struct mtd_info mtd; + struct nand_chip nand; + struct mtd_partition *partitions; + unsigned int nr_partitions; + + struct fsmc_eccplace *ecc_place; + unsigned int bank; + struct clk *clk; + + struct resource *resregs; + struct resource *rescmd; + struct resource *resaddr; + struct resource *resdata; + + void __iomem *data_va; + void __iomem *cmd_va; + void __iomem *addr_va; + void __iomem *regs_va; + + void (*select_chip)(uint32_t bank, uint32_t busw); +}; + +/* Assert CS signal based on chipnr */ +static void fsmc_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct nand_chip *chip = mtd->priv; + struct fsmc_nand_data *host; + + host = container_of(mtd, struct fsmc_nand_data, mtd); + + switch (chipnr) { + case -1: + chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); + break; + case 0: + case 1: + case 2: + case 3: + if (host->select_chip) + host->select_chip(chipnr, + chip->options & NAND_BUSWIDTH_16); + break; + + default: + BUG(); + } +} + +/* + * fsmc_cmd_ctrl - For facilitaing Hardware access + * This routine allows hardware specific access to control-lines(ALE,CLE) + */ +static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *this = mtd->priv; + struct fsmc_nand_data *host = container_of(mtd, + struct fsmc_nand_data, mtd); + struct fsmc_regs *regs = host->regs_va; + unsigned int bank = host->bank; + + if (ctrl & NAND_CTRL_CHANGE) { + if (ctrl & NAND_CLE) { + this->IO_ADDR_R = (void __iomem *)host->cmd_va; + this->IO_ADDR_W = (void __iomem *)host->cmd_va; + } else if (ctrl & NAND_ALE) { + this->IO_ADDR_R = (void __iomem *)host->addr_va; + this->IO_ADDR_W = (void __iomem *)host->addr_va; + } else { + this->IO_ADDR_R = (void __iomem *)host->data_va; + this->IO_ADDR_W = (void __iomem *)host->data_va; + } + + if (ctrl & NAND_NCE) { + writel(readl(®s->bank_regs[bank].pc) | FSMC_ENABLE, + ®s->bank_regs[bank].pc); + } else { + writel(readl(®s->bank_regs[bank].pc) & ~FSMC_ENABLE, + ®s->bank_regs[bank].pc); + } + } + + mb(); + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); +} + +/* + * fsmc_nand_setup - FSMC (Flexible Static Memory Controller) init routine + * + * This routine initializes timing parameters related to NAND memory access in + * FSMC registers + */ +static void __init fsmc_nand_setup(struct fsmc_regs *regs, uint32_t bank, + uint32_t busw) +{ + uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON; + + if (busw) + writel(value | FSMC_DEVWID_16, ®s->bank_regs[bank].pc); + else + writel(value | FSMC_DEVWID_8, ®s->bank_regs[bank].pc); + + writel(readl(®s->bank_regs[bank].pc) | FSMC_TCLR_1 | FSMC_TAR_1, + ®s->bank_regs[bank].pc); + writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, + ®s->bank_regs[bank].comm); + writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, + ®s->bank_regs[bank].attrib); +} + +/* + * fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers + */ +static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) +{ + struct fsmc_nand_data *host = container_of(mtd, + struct fsmc_nand_data, mtd); + struct fsmc_regs *regs = host->regs_va; + uint32_t bank = host->bank; + + writel(readl(®s->bank_regs[bank].pc) & ~FSMC_ECCPLEN_256, + ®s->bank_regs[bank].pc); + writel(readl(®s->bank_regs[bank].pc) & ~FSMC_ECCEN, + ®s->bank_regs[bank].pc); + writel(readl(®s->bank_regs[bank].pc) | FSMC_ECCEN, + ®s->bank_regs[bank].pc); +} + +/* + * fsmc_read_hwecc_ecc4 - Hardware ECC calculator for ecc4 option supported by + * FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction upto + * max of 8-bits) + */ +static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, + uint8_t *ecc) +{ + struct fsmc_nand_data *host = container_of(mtd, + struct fsmc_nand_data, mtd); + struct fsmc_regs *regs = host->regs_va; + uint32_t bank = host->bank; + uint32_t ecc_tmp; + unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT; + + do { + if (readl(®s->bank_regs[bank].sts) & FSMC_CODE_RDY) + break; + else + cond_resched(); + } while (!time_after_eq(jiffies, deadline)); + + ecc_tmp = readl(®s->bank_regs[bank].ecc1); + ecc[0] = (uint8_t) (ecc_tmp >> 0); + ecc[1] = (uint8_t) (ecc_tmp >> 8); + ecc[2] = (uint8_t) (ecc_tmp >> 16); + ecc[3] = (uint8_t) (ecc_tmp >> 24); + + ecc_tmp = readl(®s->bank_regs[bank].ecc2); + ecc[4] = (uint8_t) (ecc_tmp >> 0); + ecc[5] = (uint8_t) (ecc_tmp >> 8); + ecc[6] = (uint8_t) (ecc_tmp >> 16); + ecc[7] = (uint8_t) (ecc_tmp >> 24); + + ecc_tmp = readl(®s->bank_regs[bank].ecc3); + ecc[8] = (uint8_t) (ecc_tmp >> 0); + ecc[9] = (uint8_t) (ecc_tmp >> 8); + ecc[10] = (uint8_t) (ecc_tmp >> 16); + ecc[11] = (uint8_t) (ecc_tmp >> 24); + + ecc_tmp = readl(®s->bank_regs[bank].sts); + ecc[12] = (uint8_t) (ecc_tmp >> 16); + + return 0; +} + +/* + * fsmc_read_hwecc_ecc1 - Hardware ECC calculator for ecc1 option supported by + * FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction upto + * max of 1-bit) + */ +static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data, + uint8_t *ecc) +{ + struct fsmc_nand_data *host = container_of(mtd, + struct fsmc_nand_data, mtd); + struct fsmc_regs *regs = host->regs_va; + uint32_t bank = host->bank; + uint32_t ecc_tmp; + + ecc_tmp = readl(®s->bank_regs[bank].ecc1); + ecc[0] = (uint8_t) (ecc_tmp >> 0); + ecc[1] = (uint8_t) (ecc_tmp >> 8); + ecc[2] = (uint8_t) (ecc_tmp >> 16); + + return 0; +} + +/* + * fsmc_read_page_hwecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read + * + * This routine is needed for fsmc verison 8 as reading from NAND chip has to be + * performed in a strict sequence as follows: + * data(512 byte) -> ecc(13 byte) + * After this read, fsmc hardware generates and reports error data bits(upto a + * max of 8 bits) + */ +static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int page) +{ + struct fsmc_nand_data *host = container_of(mtd, + struct fsmc_nand_data, mtd); + struct fsmc_eccplace *ecc_place = host->ecc_place; + int i, j, s, stat, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + int off, len, group = 0; + /* + * ecc_oob is intentionally taken as uint16_t. In 16bit devices, we + * end up reading 14 bytes (7 words) from oob. The local array is + * to maintain word alignment + */ + uint16_t ecc_oob[7]; + uint8_t *oob = (uint8_t *)&ecc_oob[0]; + + for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { + + chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page); + chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->read_buf(mtd, p, eccsize); + + for (j = 0; j < eccbytes;) { + off = ecc_place->eccplace[group].offset; + len = ecc_place->eccplace[group].length; + group++; + + /* + * length is intentionally kept a higher multiple of 2 + * to read at least 13 bytes even in case of 16 bit NAND + * devices + */ + len = roundup(len, 2); + chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page); + chip->read_buf(mtd, oob + j, len); + j += len; + } + + memcpy(&ecc_code[i], oob, 13); + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + + return 0; +} + +/* + * fsmc_correct_data + * @mtd: mtd info structure + * @dat: buffer of read data + * @read_ecc: ecc read from device spare area + * @calc_ecc: ecc calculated from read data + * + * calc_ecc is a 104 bit information containing maximum of 8 error + * offset informations of 13 bits each in 512 bytes of read data. + */ +static int fsmc_correct_data(struct mtd_info *mtd, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) +{ + struct fsmc_nand_data *host = container_of(mtd, + struct fsmc_nand_data, mtd); + struct fsmc_regs *regs = host->regs_va; + unsigned int bank = host->bank; + uint16_t err_idx[8]; + uint64_t ecc_data[2]; + uint32_t num_err, i; + + /* The calculated ecc is actually the correction index in data */ + memcpy(ecc_data, calc_ecc, 13); + + /* + * ------------------- calc_ecc[] bit wise -----------|--13 bits--| + * |---idx[7]--|--.....-----|---idx[2]--||---idx[1]--||---idx[0]--| + * + * calc_ecc is a 104 bit information containing maximum of 8 error + * offset informations of 13 bits each. calc_ecc is copied into a + * uint64_t array and error offset indexes are populated in err_idx + * array + */ + for (i = 0; i < 8; i++) { + if (i == 4) { + err_idx[4] = ((ecc_data[1] & 0x1) << 12) | ecc_data[0]; + ecc_data[1] >>= 1; + continue; + } + err_idx[i] = (ecc_data[i/4] & 0x1FFF); + ecc_data[i/4] >>= 13; + } + + num_err = (readl(®s->bank_regs[bank].sts) >> 10) & 0xF; + + if (num_err == 0xF) + return -EBADMSG; + + i = 0; + while (num_err--) { + change_bit(0, (unsigned long *)&err_idx[i]); + change_bit(1, (unsigned long *)&err_idx[i]); + + if (err_idx[i] <= 512 * 8) { + change_bit(err_idx[i], (unsigned long *)dat); + i++; + } + } + return i; +} + +/* + * fsmc_nand_probe - Probe function + * @pdev: platform device structure + */ +static int __init fsmc_nand_probe(struct platform_device *pdev) +{ + struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct fsmc_nand_data *host; + struct mtd_info *mtd; + struct nand_chip *nand; + struct fsmc_regs *regs; + struct resource *res; + int nr_parts, ret = 0; + + if (!pdata) { + dev_err(&pdev->dev, "platform data is NULL\n"); + return -EINVAL; + } + + /* Allocate memory for the device structure (and zero it) */ + host = kzalloc(sizeof(*host), GFP_KERNEL); + if (!host) { + dev_err(&pdev->dev, "failed to allocate device structure\n"); + return -ENOMEM; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); + if (!res) { + ret = -EIO; + goto err_probe1; + } + + host->resdata = request_mem_region(res->start, resource_size(res), + pdev->name); + if (!host->resdata) { + ret = -EIO; + goto err_probe1; + } + + host->data_va = ioremap(res->start, resource_size(res)); + if (!host->data_va) { + ret = -EIO; + goto err_probe1; + } + + host->resaddr = request_mem_region(res->start + PLAT_NAND_ALE, + resource_size(res), pdev->name); + if (!host->resaddr) { + ret = -EIO; + goto err_probe1; + } + + host->addr_va = ioremap(res->start + PLAT_NAND_ALE, resource_size(res)); + if (!host->addr_va) { + ret = -EIO; + goto err_probe1; + } + + host->rescmd = request_mem_region(res->start + PLAT_NAND_CLE, + resource_size(res), pdev->name); + if (!host->rescmd) { + ret = -EIO; + goto err_probe1; + } + + host->cmd_va = ioremap(res->start + PLAT_NAND_CLE, resource_size(res)); + if (!host->cmd_va) { + ret = -EIO; + goto err_probe1; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs"); + if (!res) { + ret = -EIO; + goto err_probe1; + } + + host->resregs = request_mem_region(res->start, resource_size(res), + pdev->name); + if (!host->resregs) { + ret = -EIO; + goto err_probe1; + } + + host->regs_va = ioremap(res->start, resource_size(res)); + if (!host->regs_va) { + ret = -EIO; + goto err_probe1; + } + + host->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(host->clk)) { + dev_err(&pdev->dev, "failed to fetch block clock\n"); + ret = PTR_ERR(host->clk); + host->clk = NULL; + goto err_probe1; + } + + ret = clk_enable(host->clk); + if (ret) + goto err_probe1; + + host->bank = pdata->bank; + host->select_chip = pdata->select_bank; + regs = host->regs_va; + + /* Link all private pointers */ + mtd = &host->mtd; + nand = &host->nand; + mtd->priv = nand; + nand->priv = host; + + host->mtd.owner = THIS_MODULE; + nand->IO_ADDR_R = host->data_va; + nand->IO_ADDR_W = host->data_va; + nand->cmd_ctrl = fsmc_cmd_ctrl; + nand->chip_delay = 30; + + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.hwctl = fsmc_enable_hwecc; + nand->ecc.size = 512; + nand->options = pdata->options; + nand->select_chip = fsmc_select_chip; + + if (pdata->width == FSMC_NAND_BW16) + nand->options |= NAND_BUSWIDTH_16; + + fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16); + + if (get_fsmc_version(host->regs_va) == FSMC_VER8) { + nand->ecc.read_page = fsmc_read_page_hwecc; + nand->ecc.calculate = fsmc_read_hwecc_ecc4; + nand->ecc.correct = fsmc_correct_data; + nand->ecc.bytes = 13; + } else { + nand->ecc.calculate = fsmc_read_hwecc_ecc1; + nand->ecc.correct = nand_correct_data; + nand->ecc.bytes = 3; + } + + /* + * Scan to find existance of the device + */ + if (nand_scan_ident(&host->mtd, 1, NULL)) { + ret = -ENXIO; + dev_err(&pdev->dev, "No NAND Device found!\n"); + goto err_probe; + } + + if (get_fsmc_version(host->regs_va) == FSMC_VER8) { + if (host->mtd.writesize == 512) { + nand->ecc.layout = &fsmc_ecc4_sp_layout; + host->ecc_place = &fsmc_ecc4_sp_place; + } else { + nand->ecc.layout = &fsmc_ecc4_lp_layout; + host->ecc_place = &fsmc_ecc4_lp_place; + } + } else { + nand->ecc.layout = &fsmc_ecc1_layout; + } + + /* Second stage of scan to fill MTD data-structures */ + if (nand_scan_tail(&host->mtd)) { + ret = -ENXIO; + goto err_probe; + } + + /* + * The partition information can is accessed by (in the same precedence) + * + * command line through Bootloader, + * platform data, + * default partition information present in driver. + */ +#ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + /* + * Check if partition info passed via command line + */ + host->mtd.name = "nand"; + nr_parts = parse_mtd_partitions(&host->mtd, part_probes, + &host->partitions, 0); + if (nr_parts > 0) { + host->nr_partitions = nr_parts; + } else { +#endif + /* + * Check if partition info passed via command line + */ + if (pdata->partitions) { + host->partitions = pdata->partitions; + host->nr_partitions = pdata->nr_partitions; + } else { + struct mtd_partition *partition; + int i; + + /* Select the default partitions info */ + switch (host->mtd.size) { + case 0x01000000: + case 0x02000000: + case 0x04000000: + host->partitions = partition_info_16KB_blk; + host->nr_partitions = + sizeof(partition_info_16KB_blk) / + sizeof(struct mtd_partition); + break; + case 0x08000000: + case 0x10000000: + case 0x20000000: + case 0x40000000: + host->partitions = partition_info_128KB_blk; + host->nr_partitions = + sizeof(partition_info_128KB_blk) / + sizeof(struct mtd_partition); + break; + default: + ret = -ENXIO; + pr_err("Unsupported NAND size\n"); + goto err_probe; + } + + partition = host->partitions; + for (i = 0; i < host->nr_partitions; i++, partition++) { + if (partition->size == 0) { + partition->size = host->mtd.size - + partition->offset; + break; + } + } + } +#ifdef CONFIG_MTD_CMDLINE_PARTS + } +#endif + + if (host->partitions) { + ret = add_mtd_partitions(&host->mtd, host->partitions, + host->nr_partitions); + if (ret) + goto err_probe; + } +#else + dev_info(&pdev->dev, "Registering %s as whole device\n", mtd->name); + if (!add_mtd_device(mtd)) { + ret = -ENXIO; + goto err_probe; + } +#endif + + platform_set_drvdata(pdev, host); + dev_info(&pdev->dev, "FSMC NAND driver registration successful\n"); + return 0; + +err_probe: + clk_disable(host->clk); +err_probe1: + if (host->clk) + clk_put(host->clk); + if (host->regs_va) + iounmap(host->regs_va); + if (host->resregs) + release_mem_region(host->resregs->start, + resource_size(host->resregs)); + if (host->cmd_va) + iounmap(host->cmd_va); + if (host->rescmd) + release_mem_region(host->rescmd->start, + resource_size(host->rescmd)); + if (host->addr_va) + iounmap(host->addr_va); + if (host->resaddr) + release_mem_region(host->resaddr->start, + resource_size(host->resaddr)); + if (host->data_va) + iounmap(host->data_va); + if (host->resdata) + release_mem_region(host->resdata->start, + resource_size(host->resdata)); + + kfree(host); + return ret; +} + +/* + * Clean up routine + */ +static int fsmc_nand_remove(struct platform_device *pdev) +{ + struct fsmc_nand_data *host = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if (host) { +#ifdef CONFIG_MTD_PARTITIONS + del_mtd_partitions(&host->mtd); +#else + del_mtd_device(&host->mtd); +#endif + clk_disable(host->clk); + clk_put(host->clk); + + iounmap(host->regs_va); + release_mem_region(host->resregs->start, + resource_size(host->resregs)); + iounmap(host->cmd_va); + release_mem_region(host->rescmd->start, + resource_size(host->rescmd)); + iounmap(host->addr_va); + release_mem_region(host->resaddr->start, + resource_size(host->resaddr)); + iounmap(host->data_va); + release_mem_region(host->resdata->start, + resource_size(host->resdata)); + + kfree(host); + } + return 0; +} + +#ifdef CONFIG_PM +static int fsmc_nand_suspend(struct device *dev) +{ + struct fsmc_nand_data *host = dev_get_drvdata(dev); + if (host) + clk_disable(host->clk); + return 0; +} + +static int fsmc_nand_resume(struct device *dev) +{ + struct fsmc_nand_data *host = dev_get_drvdata(dev); + if (host) + clk_enable(host->clk); + return 0; +} + +static const struct dev_pm_ops fsmc_nand_pm_ops = { + .suspend = fsmc_nand_suspend, + .resume = fsmc_nand_resume, +}; +#endif + +static struct platform_driver fsmc_nand_driver = { + .remove = fsmc_nand_remove, + .driver = { + .owner = THIS_MODULE, + .name = "fsmc-nand", +#ifdef CONFIG_PM + .pm = &fsmc_nand_pm_ops, +#endif + }, +}; + +static int __init fsmc_nand_init(void) +{ + return platform_driver_probe(&fsmc_nand_driver, + fsmc_nand_probe); +} +module_init(fsmc_nand_init); + +static void __exit fsmc_nand_exit(void) +{ + platform_driver_unregister(&fsmc_nand_driver); +} +module_exit(fsmc_nand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>, Ashish Priyadarshi"); +MODULE_DESCRIPTION("NAND driver for SPEAr Platforms"); diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index df0c1da4ff4..469e649c911 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -568,6 +568,7 @@ static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) uint rcw_width; uint rcwh; uint romloc, ps; + int ret = 0; rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset"); if (!rmnode) { @@ -579,7 +580,8 @@ static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) rm = of_iomap(rmnode, 0); if (!rm) { dev_err(prv->dev, "Error mapping reset module node!\n"); - return -EBUSY; + ret = -EBUSY; + goto out; } rcwh = in_be32(&rm->rcwhr); @@ -628,8 +630,9 @@ static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) rcw_width * 8, rcw_pagesize, rcw_sparesize); iounmap(rm); +out: of_node_put(rmnode); - return 0; + return ret; } /* Free driver resources */ @@ -660,7 +663,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op, #endif struct nand_chip *chip; unsigned long regs_paddr, regs_size; - const uint *chips_no; + const __be32 *chips_no; int resettime = 0; int retval = 0; int rev, len; @@ -803,7 +806,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op, } /* Detect NAND chips */ - if (nand_scan(mtd, *chips_no)) { + if (nand_scan(mtd, be32_to_cpup(chips_no))) { dev_err(dev, "NAND Flash not found !\n"); devm_free_irq(dev, prv->irq, mtd); retval = -ENXIO; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d551ddd9537..1f75a1b1f7c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -45,7 +45,7 @@ #include <linux/interrupt.h> #include <linux/bitops.h> #include <linux/leds.h> -#include <asm/io.h> +#include <linux/io.h> #ifdef CONFIG_MTD_PARTITIONS #include <linux/mtd/partitions.h> @@ -59,7 +59,7 @@ static struct nand_ecclayout nand_oob_8 = { {.offset = 3, .length = 2}, {.offset = 6, - .length = 2}} + .length = 2} } }; static struct nand_ecclayout nand_oob_16 = { @@ -67,7 +67,7 @@ static struct nand_ecclayout nand_oob_16 = { .eccpos = {0, 1, 2, 3, 6, 7}, .oobfree = { {.offset = 8, - . length = 8}} + . length = 8} } }; static struct nand_ecclayout nand_oob_64 = { @@ -78,7 +78,7 @@ static struct nand_ecclayout nand_oob_64 = { 56, 57, 58, 59, 60, 61, 62, 63}, .oobfree = { {.offset = 2, - .length = 38}} + .length = 38} } }; static struct nand_ecclayout nand_oob_128 = { @@ -92,7 +92,7 @@ static struct nand_ecclayout nand_oob_128 = { 120, 121, 122, 123, 124, 125, 126, 127}, .oobfree = { {.offset = 2, - .length = 78}} + .length = 78} } }; static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, @@ -612,7 +612,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, NAND_CTRL_CLE | NAND_CTRL_CHANGE); chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; + while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) + ; return; /* This applies to read commands */ @@ -718,7 +719,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; + while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) + ; return; case NAND_CMD_RNDOUT: @@ -784,7 +786,7 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) spinlock_t *lock = &chip->controller->lock; wait_queue_head_t *wq = &chip->controller->wq; DECLARE_WAITQUEUE(wait, current); - retry: +retry: spin_lock(lock); /* Hardware controller shared among independent devices */ @@ -834,7 +836,7 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, break; } mdelay(1); - } + } } /** @@ -980,6 +982,7 @@ out: return ret; } +EXPORT_SYMBOL(nand_unlock); /** * nand_lock - [REPLACEABLE] locks all blocks present in the device @@ -1049,6 +1052,7 @@ out: return ret; } +EXPORT_SYMBOL(nand_lock); /** * nand_read_page_raw - [Intern] read raw page data without ecc @@ -1076,8 +1080,9 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, * * We need a special oob layout and handling even when OOB isn't used. */ -static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) +static int nand_read_page_raw_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, int page) { int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1158,7 +1163,8 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, * @readlen: data length * @bufpoi: buffer to store read data */ -static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) +static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, + uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) { int start_step, end_step, num_steps; uint32_t *eccpos = chip->ecc.layout->eccpos; @@ -1166,6 +1172,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3 int data_col_addr, i, gaps = 0; int datafrag_len, eccfrag_len, aligned_len, aligned_pos; int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; + int index = 0; /* Column address wihin the page aligned to ECC size (256bytes). */ start_step = data_offs / chip->ecc.size; @@ -1204,26 +1211,30 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3 } else { /* send the command to read the particular ecc bytes */ /* take care about buswidth alignment in read_buf */ - aligned_pos = eccpos[start_step * chip->ecc.bytes] & ~(busw - 1); + index = start_step * chip->ecc.bytes; + + aligned_pos = eccpos[index] & ~(busw - 1); aligned_len = eccfrag_len; - if (eccpos[start_step * chip->ecc.bytes] & (busw - 1)) + if (eccpos[index] & (busw - 1)) aligned_len++; - if (eccpos[(start_step + num_steps) * chip->ecc.bytes] & (busw - 1)) + if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1)) aligned_len++; - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1); + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, + mtd->writesize + aligned_pos, -1); chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); } for (i = 0; i < eccfrag_len; i++) - chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + start_step * chip->ecc.bytes]]; + chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]]; p = bufpoi + data_col_addr; for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { int stat; - stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); - if (stat == -1) + stat = chip->ecc.correct(mtd, p, + &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); + if (stat < 0) mtd->ecc_stats.failed++; else mtd->ecc_stats.corrected += stat; @@ -1390,7 +1401,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, struct mtd_oob_ops *ops, size_t len) { - switch(ops->mode) { + switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_RAW: @@ -1402,7 +1413,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, uint32_t boffs = 0, roffs = ops->ooboffs; size_t bytes = 0; - for(; free->length && len; free++, len -= bytes) { + for (; free->length && len; free++, len -= bytes) { /* Read request not from offset 0 ? */ if (unlikely(roffs)) { if (roffs >= free->length) { @@ -1466,7 +1477,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, buf = ops->datbuf; oob = ops->oobbuf; - while(1) { + while (1) { bytes = min(mtd->writesize - col, readlen); aligned = (bytes == mtd->writesize); @@ -1484,7 +1495,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, page); else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) - ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); + ret = chip->ecc.read_subpage(mtd, chip, + col, bytes, bufpoi); else ret = chip->ecc.read_page(mtd, chip, bufpoi, page); @@ -1493,7 +1505,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Transfer not aligned data */ if (!aligned) { - if (!NAND_SUBPAGE_READ(chip) && !oob) + if (!NAND_SUBPAGE_READ(chip) && !oob && + !(mtd->ecc_stats.failed - stats.failed)) chip->pagebuf = realpage; memcpy(buf, chip->buffers->databuf + col, bytes); } @@ -1791,7 +1804,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, realpage = (int)(from >> chip->page_shift); page = realpage & chip->pagemask; - while(1) { + while (1) { sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); len = min(len, readlen); @@ -1861,7 +1874,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, nand_get_device(chip, mtd, FL_READING); - switch(ops->mode) { + switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: case MTD_OOB_RAW: @@ -1876,7 +1889,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, else ret = nand_do_read_ops(mtd, from, ops); - out: +out: nand_release_device(mtd); return ret; } @@ -1905,8 +1918,9 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, * * We need a special oob layout and handling even when ECC isn't checked. */ -static void nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) +static void nand_write_page_raw_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf) { int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -2099,7 +2113,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, struct mtd_oob_ops *ops) { - switch(ops->mode) { + switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_RAW: @@ -2111,7 +2125,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, uint32_t boffs = 0, woffs = ops->ooboffs; size_t bytes = 0; - for(; free->length && len; free++, len -= bytes) { + for (; free->length && len; free++, len -= bytes) { /* Write request not from offset 0 ? */ if (unlikely(woffs)) { if (woffs >= free->length) { @@ -2137,7 +2151,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, return NULL; } -#define NOTALIGNED(x) (x & (chip->subpagesize - 1)) != 0 +#define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) /** * nand_do_write_ops - [Internal] NAND write with ECC @@ -2200,10 +2214,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, memset(chip->oob_poi, 0xff, mtd->oobsize); /* Don't allow multipage oob writes with offset */ - if (ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) + if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) return -EINVAL; - while(1) { + while (1) { int bytes = mtd->writesize; int cached = writelen > bytes && page != blockmask; uint8_t *wbuf = buf; @@ -2431,7 +2445,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, nand_get_device(chip, mtd, FL_WRITING); - switch(ops->mode) { + switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: case MTD_OOB_RAW: @@ -2446,7 +2460,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, else ret = nand_do_write_ops(mtd, to, ops); - out: +out: nand_release_device(mtd); return ret; } @@ -2511,7 +2525,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, { int page, status, pages_per_block, ret, chipnr; struct nand_chip *chip = mtd->priv; - loff_t rewrite_bbt[NAND_MAX_CHIPS]={0}; + loff_t rewrite_bbt[NAND_MAX_CHIPS] = {0}; unsigned int bbt_masked_page = 0xffffffff; loff_t len; @@ -2632,7 +2646,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, } instr->state = MTD_ERASE_DONE; - erase_exit: +erase_exit: ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; @@ -2706,7 +2720,8 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) struct nand_chip *chip = mtd->priv; int ret; - if ((ret = nand_block_isbad(mtd, ofs))) { + ret = nand_block_isbad(mtd, ofs); + if (ret) { /* If it was bad already, return success and do nothing. */ if (ret > 0) return 0; @@ -2787,15 +2802,115 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) } /* + * sanitize ONFI strings so we can safely print them + */ +static void sanitize_string(uint8_t *s, size_t len) +{ + ssize_t i; + + /* null terminate */ + s[len - 1] = 0; + + /* remove non printable chars */ + for (i = 0; i < len - 1; i++) { + if (s[i] < ' ' || s[i] > 127) + s[i] = '?'; + } + + /* remove trailing spaces */ + strim(s); +} + +static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) +{ + int i; + while (len--) { + crc ^= *p++ << 8; + for (i = 0; i < 8; i++) + crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); + } + + return crc; +} + +/* + * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise + */ +static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, + int busw) +{ + struct nand_onfi_params *p = &chip->onfi_params; + int i; + int val; + + /* try ONFI for unknow chip or LP */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); + if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || + chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') + return 0; + + printk(KERN_INFO "ONFI flash detected\n"); + chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); + for (i = 0; i < 3; i++) { + chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); + if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == + le16_to_cpu(p->crc)) { + printk(KERN_INFO "ONFI param page %d valid\n", i); + break; + } + } + + if (i == 3) + return 0; + + /* check version */ + val = le16_to_cpu(p->revision); + if (val == 1 || val > (1 << 4)) { + printk(KERN_INFO "%s: unsupported ONFI version: %d\n", + __func__, val); + return 0; + } + + if (val & (1 << 4)) + chip->onfi_version = 22; + else if (val & (1 << 3)) + chip->onfi_version = 21; + else if (val & (1 << 2)) + chip->onfi_version = 20; + else + chip->onfi_version = 10; + + sanitize_string(p->manufacturer, sizeof(p->manufacturer)); + sanitize_string(p->model, sizeof(p->model)); + if (!mtd->name) + mtd->name = p->model; + mtd->writesize = le32_to_cpu(p->byte_per_page); + mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; + mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); + chip->chipsize = le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; + busw = 0; + if (le16_to_cpu(p->features) & 1) + busw = NAND_BUSWIDTH_16; + + chip->options &= ~NAND_CHIPOPTIONS_MSK; + chip->options |= (NAND_NO_READRDY | + NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK; + + return 1; +} + +/* * Get the flash and manufacturer id and lookup if the type is supported */ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, - int busw, int *maf_id, + int busw, + int *maf_id, int *dev_id, struct nand_flash_dev *type) { - int i, dev_id, maf_idx; + int i, maf_idx; u8 id_data[8]; + int ret; /* Select the device */ chip->select_chip(mtd, 0); @@ -2811,7 +2926,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* Read manufacturer and device IDs */ *maf_id = chip->read_byte(mtd); - dev_id = chip->read_byte(mtd); + *dev_id = chip->read_byte(mtd); /* Try again to make sure, as some systems the bus-hold or other * interface concerns can cause random data which looks like a @@ -2821,15 +2936,13 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - /* Read entire ID string */ - - for (i = 0; i < 8; i++) + for (i = 0; i < 2; i++) id_data[i] = chip->read_byte(mtd); - if (id_data[0] != *maf_id || id_data[1] != dev_id) { + if (id_data[0] != *maf_id || id_data[1] != *dev_id) { printk(KERN_INFO "%s: second ID read did not match " "%02x,%02x against %02x,%02x\n", __func__, - *maf_id, dev_id, id_data[0], id_data[1]); + *maf_id, *dev_id, id_data[0], id_data[1]); return ERR_PTR(-ENODEV); } @@ -2837,8 +2950,23 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, type = nand_flash_ids; for (; type->name != NULL; type++) - if (dev_id == type->id) - break; + if (*dev_id == type->id) + break; + + chip->onfi_version = 0; + if (!type->name || !type->pagesize) { + /* Check is chip is ONFI compliant */ + ret = nand_flash_detect_onfi(mtd, chip, busw); + if (ret) + goto ident_done; + } + + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read entire ID string */ + + for (i = 0; i < 8; i++) + id_data[i] = chip->read_byte(mtd); if (!type->name) return ERR_PTR(-ENODEV); @@ -2848,8 +2976,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->chipsize = (uint64_t)type->chipsize << 20; - /* Newer devices have all the information in additional id bytes */ - if (!type->pagesize) { + if (!type->pagesize && chip->init_size) { + /* set the pagesize, oobsize, erasesize by the driver*/ + busw = chip->init_size(mtd, chip, id_data); + } else if (!type->pagesize) { int extid; /* The 3rd id byte holds MLC / multichip data */ chip->cellinfo = id_data[2]; @@ -2859,7 +2989,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* * Field definitions are in the following datasheets: * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) - * New style (6 byte ID): Samsung K9GAG08U0D (p.40) + * New style (6 byte ID): Samsung K9GBG08U0M (p.40) * * Check for wraparound + Samsung ID + nonzero 6th byte * to decide what to do. @@ -2872,7 +3002,20 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, mtd->writesize = 2048 << (extid & 0x03); extid >>= 2; /* Calc oobsize */ - mtd->oobsize = (extid & 0x03) == 0x01 ? 128 : 218; + switch (extid & 0x03) { + case 1: + mtd->oobsize = 128; + break; + case 2: + mtd->oobsize = 218; + break; + case 3: + mtd->oobsize = 400; + break; + default: + mtd->oobsize = 436; + break; + } extid >>= 2; /* Calc blocksize */ mtd->erasesize = (128 * 1024) << @@ -2900,7 +3043,35 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, mtd->writesize = type->pagesize; mtd->oobsize = mtd->writesize / 32; busw = type->options & NAND_BUSWIDTH_16; + + /* + * Check for Spansion/AMD ID + repeating 5th, 6th byte since + * some Spansion chips have erasesize that conflicts with size + * listed in nand_ids table + * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) + */ + if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && + id_data[5] == 0x00 && id_data[6] == 0x00 && + id_data[7] == 0x00 && mtd->writesize == 512) { + mtd->erasesize = 128 * 1024; + mtd->erasesize <<= ((id_data[3] & 0x03) << 1); + } } + /* Get chip options, preserve non chip based options */ + chip->options &= ~NAND_CHIPOPTIONS_MSK; + chip->options |= type->options & NAND_CHIPOPTIONS_MSK; + + /* Check if chip is a not a samsung device. Do not clear the + * options for chips which are not having an extended id. + */ + if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) + chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; +ident_done: + + /* + * Set chip as a default. Board drivers can override it, if necessary + */ + chip->options |= NAND_NO_AUTOINCR; /* Try to identify manufacturer */ for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { @@ -2915,7 +3086,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (busw != (chip->options & NAND_BUSWIDTH_16)) { printk(KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, - dev_id, nand_manuf_ids[maf_idx].name, mtd->name); + *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); printk(KERN_WARNING "NAND bus width %d instead %d bit\n", (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); @@ -2931,8 +3102,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, ffs(mtd->erasesize) - 1; if (chip->chipsize & 0xffffffff) chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; - else - chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1; + else { + chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)); + chip->chip_shift += 32 - 1; + } /* Set the bad block position */ if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16)) @@ -2940,27 +3113,12 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, else chip->badblockpos = NAND_SMALL_BADBLOCK_POS; - /* Get chip options, preserve non chip based options */ - chip->options &= ~NAND_CHIPOPTIONS_MSK; - chip->options |= type->options & NAND_CHIPOPTIONS_MSK; - - /* - * Set chip as a default. Board drivers can override it, if necessary - */ - chip->options |= NAND_NO_AUTOINCR; - - /* Check if chip is a not a samsung device. Do not clear the - * options for chips which are not having an extended id. - */ - if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) - chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; - /* * Bad block marker is stored in the last page of each block * on Samsung and Hynix MLC devices; stored in first two pages * of each block on Micron devices with 2KiB pages and on - * SLC Samsung, Hynix, and AMD/Spansion. All others scan only - * the first page. + * SLC Samsung, Hynix, Toshiba and AMD/Spansion. All others scan + * only the first page. */ if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (*maf_id == NAND_MFR_SAMSUNG || @@ -2969,6 +3127,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (*maf_id == NAND_MFR_SAMSUNG || *maf_id == NAND_MFR_HYNIX || + *maf_id == NAND_MFR_TOSHIBA || *maf_id == NAND_MFR_AMD)) || (mtd->writesize == 2048 && *maf_id == NAND_MFR_MICRON)) @@ -2994,9 +3153,11 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; + /* TODO onfi flash name */ printk(KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, - nand_manuf_ids[maf_idx].name, type->name); + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, + nand_manuf_ids[maf_idx].name, + chip->onfi_version ? type->name : chip->onfi_params.model); return type; } @@ -3015,7 +3176,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, int nand_scan_ident(struct mtd_info *mtd, int maxchips, struct nand_flash_dev *table) { - int i, busw, nand_maf_id; + int i, busw, nand_maf_id, nand_dev_id; struct nand_chip *chip = mtd->priv; struct nand_flash_dev *type; @@ -3025,7 +3186,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, nand_set_defaults(chip, busw); /* Read the flash type */ - type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id, table); + type = nand_get_flash_type(mtd, chip, busw, + &nand_maf_id, &nand_dev_id, table); if (IS_ERR(type)) { if (!(chip->options & NAND_SCAN_SILENT_NODEV)) @@ -3043,7 +3205,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ if (nand_maf_id != chip->read_byte(mtd) || - type->id != chip->read_byte(mtd)) + nand_dev_id != chip->read_byte(mtd)) break; } if (i > 1) @@ -3055,6 +3217,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, return 0; } +EXPORT_SYMBOL(nand_scan_ident); /** @@ -3219,7 +3382,7 @@ int nand_scan_tail(struct mtd_info *mtd) * mode */ chip->ecc.steps = mtd->writesize / chip->ecc.size; - if(chip->ecc.steps * chip->ecc.size != mtd->writesize) { + if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { printk(KERN_WARNING "Invalid ecc parameters\n"); BUG(); } @@ -3231,7 +3394,7 @@ int nand_scan_tail(struct mtd_info *mtd) */ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { - switch(chip->ecc.steps) { + switch (chip->ecc.steps) { case 2: mtd->subpage_sft = 1; break; @@ -3283,10 +3446,11 @@ int nand_scan_tail(struct mtd_info *mtd) /* Build bad block table */ return chip->scan_bbt(mtd); } +EXPORT_SYMBOL(nand_scan_tail); /* is_module_text_address() isn't exported, and it's mostly a pointless - test if this is a module _anyway_ -- they'd have to try _really_ hard - to call us from in-kernel code if the core NAND support is modular. */ + * test if this is a module _anyway_ -- they'd have to try _really_ hard + * to call us from in-kernel code if the core NAND support is modular. */ #ifdef MODULE #define caller_is_module() (1) #else @@ -3322,6 +3486,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips) ret = nand_scan_tail(mtd); return ret; } +EXPORT_SYMBOL(nand_scan); /** * nand_release - [NAND Interface] Free resources held by the NAND device @@ -3348,12 +3513,6 @@ void nand_release(struct mtd_info *mtd) & NAND_BBT_DYNAMICSTRUCT) kfree(chip->badblock_pattern); } - -EXPORT_SYMBOL_GPL(nand_lock); -EXPORT_SYMBOL_GPL(nand_unlock); -EXPORT_SYMBOL_GPL(nand_scan); -EXPORT_SYMBOL_GPL(nand_scan_ident); -EXPORT_SYMBOL_GPL(nand_scan_tail); EXPORT_SYMBOL_GPL(nand_release); static int __init nand_base_init(void) @@ -3371,5 +3530,6 @@ module_init(nand_base_init); module_exit(nand_base_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>"); +MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>"); +MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); MODULE_DESCRIPTION("Generic NAND flash driver code"); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 5fedf4a74f1..586b981f0e6 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -13,28 +13,37 @@ * Description: * * When nand_scan_bbt is called, then it tries to find the bad block table - * depending on the options in the bbt descriptor(s). If a bbt is found - * then the contents are read and the memory based bbt is created. If a - * mirrored bbt is selected then the mirror is searched too and the - * versions are compared. If the mirror has a greater version number - * than the mirror bbt is used to build the memory based bbt. + * depending on the options in the BBT descriptor(s). If no flash based BBT + * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory + * marked good / bad blocks. This information is used to create a memory BBT. + * Once a new bad block is discovered then the "factory" information is updated + * on the device. + * If a flash based BBT is specified then the function first tries to find the + * BBT on flash. If a BBT is found then the contents are read and the memory + * based BBT is created. If a mirrored BBT is selected then the mirror is + * searched too and the versions are compared. If the mirror has a greater + * version number than the mirror BBT is used to build the memory based BBT. * If the tables are not versioned, then we "or" the bad block information. - * If one of the bbt's is out of date or does not exist it is (re)created. - * If no bbt exists at all then the device is scanned for factory marked + * If one of the BBTs is out of date or does not exist it is (re)created. + * If no BBT exists at all then the device is scanned for factory marked * good / bad blocks and the bad block tables are created. * - * For manufacturer created bbts like the one found on M-SYS DOC devices - * the bbt is searched and read but never created + * For manufacturer created BBTs like the one found on M-SYS DOC devices + * the BBT is searched and read but never created * - * The autogenerated bad block table is located in the last good blocks + * The auto generated bad block table is located in the last good blocks * of the device. The table is mirrored, so it can be updated eventually. - * The table is marked in the oob area with an ident pattern and a version - * number which indicates which of both tables is more up to date. + * The table is marked in the OOB area with an ident pattern and a version + * number which indicates which of both tables is more up to date. If the NAND + * controller needs the complete OOB area for the ECC information then the + * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern + * and the version byte into the data area and the OOB area will remain + * untouched. * * The table uses 2 bits per block - * 11b: block is good - * 00b: block is factory marked bad - * 01b, 10b: block is marked bad due to wear + * 11b: block is good + * 00b: block is factory marked bad + * 01b, 10b: block is marked bad due to wear * * The memory bad block table uses the following scheme: * 00b: block is good @@ -59,6 +68,16 @@ #include <linux/delay.h> #include <linux/vmalloc.h> +static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) +{ + int ret; + + ret = memcmp(buf, td->pattern, td->len); + if (!ret) + return ret; + return -1; +} + /** * check_pattern - [GENERIC] check if a pattern is in the buffer * @buf: the buffer to search @@ -77,6 +96,9 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc int i, end = 0; uint8_t *p = buf; + if (td->options & NAND_BBT_NO_OOB) + return check_pattern_no_oob(buf, td); + end = paglen + td->offs; if (td->options & NAND_BBT_SCANEMPTY) { for (i = 0; i < end; i++) { @@ -156,32 +178,63 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) } /** + * add_marker_len - compute the length of the marker in data area + * @td: BBT descriptor used for computation + * + * The length will be 0 if the markeris located in OOB area. + */ +static u32 add_marker_len(struct nand_bbt_descr *td) +{ + u32 len; + + if (!(td->options & NAND_BBT_NO_OOB)) + return 0; + + len = td->len; + if (td->options & NAND_BBT_VERSION) + len++; + return len; +} + +/** * read_bbt - [GENERIC] Read the bad block table starting from page * @mtd: MTD device structure * @buf: temporary buffer * @page: the starting page * @num: the number of bbt descriptors to read - * @bits: number of bits per block + * @td: the bbt describtion table * @offs: offset in the memory table - * @reserved_block_code: Pattern to identify reserved blocks * * Read the bad block table starting from page. * */ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, - int bits, int offs, int reserved_block_code) + struct nand_bbt_descr *td, int offs) { int res, i, j, act = 0; struct nand_chip *this = mtd->priv; size_t retlen, len, totlen; loff_t from; + int bits = td->options & NAND_BBT_NRBITS_MSK; uint8_t msk = (uint8_t) ((1 << bits) - 1); + u32 marker_len; + int reserved_block_code = td->reserved_block_code; totlen = (num * bits) >> 3; + marker_len = add_marker_len(td); from = ((loff_t) page) << this->page_shift; while (totlen) { len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); + if (marker_len) { + /* + * In case the BBT marker is not in the OOB area it + * will be just in the first page. + */ + len -= marker_len; + from += marker_len; + marker_len = 0; + } res = mtd->read(mtd, from, len, &retlen, buf); if (res < 0) { if (retlen != len) { @@ -238,20 +291,21 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc { struct nand_chip *this = mtd->priv; int res = 0, i; - int bits; - bits = td->options & NAND_BBT_NRBITS_MSK; if (td->options & NAND_BBT_PERCHIP) { int offs = 0; for (i = 0; i < this->numchips; i++) { if (chip == -1 || chip == i) - res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code); + res = read_bbt(mtd, buf, td->pages[i], + this->chipsize >> this->bbt_erase_shift, + td, offs); if (res) return res; offs += this->chipsize >> (this->bbt_erase_shift + 2); } } else { - res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code); + res = read_bbt(mtd, buf, td->pages[0], + mtd->size >> this->bbt_erase_shift, td, 0); if (res) return res; } @@ -259,9 +313,25 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc } /* + * BBT marker is in the first page, no OOB. + */ +static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, + struct nand_bbt_descr *td) +{ + size_t retlen; + size_t len; + + len = td->len; + if (td->options & NAND_BBT_VERSION) + len++; + + return mtd->read(mtd, offs, len, &retlen, buf); +} + +/* * Scan read raw data from flash */ -static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, size_t len) { struct mtd_oob_ops ops; @@ -294,6 +364,15 @@ static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, return 0; } +static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, + size_t len, struct nand_bbt_descr *td) +{ + if (td->options & NAND_BBT_NO_OOB) + return scan_read_raw_data(mtd, buf, offs, td); + else + return scan_read_raw_oob(mtd, buf, offs, len); +} + /* * Scan write data with oob to flash */ @@ -312,6 +391,15 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, return mtd->write_oob(mtd, offs, &ops); } +static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) +{ + u32 ver_offs = td->veroffs; + + if (!(td->options & NAND_BBT_NO_OOB)) + ver_offs += mtd->writesize; + return ver_offs; +} + /** * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page * @mtd: MTD device structure @@ -331,8 +419,8 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, - mtd->writesize); - td->version[0] = buf[mtd->writesize + td->veroffs]; + mtd->writesize, td); + td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); } @@ -340,8 +428,8 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, - mtd->writesize); - md->version[0] = buf[mtd->writesize + md->veroffs]; + mtd->writesize, td); + md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); } @@ -357,7 +445,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, { int ret, j; - ret = scan_read_raw(mtd, buf, offs, readlen); + ret = scan_read_raw_oob(mtd, buf, offs, readlen); if (ret) return ret; @@ -464,6 +552,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, for (i = startblock; i < numblocks;) { int ret; + BUG_ON(bd->options & NAND_BBT_NO_OOB); + if (bd->options & NAND_BBT_SCANALLPAGES) ret = scan_block_full(mtd, bd, from, buf, readlen, scanlen, len); @@ -545,11 +635,12 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr loff_t offs = (loff_t)actblock << this->bbt_erase_shift; /* Read first page */ - scan_read_raw(mtd, buf, offs, mtd->writesize); + scan_read_raw(mtd, buf, offs, mtd->writesize, td); if (!check_pattern(buf, scanlen, mtd->writesize, td)) { td->pages[i] = actblock << blocktopage; if (td->options & NAND_BBT_VERSION) { - td->version[i] = buf[mtd->writesize + td->veroffs]; + offs = bbt_get_ver_offs(mtd, td); + td->version[i] = buf[offs]; } break; } @@ -733,12 +824,26 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); ooboffs = len + (pageoffs * mtd->oobsize); + } else if (td->options & NAND_BBT_NO_OOB) { + ooboffs = 0; + offs = td->len; + /* the version byte */ + if (td->options & NAND_BBT_VERSION) + offs++; + /* Calc length */ + len = (size_t) (numblocks >> sft); + len += offs; + /* Make it page aligned ! */ + len = ALIGN(len, mtd->writesize); + /* Preset the buffer with 0xff */ + memset(buf, 0xff, len); + /* Pattern is located at the begin of first page */ + memcpy(buf, td->pattern, td->len); } else { /* Calc length */ len = (size_t) (numblocks >> sft); /* Make it page aligned ! */ - len = (len + (mtd->writesize - 1)) & - ~(mtd->writesize - 1); + len = ALIGN(len, mtd->writesize); /* Preset the buffer with 0xff */ memset(buf, 0xff, len + (len >> this->page_shift)* mtd->oobsize); @@ -772,7 +877,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (res < 0) goto outerr; - res = scan_write_bbt(mtd, to, len, buf, &buf[len]); + res = scan_write_bbt(mtd, to, len, buf, + td->options & NAND_BBT_NO_OOB ? NULL : + &buf[len]); if (res < 0) goto outerr; @@ -892,7 +999,8 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc continue; /* Create the table in memory by scanning the chip(s) */ - create_bbt(mtd, buf, bd, chipsel); + if (!(this->options & NAND_CREATE_EMPTY_BBT)) + create_bbt(mtd, buf, bd, chipsel); td->version[i] = 1; if (md) @@ -983,6 +1091,49 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) } /** + * verify_bbt_descr - verify the bad block description + * @bd: the table to verify + * + * This functions performs a few sanity checks on the bad block description + * table. + */ +static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) +{ + struct nand_chip *this = mtd->priv; + u32 pattern_len = bd->len; + u32 bits = bd->options & NAND_BBT_NRBITS_MSK; + u32 table_size; + + if (!bd) + return; + BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && + !(this->options & NAND_USE_FLASH_BBT)); + BUG_ON(!bits); + + if (bd->options & NAND_BBT_VERSION) + pattern_len++; + + if (bd->options & NAND_BBT_NO_OOB) { + BUG_ON(!(this->options & NAND_USE_FLASH_BBT)); + BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB)); + BUG_ON(bd->offs); + if (bd->options & NAND_BBT_VERSION) + BUG_ON(bd->veroffs != bd->len); + BUG_ON(bd->options & NAND_BBT_SAVECONTENT); + } + + if (bd->options & NAND_BBT_PERCHIP) + table_size = this->chipsize >> this->bbt_erase_shift; + else + table_size = mtd->size >> this->bbt_erase_shift; + table_size >>= 3; + table_size *= bits; + if (bd->options & NAND_BBT_NO_OOB) + table_size += pattern_len; + BUG_ON(table_size > (1 << this->bbt_erase_shift)); +} + +/** * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) * @mtd: MTD device structure * @bd: descriptor for the good/bad block search pattern @@ -1023,6 +1174,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) } return res; } + verify_bbt_descr(mtd, td); + verify_bbt_descr(mtd, md); /* Allocate a temporary buffer for one eraseblock incl. oob */ len = (1 << this->bbt_erase_shift); @@ -1166,6 +1319,26 @@ static struct nand_bbt_descr bbt_mirror_descr = { .pattern = mirror_pattern }; +static struct nand_bbt_descr bbt_main_no_bbt_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP + | NAND_BBT_NO_OOB, + .len = 4, + .veroffs = 4, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP + | NAND_BBT_NO_OOB, + .len = 4, + .veroffs = 4, + .maxblocks = 4, + .pattern = mirror_pattern +}; + #define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ NAND_BBT_SCANBYTE1AND6) /** @@ -1236,8 +1409,13 @@ int nand_default_bbt(struct mtd_info *mtd) if (this->options & NAND_USE_FLASH_BBT) { /* Use the default pattern descriptors */ if (!this->bbt_td) { - this->bbt_td = &bbt_main_descr; - this->bbt_md = &bbt_mirror_descr; + if (this->options & NAND_USE_FLASH_BBT_NO_OOB) { + this->bbt_td = &bbt_main_no_bbt_descr; + this->bbt_md = &bbt_mirror_no_bbt_descr; + } else { + this->bbt_td = &bbt_main_descr; + this->bbt_md = &bbt_mirror_descr; + } } if (!this->badblock_pattern) { this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased; diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index c65f19074bc..00cf1b0d605 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -75,9 +75,13 @@ struct nand_flash_dev nand_flash_ids[] = { /*512 Megabit */ {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS}, + {"NAND 64MiB 1,8V 8-bit", 0xA0, 0, 64, 0, LP_OPTIONS}, {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS}, + {"NAND 64MiB 3,3V 8-bit", 0xD0, 0, 64, 0, LP_OPTIONS}, {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16}, + {"NAND 64MiB 1,8V 16-bit", 0xB0, 0, 64, 0, LP_OPTIONS16}, {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16}, + {"NAND 64MiB 3,3V 16-bit", 0xC0, 0, 64, 0, LP_OPTIONS16}, /* 1 Gigabit */ {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS}, @@ -112,7 +116,34 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16}, /* 32 Gigabit */ + {"NAND 4GiB 1,8V 8-bit", 0xA7, 0, 4096, 0, LP_OPTIONS}, {"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS}, + {"NAND 4GiB 1,8V 16-bit", 0xB7, 0, 4096, 0, LP_OPTIONS16}, + {"NAND 4GiB 3,3V 16-bit", 0xC7, 0, 4096, 0, LP_OPTIONS16}, + + /* 64 Gigabit */ + {"NAND 8GiB 1,8V 8-bit", 0xAE, 0, 8192, 0, LP_OPTIONS}, + {"NAND 8GiB 3,3V 8-bit", 0xDE, 0, 8192, 0, LP_OPTIONS}, + {"NAND 8GiB 1,8V 16-bit", 0xBE, 0, 8192, 0, LP_OPTIONS16}, + {"NAND 8GiB 3,3V 16-bit", 0xCE, 0, 8192, 0, LP_OPTIONS16}, + + /* 128 Gigabit */ + {"NAND 16GiB 1,8V 8-bit", 0x1A, 0, 16384, 0, LP_OPTIONS}, + {"NAND 16GiB 3,3V 8-bit", 0x3A, 0, 16384, 0, LP_OPTIONS}, + {"NAND 16GiB 1,8V 16-bit", 0x2A, 0, 16384, 0, LP_OPTIONS16}, + {"NAND 16GiB 3,3V 16-bit", 0x4A, 0, 16384, 0, LP_OPTIONS16}, + + /* 256 Gigabit */ + {"NAND 32GiB 1,8V 8-bit", 0x1C, 0, 32768, 0, LP_OPTIONS}, + {"NAND 32GiB 3,3V 8-bit", 0x3C, 0, 32768, 0, LP_OPTIONS}, + {"NAND 32GiB 1,8V 16-bit", 0x2C, 0, 32768, 0, LP_OPTIONS16}, + {"NAND 32GiB 3,3V 16-bit", 0x4C, 0, 32768, 0, LP_OPTIONS16}, + + /* 512 Gigabit */ + {"NAND 64GiB 1,8V 8-bit", 0x1E, 0, 65536, 0, LP_OPTIONS}, + {"NAND 64GiB 3,3V 8-bit", 0x3E, 0, 65536, 0, LP_OPTIONS}, + {"NAND 64GiB 1,8V 16-bit", 0x2E, 0, 65536, 0, LP_OPTIONS16}, + {"NAND 64GiB 3,3V 16-bit", 0x4E, 0, 65536, 0, LP_OPTIONS16}, /* * Renesas AND 1 Gigabit. Those chips do not support extended id and diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index c25648bb579..a6a73aab125 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -107,6 +107,7 @@ static char *gravepages = NULL; static unsigned int rptwear = 0; static unsigned int overridesize = 0; static char *cache_file = NULL; +static unsigned int bbt; module_param(first_id_byte, uint, 0400); module_param(second_id_byte, uint, 0400); @@ -130,6 +131,7 @@ module_param(gravepages, charp, 0400); module_param(rptwear, uint, 0400); module_param(overridesize, uint, 0400); module_param(cache_file, charp, 0400); +module_param(bbt, uint, 0400); MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); @@ -162,6 +164,7 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I "The size is specified in erase blocks and as the exponent of a power of two" " e.g. 5 means a size of 32 erase blocks"); MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory"); +MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area"); /* The largest possible page size */ #define NS_LARGEST_PAGE_SIZE 4096 @@ -2264,6 +2267,18 @@ static int __init ns_init_module(void) /* and 'badblocks' parameters to work */ chip->options |= NAND_SKIP_BBTSCAN; + switch (bbt) { + case 2: + chip->options |= NAND_USE_FLASH_BBT_NO_OOB; + case 1: + chip->options |= NAND_USE_FLASH_BBT; + case 0: + break; + default: + NS_ERR("bbt has to be 0..2\n"); + retval = -EINVAL; + goto error; + } /* * Perform minimum nandsim structure initialization to handle * the initial ID read command correctly @@ -2321,10 +2336,10 @@ static int __init ns_init_module(void) if ((retval = init_nandsim(nsmtd)) != 0) goto err_exit; - if ((retval = parse_badblocks(nand, nsmtd)) != 0) + if ((retval = nand_default_bbt(nsmtd)) != 0) goto err_exit; - if ((retval = nand_default_bbt(nsmtd)) != 0) + if ((retval = parse_badblocks(nand, nsmtd)) != 0) goto err_exit; /* Register NAND partitions */ diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 510554e6c11..c9ae0a5023b 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -229,7 +229,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev, const struct of_device_id *match) { struct ndfc_controller *ndfc = &ndfc_ctrl; - const u32 *reg; + const __be32 *reg; u32 ccr; int err, len; @@ -244,7 +244,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev, dev_err(&ofdev->dev, "unable read reg property (%d)\n", len); return -ENOENT; } - ndfc->chip_select = reg[0]; + ndfc->chip_select = be32_to_cpu(reg[0]); ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0); if (!ndfc->ndfcbase) { @@ -257,7 +257,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev, /* It is ok if ccr does not exist - just default to 0 */ reg = of_get_property(ofdev->dev.of_node, "ccr", NULL); if (reg) - ccr |= *reg; + ccr |= be32_to_cpup(reg); out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); @@ -265,7 +265,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev, reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL); if (reg) { int offset = NDFC_BCFG0 + (ndfc->chip_select << 2); - out_be32(ndfc->ndfcbase + offset, *reg); + out_be32(ndfc->ndfcbase + offset, be32_to_cpup(reg)); } err = ndfc_chip_init(ndfc, ofdev->dev.of_node); diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 513e0a76a4a..cd41c58b5bb 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -111,11 +111,11 @@ static int use_dma = 1; module_param(use_dma, bool, 0); MODULE_PARM_DESC(use_dma, "enable/disable use of DMA"); #else -const int use_dma; +static const int use_dma; #endif #else const int use_prefetch; -const int use_dma; +static const int use_dma; #endif struct omap_nand_info { diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 4d01cda6884..17f8518cc5e 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -117,7 +117,7 @@ struct pxa3xx_nand_info { struct nand_chip nand_chip; struct platform_device *pdev; - const struct pxa3xx_nand_flash *flash_info; + struct pxa3xx_nand_cmdset *cmdset; struct clk *clk; void __iomem *mmio_base; @@ -131,6 +131,7 @@ struct pxa3xx_nand_info { int drcmr_cmd; unsigned char *data_buff; + unsigned char *oob_buff; dma_addr_t data_buff_phys; size_t data_buff_size; int data_dma_ch; @@ -149,7 +150,8 @@ struct pxa3xx_nand_info { int use_ecc; /* use HW ECC ? */ int use_dma; /* use DMA ? */ - size_t data_size; /* data size in FIFO */ + unsigned int page_size; /* page size of attached chip */ + unsigned int data_size; /* data size in FIFO */ int retcode; struct completion cmd_complete; @@ -158,6 +160,10 @@ struct pxa3xx_nand_info { uint32_t ndcb1; uint32_t ndcb2; + /* timing calcuted from setting */ + uint32_t ndtr0cs0; + uint32_t ndtr1cs0; + /* calculated from pxa3xx_nand_flash data */ size_t oob_size; size_t read_id_bytes; @@ -174,23 +180,7 @@ MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW"); * Default NAND flash controller configuration setup by the * bootloader. This configuration is used only when pdata->keep_config is set */ -static struct pxa3xx_nand_timing default_timing; -static struct pxa3xx_nand_flash default_flash; - -static struct pxa3xx_nand_cmdset smallpage_cmdset = { - .read1 = 0x0000, - .read2 = 0x0050, - .program = 0x1080, - .read_status = 0x0070, - .read_id = 0x0090, - .erase = 0xD060, - .reset = 0x00FF, - .lock = 0x002A, - .unlock = 0x2423, - .lock_status = 0x007A, -}; - -static struct pxa3xx_nand_cmdset largepage_cmdset = { +static struct pxa3xx_nand_cmdset default_cmdset = { .read1 = 0x3000, .read2 = 0x0050, .program = 0x1080, @@ -203,142 +193,27 @@ static struct pxa3xx_nand_cmdset largepage_cmdset = { .lock_status = 0x007A, }; -#ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN -static struct pxa3xx_nand_timing samsung512MbX16_timing = { - .tCH = 10, - .tCS = 0, - .tWH = 20, - .tWP = 40, - .tRH = 30, - .tRP = 40, - .tR = 11123, - .tWHR = 110, - .tAR = 10, -}; - -static struct pxa3xx_nand_flash samsung512MbX16 = { - .timing = &samsung512MbX16_timing, - .cmdset = &smallpage_cmdset, - .page_per_block = 32, - .page_size = 512, - .flash_width = 16, - .dfc_width = 16, - .num_blocks = 4096, - .chip_id = 0x46ec, -}; - -static struct pxa3xx_nand_flash samsung2GbX8 = { - .timing = &samsung512MbX16_timing, - .cmdset = &smallpage_cmdset, - .page_per_block = 64, - .page_size = 2048, - .flash_width = 8, - .dfc_width = 8, - .num_blocks = 2048, - .chip_id = 0xdaec, +static struct pxa3xx_nand_timing timing[] = { + { 40, 80, 60, 100, 80, 100, 90000, 400, 40, }, + { 10, 0, 20, 40, 30, 40, 11123, 110, 10, }, + { 10, 25, 15, 25, 15, 30, 25000, 60, 10, }, + { 10, 35, 15, 25, 15, 25, 25000, 60, 10, }, }; -static struct pxa3xx_nand_flash samsung32GbX8 = { - .timing = &samsung512MbX16_timing, - .cmdset = &smallpage_cmdset, - .page_per_block = 128, - .page_size = 4096, - .flash_width = 8, - .dfc_width = 8, - .num_blocks = 8192, - .chip_id = 0xd7ec, +static struct pxa3xx_nand_flash builtin_flash_types[] = { + { 0, 0, 2048, 8, 8, 0, &default_cmdset, &timing[0] }, + { 0x46ec, 32, 512, 16, 16, 4096, &default_cmdset, &timing[1] }, + { 0xdaec, 64, 2048, 8, 8, 2048, &default_cmdset, &timing[1] }, + { 0xd7ec, 128, 4096, 8, 8, 8192, &default_cmdset, &timing[1] }, + { 0xa12c, 64, 2048, 8, 8, 1024, &default_cmdset, &timing[2] }, + { 0xb12c, 64, 2048, 16, 16, 1024, &default_cmdset, &timing[2] }, + { 0xdc2c, 64, 2048, 8, 8, 4096, &default_cmdset, &timing[2] }, + { 0xcc2c, 64, 2048, 16, 16, 4096, &default_cmdset, &timing[2] }, + { 0xba20, 64, 2048, 16, 16, 2048, &default_cmdset, &timing[3] }, }; -static struct pxa3xx_nand_timing micron_timing = { - .tCH = 10, - .tCS = 25, - .tWH = 15, - .tWP = 25, - .tRH = 15, - .tRP = 30, - .tR = 25000, - .tWHR = 60, - .tAR = 10, -}; - -static struct pxa3xx_nand_flash micron1GbX8 = { - .timing = µn_timing, - .cmdset = &largepage_cmdset, - .page_per_block = 64, - .page_size = 2048, - .flash_width = 8, - .dfc_width = 8, - .num_blocks = 1024, - .chip_id = 0xa12c, -}; - -static struct pxa3xx_nand_flash micron1GbX16 = { - .timing = µn_timing, - .cmdset = &largepage_cmdset, - .page_per_block = 64, - .page_size = 2048, - .flash_width = 16, - .dfc_width = 16, - .num_blocks = 1024, - .chip_id = 0xb12c, -}; - -static struct pxa3xx_nand_flash micron4GbX8 = { - .timing = µn_timing, - .cmdset = &largepage_cmdset, - .page_per_block = 64, - .page_size = 2048, - .flash_width = 8, - .dfc_width = 8, - .num_blocks = 4096, - .chip_id = 0xdc2c, -}; - -static struct pxa3xx_nand_flash micron4GbX16 = { - .timing = µn_timing, - .cmdset = &largepage_cmdset, - .page_per_block = 64, - .page_size = 2048, - .flash_width = 16, - .dfc_width = 16, - .num_blocks = 4096, - .chip_id = 0xcc2c, -}; - -static struct pxa3xx_nand_timing stm2GbX16_timing = { - .tCH = 10, - .tCS = 35, - .tWH = 15, - .tWP = 25, - .tRH = 15, - .tRP = 25, - .tR = 25000, - .tWHR = 60, - .tAR = 10, -}; - -static struct pxa3xx_nand_flash stm2GbX16 = { - .timing = &stm2GbX16_timing, - .cmdset = &largepage_cmdset, - .page_per_block = 64, - .page_size = 2048, - .flash_width = 16, - .dfc_width = 16, - .num_blocks = 2048, - .chip_id = 0xba20, -}; - -static struct pxa3xx_nand_flash *builtin_flash_types[] = { - &samsung512MbX16, - &samsung2GbX8, - &samsung32GbX8, - µn1GbX8, - µn1GbX16, - µn4GbX8, - µn4GbX16, - &stm2GbX16, -}; -#endif /* CONFIG_MTD_NAND_PXA3xx_BUILTIN */ +/* Define a default flash type setting serve as flash detecting only */ +#define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) #define NDTR0_tCH(c) (min((c), 7) << 19) #define NDTR0_tCS(c) (min((c), 7) << 16) @@ -351,23 +226,9 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = { #define NDTR1_tWHR(c) (min((c), 15) << 4) #define NDTR1_tAR(c) (min((c), 15) << 0) -#define tCH_NDTR0(r) (((r) >> 19) & 0x7) -#define tCS_NDTR0(r) (((r) >> 16) & 0x7) -#define tWH_NDTR0(r) (((r) >> 11) & 0x7) -#define tWP_NDTR0(r) (((r) >> 8) & 0x7) -#define tRH_NDTR0(r) (((r) >> 3) & 0x7) -#define tRP_NDTR0(r) (((r) >> 0) & 0x7) - -#define tR_NDTR1(r) (((r) >> 16) & 0xffff) -#define tWHR_NDTR1(r) (((r) >> 4) & 0xf) -#define tAR_NDTR1(r) (((r) >> 0) & 0xf) - /* convert nano-seconds to nand flash controller clock cycles */ #define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) -/* convert nand flash controller clock cycles to nano-seconds */ -#define cycle2ns(c, clk) ((((c) + 1) * 1000000 + clk / 500) / (clk / 1000)) - static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, const struct pxa3xx_nand_timing *t) { @@ -385,6 +246,8 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) | NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); + info->ndtr0cs0 = ndtr0; + info->ndtr1cs0 = ndtr1; nand_writel(info, NDTR0CS0, ndtr0); nand_writel(info, NDTR1CS0, ndtr1); } @@ -408,23 +271,31 @@ static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event) return -ETIMEDOUT; } -static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, - uint16_t cmd, int column, int page_addr) +static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) { - const struct pxa3xx_nand_flash *f = info->flash_info; - const struct pxa3xx_nand_cmdset *cmdset = f->cmdset; + int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; - /* calculate data size */ - switch (f->page_size) { + info->data_size = info->page_size; + if (!oob_enable) { + info->oob_size = 0; + return; + } + + switch (info->page_size) { case 2048: - info->data_size = (info->use_ecc) ? 2088 : 2112; + info->oob_size = (info->use_ecc) ? 40 : 64; break; case 512: - info->data_size = (info->use_ecc) ? 520 : 528; + info->oob_size = (info->use_ecc) ? 8 : 16; break; - default: - return -EINVAL; } +} + +static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, + uint16_t cmd, int column, int page_addr) +{ + const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; + pxa3xx_set_datasize(info); /* generate values for NDCBx registers */ info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); @@ -463,12 +334,13 @@ static int prepare_erase_cmd(struct pxa3xx_nand_info *info, static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) { - const struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset; + const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); info->ndcb1 = 0; info->ndcb2 = 0; + info->oob_size = 0; if (cmd == cmdset->read_id) { info->ndcb0 |= NDCB0_CMD_TYPE(3); info->data_size = 8; @@ -537,6 +409,9 @@ static int handle_data_pio(struct pxa3xx_nand_info *info) case STATE_PIO_WRITING: __raw_writesl(info->mmio_base + NDDB, info->data_buff, DIV_ROUND_UP(info->data_size, 4)); + if (info->oob_size > 0) + __raw_writesl(info->mmio_base + NDDB, info->oob_buff, + DIV_ROUND_UP(info->oob_size, 4)); enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); @@ -549,6 +424,9 @@ static int handle_data_pio(struct pxa3xx_nand_info *info) case STATE_PIO_READING: __raw_readsl(info->mmio_base + NDDB, info->data_buff, DIV_ROUND_UP(info->data_size, 4)); + if (info->oob_size > 0) + __raw_readsl(info->mmio_base + NDDB, info->oob_buff, + DIV_ROUND_UP(info->oob_size, 4)); break; default: printk(KERN_ERR "%s: invalid state %d\n", __func__, @@ -563,7 +441,7 @@ static int handle_data_pio(struct pxa3xx_nand_info *info) static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out) { struct pxa_dma_desc *desc = info->data_desc; - int dma_len = ALIGN(info->data_size, 32); + int dma_len = ALIGN(info->data_size + info->oob_size, 32); desc->ddadr = DDADR_STOP; desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len; @@ -700,8 +578,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr) { struct pxa3xx_nand_info *info = mtd->priv; - const struct pxa3xx_nand_flash *flash_info = info->flash_info; - const struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset; + const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; int ret; info->use_dma = (use_dma) ? 1 : 0; @@ -925,8 +802,7 @@ static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd, static int __readid(struct pxa3xx_nand_info *info, uint32_t *id) { - const struct pxa3xx_nand_flash *f = info->flash_info; - const struct pxa3xx_nand_cmdset *cmdset = f->cmdset; + const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; uint32_t ndcr; uint8_t id_buff[8]; @@ -968,7 +844,9 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, return -EINVAL; /* calculate flash information */ - info->oob_size = (f->page_size == 2048) ? 64 : 16; + info->cmdset = f->cmdset; + info->page_size = f->page_size; + info->oob_buff = info->data_buff + f->page_size; info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; /* calculate addressing information */ @@ -992,49 +870,20 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, info->reg_ndcr = ndcr; pxa3xx_nand_set_timing(info, f->timing); - info->flash_info = f; return 0; } -static void pxa3xx_nand_detect_timing(struct pxa3xx_nand_info *info, - struct pxa3xx_nand_timing *t) -{ - unsigned long nand_clk = clk_get_rate(info->clk); - uint32_t ndtr0 = nand_readl(info, NDTR0CS0); - uint32_t ndtr1 = nand_readl(info, NDTR1CS0); - - t->tCH = cycle2ns(tCH_NDTR0(ndtr0), nand_clk); - t->tCS = cycle2ns(tCS_NDTR0(ndtr0), nand_clk); - t->tWH = cycle2ns(tWH_NDTR0(ndtr0), nand_clk); - t->tWP = cycle2ns(tWP_NDTR0(ndtr0), nand_clk); - t->tRH = cycle2ns(tRH_NDTR0(ndtr0), nand_clk); - t->tRP = cycle2ns(tRP_NDTR0(ndtr0), nand_clk); - - t->tR = cycle2ns(tR_NDTR1(ndtr1), nand_clk); - t->tWHR = cycle2ns(tWHR_NDTR1(ndtr1), nand_clk); - t->tAR = cycle2ns(tAR_NDTR1(ndtr1), nand_clk); -} - static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) { uint32_t ndcr = nand_readl(info, NDCR); struct nand_flash_dev *type = NULL; - uint32_t id = -1; + uint32_t id = -1, page_per_block, num_blocks; int i; - default_flash.page_per_block = ndcr & NDCR_PG_PER_BLK ? 64 : 32; - default_flash.page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; - default_flash.flash_width = ndcr & NDCR_DWIDTH_M ? 16 : 8; - default_flash.dfc_width = ndcr & NDCR_DWIDTH_C ? 16 : 8; - - if (default_flash.page_size == 2048) - default_flash.cmdset = &largepage_cmdset; - else - default_flash.cmdset = &smallpage_cmdset; - + page_per_block = ndcr & NDCR_PG_PER_BLK ? 64 : 32; + info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; /* set info fields needed to __readid */ - info->flash_info = &default_flash; - info->read_id_bytes = (default_flash.page_size == 2048) ? 4 : 2; + info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; info->reg_ndcr = ndcr; if (__readid(info, &id)) @@ -1053,21 +902,20 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) return -ENODEV; /* fill the missing flash information */ - i = __ffs(default_flash.page_per_block * default_flash.page_size); - default_flash.num_blocks = type->chipsize << (20 - i); - - info->oob_size = (default_flash.page_size == 2048) ? 64 : 16; + i = __ffs(page_per_block * info->page_size); + num_blocks = type->chipsize << (20 - i); /* calculate addressing information */ - info->col_addr_cycles = (default_flash.page_size == 2048) ? 2 : 1; + info->col_addr_cycles = (info->page_size == 2048) ? 2 : 1; - if (default_flash.num_blocks * default_flash.page_per_block > 65536) + if (num_blocks * page_per_block > 65536) info->row_addr_cycles = 3; else info->row_addr_cycles = 2; - pxa3xx_nand_detect_timing(info, &default_timing); - default_flash.timing = &default_timing; + info->ndtr0cs0 = nand_readl(info, NDTR0CS0); + info->ndtr1cs0 = nand_readl(info, NDTR1CS0); + info->cmdset = &default_cmdset; return 0; } @@ -1083,38 +931,29 @@ static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info, if (pxa3xx_nand_detect_config(info) == 0) return 0; - for (i = 0; i<pdata->num_flash; ++i) { - f = pdata->flash + i; - - if (pxa3xx_nand_config_flash(info, f)) - continue; - - if (__readid(info, &id)) - continue; - - if (id == f->chip_id) - return 0; - } - -#ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN - for (i = 0; i < ARRAY_SIZE(builtin_flash_types); i++) { - - f = builtin_flash_types[i]; - - if (pxa3xx_nand_config_flash(info, f)) - continue; - - if (__readid(info, &id)) - continue; - - if (id == f->chip_id) + /* we use default timing to detect id */ + f = DEFAULT_FLASH_TYPE; + pxa3xx_nand_config_flash(info, f); + if (__readid(info, &id)) + goto fail_detect; + + for (i=0; i<ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1; i++) { + /* we first choose the flash definition from platfrom */ + if (i < pdata->num_flash) + f = pdata->flash + i; + else + f = &builtin_flash_types[i - pdata->num_flash + 1]; + if (f->chip_id == id) { + dev_info(&info->pdev->dev, "detect chip id: 0x%x\n", id); + pxa3xx_nand_config_flash(info, f); return 0; + } } -#endif dev_warn(&info->pdev->dev, "failed to detect configured nand flash; found %04x instead of\n", id); +fail_detect: return -ENODEV; } @@ -1177,10 +1016,9 @@ static struct nand_ecclayout hw_largepage_ecclayout = { static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, struct pxa3xx_nand_info *info) { - const struct pxa3xx_nand_flash *f = info->flash_info; struct nand_chip *this = &info->nand_chip; - this->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0; + this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0; this->waitfunc = pxa3xx_nand_waitfunc; this->select_chip = pxa3xx_nand_select_chip; @@ -1196,9 +1034,9 @@ static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, this->ecc.hwctl = pxa3xx_nand_ecc_hwctl; this->ecc.calculate = pxa3xx_nand_ecc_calculate; this->ecc.correct = pxa3xx_nand_ecc_correct; - this->ecc.size = f->page_size; + this->ecc.size = info->page_size; - if (f->page_size == 2048) + if (info->page_size == 2048) this->ecc.layout = &hw_largepage_ecclayout; else this->ecc.layout = &hw_smallpage_ecclayout; @@ -1411,9 +1249,11 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev); struct pxa3xx_nand_info *info = mtd->priv; + nand_writel(info, NDTR0CS0, info->ndtr0cs0); + nand_writel(info, NDTR1CS0, info->ndtr1cs0); clk_enable(info->clk); - return pxa3xx_nand_config_flash(info, info->flash_info); + return 0; } #else #define pxa3xx_nand_suspend NULL diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 5169ca6a66b..d9d7efbc77c 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -757,11 +757,6 @@ static irqreturn_t r852_irq(int irq, void *data) spin_lock_irqsave(&dev->irqlock, flags); - /* We can recieve shared interrupt while pci is suspended - in that case reads will return 0xFFFFFFFF.... */ - if (dev->insuspend) - goto out; - /* handle card detection interrupts first */ card_status = r852_read_reg(dev, R852_CARD_IRQ_STA); r852_write_reg(dev, R852_CARD_IRQ_STA, card_status); @@ -1035,7 +1030,6 @@ void r852_shutdown(struct pci_dev *pci_dev) int r852_suspend(struct device *device) { struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); - unsigned long flags; if (dev->ctlreg & R852_CTL_CARDENABLE) return -EBUSY; @@ -1047,43 +1041,22 @@ int r852_suspend(struct device *device) r852_disable_irqs(dev); r852_engine_disable(dev); - spin_lock_irqsave(&dev->irqlock, flags); - dev->insuspend = 1; - spin_unlock_irqrestore(&dev->irqlock, flags); - - /* At that point, even if interrupt handler is running, it will quit */ - /* So wait for this to happen explictly */ - synchronize_irq(dev->irq); - /* If card was pulled off just during the suspend, which is very unlikely, we will remove it on resume, it too late now anyway... */ dev->card_unstable = 0; - - pci_save_state(to_pci_dev(device)); - return pci_prepare_to_sleep(to_pci_dev(device)); + return 0; } int r852_resume(struct device *device) { struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); - unsigned long flags; - - /* Turn on the hardware */ - pci_back_from_sleep(to_pci_dev(device)); - pci_restore_state(to_pci_dev(device)); r852_disable_irqs(dev); r852_card_update_present(dev); r852_engine_disable(dev); - /* Now its safe for IRQ to run */ - spin_lock_irqsave(&dev->irqlock, flags); - dev->insuspend = 0; - spin_unlock_irqrestore(&dev->irqlock, flags); - - /* If card status changed, just do the work */ if (dev->card_detected != dev->card_registred) { dbg("card was %s during low power state", @@ -1121,7 +1094,6 @@ MODULE_DEVICE_TABLE(pci, r852_pci_id_tbl); SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume); - static struct pci_driver r852_pci_driver = { .name = DRV_NAME, .id_table = r852_pci_id_tbl, diff --git a/drivers/mtd/nand/r852.h b/drivers/mtd/nand/r852.h index 8096cc280c7..e6a21d9d22c 100644 --- a/drivers/mtd/nand/r852.h +++ b/drivers/mtd/nand/r852.h @@ -140,8 +140,6 @@ struct r852_device { /* interrupt handling */ spinlock_t irqlock; /* IRQ protecting lock */ int irq; /* irq num */ - int insuspend; /* device is suspended */ - /* misc */ void *tmp_buffer; /* temporary buffer */ uint8_t ctlreg; /* cached contents of control reg */ |