Commit ef32476f authored by Brian Norris's avatar Brian Norris

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.
"""
parents 8b9ef8f9 81667e9c
...@@ -3,10 +3,23 @@ ...@@ -3,10 +3,23 @@
Required properties: Required properties:
- compatible : should be one of the following: - compatible : should be one of the following:
"altr,socfpga-denali-nand" - for Altera SOCFPGA "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 : should contain registers location and length for data and reg.
- reg-names: Should contain the reg names "nand_data" and "denali_reg" - reg-names: Should contain the reg names "nand_data" and "denali_reg"
- interrupts : The interrupt number. - 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 The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail. address space. See partition.txt for more detail.
......
Error location module Error location module
Required properties: Required properties:
- compatible: Must be "ti,am33xx-elm" - compatible: Must be "ti,am3352-elm"
- reg: physical base address and size of the registers map. - reg: physical base address and size of the registers map.
- interrupts: Interrupt number for the elm. - interrupts: Interrupt number for the elm.
......
...@@ -5,7 +5,7 @@ the GPMC controller with a name of "nand". ...@@ -5,7 +5,7 @@ the GPMC controller with a name of "nand".
All timing relevant properties as well as generic gpmc child properties are All timing relevant properties as well as generic gpmc child properties are
explained in a separate documents - please refer to 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 For NAND specific properties such as ECC modes or bus width, please refer to
Documentation/devicetree/bindings/mtd/nand.txt Documentation/devicetree/bindings/mtd/nand.txt
......
...@@ -5,7 +5,7 @@ child nodes of the GPMC controller with a name of "nor". ...@@ -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 All timing relevant properties as well as generic GPMC child properties are
explained in a separate documents. Please refer to 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: Required properties:
- bank-width: Width of NOR flash in bytes. GPMC supports 8-bit and - bank-width: Width of NOR flash in bytes. GPMC supports 8-bit and
...@@ -28,7 +28,7 @@ Required properties: ...@@ -28,7 +28,7 @@ Required properties:
Optional properties: Optional properties:
- gpmc,XXX Additional GPMC timings and settings parameters. See - 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: Optional properties for partition table parsing:
- #address-cells: should be set to 1 - #address-cells: should be set to 1
......
...@@ -5,7 +5,7 @@ the GPMC controller with a name of "onenand". ...@@ -5,7 +5,7 @@ the GPMC controller with a name of "onenand".
All timing relevant properties as well as generic gpmc child properties are All timing relevant properties as well as generic gpmc child properties are
explained in a separate documents - please refer to 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: Required properties:
......
...@@ -4,7 +4,12 @@ The GPMI nand controller provides an interface to control the ...@@ -4,7 +4,12 @@ The GPMI nand controller provides an interface to control the
NAND flash chips. NAND flash chips.
Required properties: 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 : should contain registers location and length for gpmi and bch.
- reg-names: Should contain the reg names "gpmi-nand" and "bch" - reg-names: Should contain the reg names "gpmi-nand" and "bch"
- interrupts : BCH interrupt number. - interrupts : BCH interrupt number.
...@@ -13,6 +18,13 @@ Required properties: ...@@ -13,6 +18,13 @@ Required properties:
and GPMI DMA channel ID. and GPMI DMA channel ID.
Refer to dma.txt and fsl-mxs-dma.txt for details. Refer to dma.txt and fsl-mxs-dma.txt for details.
- dma-names: Must be "rx-tx". - 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: Optional properties:
- nand-on-flash-bbt: boolean to enable on flash bbt option if not - nand-on-flash-bbt: boolean to enable on flash bbt option if not
......
...@@ -12,7 +12,8 @@ tree nodes. ...@@ -12,7 +12,8 @@ tree nodes.
The first part of NFC is NAND Controller Interface (NFI) HW. The first part of NFC is NAND Controller Interface (NFI) HW.
Required NFI properties: 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. - reg: Base physical address and size of NFI.
- interrupts: Interrupts of NFI. - interrupts: Interrupts of NFI.
- clocks: NFI required clocks. - clocks: NFI required clocks.
...@@ -141,7 +142,7 @@ Example: ...@@ -141,7 +142,7 @@ Example:
============== ==============
Required BCH properties: 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. - reg: Base physical address and size of ECC.
- interrupts: Interrupts of ECC. - interrupts: Interrupts of ECC.
- clocks: ECC required clocks. - clocks: ECC required clocks.
......
...@@ -21,7 +21,7 @@ Optional NAND chip properties: ...@@ -21,7 +21,7 @@ Optional NAND chip properties:
- nand-ecc-mode : String, operation mode of the NAND ecc mode. - nand-ecc-mode : String, operation mode of the NAND ecc mode.
Supported values are: "none", "soft", "hw", "hw_syndrome", Supported values are: "none", "soft", "hw", "hw_syndrome",
"hw_oob_first". "hw_oob_first", "on-die".
Deprecated values: Deprecated values:
"soft_bch": use "soft" and nand-ecc-algo instead "soft_bch": use "soft" and nand-ecc-algo instead
- nand-ecc-algo: string, algorithm of NAND ECC. - nand-ecc-algo: string, algorithm of NAND ECC.
......
...@@ -9,7 +9,7 @@ the GPMC controller with an "ethernet" name. ...@@ -9,7 +9,7 @@ the GPMC controller with an "ethernet" name.
All timing relevant properties as well as generic GPMC child properties are All timing relevant properties as well as generic GPMC child properties are
explained in a separate documents. Please refer to 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 For the properties relevant to the ethernet controller connected to the GPMC
refer to the binding documentation of the device. For example, the documentation refer to the binding documentation of the device. For example, the documentation
...@@ -43,7 +43,7 @@ Required properties: ...@@ -43,7 +43,7 @@ Required properties:
Optional properties: Optional properties:
- gpmc,XXX Additional GPMC timings and settings parameters. See - 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: Example:
......
...@@ -3895,6 +3895,12 @@ M: Pali Rohár <pali.rohar@gmail.com> ...@@ -3895,6 +3895,12 @@ M: Pali Rohár <pali.rohar@gmail.com>
S: Maintained S: Maintained
F: drivers/platform/x86/dell-wmi.c 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 DESIGNWARE USB2 DRD IP DRIVER
M: John Youn <johnyoun@synopsys.com> M: John Youn <johnyoun@synopsys.com>
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
......
...@@ -308,6 +308,7 @@ config MTD_NAND_CS553X ...@@ -308,6 +308,7 @@ config MTD_NAND_CS553X
config MTD_NAND_ATMEL config MTD_NAND_ATMEL
tristate "Support for NAND Flash / SmartMedia on AT91" tristate "Support for NAND Flash / SmartMedia on AT91"
depends on ARCH_AT91 depends on ARCH_AT91
select MFD_ATMEL_SMC
help help
Enables support for NAND Flash / Smart Media Card interface Enables support for NAND Flash / Smart Media Card interface
on Atmel AT91 processors. on Atmel AT91 processors.
...@@ -542,6 +543,7 @@ config MTD_NAND_SUNXI ...@@ -542,6 +543,7 @@ config MTD_NAND_SUNXI
config MTD_NAND_HISI504 config MTD_NAND_HISI504
tristate "Support for NAND controller on Hisilicon SoC Hip04" tristate "Support for NAND controller on Hisilicon SoC Hip04"
depends on ARCH_HISI || COMPILE_TEST
depends on HAS_DMA depends on HAS_DMA
help help
Enables support for NAND controller on Hisilicon SoC Hip04. Enables support for NAND controller on Hisilicon SoC Hip04.
...@@ -555,6 +557,7 @@ config MTD_NAND_QCOM ...@@ -555,6 +557,7 @@ config MTD_NAND_QCOM
config MTD_NAND_MTK config MTD_NAND_MTK
tristate "Support for NAND controller on MTK SoCs" tristate "Support for NAND controller on MTK SoCs"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on HAS_DMA depends on HAS_DMA
help help
Enables support for NAND controller on MTK SoCs. Enables support for NAND controller on MTK SoCs.
......
This diff is collapsed.
...@@ -392,6 +392,8 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) ...@@ -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_byte = bcm47xxnflash_ops_bcm4706_read_byte;
b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_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; nand_chip->chip_delay = 50;
b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
......
...@@ -654,6 +654,8 @@ static int cafe_nand_probe(struct pci_dev *pdev, ...@@ -654,6 +654,8 @@ static int cafe_nand_probe(struct pci_dev *pdev,
cafe->nand.read_buf = cafe_read_buf; cafe->nand.read_buf = cafe_read_buf;
cafe->nand.write_buf = cafe_write_buf; cafe->nand.write_buf = cafe_write_buf;
cafe->nand.select_chip = cafe_select_chip; 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; cafe->nand.chip_delay = 0;
......
...@@ -771,11 +771,14 @@ static int nand_davinci_probe(struct platform_device *pdev) ...@@ -771,11 +771,14 @@ static int nand_davinci_probe(struct platform_device *pdev)
info->chip.ecc.hwctl = nand_davinci_hwctl_4bit; info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
info->chip.ecc.bytes = 10; info->chip.ecc.bytes = 10;
info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK; info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
info->chip.ecc.algo = NAND_ECC_BCH;
} else { } else {
/* 1bit ecc hamming */
info->chip.ecc.calculate = nand_davinci_calculate_1bit; info->chip.ecc.calculate = nand_davinci_calculate_1bit;
info->chip.ecc.correct = nand_davinci_correct_1bit; info->chip.ecc.correct = nand_davinci_correct_1bit;
info->chip.ecc.hwctl = nand_davinci_hwctl_1bit; info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
info->chip.ecc.bytes = 3; info->chip.ecc.bytes = 3;
info->chip.ecc.algo = NAND_ECC_HAMMING;
} }
info->chip.ecc.size = 512; info->chip.ecc.size = 512;
info->chip.ecc.strength = pdata->ecc_bits; info->chip.ecc.strength = pdata->ecc_bits;
......
This diff is collapsed.
This diff is collapsed.
...@@ -32,10 +32,31 @@ struct denali_dt { ...@@ -32,10 +32,31 @@ struct denali_dt {
struct denali_dt_data { struct denali_dt_data {
unsigned int revision; unsigned int revision;
unsigned int caps; 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 = { static const struct denali_dt_data denali_socfpga_data = {
.caps = DENALI_CAP_HW_ECC_FIXUP, .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[] = { static const struct of_device_id denali_nand_dt_ids[] = {
...@@ -43,13 +64,21 @@ 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", .compatible = "altr,socfpga-denali-nand",
.data = &denali_socfpga_data, .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 */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, denali_nand_dt_ids); MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
static int denali_dt_probe(struct platform_device *pdev) static int denali_dt_probe(struct platform_device *pdev)
{ {
struct resource *denali_reg, *nand_data; struct resource *res;
struct denali_dt *dt; struct denali_dt *dt;
const struct denali_dt_data *data; const struct denali_dt_data *data;
struct denali_nand_info *denali; struct denali_nand_info *denali;
...@@ -64,9 +93,9 @@ static int denali_dt_probe(struct platform_device *pdev) ...@@ -64,9 +93,9 @@ static int denali_dt_probe(struct platform_device *pdev)
if (data) { if (data) {
denali->revision = data->revision; denali->revision = data->revision;
denali->caps = data->caps; denali->caps = data->caps;
denali->ecc_caps = data->ecc_caps;
} }
denali->platform = DT;
denali->dev = &pdev->dev; denali->dev = &pdev->dev;
denali->irq = platform_get_irq(pdev, 0); denali->irq = platform_get_irq(pdev, 0);
if (denali->irq < 0) { if (denali->irq < 0) {
...@@ -74,17 +103,15 @@ static int denali_dt_probe(struct platform_device *pdev) ...@@ -74,17 +103,15 @@ static int denali_dt_probe(struct platform_device *pdev)
return denali->irq; return denali->irq;
} }
denali_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg");
"denali_reg"); denali->reg = devm_ioremap_resource(&pdev->dev, res);
denali->flash_reg = devm_ioremap_resource(&pdev->dev, denali_reg); if (IS_ERR(denali->reg))
if (IS_ERR(denali->flash_reg)) return PTR_ERR(denali->reg);
return PTR_ERR(denali->flash_reg);
nand_data = platform_get_resource_byname(pdev, IORESOURCE_MEM, res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
"nand_data"); denali->host = devm_ioremap_resource(&pdev->dev, res);
denali->flash_mem = devm_ioremap_resource(&pdev->dev, nand_data); if (IS_ERR(denali->host))
if (IS_ERR(denali->flash_mem)) return PTR_ERR(denali->host);
return PTR_ERR(denali->flash_mem);
dt->clk = devm_clk_get(&pdev->dev, NULL); dt->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dt->clk)) { if (IS_ERR(dt->clk)) {
...@@ -93,6 +120,8 @@ static int denali_dt_probe(struct platform_device *pdev) ...@@ -93,6 +120,8 @@ static int denali_dt_probe(struct platform_device *pdev)
} }
clk_prepare_enable(dt->clk); clk_prepare_enable(dt->clk);
denali->clk_x_rate = clk_get_rate(dt->clk);
ret = denali_init(denali); ret = denali_init(denali);
if (ret) if (ret)
goto out_disable_clk; goto out_disable_clk;
......
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
#define DENALI_NAND_NAME "denali-nand-pci" #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 */ /* List of platforms this NAND controller has be integrated into */
static const struct pci_device_id denali_pci_ids[] = { static const struct pci_device_id denali_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 }, { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
...@@ -27,6 +30,8 @@ static const struct pci_device_id denali_pci_ids[] = { ...@@ -27,6 +30,8 @@ static const struct pci_device_id denali_pci_ids[] = {
}; };
MODULE_DEVICE_TABLE(pci, 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) static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{ {
int ret; int ret;
...@@ -45,13 +50,11 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -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) { if (id->driver_data == INTEL_CE4100) {
denali->platform = INTEL_CE4100;
mem_base = pci_resource_start(dev, 0); mem_base = pci_resource_start(dev, 0);
mem_len = pci_resource_len(dev, 1); mem_len = pci_resource_len(dev, 1);
csr_base = pci_resource_start(dev, 1); csr_base = pci_resource_start(dev, 1);
csr_len = pci_resource_len(dev, 1); csr_len = pci_resource_len(dev, 1);
} else { } else {
denali->platform = INTEL_MRST;
csr_base = pci_resource_start(dev, 0); csr_base = pci_resource_start(dev, 0);
csr_len = pci_resource_len(dev, 0); csr_len = pci_resource_len(dev, 0);
mem_base = pci_resource_start(dev, 1); 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) ...@@ -65,6 +68,9 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
pci_set_master(dev); pci_set_master(dev);
denali->dev = &dev->dev; denali->dev = &dev->dev;
denali->irq = dev->irq; 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); ret = pci_request_regions(dev, DENALI_NAND_NAME);
if (ret) { if (ret) {
...@@ -72,14 +78,14 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -72,14 +78,14 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
return ret; return ret;
} }
denali->flash_reg = ioremap_nocache(csr_base, csr_len); denali->reg = ioremap_nocache(csr_base, csr_len);
if (!denali->flash_reg) { if (!denali->reg) {
dev_err(&dev->dev, "Spectra: Unable to remap memory region\n"); dev_err(&dev->dev, "Spectra: Unable to remap memory region\n");
return -ENOMEM; return -ENOMEM;
} }
denali->flash_mem = ioremap_nocache(mem_base, mem_len); denali->host = ioremap_nocache(mem_base, mem_len);
if (!denali->flash_mem) { if (!denali->host) {
dev_err(&dev->dev, "Spectra: ioremap_nocache failed!"); dev_err(&dev->dev, "Spectra: ioremap_nocache failed!");
ret = -ENOMEM; ret = -ENOMEM;
goto failed_remap_reg; goto failed_remap_reg;
...@@ -94,9 +100,9 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -94,9 +100,9 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
return 0; return 0;
failed_remap_mem: failed_remap_mem:
iounmap(denali->flash_mem); iounmap(denali->host);
failed_remap_reg: failed_remap_reg:
iounmap(denali->flash_reg); iounmap(denali->reg);
return ret; return ret;
} }
...@@ -106,8 +112,8 @@ static void denali_pci_remove(struct pci_dev *dev) ...@@ -106,8 +112,8 @@ static void denali_pci_remove(struct pci_dev *dev)
struct denali_nand_info *denali = pci_get_drvdata(dev); struct denali_nand_info *denali = pci_get_drvdata(dev);
denali_remove(denali); denali_remove(denali);
iounmap(denali->flash_reg); iounmap(denali->reg);
iounmap(denali->flash_mem); iounmap(denali->host);
} }
static struct pci_driver denali_pci_driver = { static struct pci_driver denali_pci_driver = {
......
...@@ -1260,6 +1260,8 @@ static void __init init_mtd_structs(struct mtd_info *mtd) ...@@ -1260,6 +1260,8 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
nand->read_buf = docg4_read_buf; nand->read_buf = docg4_read_buf;
nand->write_buf = docg4_write_buf16; nand->write_buf = docg4_write_buf16;
nand->erase = docg4_erase_block; 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.read_page = docg4_read_page;
nand->ecc.write_page = docg4_write_page; nand->ecc.write_page = docg4_write_page;
nand->ecc.read_page_raw = docg4_read_page_raw; nand->ecc.read_page_raw = docg4_read_page_raw;
......
...@@ -775,6 +775,8 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) ...@@ -775,6 +775,8 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
chip->select_chip = fsl_elbc_select_chip; chip->select_chip = fsl_elbc_select_chip;
chip->cmdfunc = fsl_elbc_cmdfunc; chip->cmdfunc = fsl_elbc_cmdfunc;
chip->waitfunc = fsl_elbc_wait; 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_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr; chip->bbt_md = &bbt_mirror_descr;
......
...@@ -171,34 +171,6 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) ...@@ -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; 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 */ /* returns nonzero if entire page is blank */
static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl, static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
u32 *eccstat, unsigned int bufnum) u32 *eccstat, unsigned int bufnum)
...@@ -274,16 +246,14 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) ...@@ -274,16 +246,14 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
if (errors == 15) { if (errors == 15) {
/* /*
* Uncorrectable error. * Uncorrectable error.
* OK only if the whole page is blank. * We'll check for blank pages later.
* *
* We disable ECCER reporting due to... * We disable ECCER reporting due to...
* erratum IFC-A002770 -- so report it now if we * erratum IFC-A002770 -- so report it now if we
* see an uncorrectable error in ECCSTAT. * see an uncorrectable error in ECCSTAT.
*/ */
if (!is_blank(mtd, bufnum)) ctrl->nand_stat |= IFC_NAND_EVTER_STAT_ECCER;
ctrl->nand_stat |= continue;
IFC_NAND_EVTER_STAT_ECCER;
break;
} }
mtd->ecc_stats.corrected += errors; mtd->ecc_stats.corrected += errors;
...@@ -678,6 +648,39 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip) ...@@ -678,6 +648,39 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
return nand_fsr | NAND_STATUS_WP; 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, static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page) 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, ...@@ -689,8 +692,12 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
if (oob_required) if (oob_required)
fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize); fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) {
dev_err(priv->dev, "NAND Flash ECC Uncorrectable Error\n"); 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) if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
mtd->ecc_stats.failed++; mtd->ecc_stats.failed++;
...@@ -831,6 +838,8 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) ...@@ -831,6 +838,8 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
chip->select_chip = fsl_ifc_select_chip; chip->select_chip = fsl_ifc_select_chip;
chip->cmdfunc = fsl_ifc_cmdfunc; chip->cmdfunc = fsl_ifc_cmdfunc;
chip->waitfunc = fsl_ifc_wait; 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_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr; chip->bbt_md = &bbt_mirror_descr;
...@@ -904,7 +913,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) ...@@ -904,7 +913,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
chip->ecc.algo = NAND_ECC_HAMMING; 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); fsl_ifc_sram_init(priv);
return 0; return 0;
......
...@@ -302,25 +302,13 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) ...@@ -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 * This routine initializes timing parameters related to NAND memory access in
* FSMC registers * FSMC registers
*/ */
static void fsmc_nand_setup(void __iomem *regs, uint32_t bank, static void fsmc_nand_setup(struct fsmc_nand_data *host,
uint32_t busw, struct fsmc_nand_timings *timings) struct fsmc_nand_timings *tims)
{ {
uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON; uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
uint32_t tclr, tar, thiz, thold, twait, tset; uint32_t tclr, tar, thiz, thold, twait, tset;
struct fsmc_nand_timings *tims; unsigned int bank = host->bank;
struct fsmc_nand_timings default_timings = { void __iomem *regs = host->regs_va;
.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;
tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT; tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_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, ...@@ -329,7 +317,7 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
twait = (tims->twait & FSMC_TWAIT_MASK) << FSMC_TWAIT_SHIFT; twait = (tims->twait & FSMC_TWAIT_MASK) << FSMC_TWAIT_SHIFT;
tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_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, writel_relaxed(value | FSMC_DEVWID_16,
FSMC_NAND_REG(regs, bank, PC)); FSMC_NAND_REG(regs, bank, PC));
else else
...@@ -344,6 +332,87 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank, ...@@ -344,6 +332,87 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
FSMC_NAND_REG(regs, bank, ATTRIB)); 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 * fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
*/ */
...@@ -796,10 +865,8 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, ...@@ -796,10 +865,8 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
return -ENOMEM; return -ENOMEM;
ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings, ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings,
sizeof(*host->dev_timings)); sizeof(*host->dev_timings));
if (ret) { if (ret)
dev_info(&pdev->dev, "No timings in dts specified, using default timings!\n");
host->dev_timings = NULL; host->dev_timings = NULL;
}
/* Set default NAND bank to 0 */ /* Set default NAND bank to 0 */
host->bank = 0; host->bank = 0;
...@@ -933,9 +1000,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -933,9 +1000,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
break; break;
} }
fsmc_nand_setup(host->regs_va, host->bank, if (host->dev_timings)
nand->options & NAND_BUSWIDTH_16, fsmc_nand_setup(host, host->dev_timings);
host->dev_timings); else
nand->setup_data_interface = fsmc_setup_data_interface;
if (AMBA_REV_BITS(host->pid) >= 8) { if (AMBA_REV_BITS(host->pid) >= 8) {
nand->ecc.read_page = fsmc_read_page_hwecc; nand->ecc.read_page = fsmc_read_page_hwecc;
...@@ -986,6 +1054,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -986,6 +1054,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
break; break;
} }
case NAND_ECC_ON_DIE:
break;
default: default:
dev_err(&pdev->dev, "Unsupported ECC mode!\n"); dev_err(&pdev->dev, "Unsupported ECC mode!\n");
goto err_probe; goto err_probe;
...@@ -1073,9 +1144,8 @@ static int fsmc_nand_resume(struct device *dev) ...@@ -1073,9 +1144,8 @@ static int fsmc_nand_resume(struct device *dev)
struct fsmc_nand_data *host = dev_get_drvdata(dev); struct fsmc_nand_data *host = dev_get_drvdata(dev);
if (host) { if (host) {
clk_prepare_enable(host->clk); clk_prepare_enable(host->clk);
fsmc_nand_setup(host->regs_va, host->bank, if (host->dev_timings)
host->nand.options & NAND_BUSWIDTH_16, fsmc_nand_setup(host, host->dev_timings);
host->dev_timings);
} }
return 0; return 0;
} }
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include "gpmi-regs.h" #include "gpmi-regs.h"
#include "bch-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 >> .max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >>
BP_GPMI_TIMING0_DATA_SETUP), BP_GPMI_TIMING0_DATA_SETUP),
.internal_data_setup_in_ns = 0, .internal_data_setup_in_ns = 0,
...@@ -329,7 +329,7 @@ static unsigned int ns_to_cycles(unsigned int time, ...@@ -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, static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
struct gpmi_nfc_hardware_timing *hw) 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 resources *r = &this->resources;
struct nand_chip *nand = &this->nand; struct nand_chip *nand = &this->nand;
struct nand_timing target = this->timing; struct nand_timing target = this->timing;
...@@ -932,7 +932,7 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode) ...@@ -932,7 +932,7 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
nand->select_chip(mtd, 0); nand->select_chip(mtd, 0);
/* [1] send SET FEATURE commond to NAND */ /* [1] send SET FEATURE command to NAND */
feature[0] = mode; feature[0] = mode;
ret = nand->onfi_set_features(mtd, nand, ret = nand->onfi_set_features(mtd, nand,
ONFI_FEATURE_ADDR_TIMING_MODE, feature); ONFI_FEATURE_ADDR_TIMING_MODE, feature);
......
...@@ -82,6 +82,10 @@ static int gpmi_ooblayout_free(struct mtd_info *mtd, int section, ...@@ -82,6 +82,10 @@ static int gpmi_ooblayout_free(struct mtd_info *mtd, int section,
return 0; return 0;
} }
static const char * const gpmi_clks_for_mx2x[] = {
"gpmi_io",
};
static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = { static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
.ecc = gpmi_ooblayout_ecc, .ecc = gpmi_ooblayout_ecc,
.free = gpmi_ooblayout_free, .free = gpmi_ooblayout_free,
...@@ -91,24 +95,48 @@ static const struct gpmi_devdata gpmi_devdata_imx23 = { ...@@ -91,24 +95,48 @@ static const struct gpmi_devdata gpmi_devdata_imx23 = {
.type = IS_MX23, .type = IS_MX23,
.bch_max_ecc_strength = 20, .bch_max_ecc_strength = 20,
.max_chain_delay = 16, .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 = { static const struct gpmi_devdata gpmi_devdata_imx28 = {
.type = IS_MX28, .type = IS_MX28,
.bch_max_ecc_strength = 20, .bch_max_ecc_strength = 20,
.max_chain_delay = 16, .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 = { static const struct gpmi_devdata gpmi_devdata_imx6q = {
.type = IS_MX6Q, .type = IS_MX6Q,
.bch_max_ecc_strength = 40, .bch_max_ecc_strength = 40,
.max_chain_delay = 12, .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 = { static const struct gpmi_devdata gpmi_devdata_imx6sx = {
.type = IS_MX6SX, .type = IS_MX6SX,
.bch_max_ecc_strength = 62, .bch_max_ecc_strength = 62,
.max_chain_delay = 12, .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) static irqreturn_t bch_irq(int irq, void *cookie)
...@@ -599,35 +627,14 @@ static int acquire_dma_channels(struct gpmi_nand_data *this) ...@@ -599,35 +627,14 @@ static int acquire_dma_channels(struct gpmi_nand_data *this)
return -EINVAL; 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) static int gpmi_get_clks(struct gpmi_nand_data *this)
{ {
struct resources *r = &this->resources; struct resources *r = &this->resources;
char **extra_clks = NULL;
struct clk *clk; struct clk *clk;
int err, i; int err, i;
/* The main clock is stored in the first. */ for (i = 0; i < this->devdata->clks_count; i++) {
r->clock[0] = devm_clk_get(this->dev, "gpmi_io"); clk = devm_clk_get(this->dev, this->devdata->clks[i]);
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]);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
err = PTR_ERR(clk); err = PTR_ERR(clk);
goto err_clock; goto err_clock;
...@@ -1929,12 +1936,6 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this) ...@@ -1929,12 +1936,6 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
return gpmi_alloc_dma_buffer(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) static int gpmi_init_last(struct gpmi_nand_data *this)
{ {
struct nand_chip *chip = &this->nand; struct nand_chip *chip = &this->nand;
...@@ -2048,18 +2049,20 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) ...@@ -2048,18 +2049,20 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
ret = nand_boot_init(this); ret = nand_boot_init(this);
if (ret) if (ret)
goto err_out; goto err_nand_cleanup;
ret = chip->scan_bbt(mtd); ret = chip->scan_bbt(mtd);
if (ret) if (ret)
goto err_out; goto err_nand_cleanup;
ret = mtd_device_register(mtd, NULL, 0); ret = mtd_device_register(mtd, NULL, 0);
if (ret) if (ret)
goto err_out; goto err_nand_cleanup;
return 0; return 0;
err_nand_cleanup:
nand_cleanup(chip);
err_out: err_out:
gpmi_nand_exit(this); gpmi_free_dma_buffer(this);
return ret; return ret;
} }
...@@ -2076,6 +2079,9 @@ static const struct of_device_id gpmi_nand_id_table[] = { ...@@ -2076,6 +2079,9 @@ static const struct of_device_id gpmi_nand_id_table[] = {
}, { }, {
.compatible = "fsl,imx6sx-gpmi-nand", .compatible = "fsl,imx6sx-gpmi-nand",
.data = &gpmi_devdata_imx6sx, .data = &gpmi_devdata_imx6sx,
}, {
.compatible = "fsl,imx7d-gpmi-nand",
.data = &gpmi_devdata_imx7d,
}, {} }, {}
}; };
MODULE_DEVICE_TABLE(of, gpmi_nand_id_table); MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
...@@ -2129,7 +2135,8 @@ static int gpmi_nand_remove(struct platform_device *pdev) ...@@ -2129,7 +2135,8 @@ static int gpmi_nand_remove(struct platform_device *pdev)
{ {
struct gpmi_nand_data *this = platform_get_drvdata(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); release_resources(this);
return 0; return 0;
} }
......
...@@ -123,13 +123,16 @@ enum gpmi_type { ...@@ -123,13 +123,16 @@ enum gpmi_type {
IS_MX23, IS_MX23,
IS_MX28, IS_MX28,
IS_MX6Q, IS_MX6Q,
IS_MX6SX IS_MX6SX,
IS_MX7D,
}; };
struct gpmi_devdata { struct gpmi_devdata {
enum gpmi_type type; enum gpmi_type type;
int bch_max_ecc_strength; int bch_max_ecc_strength;
int max_chain_delay; /* See the async EDO mode */ int max_chain_delay; /* See the async EDO mode */
const char * const *clks;
const int clks_count;
}; };
struct gpmi_nand_data { struct gpmi_nand_data {
...@@ -231,7 +234,7 @@ struct gpmi_nfc_hardware_timing { ...@@ -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 * @max_data_setup_cycles: The maximum number of data setup cycles that
* can be expressed in the hardware. * can be expressed in the hardware.
* @internal_data_setup_in_ns: The time, in ns, that the NFC hardware requires * @internal_data_setup_in_ns: The time, in ns, that the NFC hardware requires
...@@ -253,7 +256,7 @@ struct gpmi_nfc_hardware_timing { ...@@ -253,7 +256,7 @@ struct gpmi_nfc_hardware_timing {
* progress, this is the clock frequency during * progress, this is the clock frequency during
* the most recent I/O transaction. * the most recent I/O transaction.
*/ */
struct timing_threshod { struct timing_threshold {
const unsigned int max_chip_count; const unsigned int max_chip_count;
const unsigned int max_data_setup_cycles; const unsigned int max_data_setup_cycles;
const unsigned int internal_data_setup_in_ns; const unsigned int internal_data_setup_in_ns;
...@@ -305,6 +308,8 @@ void gpmi_copy_bits(u8 *dst, size_t dst_bit_off, ...@@ -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_MX28(x) ((x)->devdata->type == IS_MX28)
#define GPMI_IS_MX6Q(x) ((x)->devdata->type == IS_MX6Q) #define GPMI_IS_MX6Q(x) ((x)->devdata->type == IS_MX6Q)
#define GPMI_IS_MX6SX(x) ((x)->devdata->type == IS_MX6SX) #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 #endif
...@@ -764,6 +764,8 @@ static int hisi_nfc_probe(struct platform_device *pdev) ...@@ -764,6 +764,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
chip->write_buf = hisi_nfc_write_buf; chip->write_buf = hisi_nfc_write_buf;
chip->read_buf = hisi_nfc_read_buf; chip->read_buf = hisi_nfc_read_buf;
chip->chip_delay = HINFC504_CHIP_DELAY; 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); hisi_nfc_host_init(host);
......
...@@ -205,7 +205,7 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de ...@@ -205,7 +205,7 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
return -EINVAL; return -EINVAL;
} }
mtd->ooblayout = &nand_ooblayout_lp_ops; mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
return 0; return 0;
} }
......
...@@ -708,6 +708,8 @@ static int mpc5121_nfc_probe(struct platform_device *op) ...@@ -708,6 +708,8 @@ static int mpc5121_nfc_probe(struct platform_device *op)
chip->read_buf = mpc5121_nfc_read_buf; chip->read_buf = mpc5121_nfc_read_buf;
chip->write_buf = mpc5121_nfc_write_buf; chip->write_buf = mpc5121_nfc_write_buf;
chip->select_chip = mpc5121_nfc_select_chip; 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->bbt_options = NAND_BBT_USE_FLASH;
chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING; chip->ecc.algo = NAND_ECC_HAMMING;
......
...@@ -28,36 +28,16 @@ ...@@ -28,36 +28,16 @@
#define ECC_IDLE_MASK BIT(0) #define ECC_IDLE_MASK BIT(0)
#define ECC_IRQ_EN BIT(0) #define ECC_IRQ_EN BIT(0)
#define ECC_PG_IRQ_SEL BIT(1)
#define ECC_OP_ENABLE (1) #define ECC_OP_ENABLE (1)
#define ECC_OP_DISABLE (0) #define ECC_OP_DISABLE (0)
#define ECC_ENCCON (0x00) #define ECC_ENCCON (0x00)
#define ECC_ENCCNFG (0x04) #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_MODE_SHIFT (5)
#define ECC_MS_SHIFT (16) #define ECC_MS_SHIFT (16)
#define ECC_ENCDIADDR (0x08) #define ECC_ENCDIADDR (0x08)
#define ECC_ENCIDLE (0x0C) #define ECC_ENCIDLE (0x0C)
#define ECC_ENCPAR(x) (0x10 + (x) * sizeof(u32))
#define ECC_ENCIRQ_EN (0x80) #define ECC_ENCIRQ_EN (0x80)
#define ECC_ENCIRQ_STA (0x84) #define ECC_ENCIRQ_STA (0x84)
#define ECC_DECCON (0x100) #define ECC_DECCON (0x100)
...@@ -66,7 +46,6 @@ ...@@ -66,7 +46,6 @@
#define DEC_CNFG_CORRECT (0x3 << 12) #define DEC_CNFG_CORRECT (0x3 << 12)
#define ECC_DECIDLE (0x10C) #define ECC_DECIDLE (0x10C)
#define ECC_DECENUM0 (0x114) #define ECC_DECENUM0 (0x114)
#define ERR_MASK (0x3f)
#define ECC_DECDONE (0x124) #define ECC_DECDONE (0x124)
#define ECC_DECIRQ_EN (0x200) #define ECC_DECIRQ_EN (0x200)
#define ECC_DECIRQ_STA (0x204) #define ECC_DECIRQ_STA (0x204)
...@@ -78,8 +57,17 @@ ...@@ -78,8 +57,17 @@
#define ECC_IRQ_REG(op) ((op) == ECC_ENCODE ? \ #define ECC_IRQ_REG(op) ((op) == ECC_ENCODE ? \
ECC_ENCIRQ_EN : ECC_DECIRQ_EN) 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 mtk_ecc {
struct device *dev; struct device *dev;
const struct mtk_ecc_caps *caps;
void __iomem *regs; void __iomem *regs;
struct clk *clk; struct clk *clk;
...@@ -87,7 +75,18 @@ struct mtk_ecc { ...@@ -87,7 +75,18 @@ struct mtk_ecc {
struct mutex lock; struct mutex lock;
u32 sectors; 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, 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) ...@@ -136,77 +135,24 @@ static irqreturn_t mtk_ecc_irq(int irq, void *id)
return IRQ_HANDLED; 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 ecc_bit, dec_sz, enc_sz;
u32 reg; u32 reg, i;
switch (config->strength) { for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
case 4: if (ecc->caps->ecc_strength[i] == config->strength)
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; break;
case 24: }
ecc_bit = ECC_CNFG_24BIT;
break; if (i == ecc->caps->num_ecc_strength) {
case 28: dev_err(ecc->dev, "invalid ecc strength %d\n",
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); config->strength);
return -EINVAL;
} }
ecc_bit = i;
if (config->op == ECC_ENCODE) { if (config->op == ECC_ENCODE) {
/* configure ECC encoder (in bits) */ /* configure ECC encoder (in bits) */
enc_sz = config->len << 3; enc_sz = config->len << 3;
...@@ -232,6 +178,8 @@ static void mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config) ...@@ -232,6 +178,8 @@ static void mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
if (config->sectors) if (config->sectors)
ecc->sectors = 1 << (config->sectors - 1); ecc->sectors = 1 << (config->sectors - 1);
} }
return 0;
} }
void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats, 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, ...@@ -247,8 +195,8 @@ void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
offset = (i >> 2) << 2; offset = (i >> 2) << 2;
err = readl(ecc->regs + ECC_DECENUM0 + offset); err = readl(ecc->regs + ECC_DECENUM0 + offset);
err = err >> ((i % 4) * 8); err = err >> ((i % 4) * 8);
err &= ERR_MASK; err &= ecc->caps->err_mask;
if (err == ERR_MASK) { if (err == ecc->caps->err_mask) {
/* uncorrectable errors */ /* uncorrectable errors */
stats->failed++; stats->failed++;
continue; continue;
...@@ -313,6 +261,7 @@ EXPORT_SYMBOL(of_mtk_ecc_get); ...@@ -313,6 +261,7 @@ EXPORT_SYMBOL(of_mtk_ecc_get);
int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config) int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
{ {
enum mtk_ecc_operation op = config->op; enum mtk_ecc_operation op = config->op;
u16 reg_val;
int ret; int ret;
ret = mutex_lock_interruptible(&ecc->lock); ret = mutex_lock_interruptible(&ecc->lock);
...@@ -322,11 +271,27 @@ int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config) ...@@ -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_wait_idle(ecc, op);
mtk_ecc_config(ecc, config);
writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_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); init_completion(&ecc->done);
writew(ECC_IRQ_EN, ecc->regs + ECC_IRQ_REG(op)); 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; return 0;
} }
...@@ -396,7 +361,9 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config, ...@@ -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; len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
/* write the parity bytes generated by the ECC back to temp buffer */ /* 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 */ /* copy into possibly unaligned OOB region with actual length */
memcpy(data + bytes, ecc->eccdata, len); memcpy(data + bytes, ecc->eccdata, len);
...@@ -409,37 +376,79 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config, ...@@ -409,37 +376,79 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
} }
EXPORT_SYMBOL(mtk_ecc_encode); 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, const u8 *ecc_strength = ecc->caps->ecc_strength;
40, 44, 48, 52, 56, 60};
int i; int i;
for (i = 0; i < ARRAY_SIZE(ecc); i++) { for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
if (*p <= ecc[i]) { if (*p <= ecc_strength[i]) {
if (!i) if (!i)
*p = ecc[i]; *p = ecc_strength[i];
else if (*p != ecc[i]) else if (*p != ecc_strength[i])
*p = ecc[i - 1]; *p = ecc_strength[i - 1];
return; return;
} }
} }
*p = ecc[ARRAY_SIZE(ecc) - 1]; *p = ecc_strength[ecc->caps->num_ecc_strength - 1];
} }
EXPORT_SYMBOL(mtk_ecc_adjust_strength); 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) static int mtk_ecc_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct mtk_ecc *ecc; struct mtk_ecc *ecc;
struct resource *res; struct resource *res;
const struct of_device_id *of_ecc_id = NULL;
u32 max_eccdata_size;
int irq, ret; int irq, ret;
ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL); ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
if (!ecc) if (!ecc)
return -ENOMEM; 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); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ecc->regs = devm_ioremap_resource(dev, res); ecc->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(ecc->regs)) { if (IS_ERR(ecc->regs)) {
...@@ -500,19 +509,12 @@ static int mtk_ecc_resume(struct device *dev) ...@@ -500,19 +509,12 @@ static int mtk_ecc_resume(struct device *dev)
return ret; return ret;
} }
mtk_ecc_hw_init(ecc);
return 0; return 0;
} }
static SIMPLE_DEV_PM_OPS(mtk_ecc_pm_ops, mtk_ecc_suspend, mtk_ecc_resume); static SIMPLE_DEV_PM_OPS(mtk_ecc_pm_ops, mtk_ecc_suspend, mtk_ecc_resume);
#endif #endif
static const struct of_device_id mtk_ecc_dt_match[] = {
{ .compatible = "mediatek,mt2701-ecc" },
{},
};
MODULE_DEVICE_TABLE(of, mtk_ecc_dt_match); MODULE_DEVICE_TABLE(of, mtk_ecc_dt_match);
static struct platform_driver mtk_ecc_driver = { static struct platform_driver mtk_ecc_driver = {
......
...@@ -42,7 +42,7 @@ void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int); ...@@ -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_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *); int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
void mtk_ecc_disable(struct mtk_ecc *); 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 *); struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
void mtk_ecc_release(struct mtk_ecc *); void mtk_ecc_release(struct mtk_ecc *);
......
This diff is collapsed.
...@@ -152,9 +152,8 @@ struct mxc_nand_devtype_data { ...@@ -152,9 +152,8 @@ struct mxc_nand_devtype_data {
void (*select_chip)(struct mtd_info *mtd, int chip); void (*select_chip)(struct mtd_info *mtd, int chip);
int (*correct_data)(struct mtd_info *mtd, u_char *dat, int (*correct_data)(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc); u_char *read_ecc, u_char *calc_ecc);
int (*setup_data_interface)(struct mtd_info *mtd, int (*setup_data_interface)(struct mtd_info *mtd, int csline,
const struct nand_data_interface *conf, const struct nand_data_interface *conf);
bool check_only);
/* /*
* On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked * 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) ...@@ -1015,9 +1014,8 @@ static void preset_v1(struct mtd_info *mtd)
writew(0x4, NFC_V1_V2_WRPROT); writew(0x4, NFC_V1_V2_WRPROT);
} }
static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, int csline,
const struct nand_data_interface *conf, const struct nand_data_interface *conf)
bool check_only)
{ {
struct nand_chip *nand_chip = mtd_to_nand(mtd); struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 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, ...@@ -1075,7 +1073,7 @@ static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd,
return -EINVAL; return -EINVAL;
} }
if (check_only) if (csline == NAND_DATA_IFACE_CHECK_ONLY)
return 0; return 0;
ret = clk_set_rate(host->clk, rate); ret = clk_set_rate(host->clk, rate);
......
This diff is collapsed.
This diff is collapsed.
...@@ -166,7 +166,11 @@ static int __init orion_nand_probe(struct platform_device *pdev) ...@@ -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); ret = nand_scan(mtd, 1);
if (ret) if (ret)
......
...@@ -1812,6 +1812,8 @@ static int alloc_nand_resource(struct platform_device *pdev) ...@@ -1812,6 +1812,8 @@ static int alloc_nand_resource(struct platform_device *pdev)
chip->write_buf = pxa3xx_nand_write_buf; chip->write_buf = pxa3xx_nand_write_buf;
chip->options |= NAND_NO_SUBPAGE_WRITE; chip->options |= NAND_NO_SUBPAGE_WRITE;
chip->cmdfunc = nand_cmdfunc; 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); nand_hw_control_init(chip->controller);
......
...@@ -2008,6 +2008,8 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc, ...@@ -2008,6 +2008,8 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
chip->read_byte = qcom_nandc_read_byte; chip->read_byte = qcom_nandc_read_byte;
chip->read_buf = qcom_nandc_read_buf; chip->read_buf = qcom_nandc_read_buf;
chip->write_buf = qcom_nandc_write_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 * the bad block marker is readable only when we read the last codeword
......
...@@ -812,9 +812,8 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, ...@@ -812,9 +812,8 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
return -ENODEV; return -ENODEV;
} }
static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, int csline,
const struct nand_data_interface *conf, const struct nand_data_interface *conf)
bool check_only)
{ {
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
struct s3c2410_platform_nand *pdata = info->platform; struct s3c2410_platform_nand *pdata = info->platform;
......
...@@ -1183,6 +1183,8 @@ static int flctl_probe(struct platform_device *pdev) ...@@ -1183,6 +1183,8 @@ static int flctl_probe(struct platform_device *pdev)
nand->read_buf = flctl_read_buf; nand->read_buf = flctl_read_buf;
nand->select_chip = flctl_select_chip; nand->select_chip = flctl_select_chip;
nand->cmdfunc = flctl_cmdfunc; 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) if (pdata->flcmncr_val & SEL_16BIT)
nand->options |= NAND_BUSWIDTH_16; nand->options |= NAND_BUSWIDTH_16;
......
...@@ -1301,7 +1301,6 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd, ...@@ -1301,7 +1301,6 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
sunxi_nfc_hw_ecc_enable(mtd); sunxi_nfc_hw_ecc_enable(mtd);
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
for (i = data_offs / ecc->size; for (i = data_offs / ecc->size;
i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) { i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) {
int data_off = i * ecc->size; int data_off = i * ecc->size;
...@@ -1592,9 +1591,8 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration, ...@@ -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) \ #define sunxi_nand_lookup_timing(l, p, c) \
_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c) _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
const struct nand_data_interface *conf, const struct nand_data_interface *conf)
bool check_only)
{ {
struct nand_chip *nand = mtd_to_nand(mtd); struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *chip = to_sunxi_nand(nand); struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
...@@ -1707,7 +1705,7 @@ static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, ...@@ -1707,7 +1705,7 @@ static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd,
return tRHW; return tRHW;
} }
if (check_only) if (csline == NAND_DATA_IFACE_CHECK_ONLY)
return 0; return 0;
/* /*
...@@ -1922,7 +1920,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, ...@@ -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->write_subpage = sunxi_nfc_hw_ecc_write_subpage;
ecc->read_oob_raw = nand_read_oob_std; ecc->read_oob_raw = nand_read_oob_std;
ecc->write_oob_raw = nand_write_oob_std; ecc->write_oob_raw = nand_write_oob_std;
ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -703,6 +703,8 @@ static int vf610_nfc_probe(struct platform_device *pdev) ...@@ -703,6 +703,8 @@ static int vf610_nfc_probe(struct platform_device *pdev)
chip->read_buf = vf610_nfc_read_buf; chip->read_buf = vf610_nfc_read_buf;
chip->write_buf = vf610_nfc_write_buf; chip->write_buf = vf610_nfc_write_buf;
chip->select_chip = vf610_nfc_select_chip; 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; chip->options |= NAND_NO_SUBPAGE_WRITE;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment