This pull request contains the following core changes:

* addition of on-ecc support to Micron driver
 * addition of helpers to help drivers choose most appropriate ECC
   settings
 * deletion of dead-code (cached programming and ->errstat() hook)
 * make sure drivers that do not support the SET/GET FEATURES command
   return ENOTSUPP use a dummy ->set/get_features implementation
   returning -ENOTSUPP (required for Micron on-die ECC)
 * change the semantic of ecc->write_page() for drivers setting the
   NAND_ECC_CUSTOM_PAGE_ACCESS flag
 * support exiting 'GET STATUS' command in default ->cmdfunc()
   implementations
 * change the prototype of ->setup_data_interface()
 
 A bunch of driver related changes:
 
 * various cleanup, fixes and improvements of the MTK driver
 * OMAP DT bindings fixes
 * support for ->setup_data_interface() in the fsmc driver
 * support for imx7 in the gpmi driver
 * finalization of the denali driver rework (thanks to Masahiro for the
   work he's done on this driver)
 * fix "bitflips in erased pages" handling in the ifc driver
 * addition of PM ops and dynamic timing configuration to the atmel
   driver
 
 And as usual we also have a few minor cleanup/fixes/improvements
 patches across the subsystem.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJZWi1RAAoJEGXtNgF+CLcA9ukP/jpyodKn1pTyVKhAfWlx3I01
 VMS8Pns6VxfSojLA2JEhPR7rd+M0G8ZKPb+odKXxWmZXoH+1iAWWBv5LjkNXrwpP
 ajwpkVkSU5N0FI4QX6AOX5H5kUJAq5yWh+uzLO3e/0yBAdZs6Q5msemzDIdDqr22
 1J/1wUND7unGCreQ2KQGbni2es3+Lm7WDWbhc77v4bZ6yI+nDiHFeLE45CTdnG0L
 dzqSsHjSJ7mGVBSZIIlGhgemhinw9OD1prXOigmT9tnEyBBolrelDdWtaT3ncn+K
 //TlFZFd+qRIuOCRL5j+kqM0JLSyZbhsvYpfCKtnGkAw+hUqMZQuKb+V8HS2ZvnY
 6Xsbh8AZxHc8rC2hmYCj4SI8N48Y4dVDxC40UBp3TRu2qMv5u4YMQV5jhA/53s05
 AlvWQlpgIUyiinV5IyhwhikF9foCvCkyKKqB9MRJgXsQlfbBQe1c1ffZhIyen6ZM
 6+Uca6ul8pINj1q/P749GzbK5F9aymZMidiineykS3EBcytXW1yXtIHOVy9jwjIU
 +iLRDkH+Vl1dT/cOa5jm5hXgOkNggrYmtG+NzKLa4RRXrtO1yo3uocSUl49XYk4C
 OO+BeKLPs+Ffm0OnYBIOJTyywR1jRS8DCUTqg8qRjzMFVuAlbEHJ9YE/hg5IvKZK
 mgFm4rHa/460DPscBMCB
 =INC7
 -----END PGP SIGNATURE-----

Merge tag 'nand/for-4.13' into MTD

From Boris:
"""
This pull request contains the following core changes:

* addition of on-ecc support to Micron driver
* addition of helpers to help drivers choose most appropriate ECC
  settings
* deletion of dead-code (cached programming and ->errstat() hook)
* make sure drivers that do not support the SET/GET FEATURES command
  return ENOTSUPP use a dummy ->set/get_features implementation
  returning -ENOTSUPP (required for Micron on-die ECC)
* change the semantic of ecc->write_page() for drivers setting the
  NAND_ECC_CUSTOM_PAGE_ACCESS flag
* support exiting 'GET STATUS' command in default ->cmdfunc()
  implementations
* change the prototype of ->setup_data_interface()

A bunch of driver related changes:

* various cleanup, fixes and improvements of the MTK driver
* OMAP DT bindings fixes
* support for ->setup_data_interface() in the fsmc driver
* support for imx7 in the gpmi driver
* finalization of the denali driver rework (thanks to Masahiro for the
  work he's done on this driver)
* fix "bitflips in erased pages" handling in the ifc driver
* addition of PM ops and dynamic timing configuration to the atmel
  driver

And as usual we also have a few minor cleanup/fixes/improvements
patches across the subsystem.
"""
This commit is contained in:
Brian Norris 2017-07-07 18:03:11 -07:00
commit ef32476f26
45 changed files with 2581 additions and 1663 deletions

View File

@ -3,10 +3,23 @@
Required properties:
- compatible : should be one of the following:
"altr,socfpga-denali-nand" - for Altera SOCFPGA
"socionext,uniphier-denali-nand-v5a" - for Socionext UniPhier (v5a)
"socionext,uniphier-denali-nand-v5b" - for Socionext UniPhier (v5b)
- reg : should contain registers location and length for data and reg.
- reg-names: Should contain the reg names "nand_data" and "denali_reg"
- interrupts : The interrupt number.
Optional properties:
- nand-ecc-step-size: see nand.txt for details. If present, the value must be
512 for "altr,socfpga-denali-nand"
1024 for "socionext,uniphier-denali-nand-v5a"
1024 for "socionext,uniphier-denali-nand-v5b"
- nand-ecc-strength: see nand.txt for details. Valid values are:
8, 15 for "altr,socfpga-denali-nand"
8, 16, 24 for "socionext,uniphier-denali-nand-v5a"
8, 16 for "socionext,uniphier-denali-nand-v5b"
- nand-ecc-maximize: see nand.txt for details
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.

View File

@ -1,7 +1,7 @@
Error location module
Required properties:
- compatible: Must be "ti,am33xx-elm"
- compatible: Must be "ti,am3352-elm"
- reg: physical base address and size of the registers map.
- interrupts: Interrupt number for the elm.

View File

@ -5,7 +5,7 @@ the GPMC controller with a name of "nand".
All timing relevant properties as well as generic gpmc child properties are
explained in a separate documents - please refer to
Documentation/devicetree/bindings/bus/ti-gpmc.txt
Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
For NAND specific properties such as ECC modes or bus width, please refer to
Documentation/devicetree/bindings/mtd/nand.txt

View File

@ -5,7 +5,7 @@ child nodes of the GPMC controller with a name of "nor".
All timing relevant properties as well as generic GPMC child properties are
explained in a separate documents. Please refer to
Documentation/devicetree/bindings/bus/ti-gpmc.txt
Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
Required properties:
- bank-width: Width of NOR flash in bytes. GPMC supports 8-bit and
@ -28,7 +28,7 @@ Required properties:
Optional properties:
- gpmc,XXX Additional GPMC timings and settings parameters. See
Documentation/devicetree/bindings/bus/ti-gpmc.txt
Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
Optional properties for partition table parsing:
- #address-cells: should be set to 1

View File

@ -5,7 +5,7 @@ the GPMC controller with a name of "onenand".
All timing relevant properties as well as generic gpmc child properties are
explained in a separate documents - please refer to
Documentation/devicetree/bindings/bus/ti-gpmc.txt
Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
Required properties:

View File

@ -4,7 +4,12 @@ The GPMI nand controller provides an interface to control the
NAND flash chips.
Required properties:
- compatible : should be "fsl,<chip>-gpmi-nand"
- compatible : should be "fsl,<chip>-gpmi-nand", chip can be:
* imx23
* imx28
* imx6q
* imx6sx
* imx7d
- reg : should contain registers location and length for gpmi and bch.
- reg-names: Should contain the reg names "gpmi-nand" and "bch"
- interrupts : BCH interrupt number.
@ -13,6 +18,13 @@ Required properties:
and GPMI DMA channel ID.
Refer to dma.txt and fsl-mxs-dma.txt for details.
- dma-names: Must be "rx-tx".
- clocks : clocks phandle and clock specifier corresponding to each clock
specified in clock-names.
- clock-names : The "gpmi_io" clock is always required. Which clocks are
exactly required depends on chip:
* imx23/imx28 : "gpmi_io"
* imx6q/sx : "gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch"
* imx7d : "gpmi_io", "gpmi_bch_apb"
Optional properties:
- nand-on-flash-bbt: boolean to enable on flash bbt option if not

View File

@ -12,7 +12,8 @@ tree nodes.
The first part of NFC is NAND Controller Interface (NFI) HW.
Required NFI properties:
- compatible: Should be "mediatek,mtxxxx-nfc".
- compatible: Should be one of "mediatek,mt2701-nfc",
"mediatek,mt2712-nfc".
- reg: Base physical address and size of NFI.
- interrupts: Interrupts of NFI.
- clocks: NFI required clocks.
@ -141,7 +142,7 @@ Example:
==============
Required BCH properties:
- compatible: Should be "mediatek,mtxxxx-ecc".
- compatible: Should be one of "mediatek,mt2701-ecc", "mediatek,mt2712-ecc".
- reg: Base physical address and size of ECC.
- interrupts: Interrupts of ECC.
- clocks: ECC required clocks.

View File

@ -21,7 +21,7 @@ Optional NAND chip properties:
- nand-ecc-mode : String, operation mode of the NAND ecc mode.
Supported values are: "none", "soft", "hw", "hw_syndrome",
"hw_oob_first".
"hw_oob_first", "on-die".
Deprecated values:
"soft_bch": use "soft" and nand-ecc-algo instead
- nand-ecc-algo: string, algorithm of NAND ECC.

View File

@ -9,7 +9,7 @@ the GPMC controller with an "ethernet" name.
All timing relevant properties as well as generic GPMC child properties are
explained in a separate documents. Please refer to
Documentation/devicetree/bindings/bus/ti-gpmc.txt
Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
For the properties relevant to the ethernet controller connected to the GPMC
refer to the binding documentation of the device. For example, the documentation
@ -43,7 +43,7 @@ Required properties:
Optional properties:
- gpmc,XXX Additional GPMC timings and settings parameters. See
Documentation/devicetree/bindings/bus/ti-gpmc.txt
Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
Example:

View File

@ -3895,6 +3895,12 @@ M: Pali Rohár <pali.rohar@gmail.com>
S: Maintained
F: drivers/platform/x86/dell-wmi.c
DENALI NAND DRIVER
M: Masahiro Yamada <yamada.masahiro@socionext.com>
L: linux-mtd@lists.infradead.org
S: Supported
F: drivers/mtd/nand/denali*
DESIGNWARE USB2 DRD IP DRIVER
M: John Youn <johnyoun@synopsys.com>
L: linux-usb@vger.kernel.org

View File

@ -308,6 +308,7 @@ config MTD_NAND_CS553X
config MTD_NAND_ATMEL
tristate "Support for NAND Flash / SmartMedia on AT91"
depends on ARCH_AT91
select MFD_ATMEL_SMC
help
Enables support for NAND Flash / Smart Media Card interface
on Atmel AT91 processors.
@ -542,6 +543,7 @@ config MTD_NAND_SUNXI
config MTD_NAND_HISI504
tristate "Support for NAND controller on Hisilicon SoC Hip04"
depends on ARCH_HISI || COMPILE_TEST
depends on HAS_DMA
help
Enables support for NAND controller on Hisilicon SoC Hip04.
@ -555,6 +557,7 @@ config MTD_NAND_QCOM
config MTD_NAND_MTK
tristate "Support for NAND controller on MTK SoCs"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on HAS_DMA
help
Enables support for NAND controller on MTK SoCs.

View File

@ -57,6 +57,7 @@
#include <linux/interrupt.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/atmel-matrix.h>
#include <linux/mfd/syscon/atmel-smc.h>
#include <linux/module.h>
#include <linux/mtd/nand.h>
#include <linux/of_address.h>
@ -64,7 +65,6 @@
#include <linux/of_platform.h>
#include <linux/iopoll.h>
#include <linux/platform_device.h>
#include <linux/platform_data/atmel.h>
#include <linux/regmap.h>
#include "pmecc.h"
@ -151,6 +151,8 @@ struct atmel_nand_cs {
void __iomem *virt;
dma_addr_t dma;
} io;
struct atmel_smc_cs_conf smcconf;
};
struct atmel_nand {
@ -196,6 +198,8 @@ struct atmel_nand_controller_ops {
void (*nand_init)(struct atmel_nand_controller *nc,
struct atmel_nand *nand);
int (*ecc_init)(struct atmel_nand *nand);
int (*setup_data_interface)(struct atmel_nand *nand, int csline,
const struct nand_data_interface *conf);
};
struct atmel_nand_controller_caps {
@ -912,7 +916,7 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_hsmc_nand_controller *nc;
int ret;
int ret, status;
nc = to_hsmc_nand_controller(chip->controller);
@ -954,6 +958,10 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n",
ret);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return ret;
}
@ -1175,6 +1183,295 @@ static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
return 0;
}
static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
const struct nand_data_interface *conf,
struct atmel_smc_cs_conf *smcconf)
{
u32 ncycles, totalcycles, timeps, mckperiodps;
struct atmel_nand_controller *nc;
int ret;
nc = to_nand_controller(nand->base.controller);
/* DDR interface not supported. */
if (conf->type != NAND_SDR_IFACE)
return -ENOTSUPP;
/*
* tRC < 30ns implies EDO mode. This controller does not support this
* mode.
*/
if (conf->timings.sdr.tRC_min < 30)
return -ENOTSUPP;
atmel_smc_cs_conf_init(smcconf);
mckperiodps = NSEC_PER_SEC / clk_get_rate(nc->mck);
mckperiodps *= 1000;
/*
* Set write pulse timing. This one is easy to extract:
*
* NWE_PULSE = tWP
*/
ncycles = DIV_ROUND_UP(conf->timings.sdr.tWP_min, mckperiodps);
totalcycles = ncycles;
ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NWE_SHIFT,
ncycles);
if (ret)
return ret;
/*
* The write setup timing depends on the operation done on the NAND.
* All operations goes through the same data bus, but the operation
* type depends on the address we are writing to (ALE/CLE address
* lines).
* Since we have no way to differentiate the different operations at
* the SMC level, we must consider the worst case (the biggest setup
* time among all operation types):
*
* NWE_SETUP = max(tCLS, tCS, tALS, tDS) - NWE_PULSE
*/
timeps = max3(conf->timings.sdr.tCLS_min, conf->timings.sdr.tCS_min,
conf->timings.sdr.tALS_min);
timeps = max(timeps, conf->timings.sdr.tDS_min);
ncycles = DIV_ROUND_UP(timeps, mckperiodps);
ncycles = ncycles > totalcycles ? ncycles - totalcycles : 0;
totalcycles += ncycles;
ret = atmel_smc_cs_conf_set_setup(smcconf, ATMEL_SMC_NWE_SHIFT,
ncycles);
if (ret)
return ret;
/*
* As for the write setup timing, the write hold timing depends on the
* operation done on the NAND:
*
* NWE_HOLD = max(tCLH, tCH, tALH, tDH, tWH)
*/
timeps = max3(conf->timings.sdr.tCLH_min, conf->timings.sdr.tCH_min,
conf->timings.sdr.tALH_min);
timeps = max3(timeps, conf->timings.sdr.tDH_min,
conf->timings.sdr.tWH_min);
ncycles = DIV_ROUND_UP(timeps, mckperiodps);
totalcycles += ncycles;
/*
* The write cycle timing is directly matching tWC, but is also
* dependent on the other timings on the setup and hold timings we
* calculated earlier, which gives:
*
* NWE_CYCLE = max(tWC, NWE_SETUP + NWE_PULSE + NWE_HOLD)
*/
ncycles = DIV_ROUND_UP(conf->timings.sdr.tWC_min, mckperiodps);
ncycles = max(totalcycles, ncycles);
ret = atmel_smc_cs_conf_set_cycle(smcconf, ATMEL_SMC_NWE_SHIFT,
ncycles);
if (ret)
return ret;
/*
* We don't want the CS line to be toggled between each byte/word
* transfer to the NAND. The only way to guarantee that is to have the
* NCS_{WR,RD}_{SETUP,HOLD} timings set to 0, which in turn means:
*
* NCS_WR_PULSE = NWE_CYCLE
*/
ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NCS_WR_SHIFT,
ncycles);
if (ret)
return ret;
/*
* As for the write setup timing, the read hold timing depends on the
* operation done on the NAND:
*
* NRD_HOLD = max(tREH, tRHOH)
*/
timeps = max(conf->timings.sdr.tREH_min, conf->timings.sdr.tRHOH_min);
ncycles = DIV_ROUND_UP(timeps, mckperiodps);
totalcycles = ncycles;
/*
* TDF = tRHZ - NRD_HOLD
*/
ncycles = DIV_ROUND_UP(conf->timings.sdr.tRHZ_max, mckperiodps);
ncycles -= totalcycles;
/*
* In ONFI 4.0 specs, tRHZ has been increased to support EDO NANDs and
* we might end up with a config that does not fit in the TDF field.
* Just take the max value in this case and hope that the NAND is more
* tolerant than advertised.
*/
if (ncycles > ATMEL_SMC_MODE_TDF_MAX)
ncycles = ATMEL_SMC_MODE_TDF_MAX;
else if (ncycles < ATMEL_SMC_MODE_TDF_MIN)
ncycles = ATMEL_SMC_MODE_TDF_MIN;
smcconf->mode |= ATMEL_SMC_MODE_TDF(ncycles) |
ATMEL_SMC_MODE_TDFMODE_OPTIMIZED;
/*
* Read pulse timing directly matches tRP:
*
* NRD_PULSE = tRP
*/
ncycles = DIV_ROUND_UP(conf->timings.sdr.tRP_min, mckperiodps);
totalcycles += ncycles;
ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NRD_SHIFT,
ncycles);
if (ret)
return ret;
/*
* The write cycle timing is directly matching tWC, but is also
* dependent on the setup and hold timings we calculated earlier,
* which gives:
*
* NRD_CYCLE = max(tRC, NRD_PULSE + NRD_HOLD)
*
* NRD_SETUP is always 0.
*/
ncycles = DIV_ROUND_UP(conf->timings.sdr.tRC_min, mckperiodps);
ncycles = max(totalcycles, ncycles);
ret = atmel_smc_cs_conf_set_cycle(smcconf, ATMEL_SMC_NRD_SHIFT,
ncycles);
if (ret)
return ret;
/*
* We don't want the CS line to be toggled between each byte/word
* transfer from the NAND. The only way to guarantee that is to have
* the NCS_{WR,RD}_{SETUP,HOLD} timings set to 0, which in turn means:
*
* NCS_RD_PULSE = NRD_CYCLE
*/
ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NCS_RD_SHIFT,
ncycles);
if (ret)
return ret;
/* Txxx timings are directly matching tXXX ones. */
ncycles = DIV_ROUND_UP(conf->timings.sdr.tCLR_min, mckperiodps);
ret = atmel_smc_cs_conf_set_timing(smcconf,
ATMEL_HSMC_TIMINGS_TCLR_SHIFT,
ncycles);
if (ret)
return ret;
ncycles = DIV_ROUND_UP(conf->timings.sdr.tADL_min, mckperiodps);
ret = atmel_smc_cs_conf_set_timing(smcconf,
ATMEL_HSMC_TIMINGS_TADL_SHIFT,
ncycles);
if (ret)
return ret;
ncycles = DIV_ROUND_UP(conf->timings.sdr.tAR_min, mckperiodps);
ret = atmel_smc_cs_conf_set_timing(smcconf,
ATMEL_HSMC_TIMINGS_TAR_SHIFT,
ncycles);
if (ret)
return ret;
ncycles = DIV_ROUND_UP(conf->timings.sdr.tRR_min, mckperiodps);
ret = atmel_smc_cs_conf_set_timing(smcconf,
ATMEL_HSMC_TIMINGS_TRR_SHIFT,
ncycles);
if (ret)
return ret;
ncycles = DIV_ROUND_UP(conf->timings.sdr.tWB_max, mckperiodps);
ret = atmel_smc_cs_conf_set_timing(smcconf,
ATMEL_HSMC_TIMINGS_TWB_SHIFT,
ncycles);
if (ret)
return ret;
/* Attach the CS line to the NFC logic. */
smcconf->timings |= ATMEL_HSMC_TIMINGS_NFSEL;
/* Set the appropriate data bus width. */
if (nand->base.options & NAND_BUSWIDTH_16)
smcconf->mode |= ATMEL_SMC_MODE_DBW_16;
/* Operate in NRD/NWE READ/WRITEMODE. */
smcconf->mode |= ATMEL_SMC_MODE_READMODE_NRD |
ATMEL_SMC_MODE_WRITEMODE_NWE;
return 0;
}
static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand,
int csline,
const struct nand_data_interface *conf)
{
struct atmel_nand_controller *nc;
struct atmel_smc_cs_conf smcconf;
struct atmel_nand_cs *cs;
int ret;
nc = to_nand_controller(nand->base.controller);
ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf);
if (ret)
return ret;
if (csline == NAND_DATA_IFACE_CHECK_ONLY)
return 0;
cs = &nand->cs[csline];
cs->smcconf = smcconf;
atmel_smc_cs_conf_apply(nc->smc, cs->id, &cs->smcconf);
return 0;
}
static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
int csline,
const struct nand_data_interface *conf)
{
struct atmel_nand_controller *nc;
struct atmel_smc_cs_conf smcconf;
struct atmel_nand_cs *cs;
int ret;
nc = to_nand_controller(nand->base.controller);
ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf);
if (ret)
return ret;
if (csline == NAND_DATA_IFACE_CHECK_ONLY)
return 0;
cs = &nand->cs[csline];
cs->smcconf = smcconf;
if (cs->rb.type == ATMEL_NAND_NATIVE_RB)
cs->smcconf.timings |= ATMEL_HSMC_TIMINGS_RBNSEL(cs->rb.id);
atmel_hsmc_cs_conf_apply(nc->smc, cs->id, &cs->smcconf);
return 0;
}
static int atmel_nand_setup_data_interface(struct mtd_info *mtd, int csline,
const struct nand_data_interface *conf)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
nc = to_nand_controller(nand->base.controller);
if (csline >= nand->numcs ||
(csline < 0 && csline != NAND_DATA_IFACE_CHECK_ONLY))
return -EINVAL;
return nc->caps->ops->setup_data_interface(nand, csline, conf);
}
static void atmel_nand_init(struct atmel_nand_controller *nc,
struct atmel_nand *nand)
{
@ -1192,6 +1489,9 @@ static void atmel_nand_init(struct atmel_nand_controller *nc,
chip->write_buf = atmel_nand_write_buf;
chip->select_chip = atmel_nand_select_chip;
if (nc->mck && nc->caps->ops->setup_data_interface)
chip->setup_data_interface = atmel_nand_setup_data_interface;
/* Some NANDs require a longer delay than the default one (20us). */
chip->chip_delay = 40;
@ -1677,6 +1977,12 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
if (nc->caps->legacy_of_bindings)
return 0;
nc->mck = of_clk_get(dev->parent->of_node, 0);
if (IS_ERR(nc->mck)) {
dev_err(dev, "Failed to retrieve MCK clk\n");
return PTR_ERR(nc->mck);
}
np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
if (!np) {
dev_err(dev, "Missing or invalid atmel,smc property\n");
@ -1983,6 +2289,7 @@ static const struct atmel_nand_controller_ops atmel_hsmc_nc_ops = {
.remove = atmel_hsmc_nand_controller_remove,
.ecc_init = atmel_hsmc_nand_ecc_init,
.nand_init = atmel_hsmc_nand_init,
.setup_data_interface = atmel_hsmc_nand_setup_data_interface,
};
static const struct atmel_nand_controller_caps atmel_sama5_nc_caps = {
@ -2037,7 +2344,14 @@ atmel_smc_nand_controller_remove(struct atmel_nand_controller *nc)
return 0;
}
static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
/*
* The SMC reg layout of at91rm9200 is completely different which prevents us
* from re-using atmel_smc_nand_setup_data_interface() for the
* ->setup_data_interface() hook.
* At this point, there's no support for the at91rm9200 SMC IP, so we leave
* ->setup_data_interface() unassigned.
*/
static const struct atmel_nand_controller_ops at91rm9200_nc_ops = {
.probe = atmel_smc_nand_controller_probe,
.remove = atmel_smc_nand_controller_remove,
.ecc_init = atmel_nand_ecc_init,
@ -2045,6 +2359,20 @@ static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
};
static const struct atmel_nand_controller_caps atmel_rm9200_nc_caps = {
.ale_offs = BIT(21),
.cle_offs = BIT(22),
.ops = &at91rm9200_nc_ops,
};
static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
.probe = atmel_smc_nand_controller_probe,
.remove = atmel_smc_nand_controller_remove,
.ecc_init = atmel_nand_ecc_init,
.nand_init = atmel_smc_nand_init,
.setup_data_interface = atmel_smc_nand_setup_data_interface,
};
static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = {
.ale_offs = BIT(21),
.cle_offs = BIT(22),
.ops = &atmel_smc_nc_ops,
@ -2093,7 +2421,7 @@ static const struct of_device_id atmel_nand_controller_of_ids[] = {
},
{
.compatible = "atmel,at91sam9260-nand-controller",
.data = &atmel_rm9200_nc_caps,
.data = &atmel_sam9260_nc_caps,
},
{
.compatible = "atmel,at91sam9261-nand-controller",
@ -2181,6 +2509,24 @@ static int atmel_nand_controller_remove(struct platform_device *pdev)
return nc->caps->ops->remove(nc);
}
static __maybe_unused int atmel_nand_controller_resume(struct device *dev)
{
struct atmel_nand_controller *nc = dev_get_drvdata(dev);
struct atmel_nand *nand;
list_for_each_entry(nand, &nc->chips, node) {
int i;
for (i = 0; i < nand->numcs; i++)
nand_reset(&nand->base, i);
}
return 0;
}
static SIMPLE_DEV_PM_OPS(atmel_nand_controller_pm_ops, NULL,
atmel_nand_controller_resume);
static struct platform_driver atmel_nand_controller_driver = {
.driver = {
.name = "atmel-nand-controller",

View File

@ -392,6 +392,8 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
b47n->nand_chip.onfi_set_features = nand_onfi_get_set_features_notsupp;
b47n->nand_chip.onfi_get_features = nand_onfi_get_set_features_notsupp;
nand_chip->chip_delay = 50;
b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;

View File

@ -654,6 +654,8 @@ static int cafe_nand_probe(struct pci_dev *pdev,
cafe->nand.read_buf = cafe_read_buf;
cafe->nand.write_buf = cafe_write_buf;
cafe->nand.select_chip = cafe_select_chip;
cafe->nand.onfi_set_features = nand_onfi_get_set_features_notsupp;
cafe->nand.onfi_get_features = nand_onfi_get_set_features_notsupp;
cafe->nand.chip_delay = 0;

View File

@ -771,11 +771,14 @@ static int nand_davinci_probe(struct platform_device *pdev)
info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
info->chip.ecc.bytes = 10;
info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
info->chip.ecc.algo = NAND_ECC_BCH;
} else {
/* 1bit ecc hamming */
info->chip.ecc.calculate = nand_davinci_calculate_1bit;
info->chip.ecc.correct = nand_davinci_correct_1bit;
info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
info->chip.ecc.bytes = 3;
info->chip.ecc.algo = NAND_ECC_HAMMING;
}
info->chip.ecc.size = 512;
info->chip.ecc.strength = pdata->ecc_bits;

File diff suppressed because it is too large Load Diff

View File

@ -24,330 +24,315 @@
#include <linux/mtd/nand.h>
#define DEVICE_RESET 0x0
#define DEVICE_RESET__BANK0 0x0001
#define DEVICE_RESET__BANK1 0x0002
#define DEVICE_RESET__BANK2 0x0004
#define DEVICE_RESET__BANK3 0x0008
#define DEVICE_RESET__BANK(bank) BIT(bank)
#define TRANSFER_SPARE_REG 0x10
#define TRANSFER_SPARE_REG__FLAG 0x0001
#define TRANSFER_SPARE_REG__FLAG BIT(0)
#define LOAD_WAIT_CNT 0x20
#define LOAD_WAIT_CNT__VALUE 0xffff
#define LOAD_WAIT_CNT__VALUE GENMASK(15, 0)
#define PROGRAM_WAIT_CNT 0x30
#define PROGRAM_WAIT_CNT__VALUE 0xffff
#define PROGRAM_WAIT_CNT__VALUE GENMASK(15, 0)
#define ERASE_WAIT_CNT 0x40
#define ERASE_WAIT_CNT__VALUE 0xffff
#define ERASE_WAIT_CNT__VALUE GENMASK(15, 0)
#define INT_MON_CYCCNT 0x50
#define INT_MON_CYCCNT__VALUE 0xffff
#define INT_MON_CYCCNT__VALUE GENMASK(15, 0)
#define RB_PIN_ENABLED 0x60
#define RB_PIN_ENABLED__BANK0 0x0001
#define RB_PIN_ENABLED__BANK1 0x0002
#define RB_PIN_ENABLED__BANK2 0x0004
#define RB_PIN_ENABLED__BANK3 0x0008
#define RB_PIN_ENABLED__BANK(bank) BIT(bank)
#define MULTIPLANE_OPERATION 0x70
#define MULTIPLANE_OPERATION__FLAG 0x0001
#define MULTIPLANE_OPERATION__FLAG BIT(0)
#define MULTIPLANE_READ_ENABLE 0x80
#define MULTIPLANE_READ_ENABLE__FLAG 0x0001
#define MULTIPLANE_READ_ENABLE__FLAG BIT(0)
#define COPYBACK_DISABLE 0x90
#define COPYBACK_DISABLE__FLAG 0x0001
#define COPYBACK_DISABLE__FLAG BIT(0)
#define CACHE_WRITE_ENABLE 0xa0
#define CACHE_WRITE_ENABLE__FLAG 0x0001
#define CACHE_WRITE_ENABLE__FLAG BIT(0)
#define CACHE_READ_ENABLE 0xb0
#define CACHE_READ_ENABLE__FLAG 0x0001
#define CACHE_READ_ENABLE__FLAG BIT(0)
#define PREFETCH_MODE 0xc0
#define PREFETCH_MODE__PREFETCH_EN 0x0001
#define PREFETCH_MODE__PREFETCH_BURST_LENGTH 0xfff0
#define PREFETCH_MODE__PREFETCH_EN BIT(0)
#define PREFETCH_MODE__PREFETCH_BURST_LENGTH GENMASK(15, 4)
#define CHIP_ENABLE_DONT_CARE 0xd0
#define CHIP_EN_DONT_CARE__FLAG 0x01
#define CHIP_EN_DONT_CARE__FLAG BIT(0)
#define ECC_ENABLE 0xe0
#define ECC_ENABLE__FLAG 0x0001
#define ECC_ENABLE__FLAG BIT(0)
#define GLOBAL_INT_ENABLE 0xf0
#define GLOBAL_INT_EN_FLAG 0x01
#define GLOBAL_INT_EN_FLAG BIT(0)
#define WE_2_RE 0x100
#define WE_2_RE__VALUE 0x003f
#define TWHR2_AND_WE_2_RE 0x100
#define TWHR2_AND_WE_2_RE__WE_2_RE GENMASK(5, 0)
#define TWHR2_AND_WE_2_RE__TWHR2 GENMASK(13, 8)
#define ADDR_2_DATA 0x110
#define ADDR_2_DATA__VALUE 0x003f
#define TCWAW_AND_ADDR_2_DATA 0x110
/* The width of ADDR_2_DATA is 6 bit for old IP, 7 bit for new IP */
#define TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA GENMASK(6, 0)
#define TCWAW_AND_ADDR_2_DATA__TCWAW GENMASK(13, 8)
#define RE_2_WE 0x120
#define RE_2_WE__VALUE 0x003f
#define RE_2_WE__VALUE GENMASK(5, 0)
#define ACC_CLKS 0x130
#define ACC_CLKS__VALUE 0x000f
#define ACC_CLKS__VALUE GENMASK(3, 0)
#define NUMBER_OF_PLANES 0x140
#define NUMBER_OF_PLANES__VALUE 0x0007
#define NUMBER_OF_PLANES__VALUE GENMASK(2, 0)
#define PAGES_PER_BLOCK 0x150
#define PAGES_PER_BLOCK__VALUE 0xffff
#define PAGES_PER_BLOCK__VALUE GENMASK(15, 0)
#define DEVICE_WIDTH 0x160
#define DEVICE_WIDTH__VALUE 0x0003
#define DEVICE_WIDTH__VALUE GENMASK(1, 0)
#define DEVICE_MAIN_AREA_SIZE 0x170
#define DEVICE_MAIN_AREA_SIZE__VALUE 0xffff
#define DEVICE_MAIN_AREA_SIZE__VALUE GENMASK(15, 0)
#define DEVICE_SPARE_AREA_SIZE 0x180
#define DEVICE_SPARE_AREA_SIZE__VALUE 0xffff
#define DEVICE_SPARE_AREA_SIZE__VALUE GENMASK(15, 0)
#define TWO_ROW_ADDR_CYCLES 0x190
#define TWO_ROW_ADDR_CYCLES__FLAG 0x0001
#define TWO_ROW_ADDR_CYCLES__FLAG BIT(0)
#define MULTIPLANE_ADDR_RESTRICT 0x1a0
#define MULTIPLANE_ADDR_RESTRICT__FLAG 0x0001
#define MULTIPLANE_ADDR_RESTRICT__FLAG BIT(0)
#define ECC_CORRECTION 0x1b0
#define ECC_CORRECTION__VALUE 0x001f
#define ECC_CORRECTION__VALUE GENMASK(4, 0)
#define ECC_CORRECTION__ERASE_THRESHOLD GENMASK(31, 16)
#define MAKE_ECC_CORRECTION(val, thresh) \
(((val) & (ECC_CORRECTION__VALUE)) | \
(((thresh) << 16) & (ECC_CORRECTION__ERASE_THRESHOLD)))
#define READ_MODE 0x1c0
#define READ_MODE__VALUE 0x000f
#define READ_MODE__VALUE GENMASK(3, 0)
#define WRITE_MODE 0x1d0
#define WRITE_MODE__VALUE 0x000f
#define WRITE_MODE__VALUE GENMASK(3, 0)
#define COPYBACK_MODE 0x1e0
#define COPYBACK_MODE__VALUE 0x000f
#define COPYBACK_MODE__VALUE GENMASK(3, 0)
#define RDWR_EN_LO_CNT 0x1f0
#define RDWR_EN_LO_CNT__VALUE 0x001f
#define RDWR_EN_LO_CNT__VALUE GENMASK(4, 0)
#define RDWR_EN_HI_CNT 0x200
#define RDWR_EN_HI_CNT__VALUE 0x001f
#define RDWR_EN_HI_CNT__VALUE GENMASK(4, 0)
#define MAX_RD_DELAY 0x210
#define MAX_RD_DELAY__VALUE 0x000f
#define MAX_RD_DELAY__VALUE GENMASK(3, 0)
#define CS_SETUP_CNT 0x220
#define CS_SETUP_CNT__VALUE 0x001f
#define CS_SETUP_CNT__VALUE GENMASK(4, 0)
#define CS_SETUP_CNT__TWB GENMASK(17, 12)
#define SPARE_AREA_SKIP_BYTES 0x230
#define SPARE_AREA_SKIP_BYTES__VALUE 0x003f
#define SPARE_AREA_SKIP_BYTES__VALUE GENMASK(5, 0)
#define SPARE_AREA_MARKER 0x240
#define SPARE_AREA_MARKER__VALUE 0xffff
#define SPARE_AREA_MARKER__VALUE GENMASK(15, 0)
#define DEVICES_CONNECTED 0x250
#define DEVICES_CONNECTED__VALUE 0x0007
#define DEVICES_CONNECTED__VALUE GENMASK(2, 0)
#define DIE_MASK 0x260
#define DIE_MASK__VALUE 0x00ff
#define DIE_MASK__VALUE GENMASK(7, 0)
#define FIRST_BLOCK_OF_NEXT_PLANE 0x270
#define FIRST_BLOCK_OF_NEXT_PLANE__VALUE 0xffff
#define FIRST_BLOCK_OF_NEXT_PLANE__VALUE GENMASK(15, 0)
#define WRITE_PROTECT 0x280
#define WRITE_PROTECT__FLAG 0x0001
#define WRITE_PROTECT__FLAG BIT(0)
#define RE_2_RE 0x290
#define RE_2_RE__VALUE 0x003f
#define RE_2_RE__VALUE GENMASK(5, 0)
#define MANUFACTURER_ID 0x300
#define MANUFACTURER_ID__VALUE 0x00ff
#define MANUFACTURER_ID__VALUE GENMASK(7, 0)
#define DEVICE_ID 0x310
#define DEVICE_ID__VALUE 0x00ff
#define DEVICE_ID__VALUE GENMASK(7, 0)
#define DEVICE_PARAM_0 0x320
#define DEVICE_PARAM_0__VALUE 0x00ff
#define DEVICE_PARAM_0__VALUE GENMASK(7, 0)
#define DEVICE_PARAM_1 0x330
#define DEVICE_PARAM_1__VALUE 0x00ff
#define DEVICE_PARAM_1__VALUE GENMASK(7, 0)
#define DEVICE_PARAM_2 0x340
#define DEVICE_PARAM_2__VALUE 0x00ff
#define DEVICE_PARAM_2__VALUE GENMASK(7, 0)
#define LOGICAL_PAGE_DATA_SIZE 0x350
#define LOGICAL_PAGE_DATA_SIZE__VALUE 0xffff
#define LOGICAL_PAGE_DATA_SIZE__VALUE GENMASK(15, 0)
#define LOGICAL_PAGE_SPARE_SIZE 0x360
#define LOGICAL_PAGE_SPARE_SIZE__VALUE 0xffff
#define LOGICAL_PAGE_SPARE_SIZE__VALUE GENMASK(15, 0)
#define REVISION 0x370
#define REVISION__VALUE 0xffff
#define REVISION__VALUE GENMASK(15, 0)
#define ONFI_DEVICE_FEATURES 0x380
#define ONFI_DEVICE_FEATURES__VALUE 0x003f
#define ONFI_DEVICE_FEATURES__VALUE GENMASK(5, 0)
#define ONFI_OPTIONAL_COMMANDS 0x390
#define ONFI_OPTIONAL_COMMANDS__VALUE 0x003f
#define ONFI_OPTIONAL_COMMANDS__VALUE GENMASK(5, 0)
#define ONFI_TIMING_MODE 0x3a0
#define ONFI_TIMING_MODE__VALUE 0x003f
#define ONFI_TIMING_MODE__VALUE GENMASK(5, 0)
#define ONFI_PGM_CACHE_TIMING_MODE 0x3b0
#define ONFI_PGM_CACHE_TIMING_MODE__VALUE 0x003f
#define ONFI_PGM_CACHE_TIMING_MODE__VALUE GENMASK(5, 0)
#define ONFI_DEVICE_NO_OF_LUNS 0x3c0
#define ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS 0x00ff
#define ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE 0x0100
#define ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS GENMASK(7, 0)
#define ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE BIT(8)
#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L 0x3d0
#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE 0xffff
#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE GENMASK(15, 0)
#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U 0x3e0
#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE 0xffff
#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE GENMASK(15, 0)
#define FEATURES 0x3f0
#define FEATURES__N_BANKS 0x0003
#define FEATURES__ECC_MAX_ERR 0x003c
#define FEATURES__DMA 0x0040
#define FEATURES__CMD_DMA 0x0080
#define FEATURES__PARTITION 0x0100
#define FEATURES__XDMA_SIDEBAND 0x0200
#define FEATURES__GPREG 0x0400
#define FEATURES__INDEX_ADDR 0x0800
#define FEATURES 0x3f0
#define FEATURES__N_BANKS GENMASK(1, 0)
#define FEATURES__ECC_MAX_ERR GENMASK(5, 2)
#define FEATURES__DMA BIT(6)
#define FEATURES__CMD_DMA BIT(7)
#define FEATURES__PARTITION BIT(8)
#define FEATURES__XDMA_SIDEBAND BIT(9)
#define FEATURES__GPREG BIT(10)
#define FEATURES__INDEX_ADDR BIT(11)
#define TRANSFER_MODE 0x400
#define TRANSFER_MODE__VALUE 0x0003
#define TRANSFER_MODE__VALUE GENMASK(1, 0)
#define INTR_STATUS(__bank) (0x410 + ((__bank) * 0x50))
#define INTR_EN(__bank) (0x420 + ((__bank) * 0x50))
#define INTR_STATUS(bank) (0x410 + (bank) * 0x50)
#define INTR_EN(bank) (0x420 + (bank) * 0x50)
/* bit[1:0] is used differently depending on IP version */
#define INTR__ECC_UNCOR_ERR 0x0001 /* new IP */
#define INTR__ECC_TRANSACTION_DONE 0x0001 /* old IP */
#define INTR__ECC_ERR 0x0002 /* old IP */
#define INTR__DMA_CMD_COMP 0x0004
#define INTR__TIME_OUT 0x0008
#define INTR__PROGRAM_FAIL 0x0010
#define INTR__ERASE_FAIL 0x0020
#define INTR__LOAD_COMP 0x0040
#define INTR__PROGRAM_COMP 0x0080
#define INTR__ERASE_COMP 0x0100
#define INTR__PIPE_CPYBCK_CMD_COMP 0x0200
#define INTR__LOCKED_BLK 0x0400
#define INTR__UNSUP_CMD 0x0800
#define INTR__INT_ACT 0x1000
#define INTR__RST_COMP 0x2000
#define INTR__PIPE_CMD_ERR 0x4000
#define INTR__PAGE_XFER_INC 0x8000
#define INTR__ECC_UNCOR_ERR BIT(0) /* new IP */
#define INTR__ECC_TRANSACTION_DONE BIT(0) /* old IP */
#define INTR__ECC_ERR BIT(1) /* old IP */
#define INTR__DMA_CMD_COMP BIT(2)
#define INTR__TIME_OUT BIT(3)
#define INTR__PROGRAM_FAIL BIT(4)
#define INTR__ERASE_FAIL BIT(5)
#define INTR__LOAD_COMP BIT(6)
#define INTR__PROGRAM_COMP BIT(7)
#define INTR__ERASE_COMP BIT(8)
#define INTR__PIPE_CPYBCK_CMD_COMP BIT(9)
#define INTR__LOCKED_BLK BIT(10)
#define INTR__UNSUP_CMD BIT(11)
#define INTR__INT_ACT BIT(12)
#define INTR__RST_COMP BIT(13)
#define INTR__PIPE_CMD_ERR BIT(14)
#define INTR__PAGE_XFER_INC BIT(15)
#define INTR__ERASED_PAGE BIT(16)
#define PAGE_CNT(__bank) (0x430 + ((__bank) * 0x50))
#define ERR_PAGE_ADDR(__bank) (0x440 + ((__bank) * 0x50))
#define ERR_BLOCK_ADDR(__bank) (0x450 + ((__bank) * 0x50))
#define PAGE_CNT(bank) (0x430 + (bank) * 0x50)
#define ERR_PAGE_ADDR(bank) (0x440 + (bank) * 0x50)
#define ERR_BLOCK_ADDR(bank) (0x450 + (bank) * 0x50)
#define ECC_THRESHOLD 0x600
#define ECC_THRESHOLD__VALUE 0x03ff
#define ECC_THRESHOLD__VALUE GENMASK(9, 0)
#define ECC_ERROR_BLOCK_ADDRESS 0x610
#define ECC_ERROR_BLOCK_ADDRESS__VALUE 0xffff
#define ECC_ERROR_BLOCK_ADDRESS__VALUE GENMASK(15, 0)
#define ECC_ERROR_PAGE_ADDRESS 0x620
#define ECC_ERROR_PAGE_ADDRESS__VALUE 0x0fff
#define ECC_ERROR_PAGE_ADDRESS__BANK 0xf000
#define ECC_ERROR_PAGE_ADDRESS__VALUE GENMASK(11, 0)
#define ECC_ERROR_PAGE_ADDRESS__BANK GENMASK(15, 12)
#define ECC_ERROR_ADDRESS 0x630
#define ECC_ERROR_ADDRESS__OFFSET 0x0fff
#define ECC_ERROR_ADDRESS__SECTOR_NR 0xf000
#define ECC_ERROR_ADDRESS__OFFSET GENMASK(11, 0)
#define ECC_ERROR_ADDRESS__SECTOR_NR GENMASK(15, 12)
#define ERR_CORRECTION_INFO 0x640
#define ERR_CORRECTION_INFO__BYTEMASK 0x00ff
#define ERR_CORRECTION_INFO__DEVICE_NR 0x0f00
#define ERR_CORRECTION_INFO__ERROR_TYPE 0x4000
#define ERR_CORRECTION_INFO__LAST_ERR_INFO 0x8000
#define ERR_CORRECTION_INFO__BYTEMASK GENMASK(7, 0)
#define ERR_CORRECTION_INFO__DEVICE_NR GENMASK(11, 8)
#define ERR_CORRECTION_INFO__ERROR_TYPE BIT(14)
#define ERR_CORRECTION_INFO__LAST_ERR_INFO BIT(15)
#define ECC_COR_INFO(bank) (0x650 + (bank) / 2 * 0x10)
#define ECC_COR_INFO__SHIFT(bank) ((bank) % 2 * 8)
#define ECC_COR_INFO__MAX_ERRORS 0x007f
#define ECC_COR_INFO__UNCOR_ERR 0x0080
#define ECC_COR_INFO__MAX_ERRORS GENMASK(6, 0)
#define ECC_COR_INFO__UNCOR_ERR BIT(7)
#define CFG_DATA_BLOCK_SIZE 0x6b0
#define CFG_LAST_DATA_BLOCK_SIZE 0x6c0
#define CFG_NUM_DATA_BLOCKS 0x6d0
#define CFG_META_DATA_SIZE 0x6e0
#define DMA_ENABLE 0x700
#define DMA_ENABLE__FLAG 0x0001
#define DMA_ENABLE__FLAG BIT(0)
#define IGNORE_ECC_DONE 0x710
#define IGNORE_ECC_DONE__FLAG 0x0001
#define IGNORE_ECC_DONE__FLAG BIT(0)
#define DMA_INTR 0x720
#define DMA_INTR_EN 0x730
#define DMA_INTR__TARGET_ERROR 0x0001
#define DMA_INTR__DESC_COMP_CHANNEL0 0x0002
#define DMA_INTR__DESC_COMP_CHANNEL1 0x0004
#define DMA_INTR__DESC_COMP_CHANNEL2 0x0008
#define DMA_INTR__DESC_COMP_CHANNEL3 0x0010
#define DMA_INTR__MEMCOPY_DESC_COMP 0x0020
#define DMA_INTR__TARGET_ERROR BIT(0)
#define DMA_INTR__DESC_COMP_CHANNEL0 BIT(1)
#define DMA_INTR__DESC_COMP_CHANNEL1 BIT(2)
#define DMA_INTR__DESC_COMP_CHANNEL2 BIT(3)
#define DMA_INTR__DESC_COMP_CHANNEL3 BIT(4)
#define DMA_INTR__MEMCOPY_DESC_COMP BIT(5)
#define TARGET_ERR_ADDR_LO 0x740
#define TARGET_ERR_ADDR_LO__VALUE 0xffff
#define TARGET_ERR_ADDR_LO__VALUE GENMASK(15, 0)
#define TARGET_ERR_ADDR_HI 0x750
#define TARGET_ERR_ADDR_HI__VALUE 0xffff
#define TARGET_ERR_ADDR_HI__VALUE GENMASK(15, 0)
#define CHNL_ACTIVE 0x760
#define CHNL_ACTIVE__CHANNEL0 0x0001
#define CHNL_ACTIVE__CHANNEL1 0x0002
#define CHNL_ACTIVE__CHANNEL2 0x0004
#define CHNL_ACTIVE__CHANNEL3 0x0008
#define FAIL 1 /*failed flag*/
#define PASS 0 /*success flag*/
#define CLK_X 5
#define CLK_MULTI 4
#define ONFI_BLOOM_TIME 1
#define MODE5_WORKAROUND 0
#define MODE_00 0x00000000
#define MODE_01 0x04000000
#define MODE_10 0x08000000
#define MODE_11 0x0C000000
#define ECC_SECTOR_SIZE 512
struct nand_buf {
int head;
int tail;
uint8_t *buf;
dma_addr_t dma_buf;
};
#define INTEL_CE4100 1
#define INTEL_MRST 2
#define DT 3
#define CHNL_ACTIVE__CHANNEL0 BIT(0)
#define CHNL_ACTIVE__CHANNEL1 BIT(1)
#define CHNL_ACTIVE__CHANNEL2 BIT(2)
#define CHNL_ACTIVE__CHANNEL3 BIT(3)
struct denali_nand_info {
struct nand_chip nand;
int flash_bank; /* currently selected chip */
int status;
int platform;
struct nand_buf buf;
unsigned long clk_x_rate; /* bus interface clock rate */
int active_bank; /* currently selected bank */
struct device *dev;
int total_used_banks;
int page;
void __iomem *flash_reg; /* Register Interface */
void __iomem *flash_mem; /* Host Data/Command Interface */
void __iomem *reg; /* Register Interface */
void __iomem *host; /* Host Data/Command Interface */
/* elements used by ISR */
struct completion complete;
spinlock_t irq_lock;
uint32_t irq_mask;
uint32_t irq_status;
int irq;
int devnum; /* represent how many nands connected */
int bbtskipbytes;
void *buf;
dma_addr_t dma_addr;
int dma_avail;
int devs_per_cs; /* devices connected in parallel */
int oob_skip_bytes;
int max_banks;
unsigned int revision;
unsigned int caps;
const struct nand_ecc_caps *ecc_caps;
};
#define DENALI_CAP_HW_ECC_FIXUP BIT(0)
#define DENALI_CAP_DMA_64BIT BIT(1)
int denali_calc_ecc_bytes(int step_size, int strength);
extern int denali_init(struct denali_nand_info *denali);
extern void denali_remove(struct denali_nand_info *denali);

View File

@ -32,10 +32,31 @@ struct denali_dt {
struct denali_dt_data {
unsigned int revision;
unsigned int caps;
const struct nand_ecc_caps *ecc_caps;
};
NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
512, 8, 15);
static const struct denali_dt_data denali_socfpga_data = {
.caps = DENALI_CAP_HW_ECC_FIXUP,
.ecc_caps = &denali_socfpga_ecc_caps,
};
NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,
1024, 8, 16, 24);
static const struct denali_dt_data denali_uniphier_v5a_data = {
.caps = DENALI_CAP_HW_ECC_FIXUP |
DENALI_CAP_DMA_64BIT,
.ecc_caps = &denali_uniphier_v5a_ecc_caps,
};
NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes,
1024, 8, 16);
static const struct denali_dt_data denali_uniphier_v5b_data = {
.revision = 0x0501,
.caps = DENALI_CAP_HW_ECC_FIXUP |
DENALI_CAP_DMA_64BIT,
.ecc_caps = &denali_uniphier_v5b_ecc_caps,
};
static const struct of_device_id denali_nand_dt_ids[] = {
@ -43,13 +64,21 @@ static const struct of_device_id denali_nand_dt_ids[] = {
.compatible = "altr,socfpga-denali-nand",
.data = &denali_socfpga_data,
},
{
.compatible = "socionext,uniphier-denali-nand-v5a",
.data = &denali_uniphier_v5a_data,
},
{
.compatible = "socionext,uniphier-denali-nand-v5b",
.data = &denali_uniphier_v5b_data,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
static int denali_dt_probe(struct platform_device *pdev)
{
struct resource *denali_reg, *nand_data;
struct resource *res;
struct denali_dt *dt;
const struct denali_dt_data *data;
struct denali_nand_info *denali;
@ -64,9 +93,9 @@ static int denali_dt_probe(struct platform_device *pdev)
if (data) {
denali->revision = data->revision;
denali->caps = data->caps;
denali->ecc_caps = data->ecc_caps;
}
denali->platform = DT;
denali->dev = &pdev->dev;
denali->irq = platform_get_irq(pdev, 0);
if (denali->irq < 0) {
@ -74,17 +103,15 @@ static int denali_dt_probe(struct platform_device *pdev)
return denali->irq;
}
denali_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"denali_reg");
denali->flash_reg = devm_ioremap_resource(&pdev->dev, denali_reg);
if (IS_ERR(denali->flash_reg))
return PTR_ERR(denali->flash_reg);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg");
denali->reg = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(denali->reg))
return PTR_ERR(denali->reg);
nand_data = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"nand_data");
denali->flash_mem = devm_ioremap_resource(&pdev->dev, nand_data);
if (IS_ERR(denali->flash_mem))
return PTR_ERR(denali->flash_mem);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
denali->host = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(denali->host))
return PTR_ERR(denali->host);
dt->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dt->clk)) {
@ -93,6 +120,8 @@ static int denali_dt_probe(struct platform_device *pdev)
}
clk_prepare_enable(dt->clk);
denali->clk_x_rate = clk_get_rate(dt->clk);
ret = denali_init(denali);
if (ret)
goto out_disable_clk;

View File

@ -19,6 +19,9 @@
#define DENALI_NAND_NAME "denali-nand-pci"
#define INTEL_CE4100 1
#define INTEL_MRST 2
/* List of platforms this NAND controller has be integrated into */
static const struct pci_device_id denali_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
@ -27,6 +30,8 @@ static const struct pci_device_id denali_pci_ids[] = {
};
MODULE_DEVICE_TABLE(pci, denali_pci_ids);
NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15);
static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int ret;
@ -45,13 +50,11 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
}
if (id->driver_data == INTEL_CE4100) {
denali->platform = INTEL_CE4100;
mem_base = pci_resource_start(dev, 0);
mem_len = pci_resource_len(dev, 1);
csr_base = pci_resource_start(dev, 1);
csr_len = pci_resource_len(dev, 1);
} else {
denali->platform = INTEL_MRST;
csr_base = pci_resource_start(dev, 0);
csr_len = pci_resource_len(dev, 0);
mem_base = pci_resource_start(dev, 1);
@ -65,6 +68,9 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
pci_set_master(dev);
denali->dev = &dev->dev;
denali->irq = dev->irq;
denali->ecc_caps = &denali_pci_ecc_caps;
denali->nand.ecc.options |= NAND_ECC_MAXIMIZE;
denali->clk_x_rate = 200000000; /* 200 MHz */
ret = pci_request_regions(dev, DENALI_NAND_NAME);
if (ret) {
@ -72,14 +78,14 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
return ret;
}
denali->flash_reg = ioremap_nocache(csr_base, csr_len);
if (!denali->flash_reg) {
denali->reg = ioremap_nocache(csr_base, csr_len);
if (!denali->reg) {
dev_err(&dev->dev, "Spectra: Unable to remap memory region\n");
return -ENOMEM;
}
denali->flash_mem = ioremap_nocache(mem_base, mem_len);
if (!denali->flash_mem) {
denali->host = ioremap_nocache(mem_base, mem_len);
if (!denali->host) {
dev_err(&dev->dev, "Spectra: ioremap_nocache failed!");
ret = -ENOMEM;
goto failed_remap_reg;
@ -94,9 +100,9 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
return 0;
failed_remap_mem:
iounmap(denali->flash_mem);
iounmap(denali->host);
failed_remap_reg:
iounmap(denali->flash_reg);
iounmap(denali->reg);
return ret;
}
@ -106,8 +112,8 @@ static void denali_pci_remove(struct pci_dev *dev)
struct denali_nand_info *denali = pci_get_drvdata(dev);
denali_remove(denali);
iounmap(denali->flash_reg);
iounmap(denali->flash_mem);
iounmap(denali->reg);
iounmap(denali->host);
}
static struct pci_driver denali_pci_driver = {

View File

@ -1260,6 +1260,8 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
nand->read_buf = docg4_read_buf;
nand->write_buf = docg4_write_buf16;
nand->erase = docg4_erase_block;
nand->onfi_set_features = nand_onfi_get_set_features_notsupp;
nand->onfi_get_features = nand_onfi_get_set_features_notsupp;
nand->ecc.read_page = docg4_read_page;
nand->ecc.write_page = docg4_write_page;
nand->ecc.read_page_raw = docg4_read_page_raw;

View File

@ -775,6 +775,8 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
chip->select_chip = fsl_elbc_select_chip;
chip->cmdfunc = fsl_elbc_cmdfunc;
chip->waitfunc = fsl_elbc_wait;
chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;

View File

@ -171,34 +171,6 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
ifc_nand_ctrl->index += mtd->writesize;
}
static int is_blank(struct mtd_info *mtd, unsigned int bufnum)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2);
u32 __iomem *mainarea = (u32 __iomem *)addr;
u8 __iomem *oob = addr + mtd->writesize;
struct mtd_oob_region oobregion = { };
int i, section = 0;
for (i = 0; i < mtd->writesize / 4; i++) {
if (__raw_readl(&mainarea[i]) != 0xffffffff)
return 0;
}
mtd_ooblayout_ecc(mtd, section++, &oobregion);
while (oobregion.length) {
for (i = 0; i < oobregion.length; i++) {
if (__raw_readb(&oob[oobregion.offset + i]) != 0xff)
return 0;
}
mtd_ooblayout_ecc(mtd, section++, &oobregion);
}
return 1;
}
/* returns nonzero if entire page is blank */
static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
u32 *eccstat, unsigned int bufnum)
@ -274,16 +246,14 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
if (errors == 15) {
/*
* Uncorrectable error.
* OK only if the whole page is blank.
* We'll check for blank pages later.
*
* We disable ECCER reporting due to...
* erratum IFC-A002770 -- so report it now if we
* see an uncorrectable error in ECCSTAT.
*/
if (!is_blank(mtd, bufnum))
ctrl->nand_stat |=
IFC_NAND_EVTER_STAT_ECCER;
break;
ctrl->nand_stat |= IFC_NAND_EVTER_STAT_ECCER;
continue;
}
mtd->ecc_stats.corrected += errors;
@ -678,6 +648,39 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
return nand_fsr | NAND_STATUS_WP;
}
/*
* 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 *ecc = chip->oob_poi;
const int ecc_size = chip->ecc.bytes;
const int pkt_size = chip->ecc.size;
int i, res, bitflips = 0;
struct mtd_oob_region oobregion = { };
mtd_ooblayout_ecc(mtd, 0, &oobregion);
ecc += oobregion.offset;
for (i = 0; i < chip->ecc.steps; ++i) {
res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
NULL, 0,
chip->ecc.strength);
if (res < 0)
mtd->ecc_stats.failed++;
else
mtd->ecc_stats.corrected += res;
bitflips = max(res, bitflips);
buf += pkt_size;
ecc += ecc_size;
}
return bitflips;
}
static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
@ -689,8 +692,12 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
if (oob_required)
fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER)
dev_err(priv->dev, "NAND Flash ECC Uncorrectable Error\n");
if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) {
if (!oob_required)
fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
return check_erased_page(chip, buf);
}
if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
mtd->ecc_stats.failed++;
@ -831,6 +838,8 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
chip->select_chip = fsl_ifc_select_chip;
chip->cmdfunc = fsl_ifc_cmdfunc;
chip->waitfunc = fsl_ifc_wait;
chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;
@ -904,7 +913,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
chip->ecc.algo = NAND_ECC_HAMMING;
}
if (ctrl->version == FSL_IFC_VERSION_1_1_0)
if (ctrl->version >= FSL_IFC_VERSION_1_1_0)
fsl_ifc_sram_init(priv);
return 0;

View File

@ -302,25 +302,13 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
* This routine initializes timing parameters related to NAND memory access in
* FSMC registers
*/
static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
uint32_t busw, struct fsmc_nand_timings *timings)
static void fsmc_nand_setup(struct fsmc_nand_data *host,
struct fsmc_nand_timings *tims)
{
uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
uint32_t tclr, tar, thiz, thold, twait, tset;
struct fsmc_nand_timings *tims;
struct fsmc_nand_timings default_timings = {
.tclr = FSMC_TCLR_1,
.tar = FSMC_TAR_1,
.thiz = FSMC_THIZ_1,
.thold = FSMC_THOLD_4,
.twait = FSMC_TWAIT_6,
.tset = FSMC_TSET_0,
};
if (timings)
tims = timings;
else
tims = &default_timings;
unsigned int bank = host->bank;
void __iomem *regs = host->regs_va;
tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT;
@ -329,7 +317,7 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
twait = (tims->twait & FSMC_TWAIT_MASK) << FSMC_TWAIT_SHIFT;
tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
if (busw)
if (host->nand.options & NAND_BUSWIDTH_16)
writel_relaxed(value | FSMC_DEVWID_16,
FSMC_NAND_REG(regs, bank, PC));
else
@ -344,6 +332,87 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
FSMC_NAND_REG(regs, bank, ATTRIB));
}
static int fsmc_calc_timings(struct fsmc_nand_data *host,
const struct nand_sdr_timings *sdrt,
struct fsmc_nand_timings *tims)
{
unsigned long hclk = clk_get_rate(host->clk);
unsigned long hclkn = NSEC_PER_SEC / hclk;
uint32_t thiz, thold, twait, tset;
if (sdrt->tRC_min < 30000)
return -EOPNOTSUPP;
tims->tar = DIV_ROUND_UP(sdrt->tAR_min / 1000, hclkn) - 1;
if (tims->tar > FSMC_TAR_MASK)
tims->tar = FSMC_TAR_MASK;
tims->tclr = DIV_ROUND_UP(sdrt->tCLR_min / 1000, hclkn) - 1;
if (tims->tclr > FSMC_TCLR_MASK)
tims->tclr = FSMC_TCLR_MASK;
thiz = sdrt->tCS_min - sdrt->tWP_min;
tims->thiz = DIV_ROUND_UP(thiz / 1000, hclkn);
thold = sdrt->tDH_min;
if (thold < sdrt->tCH_min)
thold = sdrt->tCH_min;
if (thold < sdrt->tCLH_min)
thold = sdrt->tCLH_min;
if (thold < sdrt->tWH_min)
thold = sdrt->tWH_min;
if (thold < sdrt->tALH_min)
thold = sdrt->tALH_min;
if (thold < sdrt->tREH_min)
thold = sdrt->tREH_min;
tims->thold = DIV_ROUND_UP(thold / 1000, hclkn);
if (tims->thold == 0)
tims->thold = 1;
else if (tims->thold > FSMC_THOLD_MASK)
tims->thold = FSMC_THOLD_MASK;
twait = max(sdrt->tRP_min, sdrt->tWP_min);
tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
if (tims->twait == 0)
tims->twait = 1;
else if (tims->twait > FSMC_TWAIT_MASK)
tims->twait = FSMC_TWAIT_MASK;
tset = max(sdrt->tCS_min - sdrt->tWP_min,
sdrt->tCEA_max - sdrt->tREA_max);
tims->tset = DIV_ROUND_UP(tset / 1000, hclkn) - 1;
if (tims->tset == 0)
tims->tset = 1;
else if (tims->tset > FSMC_TSET_MASK)
tims->tset = FSMC_TSET_MASK;
return 0;
}
static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
const struct nand_data_interface *conf)
{
struct nand_chip *nand = mtd_to_nand(mtd);
struct fsmc_nand_data *host = nand_get_controller_data(nand);
struct fsmc_nand_timings tims;
const struct nand_sdr_timings *sdrt;
int ret;
sdrt = nand_get_sdr_timings(conf);
if (IS_ERR(sdrt))
return PTR_ERR(sdrt);
ret = fsmc_calc_timings(host, sdrt, &tims);
if (ret)
return ret;
if (csline == NAND_DATA_IFACE_CHECK_ONLY)
return 0;
fsmc_nand_setup(host, &tims);
return 0;
}
/*
* fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
*/
@ -796,10 +865,8 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
return -ENOMEM;
ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings,
sizeof(*host->dev_timings));
if (ret) {
dev_info(&pdev->dev, "No timings in dts specified, using default timings!\n");
if (ret)
host->dev_timings = NULL;
}
/* Set default NAND bank to 0 */
host->bank = 0;
@ -933,9 +1000,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
break;
}
fsmc_nand_setup(host->regs_va, host->bank,
nand->options & NAND_BUSWIDTH_16,
host->dev_timings);
if (host->dev_timings)
fsmc_nand_setup(host, host->dev_timings);
else
nand->setup_data_interface = fsmc_setup_data_interface;
if (AMBA_REV_BITS(host->pid) >= 8) {
nand->ecc.read_page = fsmc_read_page_hwecc;
@ -986,6 +1054,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
break;
}
case NAND_ECC_ON_DIE:
break;
default:
dev_err(&pdev->dev, "Unsupported ECC mode!\n");
goto err_probe;
@ -1073,9 +1144,8 @@ static int fsmc_nand_resume(struct device *dev)
struct fsmc_nand_data *host = dev_get_drvdata(dev);
if (host) {
clk_prepare_enable(host->clk);
fsmc_nand_setup(host->regs_va, host->bank,
host->nand.options & NAND_BUSWIDTH_16,
host->dev_timings);
if (host->dev_timings)
fsmc_nand_setup(host, host->dev_timings);
}
return 0;
}

View File

@ -26,7 +26,7 @@
#include "gpmi-regs.h"
#include "bch-regs.h"
static struct timing_threshod timing_default_threshold = {
static struct timing_threshold timing_default_threshold = {
.max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >>
BP_GPMI_TIMING0_DATA_SETUP),
.internal_data_setup_in_ns = 0,
@ -329,7 +329,7 @@ static unsigned int ns_to_cycles(unsigned int time,
static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
struct gpmi_nfc_hardware_timing *hw)
{
struct timing_threshod *nfc = &timing_default_threshold;
struct timing_threshold *nfc = &timing_default_threshold;
struct resources *r = &this->resources;
struct nand_chip *nand = &this->nand;
struct nand_timing target = this->timing;
@ -932,7 +932,7 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
nand->select_chip(mtd, 0);
/* [1] send SET FEATURE commond to NAND */
/* [1] send SET FEATURE command to NAND */
feature[0] = mode;
ret = nand->onfi_set_features(mtd, nand,
ONFI_FEATURE_ADDR_TIMING_MODE, feature);

View File

@ -82,6 +82,10 @@ static int gpmi_ooblayout_free(struct mtd_info *mtd, int section,
return 0;
}
static const char * const gpmi_clks_for_mx2x[] = {
"gpmi_io",
};
static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
.ecc = gpmi_ooblayout_ecc,
.free = gpmi_ooblayout_free,
@ -91,24 +95,48 @@ static const struct gpmi_devdata gpmi_devdata_imx23 = {
.type = IS_MX23,
.bch_max_ecc_strength = 20,
.max_chain_delay = 16,
.clks = gpmi_clks_for_mx2x,
.clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
};
static const struct gpmi_devdata gpmi_devdata_imx28 = {
.type = IS_MX28,
.bch_max_ecc_strength = 20,
.max_chain_delay = 16,
.clks = gpmi_clks_for_mx2x,
.clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
};
static const char * const gpmi_clks_for_mx6[] = {
"gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
};
static const struct gpmi_devdata gpmi_devdata_imx6q = {
.type = IS_MX6Q,
.bch_max_ecc_strength = 40,
.max_chain_delay = 12,
.clks = gpmi_clks_for_mx6,
.clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
};
static const struct gpmi_devdata gpmi_devdata_imx6sx = {
.type = IS_MX6SX,
.bch_max_ecc_strength = 62,
.max_chain_delay = 12,
.clks = gpmi_clks_for_mx6,
.clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
};
static const char * const gpmi_clks_for_mx7d[] = {
"gpmi_io", "gpmi_bch_apb",
};
static const struct gpmi_devdata gpmi_devdata_imx7d = {
.type = IS_MX7D,
.bch_max_ecc_strength = 62,
.max_chain_delay = 12,
.clks = gpmi_clks_for_mx7d,
.clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d),
};
static irqreturn_t bch_irq(int irq, void *cookie)
@ -599,35 +627,14 @@ acquire_err:
return -EINVAL;
}
static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = {
"gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
};
static int gpmi_get_clks(struct gpmi_nand_data *this)
{
struct resources *r = &this->resources;
char **extra_clks = NULL;
struct clk *clk;
int err, i;
/* The main clock is stored in the first. */
r->clock[0] = devm_clk_get(this->dev, "gpmi_io");
if (IS_ERR(r->clock[0])) {
err = PTR_ERR(r->clock[0]);
goto err_clock;
}
/* Get extra clocks */
if (GPMI_IS_MX6(this))
extra_clks = extra_clks_for_mx6q;
if (!extra_clks)
return 0;
for (i = 1; i < GPMI_CLK_MAX; i++) {
if (extra_clks[i - 1] == NULL)
break;
clk = devm_clk_get(this->dev, extra_clks[i - 1]);
for (i = 0; i < this->devdata->clks_count; i++) {
clk = devm_clk_get(this->dev, this->devdata->clks[i]);
if (IS_ERR(clk)) {
err = PTR_ERR(clk);
goto err_clock;
@ -1929,12 +1936,6 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
return gpmi_alloc_dma_buffer(this);
}
static void gpmi_nand_exit(struct gpmi_nand_data *this)
{
nand_release(nand_to_mtd(&this->nand));
gpmi_free_dma_buffer(this);
}
static int gpmi_init_last(struct gpmi_nand_data *this)
{
struct nand_chip *chip = &this->nand;
@ -2048,18 +2049,20 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
ret = nand_boot_init(this);
if (ret)
goto err_out;
goto err_nand_cleanup;
ret = chip->scan_bbt(mtd);
if (ret)
goto err_out;
goto err_nand_cleanup;
ret = mtd_device_register(mtd, NULL, 0);
if (ret)
goto err_out;
goto err_nand_cleanup;
return 0;
err_nand_cleanup:
nand_cleanup(chip);
err_out:
gpmi_nand_exit(this);
gpmi_free_dma_buffer(this);
return ret;
}
@ -2076,6 +2079,9 @@ static const struct of_device_id gpmi_nand_id_table[] = {
}, {
.compatible = "fsl,imx6sx-gpmi-nand",
.data = &gpmi_devdata_imx6sx,
}, {
.compatible = "fsl,imx7d-gpmi-nand",
.data = &gpmi_devdata_imx7d,
}, {}
};
MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
@ -2129,7 +2135,8 @@ static int gpmi_nand_remove(struct platform_device *pdev)
{
struct gpmi_nand_data *this = platform_get_drvdata(pdev);
gpmi_nand_exit(this);
nand_release(nand_to_mtd(&this->nand));
gpmi_free_dma_buffer(this);
release_resources(this);
return 0;
}

View File

@ -123,13 +123,16 @@ enum gpmi_type {
IS_MX23,
IS_MX28,
IS_MX6Q,
IS_MX6SX
IS_MX6SX,
IS_MX7D,
};
struct gpmi_devdata {
enum gpmi_type type;
int bch_max_ecc_strength;
int max_chain_delay; /* See the async EDO mode */
const char * const *clks;
const int clks_count;
};
struct gpmi_nand_data {
@ -231,7 +234,7 @@ struct gpmi_nfc_hardware_timing {
};
/**
* struct timing_threshod - Timing threshold
* struct timing_threshold - Timing threshold
* @max_data_setup_cycles: The maximum number of data setup cycles that
* can be expressed in the hardware.
* @internal_data_setup_in_ns: The time, in ns, that the NFC hardware requires
@ -253,7 +256,7 @@ struct gpmi_nfc_hardware_timing {
* progress, this is the clock frequency during
* the most recent I/O transaction.
*/
struct timing_threshod {
struct timing_threshold {
const unsigned int max_chip_count;
const unsigned int max_data_setup_cycles;
const unsigned int internal_data_setup_in_ns;
@ -305,6 +308,8 @@ void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
#define GPMI_IS_MX28(x) ((x)->devdata->type == IS_MX28)
#define GPMI_IS_MX6Q(x) ((x)->devdata->type == IS_MX6Q)
#define GPMI_IS_MX6SX(x) ((x)->devdata->type == IS_MX6SX)
#define GPMI_IS_MX7D(x) ((x)->devdata->type == IS_MX7D)
#define GPMI_IS_MX6(x) (GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x))
#define GPMI_IS_MX6(x) (GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x) || \
GPMI_IS_MX7D(x))
#endif

View File

@ -764,6 +764,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
chip->write_buf = hisi_nfc_write_buf;
chip->read_buf = hisi_nfc_read_buf;
chip->chip_delay = HINFC504_CHIP_DELAY;
chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
hisi_nfc_host_init(host);

View File

@ -205,7 +205,7 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
return -EINVAL;
}
mtd->ooblayout = &nand_ooblayout_lp_ops;
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
return 0;
}

View File

@ -708,6 +708,8 @@ static int mpc5121_nfc_probe(struct platform_device *op)
chip->read_buf = mpc5121_nfc_read_buf;
chip->write_buf = mpc5121_nfc_write_buf;
chip->select_chip = mpc5121_nfc_select_chip;
chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
chip->bbt_options = NAND_BBT_USE_FLASH;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;

View File

@ -28,36 +28,16 @@
#define ECC_IDLE_MASK BIT(0)
#define ECC_IRQ_EN BIT(0)
#define ECC_PG_IRQ_SEL BIT(1)
#define ECC_OP_ENABLE (1)
#define ECC_OP_DISABLE (0)
#define ECC_ENCCON (0x00)
#define ECC_ENCCNFG (0x04)
#define ECC_CNFG_4BIT (0)
#define ECC_CNFG_6BIT (1)
#define ECC_CNFG_8BIT (2)
#define ECC_CNFG_10BIT (3)
#define ECC_CNFG_12BIT (4)
#define ECC_CNFG_14BIT (5)
#define ECC_CNFG_16BIT (6)
#define ECC_CNFG_18BIT (7)
#define ECC_CNFG_20BIT (8)
#define ECC_CNFG_22BIT (9)
#define ECC_CNFG_24BIT (0xa)
#define ECC_CNFG_28BIT (0xb)
#define ECC_CNFG_32BIT (0xc)
#define ECC_CNFG_36BIT (0xd)
#define ECC_CNFG_40BIT (0xe)
#define ECC_CNFG_44BIT (0xf)
#define ECC_CNFG_48BIT (0x10)
#define ECC_CNFG_52BIT (0x11)
#define ECC_CNFG_56BIT (0x12)
#define ECC_CNFG_60BIT (0x13)
#define ECC_MODE_SHIFT (5)
#define ECC_MS_SHIFT (16)
#define ECC_ENCDIADDR (0x08)
#define ECC_ENCIDLE (0x0C)
#define ECC_ENCPAR(x) (0x10 + (x) * sizeof(u32))
#define ECC_ENCIRQ_EN (0x80)
#define ECC_ENCIRQ_STA (0x84)
#define ECC_DECCON (0x100)
@ -66,7 +46,6 @@
#define DEC_CNFG_CORRECT (0x3 << 12)
#define ECC_DECIDLE (0x10C)
#define ECC_DECENUM0 (0x114)
#define ERR_MASK (0x3f)
#define ECC_DECDONE (0x124)
#define ECC_DECIRQ_EN (0x200)
#define ECC_DECIRQ_STA (0x204)
@ -78,8 +57,17 @@
#define ECC_IRQ_REG(op) ((op) == ECC_ENCODE ? \
ECC_ENCIRQ_EN : ECC_DECIRQ_EN)
struct mtk_ecc_caps {
u32 err_mask;
const u8 *ecc_strength;
u8 num_ecc_strength;
u32 encode_parity_reg0;
int pg_irq_sel;
};
struct mtk_ecc {
struct device *dev;
const struct mtk_ecc_caps *caps;
void __iomem *regs;
struct clk *clk;
@ -87,7 +75,18 @@ struct mtk_ecc {
struct mutex lock;
u32 sectors;
u8 eccdata[112];
u8 *eccdata;
};
/* ecc strength that each IP supports */
static const u8 ecc_strength_mt2701[] = {
4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
40, 44, 48, 52, 56, 60
};
static const u8 ecc_strength_mt2712[] = {
4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
40, 44, 48, 52, 56, 60, 68, 72, 80
};
static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
@ -136,77 +135,24 @@ static irqreturn_t mtk_ecc_irq(int irq, void *id)
return IRQ_HANDLED;
}
static void mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
static int mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
{
u32 ecc_bit = ECC_CNFG_4BIT, dec_sz, enc_sz;
u32 reg;
u32 ecc_bit, dec_sz, enc_sz;
u32 reg, i;
switch (config->strength) {
case 4:
ecc_bit = ECC_CNFG_4BIT;
break;
case 6:
ecc_bit = ECC_CNFG_6BIT;
break;
case 8:
ecc_bit = ECC_CNFG_8BIT;
break;
case 10:
ecc_bit = ECC_CNFG_10BIT;
break;
case 12:
ecc_bit = ECC_CNFG_12BIT;
break;
case 14:
ecc_bit = ECC_CNFG_14BIT;
break;
case 16:
ecc_bit = ECC_CNFG_16BIT;
break;
case 18:
ecc_bit = ECC_CNFG_18BIT;
break;
case 20:
ecc_bit = ECC_CNFG_20BIT;
break;
case 22:
ecc_bit = ECC_CNFG_22BIT;
break;
case 24:
ecc_bit = ECC_CNFG_24BIT;
break;
case 28:
ecc_bit = ECC_CNFG_28BIT;
break;
case 32:
ecc_bit = ECC_CNFG_32BIT;
break;
case 36:
ecc_bit = ECC_CNFG_36BIT;
break;
case 40:
ecc_bit = ECC_CNFG_40BIT;
break;
case 44:
ecc_bit = ECC_CNFG_44BIT;
break;
case 48:
ecc_bit = ECC_CNFG_48BIT;
break;
case 52:
ecc_bit = ECC_CNFG_52BIT;
break;
case 56:
ecc_bit = ECC_CNFG_56BIT;
break;
case 60:
ecc_bit = ECC_CNFG_60BIT;
break;
default:
dev_err(ecc->dev, "invalid strength %d, default to 4 bits\n",
config->strength);
for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
if (ecc->caps->ecc_strength[i] == config->strength)
break;
}
if (i == ecc->caps->num_ecc_strength) {
dev_err(ecc->dev, "invalid ecc strength %d\n",
config->strength);
return -EINVAL;
}
ecc_bit = i;
if (config->op == ECC_ENCODE) {
/* configure ECC encoder (in bits) */
enc_sz = config->len << 3;
@ -232,6 +178,8 @@ static void mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
if (config->sectors)
ecc->sectors = 1 << (config->sectors - 1);
}
return 0;
}
void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
@ -247,8 +195,8 @@ void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
offset = (i >> 2) << 2;
err = readl(ecc->regs + ECC_DECENUM0 + offset);
err = err >> ((i % 4) * 8);
err &= ERR_MASK;
if (err == ERR_MASK) {
err &= ecc->caps->err_mask;
if (err == ecc->caps->err_mask) {
/* uncorrectable errors */
stats->failed++;
continue;
@ -313,6 +261,7 @@ EXPORT_SYMBOL(of_mtk_ecc_get);
int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
{
enum mtk_ecc_operation op = config->op;
u16 reg_val;
int ret;
ret = mutex_lock_interruptible(&ecc->lock);
@ -322,11 +271,27 @@ int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
}
mtk_ecc_wait_idle(ecc, op);
mtk_ecc_config(ecc, config);
writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
init_completion(&ecc->done);
writew(ECC_IRQ_EN, ecc->regs + ECC_IRQ_REG(op));
ret = mtk_ecc_config(ecc, config);
if (ret) {
mutex_unlock(&ecc->lock);
return ret;
}
if (config->mode != ECC_NFI_MODE || op != ECC_ENCODE) {
init_completion(&ecc->done);
reg_val = ECC_IRQ_EN;
/*
* For ECC_NFI_MODE, if ecc->caps->pg_irq_sel is 1, then it
* means this chip can only generate one ecc irq during page
* read / write. If is 0, generate one ecc irq each ecc step.
*/
if (ecc->caps->pg_irq_sel && config->mode == ECC_NFI_MODE)
reg_val |= ECC_PG_IRQ_SEL;
writew(reg_val, ecc->regs + ECC_IRQ_REG(op));
}
writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
return 0;
}
@ -396,7 +361,9 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
/* write the parity bytes generated by the ECC back to temp buffer */
__ioread32_copy(ecc->eccdata, ecc->regs + ECC_ENCPAR(0), round_up(len, 4));
__ioread32_copy(ecc->eccdata,
ecc->regs + ecc->caps->encode_parity_reg0,
round_up(len, 4));
/* copy into possibly unaligned OOB region with actual length */
memcpy(data + bytes, ecc->eccdata, len);
@ -409,37 +376,79 @@ timeout:
}
EXPORT_SYMBOL(mtk_ecc_encode);
void mtk_ecc_adjust_strength(u32 *p)
void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p)
{
u32 ecc[] = {4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
40, 44, 48, 52, 56, 60};
const u8 *ecc_strength = ecc->caps->ecc_strength;
int i;
for (i = 0; i < ARRAY_SIZE(ecc); i++) {
if (*p <= ecc[i]) {
for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
if (*p <= ecc_strength[i]) {
if (!i)
*p = ecc[i];
else if (*p != ecc[i])
*p = ecc[i - 1];
*p = ecc_strength[i];
else if (*p != ecc_strength[i])
*p = ecc_strength[i - 1];
return;
}
}
*p = ecc[ARRAY_SIZE(ecc) - 1];
*p = ecc_strength[ecc->caps->num_ecc_strength - 1];
}
EXPORT_SYMBOL(mtk_ecc_adjust_strength);
static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
.err_mask = 0x3f,
.ecc_strength = ecc_strength_mt2701,
.num_ecc_strength = 20,
.encode_parity_reg0 = 0x10,
.pg_irq_sel = 0,
};
static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
.err_mask = 0x7f,
.ecc_strength = ecc_strength_mt2712,
.num_ecc_strength = 23,
.encode_parity_reg0 = 0x300,
.pg_irq_sel = 1,
};
static const struct of_device_id mtk_ecc_dt_match[] = {
{
.compatible = "mediatek,mt2701-ecc",
.data = &mtk_ecc_caps_mt2701,
}, {
.compatible = "mediatek,mt2712-ecc",
.data = &mtk_ecc_caps_mt2712,
},
{},
};
static int mtk_ecc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_ecc *ecc;
struct resource *res;
const struct of_device_id *of_ecc_id = NULL;
u32 max_eccdata_size;
int irq, ret;
ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
if (!ecc)
return -ENOMEM;
of_ecc_id = of_match_device(mtk_ecc_dt_match, &pdev->dev);
if (!of_ecc_id)
return -ENODEV;
ecc->caps = of_ecc_id->data;
max_eccdata_size = ecc->caps->num_ecc_strength - 1;
max_eccdata_size = ecc->caps->ecc_strength[max_eccdata_size];
max_eccdata_size = (max_eccdata_size * ECC_PARITY_BITS + 7) >> 3;
max_eccdata_size = round_up(max_eccdata_size, 4);
ecc->eccdata = devm_kzalloc(dev, max_eccdata_size, GFP_KERNEL);
if (!ecc->eccdata)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ecc->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(ecc->regs)) {
@ -500,19 +509,12 @@ static int mtk_ecc_resume(struct device *dev)
return ret;
}
mtk_ecc_hw_init(ecc);
return 0;
}
static SIMPLE_DEV_PM_OPS(mtk_ecc_pm_ops, mtk_ecc_suspend, mtk_ecc_resume);
#endif
static const struct of_device_id mtk_ecc_dt_match[] = {
{ .compatible = "mediatek,mt2701-ecc" },
{},
};
MODULE_DEVICE_TABLE(of, mtk_ecc_dt_match);
static struct platform_driver mtk_ecc_driver = {

View File

@ -42,7 +42,7 @@ void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
void mtk_ecc_disable(struct mtk_ecc *);
void mtk_ecc_adjust_strength(u32 *);
void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p);
struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
void mtk_ecc_release(struct mtk_ecc *);

View File

@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include "mtk_ecc.h"
/* NAND controller register definition */
@ -38,23 +39,6 @@
#define NFI_PAGEFMT (0x04)
#define PAGEFMT_FDM_ECC_SHIFT (12)
#define PAGEFMT_FDM_SHIFT (8)
#define PAGEFMT_SPARE_16 (0)
#define PAGEFMT_SPARE_26 (1)
#define PAGEFMT_SPARE_27 (2)
#define PAGEFMT_SPARE_28 (3)
#define PAGEFMT_SPARE_32 (4)
#define PAGEFMT_SPARE_36 (5)
#define PAGEFMT_SPARE_40 (6)
#define PAGEFMT_SPARE_44 (7)
#define PAGEFMT_SPARE_48 (8)
#define PAGEFMT_SPARE_49 (9)
#define PAGEFMT_SPARE_50 (0xa)
#define PAGEFMT_SPARE_51 (0xb)
#define PAGEFMT_SPARE_52 (0xc)
#define PAGEFMT_SPARE_62 (0xd)
#define PAGEFMT_SPARE_63 (0xe)
#define PAGEFMT_SPARE_64 (0xf)
#define PAGEFMT_SPARE_SHIFT (4)
#define PAGEFMT_SEC_SEL_512 BIT(2)
#define PAGEFMT_512_2K (0)
#define PAGEFMT_2K_4K (1)
@ -115,6 +99,17 @@
#define MTK_RESET_TIMEOUT (1000000)
#define MTK_MAX_SECTOR (16)
#define MTK_NAND_MAX_NSELS (2)
#define MTK_NFC_MIN_SPARE (16)
#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
((tpoecs) << 28 | (tprecs) << 22 | (tc2r) << 16 | \
(tw2r) << 12 | (twh) << 8 | (twst) << 4 | (trlt))
struct mtk_nfc_caps {
const u8 *spare_size;
u8 num_spare_size;
u8 pageformat_spare_shift;
u8 nfi_clk_div;
};
struct mtk_nfc_bad_mark_ctl {
void (*bm_swap)(struct mtd_info *, u8 *buf, int raw);
@ -155,6 +150,7 @@ struct mtk_nfc {
struct mtk_ecc *ecc;
struct device *dev;
const struct mtk_nfc_caps *caps;
void __iomem *regs;
struct completion done;
@ -163,6 +159,20 @@ struct mtk_nfc {
u8 *buffer;
};
/*
* supported spare size of each IP.
* order should be the same with the spare size bitfiled defination of
* register NFI_PAGEFMT.
*/
static const u8 spare_size_mt2701[] = {
16, 26, 27, 28, 32, 36, 40, 44, 48, 49, 50, 51, 52, 62, 63, 64
};
static const u8 spare_size_mt2712[] = {
16, 26, 27, 28, 32, 36, 40, 44, 48, 49, 50, 51, 52, 62, 61, 63, 64, 67,
74
};
static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct nand_chip *nand)
{
return container_of(nand, struct mtk_nfc_nand_chip, nand);
@ -308,7 +318,7 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
struct nand_chip *chip = mtd_to_nand(mtd);
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
u32 fmt, spare;
u32 fmt, spare, i;
if (!mtd->writesize)
return 0;
@ -352,63 +362,21 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
if (chip->ecc.size == 1024)
spare >>= 1;
switch (spare) {
case 16:
fmt |= (PAGEFMT_SPARE_16 << PAGEFMT_SPARE_SHIFT);
break;
case 26:
fmt |= (PAGEFMT_SPARE_26 << PAGEFMT_SPARE_SHIFT);
break;
case 27:
fmt |= (PAGEFMT_SPARE_27 << PAGEFMT_SPARE_SHIFT);
break;
case 28:
fmt |= (PAGEFMT_SPARE_28 << PAGEFMT_SPARE_SHIFT);
break;
case 32:
fmt |= (PAGEFMT_SPARE_32 << PAGEFMT_SPARE_SHIFT);
break;
case 36:
fmt |= (PAGEFMT_SPARE_36 << PAGEFMT_SPARE_SHIFT);
break;
case 40:
fmt |= (PAGEFMT_SPARE_40 << PAGEFMT_SPARE_SHIFT);
break;
case 44:
fmt |= (PAGEFMT_SPARE_44 << PAGEFMT_SPARE_SHIFT);
break;
case 48:
fmt |= (PAGEFMT_SPARE_48 << PAGEFMT_SPARE_SHIFT);
break;
case 49:
fmt |= (PAGEFMT_SPARE_49 << PAGEFMT_SPARE_SHIFT);
break;
case 50:
fmt |= (PAGEFMT_SPARE_50 << PAGEFMT_SPARE_SHIFT);
break;
case 51:
fmt |= (PAGEFMT_SPARE_51 << PAGEFMT_SPARE_SHIFT);
break;
case 52:
fmt |= (PAGEFMT_SPARE_52 << PAGEFMT_SPARE_SHIFT);
break;
case 62:
fmt |= (PAGEFMT_SPARE_62 << PAGEFMT_SPARE_SHIFT);
break;
case 63:
fmt |= (PAGEFMT_SPARE_63 << PAGEFMT_SPARE_SHIFT);
break;
case 64:
fmt |= (PAGEFMT_SPARE_64 << PAGEFMT_SPARE_SHIFT);
break;
default:
dev_err(nfc->dev, "invalid spare per sector %d\n", spare);
for (i = 0; i < nfc->caps->num_spare_size; i++) {
if (nfc->caps->spare_size[i] == spare)
break;
}
if (i == nfc->caps->num_spare_size) {
dev_err(nfc->dev, "invalid spare size %d\n", spare);
return -EINVAL;
}
fmt |= i << nfc->caps->pageformat_spare_shift;
fmt |= mtk_nand->fdm.reg_size << PAGEFMT_FDM_SHIFT;
fmt |= mtk_nand->fdm.ecc_size << PAGEFMT_FDM_ECC_SHIFT;
nfi_writew(nfc, fmt, NFI_PAGEFMT);
nfi_writel(nfc, fmt, NFI_PAGEFMT);
nfc->ecc_cfg.strength = chip->ecc.strength;
nfc->ecc_cfg.len = chip->ecc.size + mtk_nand->fdm.ecc_size;
@ -531,6 +499,74 @@ static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
mtk_nfc_write_byte(mtd, buf[i]);
}
static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
const struct nand_data_interface *conf)
{
struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
const struct nand_sdr_timings *timings;
u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
timings = nand_get_sdr_timings(conf);
if (IS_ERR(timings))
return -ENOTSUPP;
if (csline == NAND_DATA_IFACE_CHECK_ONLY)
return 0;
rate = clk_get_rate(nfc->clk.nfi_clk);
/* There is a frequency divider in some IPs */
rate /= nfc->caps->nfi_clk_div;
/* turn clock rate into KHZ */
rate /= 1000;
tpoecs = max(timings->tALH_min, timings->tCLH_min) / 1000;
tpoecs = DIV_ROUND_UP(tpoecs * rate, 1000000);
tpoecs &= 0xf;
tprecs = max(timings->tCLS_min, timings->tALS_min) / 1000;
tprecs = DIV_ROUND_UP(tprecs * rate, 1000000);
tprecs &= 0x3f;
/* sdr interface has no tCR which means CE# low to RE# low */
tc2r = 0;
tw2r = timings->tWHR_min / 1000;
tw2r = DIV_ROUND_UP(tw2r * rate, 1000000);
tw2r = DIV_ROUND_UP(tw2r - 1, 2);
tw2r &= 0xf;
twh = max(timings->tREH_min, timings->tWH_min) / 1000;
twh = DIV_ROUND_UP(twh * rate, 1000000) - 1;
twh &= 0xf;
twst = timings->tWP_min / 1000;
twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
twst &= 0xf;
trlt = max(timings->tREA_max, timings->tRP_min) / 1000;
trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
trlt &= 0xf;
/*
* ACCON: access timing control register
* -------------------------------------
* 31:28: tpoecs, minimum required time for CS post pulling down after
* accessing the device
* 27:22: tprecs, minimum required time for CS pre pulling down before
* accessing the device
* 21:16: tc2r, minimum required time from NCEB low to NREB low
* 15:12: tw2r, minimum required time from NWEB high to NREB low.
* 11:08: twh, write enable hold time
* 07:04: twst, write wait states
* 03:00: trlt, read wait states
*/
trlt = ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt);
nfi_writel(nfc, trlt, NFI_ACCCON);
return 0;
}
static int mtk_nfc_sector_encode(struct nand_chip *chip, u8 *data)
{
struct mtk_nfc *nfc = nand_get_controller_data(chip);
@ -987,21 +1023,6 @@ static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
{
/*
* ACCON: access timing control register
* -------------------------------------
* 31:28: minimum required time for CS post pulling down after accessing
* the device
* 27:22: minimum required time for CS pre pulling down before accessing
* the device
* 21:16: minimum required time from NCEB low to NREB low
* 15:12: minimum required time from NWEB high to NREB low.
* 11:08: write enable hold time
* 07:04: write wait states
* 03:00: read wait states
*/
nfi_writel(nfc, 0x10804211, NFI_ACCCON);
/*
* CNRNB: nand ready/busy register
* -------------------------------
@ -1009,7 +1030,7 @@ static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
* 0 : poll the status of the busy/ready signal after [7:4]*16 cycles.
*/
nfi_writew(nfc, 0xf1, NFI_CNRNB);
nfi_writew(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
nfi_writel(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
mtk_nfc_hw_reset(nfc);
@ -1131,12 +1152,12 @@ static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
}
}
static void mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
static int mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
{
struct nand_chip *nand = mtd_to_nand(mtd);
u32 spare[] = {16, 26, 27, 28, 32, 36, 40, 44,
48, 49, 50, 51, 52, 62, 63, 64};
u32 eccsteps, i;
struct mtk_nfc *nfc = nand_get_controller_data(nand);
const u8 *spare = nfc->caps->spare_size;
u32 eccsteps, i, closest_spare = 0;
eccsteps = mtd->writesize / nand->ecc.size;
*sps = mtd->oobsize / eccsteps;
@ -1144,28 +1165,31 @@ static void mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
if (nand->ecc.size == 1024)
*sps >>= 1;
for (i = 0; i < ARRAY_SIZE(spare); i++) {
if (*sps <= spare[i]) {
if (!i)
*sps = spare[i];
else if (*sps != spare[i])
*sps = spare[i - 1];
break;
if (*sps < MTK_NFC_MIN_SPARE)
return -EINVAL;
for (i = 0; i < nfc->caps->num_spare_size; i++) {
if (*sps >= spare[i] && spare[i] >= spare[closest_spare]) {
closest_spare = i;
if (*sps == spare[i])
break;
}
}
if (i >= ARRAY_SIZE(spare))
*sps = spare[ARRAY_SIZE(spare) - 1];
*sps = spare[closest_spare];
if (nand->ecc.size == 1024)
*sps <<= 1;
return 0;
}
static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
{
struct nand_chip *nand = mtd_to_nand(mtd);
struct mtk_nfc *nfc = nand_get_controller_data(nand);
u32 spare;
int free;
int free, ret;
/* support only ecc hw mode */
if (nand->ecc.mode != NAND_ECC_HW) {
@ -1194,7 +1218,9 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
nand->ecc.size = 1024;
}
mtk_nfc_set_spare_per_sector(&spare, mtd);
ret = mtk_nfc_set_spare_per_sector(&spare, mtd);
if (ret)
return ret;
/* calculate oob bytes except ecc parity data */
free = ((nand->ecc.strength * ECC_PARITY_BITS) + 7) >> 3;
@ -1214,7 +1240,7 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
}
}
mtk_ecc_adjust_strength(&nand->ecc.strength);
mtk_ecc_adjust_strength(nfc->ecc, &nand->ecc.strength);
dev_info(dev, "eccsize %d eccstrength %d\n",
nand->ecc.size, nand->ecc.strength);
@ -1271,6 +1297,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
nand->read_byte = mtk_nfc_read_byte;
nand->read_buf = mtk_nfc_read_buf;
nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
nand->setup_data_interface = mtk_nfc_setup_data_interface;
/* set default mode in case dt entry is missing */
nand->ecc.mode = NAND_ECC_HW;
@ -1312,7 +1339,10 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
return -EINVAL;
}
mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
ret = mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
if (ret)
return ret;
mtk_nfc_set_fdm(&chip->fdm, mtd);
mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
@ -1354,12 +1384,39 @@ static int mtk_nfc_nand_chips_init(struct device *dev, struct mtk_nfc *nfc)
return 0;
}
static const struct mtk_nfc_caps mtk_nfc_caps_mt2701 = {
.spare_size = spare_size_mt2701,
.num_spare_size = 16,
.pageformat_spare_shift = 4,
.nfi_clk_div = 1,
};
static const struct mtk_nfc_caps mtk_nfc_caps_mt2712 = {
.spare_size = spare_size_mt2712,
.num_spare_size = 19,
.pageformat_spare_shift = 16,
.nfi_clk_div = 2,
};
static const struct of_device_id mtk_nfc_id_table[] = {
{
.compatible = "mediatek,mt2701-nfc",
.data = &mtk_nfc_caps_mt2701,
}, {
.compatible = "mediatek,mt2712-nfc",
.data = &mtk_nfc_caps_mt2712,
},
{}
};
MODULE_DEVICE_TABLE(of, mtk_nfc_id_table);
static int mtk_nfc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct mtk_nfc *nfc;
struct resource *res;
const struct of_device_id *of_nfc_id = NULL;
int ret, irq;
nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
@ -1423,6 +1480,14 @@ static int mtk_nfc_probe(struct platform_device *pdev)
goto clk_disable;
}
of_nfc_id = of_match_device(mtk_nfc_id_table, &pdev->dev);
if (!of_nfc_id) {
ret = -ENODEV;
goto clk_disable;
}
nfc->caps = of_nfc_id->data;
platform_set_drvdata(pdev, nfc);
ret = mtk_nfc_nand_chips_init(dev, nfc);
@ -1485,8 +1550,6 @@ static int mtk_nfc_resume(struct device *dev)
if (ret)
return ret;
mtk_nfc_hw_init(nfc);
/* reset NAND chip if VCC was powered off */
list_for_each_entry(chip, &nfc->chips, node) {
nand = &chip->nand;
@ -1503,12 +1566,6 @@ static int mtk_nfc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume);
#endif
static const struct of_device_id mtk_nfc_id_table[] = {
{ .compatible = "mediatek,mt2701-nfc" },
{}
};
MODULE_DEVICE_TABLE(of, mtk_nfc_id_table);
static struct platform_driver mtk_nfc_driver = {
.probe = mtk_nfc_probe,
.remove = mtk_nfc_remove,

View File

@ -152,9 +152,8 @@ struct mxc_nand_devtype_data {
void (*select_chip)(struct mtd_info *mtd, int chip);
int (*correct_data)(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc);
int (*setup_data_interface)(struct mtd_info *mtd,
const struct nand_data_interface *conf,
bool check_only);
int (*setup_data_interface)(struct mtd_info *mtd, int csline,
const struct nand_data_interface *conf);
/*
* On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
@ -1015,9 +1014,8 @@ static void preset_v1(struct mtd_info *mtd)
writew(0x4, NFC_V1_V2_WRPROT);
}
static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd,
const struct nand_data_interface *conf,
bool check_only)
static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, int csline,
const struct nand_data_interface *conf)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
@ -1075,7 +1073,7 @@ static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd,
return -EINVAL;
}
if (check_only)
if (csline == NAND_DATA_IFACE_CHECK_ONLY)
return 0;
ret = clk_set_rate(host->clk, rate);

View File

@ -753,6 +753,16 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
return;
/* This applies to read commands */
case NAND_CMD_READ0:
/*
* READ0 is sometimes used to exit GET STATUS mode. When this
* is the case no address cycles are requested, and we can use
* this information to detect that we should not wait for the
* device to be ready.
*/
if (column == -1 && page_addr == -1)
return;
default:
/*
* If we don't have access to the busy pin, we apply the given
@ -887,6 +897,15 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
return;
case NAND_CMD_READ0:
/*
* READ0 is sometimes used to exit GET STATUS mode. When this
* is the case no address cycles are requested, and we can use
* this information to detect that READSTART should not be
* issued.
*/
if (column == -1 && page_addr == -1)
return;
chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd, NAND_CMD_NONE,
@ -1042,12 +1061,13 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
/**
* nand_reset_data_interface - Reset data interface and timings
* @chip: The NAND chip
* @chipnr: Internal die id
*
* Reset the Data interface and timings to ONFI mode 0.
*
* Returns 0 for success or negative error code otherwise.
*/
static int nand_reset_data_interface(struct nand_chip *chip)
static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
{
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_data_interface *conf;
@ -1071,7 +1091,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
*/
conf = nand_get_default_data_interface();
ret = chip->setup_data_interface(mtd, conf, false);
ret = chip->setup_data_interface(mtd, chipnr, conf);
if (ret)
pr_err("Failed to configure data interface to SDR timing mode 0\n");
@ -1081,6 +1101,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
/**
* nand_setup_data_interface - Setup the best data interface and timings
* @chip: The NAND chip
* @chipnr: Internal die id
*
* Find and configure the best data interface and NAND timings supported by
* the chip and the driver.
@ -1090,7 +1111,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
*
* Returns 0 for success or negative error code otherwise.
*/
static int nand_setup_data_interface(struct nand_chip *chip)
static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
@ -1114,7 +1135,7 @@ static int nand_setup_data_interface(struct nand_chip *chip)
goto err;
}
ret = chip->setup_data_interface(mtd, chip->data_interface, false);
ret = chip->setup_data_interface(mtd, chipnr, chip->data_interface);
err:
return ret;
}
@ -1165,8 +1186,10 @@ static int nand_init_data_interface(struct nand_chip *chip)
if (ret)
continue;
ret = chip->setup_data_interface(mtd, chip->data_interface,
true);
/* Pass -1 to only */
ret = chip->setup_data_interface(mtd,
NAND_DATA_IFACE_CHECK_ONLY,
chip->data_interface);
if (!ret) {
chip->onfi_timing_mode_default = mode;
break;
@ -1193,7 +1216,7 @@ int nand_reset(struct nand_chip *chip, int chipnr)
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
ret = nand_reset_data_interface(chip);
ret = nand_reset_data_interface(chip, chipnr);
if (ret)
return ret;
@ -1206,7 +1229,7 @@ int nand_reset(struct nand_chip *chip, int chipnr)
chip->select_chip(mtd, -1);
chip->select_chip(mtd, chipnr);
ret = nand_setup_data_interface(chip);
ret = nand_setup_data_interface(chip, chipnr);
chip->select_chip(mtd, -1);
if (ret)
return ret;
@ -1421,7 +1444,10 @@ static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
for (; len >= sizeof(long);
len -= sizeof(long), bitmap += sizeof(long)) {
weight = hweight_long(*((unsigned long *)bitmap));
unsigned long d = *((unsigned long *)bitmap);
if (d == ~0UL)
continue;
weight = hweight_long(d);
bitflips += BITS_PER_LONG - weight;
if (unlikely(bitflips > bitflips_threshold))
return -EBADMSG;
@ -1524,14 +1550,15 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
*
* Not for syndrome calculating ECC controllers, which use a special oob layout.
*/
static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
chip->read_buf(mtd, buf, mtd->writesize);
if (oob_required)
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
EXPORT_SYMBOL(nand_read_page_raw);
/**
* nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
@ -2469,8 +2496,8 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
*
* Not for syndrome calculating ECC controllers, which use a special oob layout.
*/
static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page)
int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page)
{
chip->write_buf(mtd, buf, mtd->writesize);
if (oob_required)
@ -2478,6 +2505,7 @@ static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
EXPORT_SYMBOL(nand_write_page_raw);
/**
* nand_write_page_raw_syndrome - [INTERN] raw page write function
@ -2715,7 +2743,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
*/
static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offset, int data_len, const uint8_t *buf,
int oob_required, int page, int cached, int raw)
int oob_required, int page, int raw)
{
int status, subpage;
@ -2741,30 +2769,12 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
if (status < 0)
return status;
/*
* Cached progamming disabled for now. Not sure if it's worth the
* trouble. The speed gain is not very impressive. (2.3->2.6Mib/s).
*/
cached = 0;
if (nand_standard_page_accessors(&chip->ecc)) {
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
if (!cached || !NAND_HAS_CACHEPROG(chip)) {
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
* available.
*/
if ((status & NAND_STATUS_FAIL) && (chip->errstat))
status = chip->errstat(mtd, chip, FL_WRITING, status,
page);
if (status & NAND_STATUS_FAIL)
return -EIO;
} else {
chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
}
return 0;
@ -2872,7 +2882,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
while (1) {
int bytes = mtd->writesize;
int cached = writelen > bytes && page != blockmask;
uint8_t *wbuf = buf;
int use_bufpoi;
int part_pagewr = (column || writelen < mtd->writesize);
@ -2890,7 +2899,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
if (use_bufpoi) {
pr_debug("%s: using write bounce buffer for buf@%p\n",
__func__, buf);
cached = 0;
if (part_pagewr)
bytes = min_t(int, bytes - column, writelen);
chip->pagebuf = -1;
@ -2909,7 +2917,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
}
ret = nand_write_page(mtd, chip, column, bytes, wbuf,
oob_required, page, cached,
oob_required, page,
(ops->mode == MTD_OPS_RAW));
if (ret)
break;
@ -3225,14 +3233,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
status = chip->erase(mtd, page & chip->pagemask);
/*
* See if operation failed and additional status checks are
* available
*/
if ((status & NAND_STATUS_FAIL) && (chip->errstat))
status = chip->errstat(mtd, chip, FL_ERASING,
status, page);
/* See if block erase succeeded */
if (status & NAND_STATUS_FAIL) {
pr_debug("%s: failed erase, page 0x%08x\n",
@ -3418,6 +3418,25 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
/**
* nand_onfi_get_set_features_notsupp - set/get features stub returning
* -ENOTSUPP
* @mtd: MTD device structure
* @chip: nand chip info structure
* @addr: feature address.
* @subfeature_param: the subfeature parameters, a four bytes array.
*
* Should be used by NAND controller drivers that do not support the SET/GET
* FEATURES operations.
*/
int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd,
struct nand_chip *chip, int addr,
u8 *subfeature_param)
{
return -ENOTSUPP;
}
EXPORT_SYMBOL(nand_onfi_get_set_features_notsupp);
/**
* nand_suspend - [MTD Interface] Suspend the NAND flash
* @mtd: MTD device structure
@ -4177,6 +4196,7 @@ static const char * const nand_ecc_modes[] = {
[NAND_ECC_HW] = "hw",
[NAND_ECC_HW_SYNDROME] = "hw_syndrome",
[NAND_ECC_HW_OOB_FIRST] = "hw_oob_first",
[NAND_ECC_ON_DIE] = "on-die",
};
static int of_get_nand_ecc_mode(struct device_node *np)
@ -4371,7 +4391,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
* For the other dies, nand_reset() will automatically switch to the
* best mode for us.
*/
ret = nand_setup_data_interface(chip);
ret = nand_setup_data_interface(chip, 0);
if (ret)
goto err_nand_init;
@ -4509,6 +4529,226 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
}
}
/**
* nand_check_ecc_caps - check the sanity of preset ECC settings
* @chip: nand chip info structure
* @caps: ECC caps info structure
* @oobavail: OOB size that the ECC engine can use
*
* When ECC step size and strength are already set, check if they are supported
* by the controller and the calculated ECC bytes fit within the chip's OOB.
* On success, the calculated ECC bytes is set.
*/
int nand_check_ecc_caps(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail)
{
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_ecc_step_info *stepinfo;
int preset_step = chip->ecc.size;
int preset_strength = chip->ecc.strength;
int nsteps, ecc_bytes;
int i, j;
if (WARN_ON(oobavail < 0))
return -EINVAL;
if (!preset_step || !preset_strength)
return -ENODATA;
nsteps = mtd->writesize / preset_step;
for (i = 0; i < caps->nstepinfos; i++) {
stepinfo = &caps->stepinfos[i];
if (stepinfo->stepsize != preset_step)
continue;
for (j = 0; j < stepinfo->nstrengths; j++) {
if (stepinfo->strengths[j] != preset_strength)
continue;
ecc_bytes = caps->calc_ecc_bytes(preset_step,
preset_strength);
if (WARN_ON_ONCE(ecc_bytes < 0))
return ecc_bytes;
if (ecc_bytes * nsteps > oobavail) {
pr_err("ECC (step, strength) = (%d, %d) does not fit in OOB",
preset_step, preset_strength);
return -ENOSPC;
}
chip->ecc.bytes = ecc_bytes;
return 0;
}
}
pr_err("ECC (step, strength) = (%d, %d) not supported on this controller",
preset_step, preset_strength);
return -ENOTSUPP;
}
EXPORT_SYMBOL_GPL(nand_check_ecc_caps);
/**
* nand_match_ecc_req - meet the chip's requirement with least ECC bytes
* @chip: nand chip info structure
* @caps: ECC engine caps info structure
* @oobavail: OOB size that the ECC engine can use
*
* If a chip's ECC requirement is provided, try to meet it with the least
* number of ECC bytes (i.e. with the largest number of OOB-free bytes).
* On success, the chosen ECC settings are set.
*/
int nand_match_ecc_req(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail)
{
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_ecc_step_info *stepinfo;
int req_step = chip->ecc_step_ds;
int req_strength = chip->ecc_strength_ds;
int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total;
int best_step, best_strength, best_ecc_bytes;
int best_ecc_bytes_total = INT_MAX;
int i, j;
if (WARN_ON(oobavail < 0))
return -EINVAL;
/* No information provided by the NAND chip */
if (!req_step || !req_strength)
return -ENOTSUPP;
/* number of correctable bits the chip requires in a page */
req_corr = mtd->writesize / req_step * req_strength;
for (i = 0; i < caps->nstepinfos; i++) {
stepinfo = &caps->stepinfos[i];
step_size = stepinfo->stepsize;
for (j = 0; j < stepinfo->nstrengths; j++) {
strength = stepinfo->strengths[j];
/*
* If both step size and strength are smaller than the
* chip's requirement, it is not easy to compare the
* resulted reliability.
*/
if (step_size < req_step && strength < req_strength)
continue;
if (mtd->writesize % step_size)
continue;
nsteps = mtd->writesize / step_size;
ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
if (WARN_ON_ONCE(ecc_bytes < 0))
continue;
ecc_bytes_total = ecc_bytes * nsteps;
if (ecc_bytes_total > oobavail ||
strength * nsteps < req_corr)
continue;
/*
* We assume the best is to meet the chip's requrement
* with the least number of ECC bytes.
*/
if (ecc_bytes_total < best_ecc_bytes_total) {
best_ecc_bytes_total = ecc_bytes_total;
best_step = step_size;
best_strength = strength;
best_ecc_bytes = ecc_bytes;
}
}
}
if (best_ecc_bytes_total == INT_MAX)
return -ENOTSUPP;
chip->ecc.size = best_step;
chip->ecc.strength = best_strength;
chip->ecc.bytes = best_ecc_bytes;
return 0;
}
EXPORT_SYMBOL_GPL(nand_match_ecc_req);
/**
* nand_maximize_ecc - choose the max ECC strength available
* @chip: nand chip info structure
* @caps: ECC engine caps info structure
* @oobavail: OOB size that the ECC engine can use
*
* Choose the max ECC strength that is supported on the controller, and can fit
* within the chip's OOB. On success, the chosen ECC settings are set.
*/
int nand_maximize_ecc(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail)
{
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_ecc_step_info *stepinfo;
int step_size, strength, nsteps, ecc_bytes, corr;
int best_corr = 0;
int best_step = 0;
int best_strength, best_ecc_bytes;
int i, j;
if (WARN_ON(oobavail < 0))
return -EINVAL;
for (i = 0; i < caps->nstepinfos; i++) {
stepinfo = &caps->stepinfos[i];
step_size = stepinfo->stepsize;
/* If chip->ecc.size is already set, respect it */
if (chip->ecc.size && step_size != chip->ecc.size)
continue;
for (j = 0; j < stepinfo->nstrengths; j++) {
strength = stepinfo->strengths[j];
if (mtd->writesize % step_size)
continue;
nsteps = mtd->writesize / step_size;
ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
if (WARN_ON_ONCE(ecc_bytes < 0))
continue;
if (ecc_bytes * nsteps > oobavail)
continue;
corr = strength * nsteps;
/*
* If the number of correctable bits is the same,
* bigger step_size has more reliability.
*/
if (corr > best_corr ||
(corr == best_corr && step_size > best_step)) {
best_corr = corr;
best_step = step_size;
best_strength = strength;
best_ecc_bytes = ecc_bytes;
}
}
}
if (!best_corr)
return -ENOTSUPP;
chip->ecc.size = best_step;
chip->ecc.strength = best_strength;
chip->ecc.bytes = best_ecc_bytes;
return 0;
}
EXPORT_SYMBOL_GPL(nand_maximize_ecc);
/*
* Check if the chip configuration meet the datasheet requirements.
@ -4730,6 +4970,18 @@ int nand_scan_tail(struct mtd_info *mtd)
}
break;
case NAND_ECC_ON_DIE:
if (!ecc->read_page || !ecc->write_page) {
WARN(1, "No ECC functions supplied; on-die ECC not possible\n");
ret = -EINVAL;
goto err_free;
}
if (!ecc->read_oob)
ecc->read_oob = nand_read_oob_std;
if (!ecc->write_oob)
ecc->write_oob = nand_write_oob_std;
break;
case NAND_ECC_NONE:
pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n");
ecc->read_page = nand_read_page_raw;
@ -4770,6 +5022,11 @@ int nand_scan_tail(struct mtd_info *mtd)
goto err_free;
}
ecc->total = ecc->steps * ecc->bytes;
if (ecc->total > mtd->oobsize) {
WARN(1, "Total number of ECC bytes exceeded oobsize\n");
ret = -EINVAL;
goto err_free;
}
/*
* The number of bytes available for a client to place data into

View File

@ -17,6 +17,12 @@
#include <linux/mtd/nand.h>
/*
* Special Micron status bit that indicates when the block has been
* corrected by on-die ECC and should be rewritten
*/
#define NAND_STATUS_WRITE_RECOMMENDED BIT(3)
struct nand_onfi_vendor_micron {
u8 two_plane_read;
u8 read_cache;
@ -66,9 +72,197 @@ static int micron_nand_onfi_init(struct nand_chip *chip)
return 0;
}
static int micron_nand_on_die_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section >= 4)
return -ERANGE;
oobregion->offset = (section * 16) + 8;
oobregion->length = 8;
return 0;
}
static int micron_nand_on_die_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section >= 4)
return -ERANGE;
oobregion->offset = (section * 16) + 2;
oobregion->length = 6;
return 0;
}
static const struct mtd_ooblayout_ops micron_nand_on_die_ooblayout_ops = {
.ecc = micron_nand_on_die_ooblayout_ecc,
.free = micron_nand_on_die_ooblayout_free,
};
static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable)
{
u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
if (enable)
feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN;
return chip->onfi_set_features(nand_to_mtd(chip), chip,
ONFI_FEATURE_ON_DIE_ECC, feature);
}
static int
micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required,
int page)
{
int status;
int max_bitflips = 0;
micron_nand_on_die_ecc_setup(chip, true);
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
status = chip->read_byte(mtd);
if (status & NAND_STATUS_FAIL)
mtd->ecc_stats.failed++;
/*
* The internal ECC doesn't tell us the number of bitflips
* that have been corrected, but tells us if it recommends to
* rewrite the block. If it's the case, then we pretend we had
* a number of bitflips equal to the ECC strength, which will
* hint the NAND core to rewrite the block.
*/
else if (status & NAND_STATUS_WRITE_RECOMMENDED)
max_bitflips = chip->ecc.strength;
chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1);
nand_read_page_raw(mtd, chip, buf, oob_required, page);
micron_nand_on_die_ecc_setup(chip, false);
return max_bitflips;
}
static int
micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required,
int page)
{
int status;
micron_nand_on_die_ecc_setup(chip, true);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
nand_write_page_raw(mtd, chip, buf, oob_required, page);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
micron_nand_on_die_ecc_setup(chip, false);
return status & NAND_STATUS_FAIL ? -EIO : 0;
}
static int
micron_nand_read_page_raw_on_die_ecc(struct mtd_info *mtd,
struct nand_chip *chip,
uint8_t *buf, int oob_required,
int page)
{
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
nand_read_page_raw(mtd, chip, buf, oob_required, page);
return 0;
}
static int
micron_nand_write_page_raw_on_die_ecc(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf, int oob_required,
int page)
{
int status;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
nand_write_page_raw(mtd, chip, buf, oob_required, page);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
}
enum {
/* The NAND flash doesn't support on-die ECC */
MICRON_ON_DIE_UNSUPPORTED,
/*
* The NAND flash supports on-die ECC and it can be
* enabled/disabled by a set features command.
*/
MICRON_ON_DIE_SUPPORTED,
/*
* The NAND flash supports on-die ECC, and it cannot be
* disabled.
*/
MICRON_ON_DIE_MANDATORY,
};
/*
* Try to detect if the NAND support on-die ECC. To do this, we enable
* the feature, and read back if it has been enabled as expected. We
* also check if it can be disabled, because some Micron NANDs do not
* allow disabling the on-die ECC and we don't support such NANDs for
* now.
*
* This function also has the side effect of disabling on-die ECC if
* it had been left enabled by the firmware/bootloader.
*/
static int micron_supports_on_die_ecc(struct nand_chip *chip)
{
u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
int ret;
if (chip->onfi_version == 0)
return MICRON_ON_DIE_UNSUPPORTED;
if (chip->bits_per_cell != 1)
return MICRON_ON_DIE_UNSUPPORTED;
ret = micron_nand_on_die_ecc_setup(chip, true);
if (ret)
return MICRON_ON_DIE_UNSUPPORTED;
chip->onfi_get_features(nand_to_mtd(chip), chip,
ONFI_FEATURE_ON_DIE_ECC, feature);
if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0)
return MICRON_ON_DIE_UNSUPPORTED;
ret = micron_nand_on_die_ecc_setup(chip, false);
if (ret)
return MICRON_ON_DIE_UNSUPPORTED;
chip->onfi_get_features(nand_to_mtd(chip), chip,
ONFI_FEATURE_ON_DIE_ECC, feature);
if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN)
return MICRON_ON_DIE_MANDATORY;
/*
* Some Micron NANDs have an on-die ECC of 4/512, some other
* 8/512. We only support the former.
*/
if (chip->onfi_params.ecc_bits != 4)
return MICRON_ON_DIE_UNSUPPORTED;
return MICRON_ON_DIE_SUPPORTED;
}
static int micron_nand_init(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int ondie;
int ret;
ret = micron_nand_onfi_init(chip);
@ -78,6 +272,34 @@ static int micron_nand_init(struct nand_chip *chip)
if (mtd->writesize == 2048)
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
ondie = micron_supports_on_die_ecc(chip);
if (ondie == MICRON_ON_DIE_MANDATORY) {
pr_err("On-die ECC forcefully enabled, not supported\n");
return -EINVAL;
}
if (chip->ecc.mode == NAND_ECC_ON_DIE) {
if (ondie == MICRON_ON_DIE_UNSUPPORTED) {
pr_err("On-die ECC selected but not supported\n");
return -EINVAL;
}
chip->ecc.options = NAND_ECC_CUSTOM_PAGE_ACCESS;
chip->ecc.bytes = 8;
chip->ecc.size = 512;
chip->ecc.strength = 4;
chip->ecc.algo = NAND_ECC_BCH;
chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
chip->ecc.read_page_raw =
micron_nand_read_page_raw_on_die_ecc;
chip->ecc.write_page_raw =
micron_nand_write_page_raw_on_die_ecc;
mtd_set_ooblayout(mtd, &micron_nand_on_die_ooblayout_ops);
}
return 0;
}

View File

@ -166,7 +166,11 @@ static int __init orion_nand_probe(struct platform_device *pdev)
}
}
clk_prepare_enable(info->clk);
ret = clk_prepare_enable(info->clk);
if (ret) {
dev_err(&pdev->dev, "failed to prepare clock!\n");
return ret;
}
ret = nand_scan(mtd, 1);
if (ret)

View File

@ -1812,6 +1812,8 @@ static int alloc_nand_resource(struct platform_device *pdev)
chip->write_buf = pxa3xx_nand_write_buf;
chip->options |= NAND_NO_SUBPAGE_WRITE;
chip->cmdfunc = nand_cmdfunc;
chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
}
nand_hw_control_init(chip->controller);

View File

@ -2008,6 +2008,8 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
chip->read_byte = qcom_nandc_read_byte;
chip->read_buf = qcom_nandc_read_buf;
chip->write_buf = qcom_nandc_write_buf;
chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
/*
* the bad block marker is readable only when we read the last codeword

View File

@ -812,9 +812,8 @@ 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)
static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, int csline,
const struct nand_data_interface *conf)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
struct s3c2410_platform_nand *pdata = info->platform;

View File

@ -1183,6 +1183,8 @@ static int flctl_probe(struct platform_device *pdev)
nand->read_buf = flctl_read_buf;
nand->select_chip = flctl_select_chip;
nand->cmdfunc = flctl_cmdfunc;
nand->onfi_set_features = nand_onfi_get_set_features_notsupp;
nand->onfi_get_features = nand_onfi_get_set_features_notsupp;
if (pdata->flcmncr_val & SEL_16BIT)
nand->options |= NAND_BUSWIDTH_16;

View File

@ -1301,7 +1301,6 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
sunxi_nfc_hw_ecc_enable(mtd);
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
for (i = data_offs / ecc->size;
i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) {
int data_off = i * ecc->size;
@ -1592,9 +1591,8 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
#define sunxi_nand_lookup_timing(l, p, c) \
_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd,
const struct nand_data_interface *conf,
bool check_only)
static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
const struct nand_data_interface *conf)
{
struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
@ -1707,7 +1705,7 @@ static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd,
return tRHW;
}
if (check_only)
if (csline == NAND_DATA_IFACE_CHECK_ONLY)
return 0;
/*
@ -1922,7 +1920,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage;
ecc->read_oob_raw = nand_read_oob_std;
ecc->write_oob_raw = nand_write_oob_std;
ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
return 0;
}

View File

@ -303,7 +303,7 @@ 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;
int err, status, len = mtd->writesize;
/* Calling tango_write_oob() would send PAGEPROG twice */
if (oob_required)
@ -314,6 +314,10 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
if (err)
return err;
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
}
@ -340,7 +344,7 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
if (!*buf) {
/* skip over "len" bytes */
chip->cmdfunc(mtd, NAND_CMD_SEQIN, *pos, -1);
chip->cmdfunc(mtd, NAND_CMD_RNDIN, *pos, -1);
} else {
tango_write_buf(mtd, *buf, len);
*buf += len;
@ -431,9 +435,16 @@ static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const u8 *buf, int oob_required, int page)
{
int status;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
raw_write(chip, buf, chip->oob_poi);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
}
@ -484,9 +495,8 @@ 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)
static int tango_set_timings(struct mtd_info *mtd, int csline,
const struct nand_data_interface *conf)
{
const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
struct nand_chip *chip = mtd_to_nand(mtd);
@ -498,7 +508,7 @@ static int tango_set_timings(struct mtd_info *mtd,
if (IS_ERR(sdr))
return PTR_ERR(sdr);
if (check_only)
if (csline == NAND_DATA_IFACE_CHECK_ONLY)
return 0;
Trdy = to_ticks(kHz, sdr->tCEA_max - sdr->tREA_max);

View File

@ -703,6 +703,8 @@ static int vf610_nfc_probe(struct platform_device *pdev)
chip->read_buf = vf610_nfc_read_buf;
chip->write_buf = vf610_nfc_write_buf;
chip->select_chip = vf610_nfc_select_chip;
chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
chip->options |= NAND_NO_SUBPAGE_WRITE;

View File

@ -915,6 +915,8 @@ static int spinand_probe(struct spi_device *spi_nand)
chip->waitfunc = spinand_wait;
chip->options |= NAND_CACHEPRG;
chip->select_chip = spinand_select_chip;
chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
mtd = nand_to_mtd(chip);

View File

@ -107,6 +107,8 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
#define NAND_STATUS_READY 0x40
#define NAND_STATUS_WP 0x80
#define NAND_DATA_IFACE_CHECK_ONLY -1
/*
* Constants for ECC_MODES
*/
@ -116,6 +118,7 @@ typedef enum {
NAND_ECC_HW,
NAND_ECC_HW_SYNDROME,
NAND_ECC_HW_OOB_FIRST,
NAND_ECC_ON_DIE,
} nand_ecc_modes_t;
enum nand_ecc_algo {
@ -257,6 +260,8 @@ struct nand_chip;
/* Vendor-specific feature address (Micron) */
#define ONFI_FEATURE_ADDR_READ_RETRY 0x89
#define ONFI_FEATURE_ON_DIE_ECC 0x90
#define ONFI_FEATURE_ON_DIE_ECC_EN BIT(3)
/* ONFI subfeature parameters length */
#define ONFI_SUBFEATURE_PARAM_LEN 4
@ -476,6 +481,44 @@ static inline void nand_hw_control_init(struct nand_hw_control *nfc)
init_waitqueue_head(&nfc->wq);
}
/**
* struct nand_ecc_step_info - ECC step information of ECC engine
* @stepsize: data bytes per ECC step
* @strengths: array of supported strengths
* @nstrengths: number of supported strengths
*/
struct nand_ecc_step_info {
int stepsize;
const int *strengths;
int nstrengths;
};
/**
* struct nand_ecc_caps - capability of ECC engine
* @stepinfos: array of ECC step information
* @nstepinfos: number of ECC step information
* @calc_ecc_bytes: driver's hook to calculate ECC bytes per step
*/
struct nand_ecc_caps {
const struct nand_ecc_step_info *stepinfos;
int nstepinfos;
int (*calc_ecc_bytes)(int step_size, int strength);
};
/* a shorthand to generate struct nand_ecc_caps with only one ECC stepsize */
#define NAND_ECC_CAPS_SINGLE(__name, __calc, __step, ...) \
static const int __name##_strengths[] = { __VA_ARGS__ }; \
static const struct nand_ecc_step_info __name##_stepinfo = { \
.stepsize = __step, \
.strengths = __name##_strengths, \
.nstrengths = ARRAY_SIZE(__name##_strengths), \
}; \
static const struct nand_ecc_caps __name = { \
.stepinfos = &__name##_stepinfo, \
.nstepinfos = 1, \
.calc_ecc_bytes = __calc, \
}
/**
* struct nand_ecc_ctrl - Control structure for ECC
* @mode: ECC mode
@ -815,7 +858,10 @@ struct nand_manufacturer_ops {
* @read_retries: [INTERN] the number of read retry modes supported
* @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
* @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
* @setup_data_interface: [OPTIONAL] setup the data interface and timing
* @setup_data_interface: [OPTIONAL] setup the data interface and timing. If
* chipnr is set to %NAND_DATA_IFACE_CHECK_ONLY this
* means the configuration should not be applied but
* only checked.
* @bbt: [INTERN] bad block table pointer
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash
* lookup.
@ -826,9 +872,6 @@ struct nand_manufacturer_ops {
* structure which is shared among multiple independent
* devices.
* @priv: [OPTIONAL] pointer to private chip data
* @errstat: [OPTIONAL] hardware specific function to perform
* additional error status checks (determine if errors are
* correctable).
* @manufacturer: [INTERN] Contains manufacturer information
*/
@ -852,16 +895,13 @@ struct nand_chip {
int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
int (*erase)(struct mtd_info *mtd, int page);
int (*scan_bbt)(struct mtd_info *mtd);
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
int status, int page);
int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip,
int feature_addr, uint8_t *subfeature_para);
int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
int feature_addr, uint8_t *subfeature_para);
int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);
int (*setup_data_interface)(struct mtd_info *mtd,
const struct nand_data_interface *conf,
bool check_only);
int (*setup_data_interface)(struct mtd_info *mtd, int chipnr,
const struct nand_data_interface *conf);
int chip_delay;
@ -1244,6 +1284,15 @@ int nand_check_erased_ecc_chunk(void *data, int datalen,
void *extraoob, int extraooblen,
int threshold);
int nand_check_ecc_caps(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail);
int nand_match_ecc_req(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail);
int nand_maximize_ecc(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail);
/* Default write_oob implementation */
int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
@ -1258,6 +1307,19 @@ int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
int page);
/* Stub used by drivers that do not support GET/SET FEATURES operations */
int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd,
struct nand_chip *chip, int addr,
u8 *subfeature_param);
/* Default read_page_raw implementation */
int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page);
/* Default write_page_raw implementation */
int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page);
/* Reset and initialize a NAND device */
int nand_reset(struct nand_chip *chip, int chipnr);