MTD updates for v4.10-rc1:

Core:
 
   * dynamic BDI object allocation (resolves some problems when built as a
     module)
   * cleanups in the ooblayout handling
 
 NAND:
 
   * new tango NAND controller driver
   * new ox820 NAND controller driver
   * addition of a new full-ID entry in the nand_ids table
   * rework of the s3c240 driver to support DT
   * extension of the nand_sdr_timings to expose tCCS, tPROG and tR
   * addition of a new flag to ask the core to wait for tCCS when sending
     a RNDIN/RNDOUT command
   * addition of a new flag to ask the core to let the controller driver
     send the READ/PROGPAGE command
 
   Minor fixes/cleanup/cosmetic changes:
   * properly support 512 ECC step size in the sunxi driver
   * improve the error messages in the PXA probe path
   * fix module autoload in the omap2 driver
   * cleanup of several nand drivers to return nand_scan{_tail}() error
     code instead of returning -EIO
   * various cleanups in the denali driver
   * fix an error check in nandsim
 
 SPI NOR:
 
   * new flash IDs
   * wait for Spansion flash to be ready after quad-enable
   * error handling fixes for Candence QSPI
   * constify some structures in Freescale QSPI driver
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJYVEDMAAoJEFySrpd9RFgtHfoP/33L6OgHn0kzonYhB3/BKFol
 WFEAdu2Z2cT9sQE0GpZFAcySasVisQMONoL0RBmvxZTeW2YtiN6NEJkr98JropzJ
 HowNDxuVuDiJ2clmTkE5J1i9WMUV0t6TqWzdbXSme9s68P6p1q9RLH6rmq06JITj
 zc56HrHgtYLCyFn5MtHPat4/jOPhqPHXfVnadtNAJ28FazhnsurkJe/ChUvGS1xJ
 2xSfueERHuPcNrpMEbNcyS4OOJpFqI1Ds3+7vJxz4kpWomAJEQ4l7Jw7e+GaKI5q
 2DsEUbvIPCMZMH1cqyWgVsWaDO820KFcJ4MwHT7nsNSvrjOEUivZCPpk/L2Wa7sd
 x6A4YvRPrKMoaE8CFgjz7K7UXDLU6Xa+ZwyIqn4YsnuunzhspjJI7BdrhApTRMwn
 Nhwr2bNmK1Hf4nfUnddH9/+0X06wOnEgzCx8I3t3VjvzbPIVozcfNVXFhLURxICR
 WRRAgbNA2ES88DFtLF2pnwIi8z+WLYRhe0tWsjb8h3/Xr8BQGS2hEy0N+MLolglj
 GlH1SMOddHHOAyG53YUNdhb3T7MbBEIcBmQH6ihJgkDqHcVrgCcaUtR2fSJII0Ln
 fpmlSBeut/KC2wIrf0+UACv2kUWpfgOQLCoKMZLjJMGytolNl63+Q/Jmrng5LjXv
 lx7sMp3dE9kBRORPeaw0
 =H2FS
 -----END PGP SIGNATURE-----

Merge tag 'for-linus-20161216' of git://git.infradead.org/linux-mtd

Pull MTD updates from Brian Norris:
 "Nothing enormous here, though notably we have some of the first work
  of a few new maintainers. I think for now I'll still be sending pull
  requests, but that's open to change in the future. Summary:

  Core:

   - dynamic BDI object allocation (resolves some problems when built as
     a module)
   - cleanups in the ooblayout handling

  NAND:

   - new tango NAND controller driver
   - new ox820 NAND controller driver
   - addition of a new full-ID entry in the nand_ids table
   - rework of the s3c240 driver to support DT
   - extension of the nand_sdr_timings to expose tCCS, tPROG and tR
   - addition of a new flag to ask the core to wait for tCCS when
     sending a RNDIN/RNDOUT command
   - addition of a new flag to ask the core to let the controller driver
     send the READ/PROGPAGE command

  Minor fixes/cleanup/cosmetic changes:

   - properly support 512 ECC step size in the sunxi driver
   - improve the error messages in the PXA probe path
   - fix module autoload in the omap2 driver
   - cleanup of several nand drivers to return nand_scan{_tail}() error
     code instead of returning -EIO
   - various cleanups in the denali driver
   - fix an error check in nandsim

  SPI NOR:

   - new flash IDs
   - wait for Spansion flash to be ready after quad-enable
   - error handling fixes for Candence QSPI
   - constify some structures in Freescale QSPI driver"

* tag 'for-linus-20161216' of git://git.infradead.org/linux-mtd: (71 commits)
  mtd: Allocate bdi objects dynamically
  mtd: nand: tango: Add standard legalese header
  mtd: maps: add missing iounmap() in error path
  mtd: spi-nor: constify fsl_qspi_devtype_data
  mtd: spi-nor: Add support for mr25h40
  mtd: spi-nor: Add support for N25Q016A
  mtd: spi-nor: Add at25df321 spi-nor flash support
  mtd: spi-nor: Fix some error codes in cqspi_setup_flash()
  mtd: spi-nor: Off by one in cqspi_setup_flash()
  mtd: spi-nor: add support for s25fl208k
  mtd: spi-nor: fix flags for s25fl128s
  mtd: spi-nor: fix spansion quad enable
  mtd: spi-nor: add Macronix mx25u25635f to list of known devices.
  mtd: mtdswap: fix spelling mistake "erassure" -> "erasure"
  mtd: bcm47xxpart: fix parsing first block after aligned TRX
  mtd: nand: tango: Use nand_to_mtd() instead of directly accessing chip->mtd
  mtd: remove unneeded initializer in mtd_ooblayout_count_bytes()
  mtd: use min_t() to refactor mtd_ooblayout_{get, set}_bytes()
  mtd: remove unneeded initializer in mtd_ooblayout_{get, set}_bytes()
  mtd: nand: nandsim: fix error check
  ...
This commit is contained in:
Linus Torvalds 2016-12-17 16:41:10 -08:00
commit c07dee7348
64 changed files with 1555 additions and 351 deletions

View File

@ -0,0 +1,41 @@
* Oxford Semiconductor OXNAS NAND Controller
Please refer to nand.txt for generic information regarding MTD NAND bindings.
Required properties:
- compatible: "oxsemi,ox820-nand"
- reg: Base address and length for NAND mapped memory.
Optional Properties:
- clocks: phandle to the NAND gate clock if needed.
- resets: phandle to the NAND reset control if needed.
Example:
nandc: nand-controller@41000000 {
compatible = "oxsemi,ox820-nand";
reg = <0x41000000 0x100000>;
clocks = <&stdclk CLK_820_NAND>;
resets = <&reset RESET_NAND>;
#address-cells = <1>;
#size-cells = <0>;
nand@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
nand-ecc-mode = "soft";
nand-ecc-algo = "hamming";
partition@0 {
label = "boot";
reg = <0x00000000 0x00e00000>;
read-only;
};
partition@e00000 {
label = "ubi";
reg = <0x00e00000 0x07200000>;
};
};
};

View File

@ -0,0 +1,56 @@
* Samsung S3C2410 and compatible NAND flash controller
Required properties:
- compatible : The possible values are:
"samsung,s3c2410-nand"
"samsung,s3c2412-nand"
"samsung,s3c2440-nand"
- reg : register's location and length.
- #address-cells, #size-cells : see nand.txt
- clocks : phandle to the nand controller clock
- clock-names : must contain "nand"
Optional child nodes:
Child nodes representing the available nand chips.
Optional child properties:
- nand-ecc-mode : see nand.txt
- nand-on-flash-bbt : see nand.txt
Each child device node may optionally contain a 'partitions' sub-node,
which further contains sub-nodes describing the flash partition mapping.
See partition.txt for more detail.
Example:
nand-controller@4e000000 {
compatible = "samsung,s3c2440-nand";
reg = <0x4e000000 0x40>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&clocks HCLK_NAND>;
clock-names = "nand";
nand {
nand-ecc-mode = "soft";
nand-on-flash-bbt;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "u-boot";
reg = <0 0x040000>;
};
partition@40000 {
label = "kernel";
reg = <0x040000 0x500000>;
};
};
};
};

View File

@ -0,0 +1,38 @@
Sigma Designs Tango4 NAND Flash Controller (NFC)
Required properties:
- compatible: "sigma,smp8758-nand"
- reg: address/size of nfc_reg, nfc_mem, and pbus_reg
- dmas: reference to the DMA channel used by the controller
- dma-names: "nfc_sbox"
- clocks: reference to the system clock
- #address-cells: <1>
- #size-cells: <0>
Children nodes represent the available NAND chips.
See Documentation/devicetree/bindings/mtd/nand.txt for generic bindings.
Example:
nandc: nand-controller@2c000 {
compatible = "sigma,smp8758-nand";
reg = <0x2c000 0x30 0x2d000 0x800 0x20000 0x1000>;
dmas = <&dma0 3>;
dma-names = "nfc_sbox";
clocks = <&clkgen SYS_CLK>;
#address-cells = <1>;
#size-cells = <0>;
nand@0 {
reg = <0>; /* CS0 */
nand-ecc-strength = <14>;
nand-ecc-step-size = <1024>;
};
nand@1 {
reg = <1>; /* CS1 */
nand-ecc-strength = <14>;
nand-ecc-step-size = <1024>;
};
};

View File

@ -171,6 +171,7 @@ static struct s3c2410_platform_nand smdk_nand_info = {
.twrph1 = 20,
.nr_sets = ARRAY_SIZE(smdk_nand_sets),
.sets = smdk_nand_sets,
.ecc_mode = NAND_ECC_SOFT,
};
/* devices we initialise */

View File

@ -223,6 +223,7 @@ static struct s3c2410_platform_nand __initdata anubis_nand_info = {
.nr_sets = ARRAY_SIZE(anubis_nand_sets),
.sets = anubis_nand_sets,
.select_chip = anubis_nand_select,
.ecc_mode = NAND_ECC_SOFT,
};
/* IDE channels */

View File

@ -114,6 +114,7 @@ static struct s3c2410_platform_nand __initdata at2440evb_nand_info = {
.twrph1 = 40,
.nr_sets = ARRAY_SIZE(at2440evb_nand_sets),
.sets = at2440evb_nand_sets,
.ecc_mode = NAND_ECC_SOFT,
};
/* DM9000AEP 10/100 ethernet controller */

View File

@ -299,6 +299,7 @@ static struct s3c2410_platform_nand __initdata bast_nand_info = {
.nr_sets = ARRAY_SIZE(bast_nand_sets),
.sets = bast_nand_sets,
.select_chip = bast_nand_select,
.ecc_mode = NAND_ECC_SOFT,
};
/* DM9000 */

View File

@ -443,6 +443,7 @@ static struct s3c2410_platform_nand __initdata gta02_nand_info = {
.twrph1 = 15,
.nr_sets = ARRAY_SIZE(gta02_nand_sets),
.sets = gta02_nand_sets,
.ecc_mode = NAND_ECC_SOFT,
};

View File

@ -232,6 +232,7 @@ static struct s3c2410_platform_nand __initdata jive_nand_info = {
.twrph1 = 40,
.sets = jive_nand_sets,
.nr_sets = ARRAY_SIZE(jive_nand_sets),
.ecc_mode = NAND_ECC_SOFT,
};
static int __init jive_mtdset(char *options)

View File

@ -287,6 +287,7 @@ static struct s3c2410_platform_nand mini2440_nand_info __initdata = {
.nr_sets = ARRAY_SIZE(mini2440_nand_sets),
.sets = mini2440_nand_sets,
.ignore_unset_ecc = 1,
.ecc_mode = NAND_ECC_SOFT,
};
/* DM9000AEP 10/100 ethernet controller */

View File

@ -238,6 +238,7 @@ static struct s3c2410_platform_nand __initdata osiris_nand_info = {
.nr_sets = ARRAY_SIZE(osiris_nand_sets),
.sets = osiris_nand_sets,
.select_chip = osiris_nand_select,
.ecc_mode = NAND_ECC_SOFT,
};
/* PCMCIA control and configuration */

View File

@ -284,6 +284,7 @@ static struct s3c2410_platform_nand __initdata qt2410_nand_info = {
.twrph1 = 20,
.nr_sets = ARRAY_SIZE(qt2410_nand_sets),
.sets = qt2410_nand_sets,
.ecc_mode = NAND_ECC_SOFT,
};
/* UDC */

View File

@ -611,6 +611,7 @@ static struct s3c2410_platform_nand rx1950_nand_info = {
.twrph1 = 15,
.nr_sets = ARRAY_SIZE(rx1950_nand_sets),
.sets = rx1950_nand_sets,
.ecc_mode = NAND_ECC_SOFT,
};
static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {

View File

@ -164,6 +164,7 @@ static struct s3c2410_platform_nand __initdata rx3715_nand_info = {
.twrph1 = 15,
.nr_sets = ARRAY_SIZE(rx3715_nand_sets),
.sets = rx3715_nand_sets,
.ecc_mode = NAND_ECC_SOFT,
};
static struct platform_device *rx3715_devices[] __initdata = {

View File

@ -117,6 +117,7 @@ static struct s3c2410_platform_nand __initdata vstms_nand_info = {
.twrph1 = 20,
.nr_sets = ARRAY_SIZE(vstms_nand_sets),
.sets = vstms_nand_sets,
.ecc_mode = NAND_ECC_SOFT,
};
static struct platform_device *vstms_devices[] __initdata = {

View File

@ -204,6 +204,7 @@ static struct s3c2410_platform_nand hmt_nand_info = {
.twrph1 = 40,
.nr_sets = ARRAY_SIZE(hmt_nand_sets),
.sets = hmt_nand_sets,
.ecc_mode = NAND_ECC_SOFT,
};
static struct gpio_led hmt_leds[] = {

View File

@ -142,6 +142,7 @@ static struct s3c2410_platform_nand mini6410_nand_info = {
.twrph1 = 40,
.nr_sets = ARRAY_SIZE(mini6410_nand_sets),
.sets = mini6410_nand_sets,
.ecc_mode = NAND_ECC_SOFT,
};
static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = {

View File

@ -194,6 +194,7 @@ static struct s3c2410_platform_nand real6410_nand_info = {
.twrph1 = 40,
.nr_sets = ARRAY_SIZE(real6410_nand_sets),
.sets = real6410_nand_sets,
.ecc_mode = NAND_ECC_SOFT,
};
static struct platform_device *real6410_devices[] __initdata = {

View File

@ -229,12 +229,10 @@ static int bcm47xxpart_parse(struct mtd_info *master,
last_trx_part = curr_part - 1;
/*
* We have whole TRX scanned, skip to the next part. Use
* roundown (not roundup), as the loop will increase
* offset in next step.
*/
offset = rounddown(offset + trx->length, blocksize);
/* Jump to the end of TRX */
offset = roundup(offset + trx->length, blocksize);
/* Next loop iteration will increase the offset */
offset -= blocksize;
continue;
}

View File

@ -296,16 +296,30 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
dev_err(dev, "can't request region for resource %pR\n", res);
return -EBUSY;
}
b47s->window = ioremap_cache(res->start, resource_size(res));
if (!b47s->window) {
dev_err(dev, "ioremap failed for resource %pR\n", res);
return -ENOMEM;
}
b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
b47s->cc_read = bcm47xxsflash_bcma_cc_read;
b47s->cc_write = bcm47xxsflash_bcma_cc_write;
/*
* On old MIPS devices cache was magically invalidated when needed,
* allowing us to use cached access and gain some performance. Trying
* the same on ARM based BCM53573 results in flash corruptions, we need
* to use uncached access for it.
*
* It may be arch specific, but right now there is only 1 ARM SoC using
* this driver, so let's follow Broadcom's reference code and check
* ChipCommon revision.
*/
if (b47s->bcma_cc->core->id.rev == 54)
b47s->window = ioremap_nocache(res->start, resource_size(res));
else
b47s->window = ioremap_cache(res->start, resource_size(res));
if (!b47s->window) {
dev_err(dev, "ioremap failed for resource %pR\n", res);
return -ENOMEM;
}
switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
case BCMA_CC_FLASHT_STSER:
b47s->type = BCM47XXSFLASH_TYPE_ST;

View File

@ -227,7 +227,7 @@ static void sc520cdp_setup_par(void)
static int __init init_sc520cdp(void)
{
int i, devices_found = 0;
int i, j, devices_found = 0;
#ifdef REPROGRAM_PAR
/* reprogram PAR registers so flash appears at the desired addresses */
@ -243,6 +243,12 @@ static int __init init_sc520cdp(void)
if (!sc520cdp_map[i].virt) {
printk("Failed to ioremap_nocache\n");
for (j = 0; j < i; j++) {
if (mymtd[j]) {
map_destroy(mymtd[j]);
iounmap(sc520cdp_map[j].virt);
}
}
return -EIO;
}

View File

@ -46,8 +46,7 @@
#include "mtdcore.h"
static struct backing_dev_info mtd_bdi = {
};
static struct backing_dev_info *mtd_bdi;
#ifdef CONFIG_PM_SLEEP
@ -500,7 +499,7 @@ int add_mtd_device(struct mtd_info *mtd)
if (WARN_ONCE(mtd->backing_dev_info, "MTD already registered\n"))
return -EEXIST;
mtd->backing_dev_info = &mtd_bdi;
mtd->backing_dev_info = mtd_bdi;
BUG_ON(mtd->writesize == 0);
mutex_lock(&mtd_table_mutex);
@ -1274,8 +1273,8 @@ static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
int section,
struct mtd_oob_region *oobregion))
{
struct mtd_oob_region oobregion = { };
int section = 0, ret;
struct mtd_oob_region oobregion;
int section, ret;
ret = mtd_ooblayout_find_region(mtd, start, &section,
&oobregion, iter);
@ -1283,7 +1282,7 @@ static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
while (!ret) {
int cnt;
cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
cnt = min_t(int, nbytes, oobregion.length);
memcpy(buf, oobbuf + oobregion.offset, cnt);
buf += cnt;
nbytes -= cnt;
@ -1317,8 +1316,8 @@ static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
int section,
struct mtd_oob_region *oobregion))
{
struct mtd_oob_region oobregion = { };
int section = 0, ret;
struct mtd_oob_region oobregion;
int section, ret;
ret = mtd_ooblayout_find_region(mtd, start, &section,
&oobregion, iter);
@ -1326,7 +1325,7 @@ static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
while (!ret) {
int cnt;
cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
cnt = min_t(int, nbytes, oobregion.length);
memcpy(oobbuf + oobregion.offset, buf, cnt);
buf += cnt;
nbytes -= cnt;
@ -1354,7 +1353,7 @@ static int mtd_ooblayout_count_bytes(struct mtd_info *mtd,
int section,
struct mtd_oob_region *oobregion))
{
struct mtd_oob_region oobregion = { };
struct mtd_oob_region oobregion;
int section = 0, ret, nbytes = 0;
while (1) {
@ -1771,18 +1770,20 @@ static const struct file_operations mtd_proc_ops = {
/*====================================================================*/
/* Init code */
static int __init mtd_bdi_init(struct backing_dev_info *bdi, const char *name)
static struct backing_dev_info * __init mtd_bdi_init(char *name)
{
struct backing_dev_info *bdi;
int ret;
ret = bdi_init(bdi);
if (!ret)
ret = bdi_register(bdi, NULL, "%s", name);
bdi = kzalloc(sizeof(*bdi), GFP_KERNEL);
if (!bdi)
return ERR_PTR(-ENOMEM);
ret = bdi_setup_and_register(bdi, name);
if (ret)
bdi_destroy(bdi);
kfree(bdi);
return ret;
return ret ? ERR_PTR(ret) : bdi;
}
static struct proc_dir_entry *proc_mtd;
@ -1795,9 +1796,11 @@ static int __init init_mtd(void)
if (ret)
goto err_reg;
ret = mtd_bdi_init(&mtd_bdi, "mtd");
if (ret)
mtd_bdi = mtd_bdi_init("mtd");
if (IS_ERR(mtd_bdi)) {
ret = PTR_ERR(mtd_bdi);
goto err_bdi;
}
proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops);
@ -1810,6 +1813,8 @@ static int __init init_mtd(void)
out_procfs:
if (proc_mtd)
remove_proc_entry("mtd", NULL);
bdi_destroy(mtd_bdi);
kfree(mtd_bdi);
err_bdi:
class_unregister(&mtd_class);
err_reg:
@ -1823,7 +1828,8 @@ static void __exit cleanup_mtd(void)
if (proc_mtd)
remove_proc_entry("mtd", NULL);
class_unregister(&mtd_class);
bdi_destroy(&mtd_bdi);
bdi_destroy(mtd_bdi);
kfree(mtd_bdi);
idr_destroy(&mtd_idr);
}

View File

@ -587,7 +587,7 @@ retry:
ret = wait_event_interruptible(wq, erase.state == MTD_ERASE_DONE ||
erase.state == MTD_ERASE_FAILED);
if (ret) {
dev_err(d->dev, "Interrupted erase block %#llx erassure on %s",
dev_err(d->dev, "Interrupted erase block %#llx erasure on %s\n",
erase.addr, mtd->name);
return -EINTR;
}

View File

@ -179,15 +179,6 @@ config MTD_NAND_S3C2410_DEBUG
help
Enable debugging of the S3C NAND driver
config MTD_NAND_S3C2410_HWECC
bool "Samsung S3C NAND Hardware ECC"
depends on MTD_NAND_S3C2410
help
Enable the use of the controller's internal ECC generator when
using NAND. Early versions of the chips have had problems with
incorrect ECC generation, and if using these, the default of
software ECC is preferable.
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
depends on 4xx
@ -205,6 +196,13 @@ config MTD_NAND_S3C2410_CLKSTOP
when the is NAND chip selected or released, but will save
approximately 5mA of power when there is nothing happening.
config MTD_NAND_TANGO
tristate "NAND Flash support for Tango chips"
depends on ARCH_TANGO || COMPILE_TEST
depends on HAS_DMA
help
Enables the NAND Flash controller on Tango chips.
config MTD_NAND_DISKONCHIP
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
depends on HAS_IOMEM
@ -426,6 +424,11 @@ config MTD_NAND_ORION
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
config MTD_NAND_OXNAS
tristate "NAND Flash support for Oxford Semiconductor SoC"
help
This enables the NAND flash controller on Oxford Semiconductor SoCs.
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on FSL_SOC

View File

@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
obj-$(CONFIG_MTD_NAND_TANGO) += tango_nand.o
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o
@ -35,6 +36,7 @@ obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o

View File

@ -234,10 +234,9 @@ static int ams_delta_init(struct platform_device *pdev)
goto out_gpio;
/* Scan to find existence of the device */
if (nand_scan(ams_delta_mtd, 1)) {
err = -ENXIO;
err = nand_scan(ams_delta_mtd, 1);
if (err)
goto out_mtd;
}
/* Register the partitions */
mtd_device_register(ams_delta_mtd, partition_info,

View File

@ -2267,10 +2267,9 @@ static int atmel_nand_probe(struct platform_device *pdev)
dev_info(host->dev, "No DMA support for NAND access.\n");
/* first scan to find the device and get the page size */
if (nand_scan_ident(mtd, 1, NULL)) {
res = -ENXIO;
res = nand_scan_ident(mtd, 1, NULL);
if (res)
goto err_scan_ident;
}
if (host->board.on_flash_bbt || on_flash_bbt)
nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
@ -2304,10 +2303,9 @@ static int atmel_nand_probe(struct platform_device *pdev)
}
/* second phase scan */
if (nand_scan_tail(mtd)) {
res = -ENXIO;
res = nand_scan_tail(mtd);
if (res)
goto err_scan_tail;
}
mtd->name = "atmel_nand";
res = mtd_device_register(mtd, host->board.parts,

View File

@ -2209,8 +2209,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
nand_writereg(ctrl, cfg_offs,
nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
if (nand_scan_ident(mtd, 1, NULL))
return -ENXIO;
ret = nand_scan_ident(mtd, 1, NULL);
if (ret)
return ret;
chip->options |= NAND_NO_SUBPAGE_WRITE;
/*
@ -2234,8 +2235,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
if (ret)
return ret;
if (nand_scan_tail(mtd))
return -ENXIO;
ret = nand_scan_tail(mtd);
if (ret)
return ret;
return mtd_device_register(mtd, NULL, 0);
}

View File

@ -725,10 +725,9 @@ static int cafe_nand_probe(struct pci_dev *pdev,
usedma = 0;
/* Scan to find existence of the device */
if (nand_scan_ident(mtd, 2, NULL)) {
err = -ENXIO;
err = nand_scan_ident(mtd, 2, NULL);
if (err)
goto out_irq;
}
cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev,
2112 + sizeof(struct nand_buffers) +

View File

@ -195,9 +195,9 @@ static int __init cmx270_init(void)
this->write_buf = cmx270_write_buf;
/* Scan to find existence of the device */
if (nand_scan (cmx270_nand_mtd, 1)) {
ret = nand_scan(cmx270_nand_mtd, 1);
if (ret) {
pr_notice("No NAND device\n");
ret = -ENXIO;
goto err_scan;
}

View File

@ -242,10 +242,9 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
}
/* Scan to find existence of the device */
if (nand_scan(new_mtd, 1)) {
err = -ENXIO;
err = nand_scan(new_mtd, 1);
if (err)
goto out_free;
}
cs553x_mtd[cs] = new_mtd;
goto out;

View File

@ -21,7 +21,6 @@
#include <linux/dma-mapping.h>
#include <linux/wait.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/module.h>
@ -182,9 +181,6 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali)
{
int i;
dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
__FILE__, __LINE__, __func__);
for (i = 0; i < denali->max_banks; i++)
iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
denali->flash_reg + INTR_STATUS(i));
@ -234,9 +230,6 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
uint16_t acc_clks;
uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt;
dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
__FILE__, __LINE__, __func__);
en_lo = CEIL_DIV(Trp[mode], CLK_X);
en_hi = CEIL_DIV(Treh[mode], CLK_X);
#if ONFI_BLOOM_TIME
@ -403,7 +396,7 @@ static void get_hynix_nand_para(struct denali_nand_info *denali,
break;
default:
dev_warn(denali->dev,
"Spectra: Unknown Hynix NAND (Device ID: 0x%x).\n"
"Unknown Hynix NAND (Device ID: 0x%x).\n"
"Will use default parameter values instead.\n",
device_id);
}
@ -474,33 +467,6 @@ static void detect_max_banks(struct denali_nand_info *denali)
denali->max_banks = 1 << (features & FEATURES__N_BANKS);
}
static void detect_partition_feature(struct denali_nand_info *denali)
{
/*
* For MRST platform, denali->fwblks represent the
* number of blocks firmware is taken,
* FW is in protect partition and MTD driver has no
* permission to access it. So let driver know how many
* blocks it can't touch.
*/
if (ioread32(denali->flash_reg + FEATURES) & FEATURES__PARTITION) {
if ((ioread32(denali->flash_reg + PERM_SRC_ID(1)) &
PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) {
denali->fwblks =
((ioread32(denali->flash_reg + MIN_MAX_BANK(1)) &
MIN_MAX_BANK__MIN_VALUE) *
denali->blksperchip)
+
(ioread32(denali->flash_reg + MIN_BLK_ADDR(1)) &
MIN_BLK_ADDR__VALUE);
} else {
denali->fwblks = SPECTRA_START_BLOCK;
}
} else {
denali->fwblks = SPECTRA_START_BLOCK;
}
}
static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
{
uint16_t status = PASS;
@ -508,9 +474,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
uint8_t maf_id, device_id;
int i;
dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
__FILE__, __LINE__, __func__);
/*
* Use read id method to get device ID and other params.
* For some NAND chips, controller can't report the correct
@ -552,8 +515,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
find_valid_banks(denali);
detect_partition_feature(denali);
/*
* If the user specified to override the default timings
* with a specific ONFI mode, we apply those changes here.
@ -567,9 +528,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
static void denali_set_intr_modes(struct denali_nand_info *denali,
uint16_t INT_ENABLE)
{
dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
__FILE__, __LINE__, __func__);
if (INT_ENABLE)
iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE);
else
@ -605,7 +563,6 @@ static void denali_irq_init(struct denali_nand_info *denali)
static void denali_irq_cleanup(int irqnum, struct denali_nand_info *denali)
{
denali_set_intr_modes(denali, false);
free_irq(irqnum, denali);
}
static void denali_irq_enable(struct denali_nand_info *denali,
@ -1437,9 +1394,6 @@ static struct nand_bbt_descr bbt_mirror_descr = {
/* initialize driver data structures */
static void denali_drv_init(struct denali_nand_info *denali)
{
denali->idx = 0;
/* setup interrupt handler */
/*
* the completion object will be used to notify
* the callee that the interrupt is done
@ -1485,14 +1439,12 @@ int denali_init(struct denali_nand_info *denali)
denali_hw_init(denali);
denali_drv_init(denali);
/*
* denali_isr register is done after all the hardware
* initilization is finished
*/
if (request_irq(denali->irq, denali_isr, IRQF_SHARED,
DENALI_NAND_NAME, denali)) {
pr_err("Spectra: Unable to allocate IRQ\n");
return -ENODEV;
/* Request IRQ after all the hardware initialization is finished */
ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
IRQF_SHARED, DENALI_NAND_NAME, denali);
if (ret) {
dev_err(denali->dev, "Unable to request IRQ\n");
return ret;
}
/* now that our ISR is registered, we can enable interrupts */
@ -1510,10 +1462,9 @@ int denali_init(struct denali_nand_info *denali)
* this is the first stage in a two step process to register
* with the nand subsystem
*/
if (nand_scan_ident(mtd, denali->max_banks, NULL)) {
ret = -ENXIO;
ret = nand_scan_ident(mtd, denali->max_banks, NULL);
if (ret)
goto failed_req_irq;
}
/* allocate the right size buffer now */
devm_kfree(denali->dev, denali->buf.buf);
@ -1528,7 +1479,7 @@ int denali_init(struct denali_nand_info *denali)
/* Is 32-bit DMA supported? */
ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
if (ret) {
pr_err("Spectra: no usable DMA configuration\n");
dev_err(denali->dev, "No usable DMA configuration\n");
goto failed_req_irq;
}
@ -1536,7 +1487,7 @@ int denali_init(struct denali_nand_info *denali)
mtd->writesize + mtd->oobsize,
DMA_BIDIRECTIONAL);
if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
dev_err(denali->dev, "Spectra: failed to map DMA buffer\n");
dev_err(denali->dev, "Failed to map DMA buffer\n");
ret = -EIO;
goto failed_req_irq;
}
@ -1547,16 +1498,16 @@ int denali_init(struct denali_nand_info *denali)
* the real pagesize and anything necessery
*/
denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
denali->nand.chipsize <<= (denali->devnum - 1);
denali->nand.page_shift += (denali->devnum - 1);
denali->nand.chipsize <<= denali->devnum - 1;
denali->nand.page_shift += denali->devnum - 1;
denali->nand.pagemask = (denali->nand.chipsize >>
denali->nand.page_shift) - 1;
denali->nand.bbt_erase_shift += (denali->devnum - 1);
denali->nand.bbt_erase_shift += denali->devnum - 1;
denali->nand.phys_erase_shift = denali->nand.bbt_erase_shift;
denali->nand.chip_shift += (denali->devnum - 1);
mtd->writesize <<= (denali->devnum - 1);
mtd->oobsize <<= (denali->devnum - 1);
mtd->erasesize <<= (denali->devnum - 1);
denali->nand.chip_shift += denali->devnum - 1;
mtd->writesize <<= denali->devnum - 1;
mtd->oobsize <<= denali->devnum - 1;
mtd->erasesize <<= denali->devnum - 1;
mtd->size = denali->nand.numchips * denali->nand.chipsize;
denali->bbtskipbytes *= denali->devnum;
@ -1606,14 +1557,6 @@ int denali_init(struct denali_nand_info *denali)
denali->nand.ecc.bytes *= denali->devnum;
denali->nand.ecc.strength *= denali->devnum;
/*
* Let driver know the total blocks number and how many blocks
* contained by each nand chip. blksperchip will help driver to
* know how many blocks is taken by FW.
*/
denali->totalblks = mtd->size >> denali->nand.phys_erase_shift;
denali->blksperchip = denali->totalblks / denali->nand.numchips;
/* override the default read operations */
denali->nand.ecc.size = ECC_SECTOR_SIZE * denali->devnum;
denali->nand.ecc.read_page = denali_read_page;
@ -1624,15 +1567,13 @@ int denali_init(struct denali_nand_info *denali)
denali->nand.ecc.write_oob = denali_write_oob;
denali->nand.erase = denali_erase;
if (nand_scan_tail(mtd)) {
ret = -ENXIO;
ret = nand_scan_tail(mtd);
if (ret)
goto failed_req_irq;
}
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(denali->dev, "Spectra: Failed to register MTD: %d\n",
ret);
dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
goto failed_req_irq;
}
return 0;

View File

@ -383,14 +383,6 @@
#define CLK_X 5
#define CLK_MULTI 4
/* spectraswconfig.h */
#define CMD_DMA 0
#define SPECTRA_PARTITION_ID 0
/**** Block Table and Reserved Block Parameters *****/
#define SPECTRA_START_BLOCK 3
#define NUM_FREE_BLOCKS_GATE 30
/* KBV - Updated to LNW scratch register address */
#define SCRATCH_REG_ADDR CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR
#define SCRATCH_REG_SIZE 64
@ -467,13 +459,9 @@ struct denali_nand_info {
spinlock_t irq_lock;
uint32_t irq_status;
int irq_debug_array[32];
int idx;
int irq;
uint32_t devnum; /* represent how many nands connected */
uint32_t fwblks; /* represent how many blocks FW used */
uint32_t totalblks;
uint32_t blksperchip;
uint32_t bbtskipbytes;
uint32_t max_banks;
};

View File

@ -21,7 +21,6 @@
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include "denali.h"
@ -110,7 +109,7 @@ static int denali_dt_remove(struct platform_device *ofdev)
struct denali_dt *dt = platform_get_drvdata(ofdev);
denali_remove(&dt->denali);
clk_disable(dt->clk);
clk_disable_unprepare(dt->clk);
return 0;
}

View File

@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include "denali.h"

View File

@ -926,8 +926,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
/*
* Scan to find existence of the device
*/
if (nand_scan_ident(mtd, 1, NULL)) {
ret = -ENXIO;
ret = nand_scan_ident(mtd, 1, NULL);
if (ret) {
dev_err(&pdev->dev, "No NAND Device found!\n");
goto err_scan_ident;
}
@ -992,10 +992,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
}
/* Second stage of scan to fill MTD data-structures */
if (nand_scan_tail(mtd)) {
ret = -ENXIO;
ret = nand_scan_tail(mtd);
if (ret)
goto err_probe;
}
/*
* The partition information can is accessed by (in the same precedence)

View File

@ -286,10 +286,9 @@ static int gpio_nand_probe(struct platform_device *pdev)
if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
if (nand_scan(mtd, 1)) {
ret = -ENXIO;
ret = nand_scan(mtd, 1);
if (ret)
goto err_wp;
}
if (gpiomtd->plat.adjust_parts)
gpiomtd->plat.adjust_parts(&gpiomtd->plat, mtd->size);

View File

@ -774,10 +774,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
}
ret = nand_scan_ident(mtd, max_chips, NULL);
if (ret) {
ret = -ENODEV;
if (ret)
goto err_res;
}
host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
&host->dma_buffer, GFP_KERNEL);

View File

@ -747,10 +747,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
* Scan to find existance of the device and
* Get the type of NAND device SMALL block or LARGE block
*/
if (nand_scan_ident(mtd, 1, NULL)) {
res = -ENXIO;
res = nand_scan_ident(mtd, 1, NULL);
if (res)
goto err_exit3;
}
host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
if (!host->dma_buf) {
@ -793,10 +792,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
* Fills out all the uninitialized function pointers with the defaults
* And scans for a bad block table if appropriate.
*/
if (nand_scan_tail(mtd)) {
res = -ENXIO;
res = nand_scan_tail(mtd);
if (res)
goto err_exit4;
}
mtd->name = DRV_NAME;

View File

@ -894,10 +894,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
}
/* Find NAND device */
if (nand_scan_ident(mtd, 1, NULL)) {
res = -ENXIO;
res = nand_scan_ident(mtd, 1, NULL);
if (res)
goto err_exit3;
}
/* OOB and ECC CPU and DMA work areas */
host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
@ -929,10 +928,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
/*
* Fills out all the uninitialized function pointers with the defaults
*/
if (nand_scan_tail(mtd)) {
res = -ENXIO;
res = nand_scan_tail(mtd);
if (res)
goto err_exit3;
}
mtd->name = "nxp_lpc3220_slc";
res = mtd_device_register(mtd, host->ncfg->parts,

View File

@ -777,9 +777,9 @@ static int mpc5121_nfc_probe(struct platform_device *op)
}
/* Detect NAND chips */
if (nand_scan(mtd, be32_to_cpup(chips_no))) {
retval = nand_scan(mtd, be32_to_cpup(chips_no));
if (retval) {
dev_err(dev, "NAND Flash not found !\n");
retval = -ENXIO;
goto error;
}

View File

@ -1297,7 +1297,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
ret = nand_scan_ident(mtd, nsels, NULL);
if (ret)
return -ENODEV;
return ret;
/* store bbt magic in page, cause OOB is not protected */
if (nand->bbt_options & NAND_BBT_USE_FLASH)
@ -1323,7 +1323,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
ret = nand_scan_tail(mtd);
if (ret)
return -ENODEV;
return ret;
ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
if (ret) {

View File

@ -1747,10 +1747,9 @@ static int mxcnd_probe(struct platform_device *pdev)
}
/* first scan to find the device and get the page size */
if (nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL)) {
err = -ENXIO;
err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL);
if (err)
goto escan;
}
switch (this->ecc.mode) {
case NAND_ECC_HW:
@ -1808,10 +1807,9 @@ static int mxcnd_probe(struct platform_device *pdev)
}
/* second phase scan */
if (nand_scan_tail(mtd)) {
err = -ENXIO;
err = nand_scan_tail(mtd);
if (err)
goto escan;
}
/* Register the partitions */
mtd_device_parse_register(mtd, part_probes,

View File

@ -709,6 +709,25 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
nand_wait_ready(mtd);
}
static void nand_ccs_delay(struct nand_chip *chip)
{
/*
* The controller already takes care of waiting for tCCS when the RNDIN
* or RNDOUT command is sent, return directly.
*/
if (!(chip->options & NAND_WAIT_TCCS))
return;
/*
* Wait tCCS_min if it is correctly defined, otherwise wait 500ns
* (which should be safe for all NANDs).
*/
if (chip->data_interface && chip->data_interface->timings.sdr.tCCS_min)
ndelay(chip->data_interface->timings.sdr.tCCS_min / 1000);
else
ndelay(500);
}
/**
* nand_command_lp - [DEFAULT] Send command to NAND large page device
* @mtd: MTD device structure
@ -773,10 +792,13 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_RNDIN:
case NAND_CMD_STATUS:
return;
case NAND_CMD_RNDIN:
nand_ccs_delay(chip);
return;
case NAND_CMD_RESET:
if (chip->dev_ready)
break;
@ -795,6 +817,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);
nand_ccs_delay(chip);
return;
case NAND_CMD_READ0:
@ -1946,7 +1970,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
__func__, buf);
read_retry:
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
if (nand_standard_page_accessors(&chip->ecc))
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
/*
* Now read the page into the buffer. Absent an error,
@ -2634,7 +2659,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
else
subpage = 0;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
if (nand_standard_page_accessors(&chip->ecc))
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
if (unlikely(raw))
status = chip->ecc.write_page_raw(mtd, chip, buf,
@ -2657,7 +2683,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
if (!cached || !NAND_HAS_CACHEPROG(chip)) {
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
if (nand_standard_page_accessors(&chip->ecc))
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
/*
* See if operation failed and additional status checks are
@ -3985,10 +4012,9 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
/*
* 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 *maf_id, int *dev_id,
struct nand_flash_dev *type)
static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
int *maf_id, int *dev_id,
struct nand_flash_dev *type)
{
int busw;
int i, maf_idx;
@ -4026,7 +4052,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
*maf_id, *dev_id, id_data[0], id_data[1]);
return ERR_PTR(-ENODEV);
return -ENODEV;
}
if (!type)
@ -4053,7 +4079,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
}
if (!type->name)
return ERR_PTR(-ENODEV);
return -ENODEV;
if (!mtd->name)
mtd->name = type->name;
@ -4098,7 +4124,7 @@ ident_done:
pr_warn("bus width %d instead %d bit\n",
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
busw ? 16 : 8);
return ERR_PTR(-EINVAL);
return -EINVAL;
}
nand_decode_bbm_options(mtd, chip, id_data);
@ -4140,7 +4166,7 @@ ident_done:
pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
return type;
return 0;
}
static const char * const nand_ecc_modes[] = {
@ -4306,7 +4332,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
{
int i, nand_maf_id, nand_dev_id;
struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_flash_dev *type;
int ret;
ret = nand_dt_init(chip);
@ -4329,14 +4354,12 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
/* Read the flash type */
type = nand_get_flash_type(mtd, chip, &nand_maf_id,
&nand_dev_id, table);
if (IS_ERR(type)) {
ret = nand_get_flash_type(mtd, chip, &nand_maf_id, &nand_dev_id, table);
if (ret) {
if (!(chip->options & NAND_SCAN_SILENT_NODEV))
pr_warn("No NAND device found\n");
chip->select_chip(mtd, -1);
return PTR_ERR(type);
return ret;
}
/* Initialize the ->data_interface field. */
@ -4515,6 +4538,26 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
}
static bool invalid_ecc_page_accessors(struct nand_chip *chip)
{
struct nand_ecc_ctrl *ecc = &chip->ecc;
if (nand_standard_page_accessors(ecc))
return false;
/*
* NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND
* controller driver implements all the page accessors because
* default helpers are not suitable when the core does not
* send the READ0/PAGEPROG commands.
*/
return (!ecc->read_page || !ecc->write_page ||
!ecc->read_page_raw || !ecc->write_page_raw ||
(NAND_HAS_SUBPAGE_READ(chip) && !ecc->read_subpage) ||
(NAND_HAS_SUBPAGE_WRITE(chip) && !ecc->write_subpage &&
ecc->hwctl && ecc->calculate));
}
/**
* nand_scan_tail - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
@ -4535,6 +4578,11 @@ int nand_scan_tail(struct mtd_info *mtd)
!(chip->bbt_options & NAND_BBT_USE_FLASH)))
return -EINVAL;
if (invalid_ecc_page_accessors(chip)) {
pr_err("Invalid ECC page accessors setup\n");
return -EINVAL;
}
if (!(chip->options & NAND_OWN_BUFFERS)) {
nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
+ mtd->oobsize * 3, GFP_KERNEL);

View File

@ -36,6 +36,9 @@ struct nand_flash_dev nand_flash_ids[] = {
{"TC58NVG2S0F 4G 3.3V 8-bit",
{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
{"TC58NVG2S0H 4G 3.3V 8-bit",
{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} },
SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) },
{"TC58NVG3S0F 8G 3.3V 8-bit",
{ .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },

View File

@ -18,6 +18,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
{
.type = NAND_SDR_IFACE,
.timings.sdr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 20000,
.tALS_min = 50000,
@ -58,6 +60,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
{
.type = NAND_SDR_IFACE,
.timings.sdr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 10000,
.tALS_min = 25000,
@ -98,6 +102,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
{
.type = NAND_SDR_IFACE,
.timings.sdr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 10000,
.tALS_min = 15000,
@ -138,6 +144,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
{
.type = NAND_SDR_IFACE,
.timings.sdr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 5000,
.tALS_min = 10000,
@ -178,6 +186,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
{
.type = NAND_SDR_IFACE,
.timings.sdr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 5000,
.tALS_min = 10000,
@ -218,6 +228,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
{
.type = NAND_SDR_IFACE,
.timings.sdr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 5000,
.tALS_min = 10000,
@ -290,10 +302,22 @@ int onfi_init_data_interface(struct nand_chip *chip,
*iface = onfi_sdr_timings[timing_mode];
/*
* TODO: initialize timings that cannot be deduced from timing mode:
* Initialize timings that cannot be deduced from timing mode:
* tR, tPROG, tCCS, ...
* These information are part of the ONFI parameter page.
*/
if (chip->onfi_version) {
struct nand_onfi_params *params = &chip->onfi_params;
struct nand_sdr_timings *timings = &iface->timings.sdr;
/* microseconds -> picoseconds */
timings->tPROG_max = 1000000UL * le16_to_cpu(params->t_prog);
timings->tBERS_max = 1000000UL * le16_to_cpu(params->t_bers);
timings->tR_max = 1000000UL * le16_to_cpu(params->t_r);
/* nanoseconds -> picoseconds */
timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs);
}
return 0;
}

View File

@ -525,24 +525,20 @@ static int nandsim_debugfs_create(struct nandsim *dev)
{
struct nandsim_debug_info *dbg = &dev->dbg;
struct dentry *dent;
int err;
if (!IS_ENABLED(CONFIG_DEBUG_FS))
return 0;
dent = debugfs_create_dir("nandsim", NULL);
if (IS_ERR_OR_NULL(dent)) {
int err = dent ? -ENODEV : PTR_ERR(dent);
NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n",
err);
return err;
if (!dent) {
NS_ERR("cannot create \"nandsim\" debugfs directory\n");
return -ENODEV;
}
dbg->dfs_root = dent;
dent = debugfs_create_file("wear_report", S_IRUSR,
dbg->dfs_root, dev, &dfs_fops);
if (IS_ERR_OR_NULL(dent))
if (!dent)
goto out_remove;
dbg->dfs_wear_report = dent;
@ -550,8 +546,7 @@ static int nandsim_debugfs_create(struct nandsim *dev)
out_remove:
debugfs_remove_recursive(dbg->dfs_root);
err = dent ? PTR_ERR(dent) : -ENODEV;
return err;
return -ENODEV;
}
/**
@ -2313,8 +2308,6 @@ static int __init ns_init_module(void)
retval = nand_scan_ident(nsmtd, 1, NULL);
if (retval) {
NS_ERR("cannot scan NAND Simulator device\n");
if (retval > 0)
retval = -ENXIO;
goto error;
}
@ -2350,8 +2343,6 @@ static int __init ns_init_module(void)
retval = nand_scan_tail(nsmtd);
if (retval) {
NS_ERR("can't register NAND Simulator\n");
if (retval > 0)
retval = -ENXIO;
goto error;
}

View File

@ -1895,10 +1895,10 @@ static int omap_nand_probe(struct platform_device *pdev)
/* scan NAND device connected to chip controller */
nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
if (nand_scan_ident(mtd, 1, NULL)) {
err = nand_scan_ident(mtd, 1, NULL);
if (err) {
dev_err(&info->pdev->dev,
"scan failed, may be bus-width mismatch\n");
err = -ENXIO;
goto return_error;
}
@ -2154,10 +2154,9 @@ static int omap_nand_probe(struct platform_device *pdev)
scan_tail:
/* second phase scan */
if (nand_scan_tail(mtd)) {
err = -ENXIO;
err = nand_scan_tail(mtd);
if (err)
goto return_error;
}
if (dev->of_node)
mtd_device_register(mtd, NULL, 0);
@ -2197,6 +2196,7 @@ static const struct of_device_id omap_nand_ids[] = {
{ .compatible = "ti,omap2-nand", },
{},
};
MODULE_DEVICE_TABLE(of, omap_nand_ids);
static struct platform_driver omap_nand_driver = {
.probe = omap_nand_probe,

View File

@ -155,10 +155,9 @@ static int __init orion_nand_probe(struct platform_device *pdev)
clk_put(clk);
}
if (nand_scan(mtd, 1)) {
ret = -ENXIO;
ret = nand_scan(mtd, 1);
if (ret)
goto no_dev;
}
mtd->name = "orion_nand";
ret = mtd_device_register(mtd, board->parts, board->nr_parts);

View File

@ -0,0 +1,195 @@
/*
* Oxford Semiconductor OXNAS NAND driver
* Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
* Heavily based on plat_nand.c :
* Author: Vitaly Wool <vitalywool@gmail.com>
* Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
* Copyright (C) 2012 John Crispin <blogic@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/of.h>
/* Nand commands */
#define OXNAS_NAND_CMD_ALE BIT(18)
#define OXNAS_NAND_CMD_CLE BIT(19)
#define OXNAS_NAND_MAX_CHIPS 1
struct oxnas_nand_ctrl {
struct nand_hw_control base;
void __iomem *io_base;
struct clk *clk;
struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
};
static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
return readb(oxnas->io_base);
}
static void oxnas_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
ioread8_rep(oxnas->io_base, buf, len);
}
static void oxnas_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
iowrite8_rep(oxnas->io_base, buf, len);
}
/* Single CS command control */
static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
if (ctrl & NAND_CLE)
writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
else if (ctrl & NAND_ALE)
writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);
}
/*
* Probe for the NAND device.
*/
static int oxnas_nand_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *nand_np;
struct oxnas_nand_ctrl *oxnas;
struct nand_chip *chip;
struct mtd_info *mtd;
struct resource *res;
int nchips = 0;
int count = 0;
int err = 0;
/* Allocate memory for the device structure (and zero it) */
oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
GFP_KERNEL);
if (!oxnas)
return -ENOMEM;
nand_hw_control_init(&oxnas->base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(oxnas->io_base))
return PTR_ERR(oxnas->io_base);
oxnas->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(oxnas->clk))
oxnas->clk = NULL;
/* Only a single chip node is supported */
count = of_get_child_count(np);
if (count > 1)
return -EINVAL;
clk_prepare_enable(oxnas->clk);
device_reset_optional(&pdev->dev);
for_each_child_of_node(np, nand_np) {
chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->controller = &oxnas->base;
nand_set_flash_node(chip, nand_np);
nand_set_controller_data(chip, oxnas);
mtd = nand_to_mtd(chip);
mtd->dev.parent = &pdev->dev;
mtd->priv = chip;
chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
chip->read_buf = oxnas_nand_read_buf;
chip->read_byte = oxnas_nand_read_byte;
chip->write_buf = oxnas_nand_write_buf;
chip->chip_delay = 30;
/* Scan to find existence of the device */
err = nand_scan(mtd, 1);
if (err)
return err;
err = mtd_device_register(mtd, NULL, 0);
if (err) {
nand_release(mtd);
return err;
}
oxnas->chips[nchips] = chip;
++nchips;
}
/* Exit if no chips found */
if (!nchips)
return -ENODEV;
platform_set_drvdata(pdev, oxnas);
return 0;
}
static int oxnas_nand_remove(struct platform_device *pdev)
{
struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
if (oxnas->chips[0])
nand_release(nand_to_mtd(oxnas->chips[0]));
clk_disable_unprepare(oxnas->clk);
return 0;
}
static const struct of_device_id oxnas_nand_match[] = {
{ .compatible = "oxsemi,ox820-nand" },
{},
};
MODULE_DEVICE_TABLE(of, oxnas_nand_match);
static struct platform_driver oxnas_nand_driver = {
.probe = oxnas_nand_probe,
.remove = oxnas_nand_remove,
.driver = {
.name = "oxnas_nand",
.of_match_table = oxnas_nand_match,
},
};
module_platform_driver(oxnas_nand_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
MODULE_DESCRIPTION("Oxnas NAND driver");
MODULE_ALIAS("platform:oxnas_nand");

View File

@ -156,10 +156,9 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
chip->bbt_options = NAND_BBT_USE_FLASH;
/* Scan to find existence of the device */
if (nand_scan(pasemi_nand_mtd, 1)) {
err = -ENXIO;
err = nand_scan(pasemi_nand_mtd, 1);
if (err)
goto out_lpc;
}
if (mtd_device_register(pasemi_nand_mtd, NULL, 0)) {
dev_err(dev, "Unable to register MTD device\n");

View File

@ -86,10 +86,9 @@ static int plat_nand_probe(struct platform_device *pdev)
}
/* Scan to find existence of the device */
if (nand_scan(mtd, pdata->chip.nr_chips)) {
err = -ENXIO;
err = nand_scan(mtd, pdata->chip.nr_chips);
if (err)
goto out;
}
part_types = pdata->chip.part_probe_types;

View File

@ -1680,8 +1680,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
chip->ecc.strength = pdata->ecc_strength;
chip->ecc.size = pdata->ecc_step_size;
if (nand_scan_ident(mtd, 1, NULL))
return -ENODEV;
ret = nand_scan_ident(mtd, 1, NULL);
if (ret)
return ret;
if (!pdata->keep_config) {
ret = pxa3xx_nand_init(host);
@ -1774,8 +1775,11 @@ static int alloc_nand_resource(struct platform_device *pdev)
int ret, irq, cs;
pdata = dev_get_platdata(&pdev->dev);
if (pdata->num_cs <= 0)
if (pdata->num_cs <= 0) {
dev_err(&pdev->dev, "invalid number of chip selects\n");
return -ENODEV;
}
info = devm_kzalloc(&pdev->dev,
sizeof(*info) + sizeof(*host) * pdata->num_cs,
GFP_KERNEL);
@ -1813,8 +1817,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
nand_hw_control_init(chip->controller);
info->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed to get nand clock\n");
return PTR_ERR(info->clk);
ret = PTR_ERR(info->clk);
dev_err(&pdev->dev, "failed to get nand clock: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(info->clk);
if (ret < 0)
@ -1842,6 +1847,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(info->mmio_base)) {
ret = PTR_ERR(info->mmio_base);
dev_err(&pdev->dev, "failed to map register space: %d\n", ret);
goto fail_disable_clk;
}
info->mmio_phys = r->start;
@ -1861,7 +1867,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
pxa3xx_nand_irq_thread, IRQF_ONESHOT,
pdev->name, info);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request IRQ\n");
dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);
goto fail_free_buf;
}
@ -1960,10 +1966,8 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
}
ret = alloc_nand_resource(pdev);
if (ret) {
dev_err(&pdev->dev, "alloc nand resource failed\n");
if (ret)
return ret;
}
info = platform_get_drvdata(pdev);
probe_success = 0;

View File

@ -39,6 +39,8 @@
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
@ -185,6 +187,22 @@ struct s3c2410_nand_info {
#endif
};
struct s3c24XX_nand_devtype_data {
enum s3c_cpu_type type;
};
static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
.type = TYPE_S3C2410,
};
static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
.type = TYPE_S3C2412,
};
static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
.type = TYPE_S3C2440,
};
/* conversion functions */
static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
@ -497,7 +515,6 @@ static int s3c2412_nand_devready(struct mtd_info *mtd)
/* ECC handling functions */
#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
@ -649,7 +666,6 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
return 0;
}
#endif
/* over-ride the standard functions for a little more speed. We can
* use read/write block to move the data buffers to/from the controller
@ -796,6 +812,30 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
return -ENODEV;
}
static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
const struct nand_data_interface *conf,
bool check_only)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
struct s3c2410_platform_nand *pdata = info->platform;
const struct nand_sdr_timings *timings;
int tacls;
timings = nand_get_sdr_timings(conf);
if (IS_ERR(timings))
return -ENOTSUPP;
tacls = timings->tCLS_min - timings->tWP_min;
if (tacls < 0)
tacls = 0;
pdata->tacls = DIV_ROUND_UP(tacls, 1000);
pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
return s3c2410_nand_setrate(info);
}
/**
* s3c2410_nand_init_chip - initialise a single instance of an chip
* @info: The base NAND controller the chip is on.
@ -810,9 +850,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
struct s3c2410_nand_mtd *nmtd,
struct s3c2410_nand_set *set)
{
struct device_node *np = info->device->of_node;
struct nand_chip *chip = &nmtd->chip;
void __iomem *regs = info->regs;
nand_set_flash_node(chip, set->of_node);
chip->write_buf = s3c2410_nand_write_buf;
chip->read_buf = s3c2410_nand_read_buf;
chip->select_chip = s3c2410_nand_select_chip;
@ -821,6 +864,13 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->options = set->options;
chip->controller = &info->controller;
/*
* let's keep behavior unchanged for legacy boards booting via pdata and
* auto-detect timings only when booting with a device tree.
*/
if (np)
chip->setup_data_interface = s3c2410_nand_setup_data_interface;
switch (info->cpu_type) {
case TYPE_S3C2410:
chip->IO_ADDR_W = regs + S3C2410_NFDATA;
@ -858,58 +908,14 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
nmtd->info = info;
nmtd->set = set;
#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
chip->ecc.correct = s3c2410_nand_correct_data;
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.strength = 1;
chip->ecc.mode = info->platform->ecc_mode;
switch (info->cpu_type) {
case TYPE_S3C2410:
chip->ecc.hwctl = s3c2410_nand_enable_hwecc;
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
break;
case TYPE_S3C2412:
chip->ecc.hwctl = s3c2412_nand_enable_hwecc;
chip->ecc.calculate = s3c2412_nand_calculate_ecc;
break;
case TYPE_S3C2440:
chip->ecc.hwctl = s3c2440_nand_enable_hwecc;
chip->ecc.calculate = s3c2440_nand_calculate_ecc;
break;
}
#else
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
#endif
if (set->disable_ecc)
chip->ecc.mode = NAND_ECC_NONE;
switch (chip->ecc.mode) {
case NAND_ECC_NONE:
dev_info(info->device, "NAND ECC disabled\n");
break;
case NAND_ECC_SOFT:
dev_info(info->device, "NAND soft ECC\n");
break;
case NAND_ECC_HW:
dev_info(info->device, "NAND hardware ECC\n");
break;
default:
dev_info(info->device, "NAND ECC UNKNOWN\n");
break;
}
/* If you use u-boot BBT creation code, specifying this flag will
* let the kernel fish out the BBT from the NAND, and also skip the
* full NAND scan that can take 1/2s or so. Little things... */
if (set->flash_bbt) {
/*
* If you use u-boot BBT creation code, specifying this flag will
* let the kernel fish out the BBT from the NAND.
*/
if (set->flash_bbt)
chip->bbt_options |= NAND_BBT_USE_FLASH;
chip->options |= NAND_SKIP_BBTSCAN;
}
}
/**
@ -923,28 +929,146 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
*
* The internal state is currently limited to the ECC state information.
*/
static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
struct s3c2410_nand_mtd *nmtd)
static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
struct s3c2410_nand_mtd *nmtd)
{
struct nand_chip *chip = &nmtd->chip;
dev_dbg(info->device, "chip %p => page shift %d\n",
chip, chip->page_shift);
switch (chip->ecc.mode) {
if (chip->ecc.mode != NAND_ECC_HW)
return;
case NAND_ECC_NONE:
dev_info(info->device, "ECC disabled\n");
break;
case NAND_ECC_SOFT:
/*
* This driver expects Hamming based ECC when ecc_mode is set
* to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
* avoid adding an extra ecc_algo field to
* s3c2410_platform_nand.
*/
chip->ecc.algo = NAND_ECC_HAMMING;
dev_info(info->device, "soft ECC\n");
break;
case NAND_ECC_HW:
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
chip->ecc.correct = s3c2410_nand_correct_data;
chip->ecc.strength = 1;
switch (info->cpu_type) {
case TYPE_S3C2410:
chip->ecc.hwctl = s3c2410_nand_enable_hwecc;
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
break;
case TYPE_S3C2412:
chip->ecc.hwctl = s3c2412_nand_enable_hwecc;
chip->ecc.calculate = s3c2412_nand_calculate_ecc;
break;
case TYPE_S3C2440:
chip->ecc.hwctl = s3c2440_nand_enable_hwecc;
chip->ecc.calculate = s3c2440_nand_calculate_ecc;
break;
}
dev_dbg(info->device, "chip %p => page shift %d\n",
chip, chip->page_shift);
/* change the behaviour depending on whether we are using
* the large or small page nand device */
if (chip->page_shift > 10) {
chip->ecc.size = 256;
chip->ecc.bytes = 3;
} else {
chip->ecc.size = 512;
chip->ecc.bytes = 3;
mtd_set_ooblayout(nand_to_mtd(chip),
&s3c2410_ooblayout_ops);
}
if (chip->page_shift > 10) {
chip->ecc.size = 256;
chip->ecc.bytes = 3;
} else {
chip->ecc.size = 512;
chip->ecc.bytes = 3;
mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
dev_info(info->device, "hardware ECC\n");
break;
default:
dev_err(info->device, "invalid ECC mode!\n");
return -EINVAL;
}
if (chip->bbt_options & NAND_BBT_USE_FLASH)
chip->options |= NAND_SKIP_BBTSCAN;
return 0;
}
static const struct of_device_id s3c24xx_nand_dt_ids[] = {
{
.compatible = "samsung,s3c2410-nand",
.data = &s3c2410_nand_devtype_data,
}, {
/* also compatible with s3c6400 */
.compatible = "samsung,s3c2412-nand",
.data = &s3c2412_nand_devtype_data,
}, {
.compatible = "samsung,s3c2440-nand",
.data = &s3c2440_nand_devtype_data,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
{
const struct s3c24XX_nand_devtype_data *devtype_data;
struct s3c2410_platform_nand *pdata;
struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
struct device_node *np = pdev->dev.of_node, *child;
struct s3c2410_nand_set *sets;
devtype_data = of_device_get_match_data(&pdev->dev);
if (!devtype_data)
return -ENODEV;
info->cpu_type = devtype_data->type;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
pdev->dev.platform_data = pdata;
pdata->nr_sets = of_get_child_count(np);
if (!pdata->nr_sets)
return 0;
sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets,
GFP_KERNEL);
if (!sets)
return -ENOMEM;
pdata->sets = sets;
for_each_available_child_of_node(np, child) {
sets->name = (char *)child->name;
sets->of_node = child;
sets->nr_chips = 1;
of_node_get(child);
sets++;
}
return 0;
}
static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
{
struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
info->cpu_type = platform_get_device_id(pdev)->driver_data;
return 0;
}
/* s3c24xx_nand_probe
@ -956,8 +1080,7 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
*/
static int s3c24xx_nand_probe(struct platform_device *pdev)
{
struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
enum s3c_cpu_type cpu_type;
struct s3c2410_platform_nand *plat;
struct s3c2410_nand_info *info;
struct s3c2410_nand_mtd *nmtd;
struct s3c2410_nand_set *sets;
@ -967,8 +1090,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
int nr_sets;
int setno;
cpu_type = platform_get_device_id(pdev)->driver_data;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (info == NULL) {
err = -ENOMEM;
@ -990,6 +1111,16 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
if (pdev->dev.of_node)
err = s3c24xx_nand_probe_dt(pdev);
else
err = s3c24xx_nand_probe_pdata(pdev);
if (err)
goto exit_error;
plat = to_nand_plat(pdev);
/* allocate and map the resource */
/* currently we assume we have the one resource */
@ -998,7 +1129,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
info->device = &pdev->dev;
info->platform = plat;
info->cpu_type = cpu_type;
info->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(info->regs)) {
@ -1008,12 +1138,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
/* initialise the hardware */
err = s3c2410_nand_inithw(info);
if (err != 0)
goto exit_error;
sets = (plat != NULL) ? plat->sets : NULL;
nr_sets = (plat != NULL) ? plat->nr_sets : 1;
@ -1046,7 +1170,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
NULL);
if (nmtd->scan_res == 0) {
s3c2410_nand_update_chip(info, nmtd);
err = s3c2410_nand_update_chip(info, nmtd);
if (err < 0)
goto exit_error;
nand_scan_tail(mtd);
s3c2410_nand_add_partition(info, nmtd, sets);
}
@ -1055,6 +1181,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
sets++;
}
/* initialise the hardware */
err = s3c2410_nand_inithw(info);
if (err != 0)
goto exit_error;
err = s3c2410_nand_cpufreq_register(info);
if (err < 0) {
dev_err(&pdev->dev, "failed to init cpufreq support\n");
@ -1155,6 +1286,7 @@ static struct platform_driver s3c24xx_nand_driver = {
.id_table = s3c24xx_driver_ids,
.driver = {
.name = "s3c24xx-nand",
.of_match_table = s3c24xx_nand_dt_ids,
},
};

View File

@ -187,17 +187,9 @@ static int socrates_nand_probe(struct platform_device *ofdev)
dev_set_drvdata(&ofdev->dev, host);
/* first scan to find the device and get the page size */
if (nand_scan_ident(mtd, 1, NULL)) {
res = -ENXIO;
res = nand_scan(mtd, 1);
if (res)
goto out;
}
/* second phase scan */
if (nand_scan_tail(mtd)) {
res = -ENXIO;
goto out;
}
res = mtd_device_register(mtd, NULL, 0);
if (!res)

View File

@ -145,6 +145,7 @@
#define NFC_ECC_PIPELINE BIT(3)
#define NFC_ECC_EXCEPTION BIT(4)
#define NFC_ECC_BLOCK_SIZE_MSK BIT(5)
#define NFC_ECC_BLOCK_512 BIT(5)
#define NFC_RANDOM_EN BIT(9)
#define NFC_RANDOM_DIRECTION BIT(10)
#define NFC_ECC_MODE_MSK GENMASK(15, 12)
@ -817,6 +818,9 @@ static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION |
NFC_ECC_PIPELINE;
if (nand->ecc.size == 512)
ecc_ctl |= NFC_ECC_BLOCK_512;
writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
}

View File

@ -0,0 +1,676 @@
/*
* Copyright (C) 2016 Sigma Designs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#include <linux/io.h>
#include <linux/of.h>
#include <linux/clk.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/mtd/nand.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
/* Offsets relative to chip->base */
#define PBUS_CMD 0
#define PBUS_ADDR 4
#define PBUS_DATA 8
/* Offsets relative to reg_base */
#define NFC_STATUS 0x00
#define NFC_FLASH_CMD 0x04
#define NFC_DEVICE_CFG 0x08
#define NFC_TIMING1 0x0c
#define NFC_TIMING2 0x10
#define NFC_XFER_CFG 0x14
#define NFC_PKT_0_CFG 0x18
#define NFC_PKT_N_CFG 0x1c
#define NFC_BB_CFG 0x20
#define NFC_ADDR_PAGE 0x24
#define NFC_ADDR_OFFSET 0x28
#define NFC_XFER_STATUS 0x2c
/* NFC_STATUS values */
#define CMD_READY BIT(31)
/* NFC_FLASH_CMD values */
#define NFC_READ 1
#define NFC_WRITE 2
/* NFC_XFER_STATUS values */
#define PAGE_IS_EMPTY BIT(16)
/* Offsets relative to mem_base */
#define METADATA 0x000
#define ERROR_REPORT 0x1c0
/*
* Error reports are split in two bytes:
* byte 0 for the first packet in the page (PKT_0)
* byte 1 for other packets in the page (PKT_N, for N > 0)
* ERR_COUNT_PKT_N is the max error count over all but the first packet.
*/
#define DECODE_OK_PKT_0(v) ((v) & BIT(7))
#define DECODE_OK_PKT_N(v) ((v) & BIT(15))
#define ERR_COUNT_PKT_0(v) (((v) >> 0) & 0x3f)
#define ERR_COUNT_PKT_N(v) (((v) >> 8) & 0x3f)
/* Offsets relative to pbus_base */
#define PBUS_CS_CTRL 0x83c
#define PBUS_PAD_MODE 0x8f0
/* PBUS_CS_CTRL values */
#define PBUS_IORDY BIT(31)
/*
* PBUS_PAD_MODE values
* In raw mode, the driver communicates directly with the NAND chips.
* In NFC mode, the NAND Flash controller manages the communication.
* We use NFC mode for read and write; raw mode for everything else.
*/
#define MODE_RAW 0
#define MODE_NFC BIT(31)
#define METADATA_SIZE 4
#define BBM_SIZE 6
#define FIELD_ORDER 15
#define MAX_CS 4
struct tango_nfc {
struct nand_hw_control hw;
void __iomem *reg_base;
void __iomem *mem_base;
void __iomem *pbus_base;
struct tango_chip *chips[MAX_CS];
struct dma_chan *chan;
int freq_kHz;
};
#define to_tango_nfc(ptr) container_of(ptr, struct tango_nfc, hw)
struct tango_chip {
struct nand_chip nand_chip;
void __iomem *base;
u32 timing1;
u32 timing2;
u32 xfer_cfg;
u32 pkt_0_cfg;
u32 pkt_n_cfg;
u32 bb_cfg;
};
#define to_tango_chip(ptr) container_of(ptr, struct tango_chip, nand_chip)
#define XFER_CFG(cs, page_count, steps, metadata_size) \
((cs) << 24 | (page_count) << 16 | (steps) << 8 | (metadata_size))
#define PKT_CFG(size, strength) ((size) << 16 | (strength))
#define BB_CFG(bb_offset, bb_size) ((bb_offset) << 16 | (bb_size))
#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
if (ctrl & NAND_CLE)
writeb_relaxed(dat, tchip->base + PBUS_CMD);
if (ctrl & NAND_ALE)
writeb_relaxed(dat, tchip->base + PBUS_ADDR);
}
static int tango_dev_ready(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
}
static u8 tango_read_byte(struct mtd_info *mtd)
{
struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
return readb_relaxed(tchip->base + PBUS_DATA);
}
static void tango_read_buf(struct mtd_info *mtd, u8 *buf, int len)
{
struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
ioread8_rep(tchip->base + PBUS_DATA, buf, len);
}
static void tango_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
{
struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
}
static void tango_select_chip(struct mtd_info *mtd, int idx)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
struct tango_chip *tchip = to_tango_chip(chip);
if (idx < 0)
return; /* No "chip unselect" function */
writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
}
/*
* The controller does not check for bitflips in erased pages,
* therefore software must check instead.
*/
static int check_erased_page(struct nand_chip *chip, u8 *buf)
{
struct mtd_info *mtd = nand_to_mtd(chip);
u8 *meta = chip->oob_poi + BBM_SIZE;
u8 *ecc = chip->oob_poi + BBM_SIZE + METADATA_SIZE;
const int ecc_size = chip->ecc.bytes;
const int pkt_size = chip->ecc.size;
int i, res, meta_len, bitflips = 0;
for (i = 0; i < chip->ecc.steps; ++i) {
meta_len = i ? 0 : METADATA_SIZE;
res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
meta, meta_len,
chip->ecc.strength);
if (res < 0)
mtd->ecc_stats.failed++;
bitflips = max(res, bitflips);
buf += pkt_size;
ecc += ecc_size;
}
return bitflips;
}
static int decode_error_report(struct tango_nfc *nfc)
{
u32 status, res;
status = readl_relaxed(nfc->reg_base + NFC_XFER_STATUS);
if (status & PAGE_IS_EMPTY)
return 0;
res = readl_relaxed(nfc->mem_base + ERROR_REPORT);
if (DECODE_OK_PKT_0(res) && DECODE_OK_PKT_N(res))
return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res));
return -EBADMSG;
}
static void tango_dma_callback(void *arg)
{
complete(arg);
}
static int do_dma(struct tango_nfc *nfc, int dir, int cmd, const void *buf,
int len, int page)
{
void __iomem *addr = nfc->reg_base + NFC_STATUS;
struct dma_chan *chan = nfc->chan;
struct dma_async_tx_descriptor *desc;
struct scatterlist sg;
struct completion tx_done;
int err = -EIO;
u32 res, val;
sg_init_one(&sg, buf, len);
if (dma_map_sg(chan->device->dev, &sg, 1, dir) != 1)
return -EIO;
desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, DMA_PREP_INTERRUPT);
if (!desc)
goto dma_unmap;
desc->callback = tango_dma_callback;
desc->callback_param = &tx_done;
init_completion(&tx_done);
writel_relaxed(MODE_NFC, nfc->pbus_base + PBUS_PAD_MODE);
writel_relaxed(page, nfc->reg_base + NFC_ADDR_PAGE);
writel_relaxed(0, nfc->reg_base + NFC_ADDR_OFFSET);
writel_relaxed(cmd, nfc->reg_base + NFC_FLASH_CMD);
dmaengine_submit(desc);
dma_async_issue_pending(chan);
res = wait_for_completion_timeout(&tx_done, HZ);
if (res > 0)
err = readl_poll_timeout(addr, val, val & CMD_READY, 0, 1000);
writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
dma_unmap:
dma_unmap_sg(chan->device->dev, &sg, 1, dir);
return err;
}
static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
u8 *buf, int oob_required, int page)
{
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
int err, res, len = mtd->writesize;
if (oob_required)
chip->ecc.read_oob(mtd, chip, page);
err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
if (err)
return err;
res = decode_error_report(nfc);
if (res < 0) {
chip->ecc.read_oob_raw(mtd, chip, page);
res = check_erased_page(chip, buf);
}
return res;
}
static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const u8 *buf, int oob_required, int page)
{
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
int err, len = mtd->writesize;
/* Calling tango_write_oob() would send PAGEPROG twice */
if (oob_required)
return -ENOTSUPP;
writel_relaxed(0xffffffff, nfc->mem_base + METADATA);
err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page);
if (err)
return err;
return 0;
}
static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
{
struct mtd_info *mtd = nand_to_mtd(chip);
*pos += len;
if (!*buf) {
/* skip over "len" bytes */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, *pos, -1);
} else {
tango_read_buf(mtd, *buf, len);
*buf += len;
}
}
static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
{
struct mtd_info *mtd = nand_to_mtd(chip);
*pos += len;
if (!*buf) {
/* skip over "len" bytes */
chip->cmdfunc(mtd, NAND_CMD_SEQIN, *pos, -1);
} else {
tango_write_buf(mtd, *buf, len);
*buf += len;
}
}
/*
* Physical page layout (not drawn to scale)
*
* NB: Bad Block Marker area splits PKT_N in two (N1, N2).
*
* +---+-----------------+-------+-----+-----------+-----+----+-------+
* | M | PKT_0 | ECC_0 | ... | N1 | BBM | N2 | ECC_N |
* +---+-----------------+-------+-----+-----------+-----+----+-------+
*
* Logical page layout:
*
* +-----+---+-------+-----+-------+
* oob = | BBM | M | ECC_0 | ... | ECC_N |
* +-----+---+-------+-----+-------+
*
* +-----------------+-----+-----------------+
* buf = | PKT_0 | ... | PKT_N |
* +-----------------+-----+-----------------+
*/
static void raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
{
struct mtd_info *mtd = nand_to_mtd(chip);
u8 *oob_orig = oob;
const int page_size = mtd->writesize;
const int ecc_size = chip->ecc.bytes;
const int pkt_size = chip->ecc.size;
int pos = 0; /* position within physical page */
int rem = page_size; /* bytes remaining until BBM area */
if (oob)
oob += BBM_SIZE;
aux_read(chip, &oob, METADATA_SIZE, &pos);
while (rem > pkt_size) {
aux_read(chip, &buf, pkt_size, &pos);
aux_read(chip, &oob, ecc_size, &pos);
rem = page_size - pos;
}
aux_read(chip, &buf, rem, &pos);
aux_read(chip, &oob_orig, BBM_SIZE, &pos);
aux_read(chip, &buf, pkt_size - rem, &pos);
aux_read(chip, &oob, ecc_size, &pos);
}
static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
{
struct mtd_info *mtd = nand_to_mtd(chip);
const u8 *oob_orig = oob;
const int page_size = mtd->writesize;
const int ecc_size = chip->ecc.bytes;
const int pkt_size = chip->ecc.size;
int pos = 0; /* position within physical page */
int rem = page_size; /* bytes remaining until BBM area */
if (oob)
oob += BBM_SIZE;
aux_write(chip, &oob, METADATA_SIZE, &pos);
while (rem > pkt_size) {
aux_write(chip, &buf, pkt_size, &pos);
aux_write(chip, &oob, ecc_size, &pos);
rem = page_size - pos;
}
aux_write(chip, &buf, rem, &pos);
aux_write(chip, &oob_orig, BBM_SIZE, &pos);
aux_write(chip, &buf, pkt_size - rem, &pos);
aux_write(chip, &oob, ecc_size, &pos);
}
static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
u8 *buf, int oob_required, int page)
{
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
raw_read(chip, buf, chip->oob_poi);
return 0;
}
static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const u8 *buf, int oob_required, int page)
{
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
raw_write(chip, buf, chip->oob_poi);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
return 0;
}
static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
raw_read(chip, NULL, chip->oob_poi);
return 0;
}
static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
raw_write(chip, NULL, chip->oob_poi);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
chip->waitfunc(mtd, chip);
return 0;
}
static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_ecc_ctrl *ecc = &chip->ecc;
if (idx >= ecc->steps)
return -ERANGE;
res->offset = BBM_SIZE + METADATA_SIZE + ecc->bytes * idx;
res->length = ecc->bytes;
return 0;
}
static int oob_free(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
{
return -ERANGE; /* no free space in spare area */
}
static const struct mtd_ooblayout_ops tango_nand_ooblayout_ops = {
.ecc = oob_ecc,
.free = oob_free,
};
static u32 to_ticks(int kHz, int ps)
{
return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
}
static int tango_set_timings(struct mtd_info *mtd,
const struct nand_data_interface *conf,
bool check_only)
{
const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
struct nand_chip *chip = mtd_to_nand(mtd);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
struct tango_chip *tchip = to_tango_chip(chip);
u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
int kHz = nfc->freq_kHz;
if (IS_ERR(sdr))
return PTR_ERR(sdr);
if (check_only)
return 0;
Trdy = to_ticks(kHz, sdr->tCEA_max - sdr->tREA_max);
Textw = to_ticks(kHz, sdr->tWB_max);
Twc = to_ticks(kHz, sdr->tWC_min);
Twpw = to_ticks(kHz, sdr->tWC_min - sdr->tWP_min);
Tacc = to_ticks(kHz, sdr->tREA_max);
Thold = to_ticks(kHz, sdr->tREH_min);
Trpw = to_ticks(kHz, sdr->tRC_min - sdr->tREH_min);
Textr = to_ticks(kHz, sdr->tRHZ_max);
tchip->timing1 = TIMING(Trdy, Textw, Twc, Twpw);
tchip->timing2 = TIMING(Tacc, Thold, Trpw, Textr);
return 0;
}
static int chip_init(struct device *dev, struct device_node *np)
{
u32 cs;
int err, res;
struct mtd_info *mtd;
struct nand_chip *chip;
struct tango_chip *tchip;
struct nand_ecc_ctrl *ecc;
struct tango_nfc *nfc = dev_get_drvdata(dev);
tchip = devm_kzalloc(dev, sizeof(*tchip), GFP_KERNEL);
if (!tchip)
return -ENOMEM;
res = of_property_count_u32_elems(np, "reg");
if (res < 0)
return res;
if (res != 1)
return -ENOTSUPP; /* Multi-CS chips are not supported */
err = of_property_read_u32_index(np, "reg", 0, &cs);
if (err)
return err;
if (cs >= MAX_CS)
return -EINVAL;
chip = &tchip->nand_chip;
ecc = &chip->ecc;
mtd = nand_to_mtd(chip);
chip->read_byte = tango_read_byte;
chip->write_buf = tango_write_buf;
chip->read_buf = tango_read_buf;
chip->select_chip = tango_select_chip;
chip->cmd_ctrl = tango_cmd_ctrl;
chip->dev_ready = tango_dev_ready;
chip->setup_data_interface = tango_set_timings;
chip->options = NAND_USE_BOUNCE_BUFFER |
NAND_NO_SUBPAGE_WRITE |
NAND_WAIT_TCCS;
chip->controller = &nfc->hw;
tchip->base = nfc->pbus_base + (cs * 256);
nand_set_flash_node(chip, np);
mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
mtd->dev.parent = dev;
err = nand_scan_ident(mtd, 1, NULL);
if (err)
return err;
ecc->mode = NAND_ECC_HW;
ecc->algo = NAND_ECC_BCH;
ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
ecc->read_page_raw = tango_read_page_raw;
ecc->write_page_raw = tango_write_page_raw;
ecc->read_page = tango_read_page;
ecc->write_page = tango_write_page;
ecc->read_oob = tango_read_oob;
ecc->write_oob = tango_write_oob;
ecc->options = NAND_ECC_CUSTOM_PAGE_ACCESS;
err = nand_scan_tail(mtd);
if (err)
return err;
tchip->xfer_cfg = XFER_CFG(cs, 1, ecc->steps, METADATA_SIZE);
tchip->pkt_0_cfg = PKT_CFG(ecc->size + METADATA_SIZE, ecc->strength);
tchip->pkt_n_cfg = PKT_CFG(ecc->size, ecc->strength);
tchip->bb_cfg = BB_CFG(mtd->writesize, BBM_SIZE);
err = mtd_device_register(mtd, NULL, 0);
if (err)
return err;
nfc->chips[cs] = tchip;
return 0;
}
static int tango_nand_remove(struct platform_device *pdev)
{
int cs;
struct tango_nfc *nfc = platform_get_drvdata(pdev);
dma_release_channel(nfc->chan);
for (cs = 0; cs < MAX_CS; ++cs) {
if (nfc->chips[cs])
nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip));
}
return 0;
}
static int tango_nand_probe(struct platform_device *pdev)
{
int err;
struct clk *clk;
struct resource *res;
struct tango_nfc *nfc;
struct device_node *np;
nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
if (!nfc)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nfc->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(nfc->reg_base))
return PTR_ERR(nfc->reg_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
nfc->mem_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(nfc->mem_base))
return PTR_ERR(nfc->mem_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
nfc->pbus_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(nfc->pbus_base))
return PTR_ERR(nfc->pbus_base);
clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
nfc->chan = dma_request_chan(&pdev->dev, "nfc_sbox");
if (IS_ERR(nfc->chan))
return PTR_ERR(nfc->chan);
platform_set_drvdata(pdev, nfc);
nand_hw_control_init(&nfc->hw);
nfc->freq_kHz = clk_get_rate(clk) / 1000;
for_each_child_of_node(pdev->dev.of_node, np) {
err = chip_init(&pdev->dev, np);
if (err) {
tango_nand_remove(pdev);
return err;
}
}
return 0;
}
static const struct of_device_id tango_nand_ids[] = {
{ .compatible = "sigma,smp8758-nand" },
{ /* sentinel */ }
};
static struct platform_driver tango_nand_driver = {
.probe = tango_nand_probe,
.remove = tango_nand_remove,
.driver = {
.name = "tango-nand",
.of_match_table = tango_nand_ids,
},
};
module_platform_driver(tango_nand_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sigma Designs");
MODULE_DESCRIPTION("Tango4 NAND Flash controller driver");

View File

@ -435,10 +435,10 @@ static int tmio_probe(struct platform_device *dev)
nand_chip->waitfunc = tmio_nand_wait;
/* Scan to find existence of the device */
if (nand_scan(mtd, 1)) {
retval = -ENODEV;
retval = nand_scan(mtd, 1);
if (retval)
goto err_irq;
}
/* Register the partitions */
retval = mtd_device_parse_register(mtd, NULL, NULL,
data ? data->partition : NULL,

View File

@ -717,10 +717,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
vf610_nfc_preinit_controller(nfc);
/* first scan to find the device and get the page size */
if (nand_scan_ident(mtd, 1, NULL)) {
err = -ENXIO;
err = nand_scan_ident(mtd, 1, NULL);
if (err)
goto error;
}
vf610_nfc_init_controller(nfc);
@ -775,10 +774,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
}
/* second phase scan */
if (nand_scan_tail(mtd)) {
err = -ENXIO;
err = nand_scan_tail(mtd);
if (err)
goto error;
}
platform_set_drvdata(pdev, mtd);

View File

@ -1077,12 +1077,14 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
/* Get flash device data */
for_each_available_child_of_node(dev->of_node, np) {
if (of_property_read_u32(np, "reg", &cs)) {
ret = of_property_read_u32(np, "reg", &cs);
if (ret) {
dev_err(dev, "Couldn't determine chip select.\n");
goto err;
}
if (cs > CQSPI_MAX_CHIPSELECT) {
if (cs >= CQSPI_MAX_CHIPSELECT) {
ret = -EINVAL;
dev_err(dev, "Chip select %d out of range.\n", cs);
goto err;
}

View File

@ -224,7 +224,7 @@ struct fsl_qspi_devtype_data {
int driver_data;
};
static struct fsl_qspi_devtype_data vybrid_data = {
static const struct fsl_qspi_devtype_data vybrid_data = {
.devtype = FSL_QUADSPI_VYBRID,
.rxfifo = 128,
.txfifo = 64,
@ -232,7 +232,7 @@ static struct fsl_qspi_devtype_data vybrid_data = {
.driver_data = QUADSPI_QUIRK_SWAP_ENDIAN,
};
static struct fsl_qspi_devtype_data imx6sx_data = {
static const struct fsl_qspi_devtype_data imx6sx_data = {
.devtype = FSL_QUADSPI_IMX6SX,
.rxfifo = 128,
.txfifo = 512,
@ -241,7 +241,7 @@ static struct fsl_qspi_devtype_data imx6sx_data = {
| QUADSPI_QUIRK_TKT245618,
};
static struct fsl_qspi_devtype_data imx7d_data = {
static const struct fsl_qspi_devtype_data imx7d_data = {
.devtype = FSL_QUADSPI_IMX7D,
.rxfifo = 512,
.txfifo = 512,
@ -250,7 +250,7 @@ static struct fsl_qspi_devtype_data imx7d_data = {
| QUADSPI_QUIRK_4X_INT_CLK,
};
static struct fsl_qspi_devtype_data imx6ul_data = {
static const struct fsl_qspi_devtype_data imx6ul_data = {
.devtype = FSL_QUADSPI_IMX6UL,
.rxfifo = 128,
.txfifo = 512,

View File

@ -799,6 +799,7 @@ static const struct flash_info spi_nor_ids[] = {
{ "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) },
{ "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) },
{ "at25df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
{ "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) },
{ "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },
@ -825,6 +826,7 @@ static const struct flash_info spi_nor_ids[] = {
/* Everspin */
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{ "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{ "mr25h40", CAT25_INFO(512 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
/* Fujitsu */
{ "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) },
@ -872,11 +874,13 @@ static const struct flash_info spi_nor_ids[] = {
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
/* Micron */
{ "n25q016a", INFO(0x20bb15, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
{ "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
@ -905,7 +909,7 @@ static const struct flash_info spi_nor_ids[] = {
{ "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
{ "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
{ "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) },
@ -921,6 +925,7 @@ static const struct flash_info spi_nor_ids[] = {
{ "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) },
{ "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) },
{ "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_DUAL_READ) },
{ "s25fl208k", INFO(0x014014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ) },
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
@ -1255,6 +1260,13 @@ static int spansion_quad_enable(struct spi_nor *nor)
return -EINVAL;
}
ret = spi_nor_wait_till_ready(nor);
if (ret) {
dev_err(nor->dev,
"timeout while writing configuration register\n");
return ret;
}
/* read back and check it */
ret = read_cr(nor);
if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {

View File

@ -142,6 +142,12 @@ enum nand_ecc_algo {
*/
#define NAND_ECC_GENERIC_ERASED_CHECK BIT(0)
#define NAND_ECC_MAXIMIZE BIT(1)
/*
* If your controller already sends the required NAND commands when
* reading or writing a page, then the framework is not supposed to
* send READ0 and SEQIN/PAGEPROG respectively.
*/
#define NAND_ECC_CUSTOM_PAGE_ACCESS BIT(2)
/* Bit mask for flags passed to do_nand_read_ecc */
#define NAND_GET_DEVICE 0x80
@ -186,6 +192,7 @@ enum nand_ecc_algo {
/* Macros to identify the above */
#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
#define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ))
#define NAND_HAS_SUBPAGE_WRITE(chip) !((chip)->options & NAND_NO_SUBPAGE_WRITE)
/* Non chip related options */
/* This option skips the bbt scan during initialization. */
@ -210,6 +217,16 @@ enum nand_ecc_algo {
*/
#define NAND_USE_BOUNCE_BUFFER 0x00100000
/*
* In case your controller is implementing ->cmd_ctrl() and is relying on the
* default ->cmdfunc() implementation, you may want to let the core handle the
* tCCS delay which is required when a column change (RNDIN or RNDOUT) is
* requested.
* If your controller already takes care of this delay, you don't need to set
* this flag.
*/
#define NAND_WAIT_TCCS 0x00200000
/* Options set by nand scan */
/* Nand scan has allocated controller struct */
#define NAND_CONTROLLER_ALLOC 0x80000000
@ -558,6 +575,11 @@ struct nand_ecc_ctrl {
int page);
};
static inline int nand_standard_page_accessors(struct nand_ecc_ctrl *ecc)
{
return !(ecc->options & NAND_ECC_CUSTOM_PAGE_ACCESS);
}
/**
* struct nand_buffers - buffer structure for read/write
* @ecccalc: buffer pointer for calculated ECC, size is oobsize.
@ -584,6 +606,10 @@ struct nand_buffers {
*
* All these timings are expressed in picoseconds.
*
* @tBERS_max: Block erase time
* @tCCS_min: Change column setup time
* @tPROG_max: Page program time
* @tR_max: Page read time
* @tALH_min: ALE hold time
* @tADL_min: ALE to data loading time
* @tALS_min: ALE setup time
@ -621,6 +647,10 @@ struct nand_buffers {
* @tWW_min: WP# transition to WE# low
*/
struct nand_sdr_timings {
u32 tBERS_max;
u32 tCCS_min;
u32 tPROG_max;
u32 tR_max;
u32 tALH_min;
u32 tADL_min;
u32 tALS_min;

View File

@ -12,9 +12,10 @@
#ifndef __MTD_NAND_S3C2410_H
#define __MTD_NAND_S3C2410_H
#include <linux/mtd/nand.h>
/**
* struct s3c2410_nand_set - define a set of one or more nand chips
* @disable_ecc: Entirely disable ECC - Dangerous
* @flash_bbt: Openmoko u-boot can create a Bad Block Table
* Setting this flag will allow the kernel to
* look for it at boot time and also skip the NAND
@ -31,7 +32,6 @@
* a warning at boot time.
*/
struct s3c2410_nand_set {
unsigned int disable_ecc:1;
unsigned int flash_bbt:1;
unsigned int options;
@ -40,6 +40,7 @@ struct s3c2410_nand_set {
char *name;
int *nr_map;
struct mtd_partition *partitions;
struct device_node *of_node;
};
struct s3c2410_platform_nand {
@ -51,6 +52,8 @@ struct s3c2410_platform_nand {
unsigned int ignore_unset_ecc:1;
nand_ecc_modes_t ecc_mode;
int nr_sets;
struct s3c2410_nand_set *sets;