提交 ef32476f 编写于 作者: B 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.
"""
...@@ -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.
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/atmel-matrix.h> #include <linux/mfd/syscon/atmel-matrix.h>
#include <linux/mfd/syscon/atmel-smc.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mtd/nand.h> #include <linux/mtd/nand.h>
#include <linux/of_address.h> #include <linux/of_address.h>
...@@ -64,7 +65,6 @@ ...@@ -64,7 +65,6 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/platform_data/atmel.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include "pmecc.h" #include "pmecc.h"
...@@ -151,6 +151,8 @@ struct atmel_nand_cs { ...@@ -151,6 +151,8 @@ struct atmel_nand_cs {
void __iomem *virt; void __iomem *virt;
dma_addr_t dma; dma_addr_t dma;
} io; } io;
struct atmel_smc_cs_conf smcconf;
}; };
struct atmel_nand { struct atmel_nand {
...@@ -196,6 +198,8 @@ struct atmel_nand_controller_ops { ...@@ -196,6 +198,8 @@ struct atmel_nand_controller_ops {
void (*nand_init)(struct atmel_nand_controller *nc, void (*nand_init)(struct atmel_nand_controller *nc,
struct atmel_nand *nand); struct atmel_nand *nand);
int (*ecc_init)(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 { struct atmel_nand_controller_caps {
...@@ -912,7 +916,7 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip, ...@@ -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 mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_hsmc_nand_controller *nc; struct atmel_hsmc_nand_controller *nc;
int ret; int ret, status;
nc = to_hsmc_nand_controller(chip->controller); nc = to_hsmc_nand_controller(chip->controller);
...@@ -954,6 +958,10 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip, ...@@ -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", dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n",
ret); ret);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return ret; return ret;
} }
...@@ -1175,6 +1183,295 @@ static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand) ...@@ -1175,6 +1183,295 @@ static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
return 0; 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, static void atmel_nand_init(struct atmel_nand_controller *nc,
struct atmel_nand *nand) struct atmel_nand *nand)
{ {
...@@ -1192,6 +1489,9 @@ static void atmel_nand_init(struct atmel_nand_controller *nc, ...@@ -1192,6 +1489,9 @@ static void atmel_nand_init(struct atmel_nand_controller *nc,
chip->write_buf = atmel_nand_write_buf; chip->write_buf = atmel_nand_write_buf;
chip->select_chip = atmel_nand_select_chip; 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). */ /* Some NANDs require a longer delay than the default one (20us). */
chip->chip_delay = 40; chip->chip_delay = 40;
...@@ -1677,6 +1977,12 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc, ...@@ -1677,6 +1977,12 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
if (nc->caps->legacy_of_bindings) if (nc->caps->legacy_of_bindings)
return 0; 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); np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
if (!np) { if (!np) {
dev_err(dev, "Missing or invalid atmel,smc property\n"); 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 = { ...@@ -1983,6 +2289,7 @@ static const struct atmel_nand_controller_ops atmel_hsmc_nc_ops = {
.remove = atmel_hsmc_nand_controller_remove, .remove = atmel_hsmc_nand_controller_remove,
.ecc_init = atmel_hsmc_nand_ecc_init, .ecc_init = atmel_hsmc_nand_ecc_init,
.nand_init = atmel_hsmc_nand_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 = { 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) ...@@ -2037,7 +2344,14 @@ atmel_smc_nand_controller_remove(struct atmel_nand_controller *nc)
return 0; 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, .probe = atmel_smc_nand_controller_probe,
.remove = atmel_smc_nand_controller_remove, .remove = atmel_smc_nand_controller_remove,
.ecc_init = atmel_nand_ecc_init, .ecc_init = atmel_nand_ecc_init,
...@@ -2045,6 +2359,20 @@ static const struct atmel_nand_controller_ops atmel_smc_nc_ops = { ...@@ -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 = { 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), .ale_offs = BIT(21),
.cle_offs = BIT(22), .cle_offs = BIT(22),
.ops = &atmel_smc_nc_ops, .ops = &atmel_smc_nc_ops,
...@@ -2093,7 +2421,7 @@ static const struct of_device_id atmel_nand_controller_of_ids[] = { ...@@ -2093,7 +2421,7 @@ static const struct of_device_id atmel_nand_controller_of_ids[] = {
}, },
{ {
.compatible = "atmel,at91sam9260-nand-controller", .compatible = "atmel,at91sam9260-nand-controller",
.data = &atmel_rm9200_nc_caps, .data = &atmel_sam9260_nc_caps,
}, },
{ {
.compatible = "atmel,at91sam9261-nand-controller", .compatible = "atmel,at91sam9261-nand-controller",
...@@ -2181,6 +2509,24 @@ static int atmel_nand_controller_remove(struct platform_device *pdev) ...@@ -2181,6 +2509,24 @@ static int atmel_nand_controller_remove(struct platform_device *pdev)
return nc->caps->ops->remove(nc); 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 = { static struct platform_driver atmel_nand_controller_driver = {
.driver = { .driver = {
.name = "atmel-nand-controller", .name = "atmel-nand-controller",
......
...@@ -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;
......
此差异已折叠。
...@@ -24,330 +24,315 @@ ...@@ -24,330 +24,315 @@
#include <linux/mtd/nand.h> #include <linux/mtd/nand.h>
#define DEVICE_RESET 0x0 #define DEVICE_RESET 0x0
#define DEVICE_RESET__BANK0 0x0001 #define DEVICE_RESET__BANK(bank) BIT(bank)
#define DEVICE_RESET__BANK1 0x0002
#define DEVICE_RESET__BANK2 0x0004
#define DEVICE_RESET__BANK3 0x0008
#define TRANSFER_SPARE_REG 0x10 #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 0x20
#define LOAD_WAIT_CNT__VALUE 0xffff #define LOAD_WAIT_CNT__VALUE GENMASK(15, 0)
#define PROGRAM_WAIT_CNT 0x30 #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 0x40
#define ERASE_WAIT_CNT__VALUE 0xffff #define ERASE_WAIT_CNT__VALUE GENMASK(15, 0)
#define INT_MON_CYCCNT 0x50 #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 0x60
#define RB_PIN_ENABLED__BANK0 0x0001 #define RB_PIN_ENABLED__BANK(bank) BIT(bank)
#define RB_PIN_ENABLED__BANK1 0x0002
#define RB_PIN_ENABLED__BANK2 0x0004
#define RB_PIN_ENABLED__BANK3 0x0008
#define MULTIPLANE_OPERATION 0x70 #define MULTIPLANE_OPERATION 0x70
#define MULTIPLANE_OPERATION__FLAG 0x0001 #define MULTIPLANE_OPERATION__FLAG BIT(0)
#define MULTIPLANE_READ_ENABLE 0x80 #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 0x90
#define COPYBACK_DISABLE__FLAG 0x0001 #define COPYBACK_DISABLE__FLAG BIT(0)
#define CACHE_WRITE_ENABLE 0xa0 #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 0xb0
#define CACHE_READ_ENABLE__FLAG 0x0001 #define CACHE_READ_ENABLE__FLAG BIT(0)
#define PREFETCH_MODE 0xc0 #define PREFETCH_MODE 0xc0
#define PREFETCH_MODE__PREFETCH_EN 0x0001 #define PREFETCH_MODE__PREFETCH_EN BIT(0)
#define PREFETCH_MODE__PREFETCH_BURST_LENGTH 0xfff0 #define PREFETCH_MODE__PREFETCH_BURST_LENGTH GENMASK(15, 4)
#define CHIP_ENABLE_DONT_CARE 0xd0 #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 0xe0
#define ECC_ENABLE__FLAG 0x0001 #define ECC_ENABLE__FLAG BIT(0)
#define GLOBAL_INT_ENABLE 0xf0 #define GLOBAL_INT_ENABLE 0xf0
#define GLOBAL_INT_EN_FLAG 0x01 #define GLOBAL_INT_EN_FLAG BIT(0)
#define WE_2_RE 0x100 #define TWHR2_AND_WE_2_RE 0x100
#define WE_2_RE__VALUE 0x003f #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 TCWAW_AND_ADDR_2_DATA 0x110
#define ADDR_2_DATA__VALUE 0x003f /* 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 0x120
#define RE_2_WE__VALUE 0x003f #define RE_2_WE__VALUE GENMASK(5, 0)
#define ACC_CLKS 0x130 #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 0x140
#define NUMBER_OF_PLANES__VALUE 0x0007 #define NUMBER_OF_PLANES__VALUE GENMASK(2, 0)
#define PAGES_PER_BLOCK 0x150 #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 0x160
#define DEVICE_WIDTH__VALUE 0x0003 #define DEVICE_WIDTH__VALUE GENMASK(1, 0)
#define DEVICE_MAIN_AREA_SIZE 0x170 #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 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 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 0x1a0
#define MULTIPLANE_ADDR_RESTRICT__FLAG 0x0001 #define MULTIPLANE_ADDR_RESTRICT__FLAG BIT(0)
#define ECC_CORRECTION 0x1b0 #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 0x1c0
#define READ_MODE__VALUE 0x000f #define READ_MODE__VALUE GENMASK(3, 0)
#define WRITE_MODE 0x1d0 #define WRITE_MODE 0x1d0
#define WRITE_MODE__VALUE 0x000f #define WRITE_MODE__VALUE GENMASK(3, 0)
#define COPYBACK_MODE 0x1e0 #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 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 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 0x210
#define MAX_RD_DELAY__VALUE 0x000f #define MAX_RD_DELAY__VALUE GENMASK(3, 0)
#define CS_SETUP_CNT 0x220 #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 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 0x240
#define SPARE_AREA_MARKER__VALUE 0xffff #define SPARE_AREA_MARKER__VALUE GENMASK(15, 0)
#define DEVICES_CONNECTED 0x250 #define DEVICES_CONNECTED 0x250
#define DEVICES_CONNECTED__VALUE 0x0007 #define DEVICES_CONNECTED__VALUE GENMASK(2, 0)
#define DIE_MASK 0x260 #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 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 0x280
#define WRITE_PROTECT__FLAG 0x0001 #define WRITE_PROTECT__FLAG BIT(0)
#define RE_2_RE 0x290 #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 0x300
#define MANUFACTURER_ID__VALUE 0x00ff #define MANUFACTURER_ID__VALUE GENMASK(7, 0)
#define DEVICE_ID 0x310 #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 0x320
#define DEVICE_PARAM_0__VALUE 0x00ff #define DEVICE_PARAM_0__VALUE GENMASK(7, 0)
#define DEVICE_PARAM_1 0x330 #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 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 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 0x360
#define LOGICAL_PAGE_SPARE_SIZE__VALUE 0xffff #define LOGICAL_PAGE_SPARE_SIZE__VALUE GENMASK(15, 0)
#define REVISION 0x370 #define REVISION 0x370
#define REVISION__VALUE 0xffff #define REVISION__VALUE GENMASK(15, 0)
#define ONFI_DEVICE_FEATURES 0x380 #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 0x390
#define ONFI_OPTIONAL_COMMANDS__VALUE 0x003f #define ONFI_OPTIONAL_COMMANDS__VALUE GENMASK(5, 0)
#define ONFI_TIMING_MODE 0x3a0 #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 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 0x3c0
#define ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS 0x00ff #define ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS GENMASK(7, 0)
#define ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE 0x0100 #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 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 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 0x3f0
#define FEATURES__N_BANKS 0x0003 #define FEATURES__N_BANKS GENMASK(1, 0)
#define FEATURES__ECC_MAX_ERR 0x003c #define FEATURES__ECC_MAX_ERR GENMASK(5, 2)
#define FEATURES__DMA 0x0040 #define FEATURES__DMA BIT(6)
#define FEATURES__CMD_DMA 0x0080 #define FEATURES__CMD_DMA BIT(7)
#define FEATURES__PARTITION 0x0100 #define FEATURES__PARTITION BIT(8)
#define FEATURES__XDMA_SIDEBAND 0x0200 #define FEATURES__XDMA_SIDEBAND BIT(9)
#define FEATURES__GPREG 0x0400 #define FEATURES__GPREG BIT(10)
#define FEATURES__INDEX_ADDR 0x0800 #define FEATURES__INDEX_ADDR BIT(11)
#define TRANSFER_MODE 0x400 #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_STATUS(bank) (0x410 + (bank) * 0x50)
#define INTR_EN(__bank) (0x420 + ((__bank) * 0x50)) #define INTR_EN(bank) (0x420 + (bank) * 0x50)
/* bit[1:0] is used differently depending on IP version */ /* bit[1:0] is used differently depending on IP version */
#define INTR__ECC_UNCOR_ERR 0x0001 /* new IP */ #define INTR__ECC_UNCOR_ERR BIT(0) /* new IP */
#define INTR__ECC_TRANSACTION_DONE 0x0001 /* old IP */ #define INTR__ECC_TRANSACTION_DONE BIT(0) /* old IP */
#define INTR__ECC_ERR 0x0002 /* old IP */ #define INTR__ECC_ERR BIT(1) /* old IP */
#define INTR__DMA_CMD_COMP 0x0004 #define INTR__DMA_CMD_COMP BIT(2)
#define INTR__TIME_OUT 0x0008 #define INTR__TIME_OUT BIT(3)
#define INTR__PROGRAM_FAIL 0x0010 #define INTR__PROGRAM_FAIL BIT(4)
#define INTR__ERASE_FAIL 0x0020 #define INTR__ERASE_FAIL BIT(5)
#define INTR__LOAD_COMP 0x0040 #define INTR__LOAD_COMP BIT(6)
#define INTR__PROGRAM_COMP 0x0080 #define INTR__PROGRAM_COMP BIT(7)
#define INTR__ERASE_COMP 0x0100 #define INTR__ERASE_COMP BIT(8)
#define INTR__PIPE_CPYBCK_CMD_COMP 0x0200 #define INTR__PIPE_CPYBCK_CMD_COMP BIT(9)
#define INTR__LOCKED_BLK 0x0400 #define INTR__LOCKED_BLK BIT(10)
#define INTR__UNSUP_CMD 0x0800 #define INTR__UNSUP_CMD BIT(11)
#define INTR__INT_ACT 0x1000 #define INTR__INT_ACT BIT(12)
#define INTR__RST_COMP 0x2000 #define INTR__RST_COMP BIT(13)
#define INTR__PIPE_CMD_ERR 0x4000 #define INTR__PIPE_CMD_ERR BIT(14)
#define INTR__PAGE_XFER_INC 0x8000 #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 PAGE_CNT(bank) (0x430 + (bank) * 0x50)
#define ERR_BLOCK_ADDR(__bank) (0x450 + ((__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 0x600
#define ECC_THRESHOLD__VALUE 0x03ff #define ECC_THRESHOLD__VALUE GENMASK(9, 0)
#define ECC_ERROR_BLOCK_ADDRESS 0x610 #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 0x620
#define ECC_ERROR_PAGE_ADDRESS__VALUE 0x0fff #define ECC_ERROR_PAGE_ADDRESS__VALUE GENMASK(11, 0)
#define ECC_ERROR_PAGE_ADDRESS__BANK 0xf000 #define ECC_ERROR_PAGE_ADDRESS__BANK GENMASK(15, 12)
#define ECC_ERROR_ADDRESS 0x630 #define ECC_ERROR_ADDRESS 0x630
#define ECC_ERROR_ADDRESS__OFFSET 0x0fff #define ECC_ERROR_ADDRESS__OFFSET GENMASK(11, 0)
#define ECC_ERROR_ADDRESS__SECTOR_NR 0xf000 #define ECC_ERROR_ADDRESS__SECTOR_NR GENMASK(15, 12)
#define ERR_CORRECTION_INFO 0x640 #define ERR_CORRECTION_INFO 0x640
#define ERR_CORRECTION_INFO__BYTEMASK 0x00ff #define ERR_CORRECTION_INFO__BYTEMASK GENMASK(7, 0)
#define ERR_CORRECTION_INFO__DEVICE_NR 0x0f00 #define ERR_CORRECTION_INFO__DEVICE_NR GENMASK(11, 8)
#define ERR_CORRECTION_INFO__ERROR_TYPE 0x4000 #define ERR_CORRECTION_INFO__ERROR_TYPE BIT(14)
#define ERR_CORRECTION_INFO__LAST_ERR_INFO 0x8000 #define ERR_CORRECTION_INFO__LAST_ERR_INFO BIT(15)
#define ECC_COR_INFO(bank) (0x650 + (bank) / 2 * 0x10) #define ECC_COR_INFO(bank) (0x650 + (bank) / 2 * 0x10)
#define ECC_COR_INFO__SHIFT(bank) ((bank) % 2 * 8) #define ECC_COR_INFO__SHIFT(bank) ((bank) % 2 * 8)
#define ECC_COR_INFO__MAX_ERRORS 0x007f #define ECC_COR_INFO__MAX_ERRORS GENMASK(6, 0)
#define ECC_COR_INFO__UNCOR_ERR 0x0080 #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 0x700
#define DMA_ENABLE__FLAG 0x0001 #define DMA_ENABLE__FLAG BIT(0)
#define IGNORE_ECC_DONE 0x710 #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 0x720
#define DMA_INTR_EN 0x730 #define DMA_INTR_EN 0x730
#define DMA_INTR__TARGET_ERROR 0x0001 #define DMA_INTR__TARGET_ERROR BIT(0)
#define DMA_INTR__DESC_COMP_CHANNEL0 0x0002 #define DMA_INTR__DESC_COMP_CHANNEL0 BIT(1)
#define DMA_INTR__DESC_COMP_CHANNEL1 0x0004 #define DMA_INTR__DESC_COMP_CHANNEL1 BIT(2)
#define DMA_INTR__DESC_COMP_CHANNEL2 0x0008 #define DMA_INTR__DESC_COMP_CHANNEL2 BIT(3)
#define DMA_INTR__DESC_COMP_CHANNEL3 0x0010 #define DMA_INTR__DESC_COMP_CHANNEL3 BIT(4)
#define DMA_INTR__MEMCOPY_DESC_COMP 0x0020 #define DMA_INTR__MEMCOPY_DESC_COMP BIT(5)
#define TARGET_ERR_ADDR_LO 0x740 #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 0x750
#define TARGET_ERR_ADDR_HI__VALUE 0xffff #define TARGET_ERR_ADDR_HI__VALUE GENMASK(15, 0)
#define CHNL_ACTIVE 0x760 #define CHNL_ACTIVE 0x760
#define CHNL_ACTIVE__CHANNEL0 0x0001 #define CHNL_ACTIVE__CHANNEL0 BIT(0)
#define CHNL_ACTIVE__CHANNEL1 0x0002 #define CHNL_ACTIVE__CHANNEL1 BIT(1)
#define CHNL_ACTIVE__CHANNEL2 0x0004 #define CHNL_ACTIVE__CHANNEL2 BIT(2)
#define CHNL_ACTIVE__CHANNEL3 0x0008 #define CHNL_ACTIVE__CHANNEL3 BIT(3)
#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
struct denali_nand_info { struct denali_nand_info {
struct nand_chip nand; struct nand_chip nand;
int flash_bank; /* currently selected chip */ unsigned long clk_x_rate; /* bus interface clock rate */
int status; int active_bank; /* currently selected bank */
int platform;
struct nand_buf buf;
struct device *dev; struct device *dev;
int total_used_banks; void __iomem *reg; /* Register Interface */
int page; void __iomem *host; /* Host Data/Command Interface */
void __iomem *flash_reg; /* Register Interface */
void __iomem *flash_mem; /* Host Data/Command Interface */
/* elements used by ISR */ /* elements used by ISR */
struct completion complete; struct completion complete;
spinlock_t irq_lock; spinlock_t irq_lock;
uint32_t irq_mask;
uint32_t irq_status; uint32_t irq_status;
int irq; int irq;
int devnum; /* represent how many nands connected */ void *buf;
int bbtskipbytes; dma_addr_t dma_addr;
int dma_avail;
int devs_per_cs; /* devices connected in parallel */
int oob_skip_bytes;
int max_banks; int max_banks;
unsigned int revision; unsigned int revision;
unsigned int caps; unsigned int caps;
const struct nand_ecc_caps *ecc_caps;
}; };
#define DENALI_CAP_HW_ECC_FIXUP BIT(0) #define DENALI_CAP_HW_ECC_FIXUP BIT(0)
#define DENALI_CAP_DMA_64BIT BIT(1) #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 int denali_init(struct denali_nand_info *denali);
extern void denali_remove(struct denali_nand_info *denali); extern void denali_remove(struct denali_nand_info *denali);
......
...@@ -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;
break; }
case 6:
ecc_bit = ECC_CNFG_6BIT; if (i == ecc->caps->num_ecc_strength) {
break; dev_err(ecc->dev, "invalid ecc strength %d\n",
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); 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));
init_completion(&ecc->done); ret = mtk_ecc_config(ecc, config);
writew(ECC_IRQ_EN, ecc->regs + ECC_IRQ_REG(op)); 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; 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 *);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include "mtk_ecc.h" #include "mtk_ecc.h"
/* NAND controller register definition */ /* NAND controller register definition */
...@@ -38,23 +39,6 @@ ...@@ -38,23 +39,6 @@
#define NFI_PAGEFMT (0x04) #define NFI_PAGEFMT (0x04)
#define PAGEFMT_FDM_ECC_SHIFT (12) #define PAGEFMT_FDM_ECC_SHIFT (12)
#define PAGEFMT_FDM_SHIFT (8) #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_SEC_SEL_512 BIT(2)
#define PAGEFMT_512_2K (0) #define PAGEFMT_512_2K (0)
#define PAGEFMT_2K_4K (1) #define PAGEFMT_2K_4K (1)
...@@ -115,6 +99,17 @@ ...@@ -115,6 +99,17 @@
#define MTK_RESET_TIMEOUT (1000000) #define MTK_RESET_TIMEOUT (1000000)
#define MTK_MAX_SECTOR (16) #define MTK_MAX_SECTOR (16)
#define MTK_NAND_MAX_NSELS (2) #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 { struct mtk_nfc_bad_mark_ctl {
void (*bm_swap)(struct mtd_info *, u8 *buf, int raw); void (*bm_swap)(struct mtd_info *, u8 *buf, int raw);
...@@ -155,6 +150,7 @@ struct mtk_nfc { ...@@ -155,6 +150,7 @@ struct mtk_nfc {
struct mtk_ecc *ecc; struct mtk_ecc *ecc;
struct device *dev; struct device *dev;
const struct mtk_nfc_caps *caps;
void __iomem *regs; void __iomem *regs;
struct completion done; struct completion done;
...@@ -163,6 +159,20 @@ struct mtk_nfc { ...@@ -163,6 +159,20 @@ struct mtk_nfc {
u8 *buffer; 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) static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct nand_chip *nand)
{ {
return container_of(nand, struct mtk_nfc_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) ...@@ -308,7 +318,7 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
struct nand_chip *chip = mtd_to_nand(mtd); struct nand_chip *chip = mtd_to_nand(mtd);
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip); struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
struct mtk_nfc *nfc = nand_get_controller_data(chip); struct mtk_nfc *nfc = nand_get_controller_data(chip);
u32 fmt, spare; u32 fmt, spare, i;
if (!mtd->writesize) if (!mtd->writesize)
return 0; return 0;
...@@ -352,63 +362,21 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd) ...@@ -352,63 +362,21 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
if (chip->ecc.size == 1024) if (chip->ecc.size == 1024)
spare >>= 1; spare >>= 1;
switch (spare) { for (i = 0; i < nfc->caps->num_spare_size; i++) {
case 16: if (nfc->caps->spare_size[i] == spare)
fmt |= (PAGEFMT_SPARE_16 << PAGEFMT_SPARE_SHIFT); break;
break; }
case 26:
fmt |= (PAGEFMT_SPARE_26 << PAGEFMT_SPARE_SHIFT); if (i == nfc->caps->num_spare_size) {
break; dev_err(nfc->dev, "invalid spare size %d\n", spare);
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);
return -EINVAL; return -EINVAL;
} }
fmt |= i << nfc->caps->pageformat_spare_shift;
fmt |= mtk_nand->fdm.reg_size << PAGEFMT_FDM_SHIFT; fmt |= mtk_nand->fdm.reg_size << PAGEFMT_FDM_SHIFT;
fmt |= mtk_nand->fdm.ecc_size << PAGEFMT_FDM_ECC_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.strength = chip->ecc.strength;
nfc->ecc_cfg.len = chip->ecc.size + mtk_nand->fdm.ecc_size; 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) ...@@ -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]); 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) static int mtk_nfc_sector_encode(struct nand_chip *chip, u8 *data)
{ {
struct mtk_nfc *nfc = nand_get_controller_data(chip); 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, ...@@ -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) 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 * CNRNB: nand ready/busy register
* ------------------------------- * -------------------------------
...@@ -1009,7 +1030,7 @@ static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc) ...@@ -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. * 0 : poll the status of the busy/ready signal after [7:4]*16 cycles.
*/ */
nfi_writew(nfc, 0xf1, NFI_CNRNB); 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); 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, ...@@ -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); struct nand_chip *nand = mtd_to_nand(mtd);
u32 spare[] = {16, 26, 27, 28, 32, 36, 40, 44, struct mtk_nfc *nfc = nand_get_controller_data(nand);
48, 49, 50, 51, 52, 62, 63, 64}; const u8 *spare = nfc->caps->spare_size;
u32 eccsteps, i; u32 eccsteps, i, closest_spare = 0;
eccsteps = mtd->writesize / nand->ecc.size; eccsteps = mtd->writesize / nand->ecc.size;
*sps = mtd->oobsize / eccsteps; *sps = mtd->oobsize / eccsteps;
...@@ -1144,28 +1165,31 @@ static void mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd) ...@@ -1144,28 +1165,31 @@ static void mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
if (nand->ecc.size == 1024) if (nand->ecc.size == 1024)
*sps >>= 1; *sps >>= 1;
for (i = 0; i < ARRAY_SIZE(spare); i++) { if (*sps < MTK_NFC_MIN_SPARE)
if (*sps <= spare[i]) { return -EINVAL;
if (!i)
*sps = spare[i]; for (i = 0; i < nfc->caps->num_spare_size; i++) {
else if (*sps != spare[i]) if (*sps >= spare[i] && spare[i] >= spare[closest_spare]) {
*sps = spare[i - 1]; closest_spare = i;
break; if (*sps == spare[i])
break;
} }
} }
if (i >= ARRAY_SIZE(spare)) *sps = spare[closest_spare];
*sps = spare[ARRAY_SIZE(spare) - 1];
if (nand->ecc.size == 1024) if (nand->ecc.size == 1024)
*sps <<= 1; *sps <<= 1;
return 0;
} }
static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd) static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
{ {
struct nand_chip *nand = mtd_to_nand(mtd); struct nand_chip *nand = mtd_to_nand(mtd);
struct mtk_nfc *nfc = nand_get_controller_data(nand);
u32 spare; u32 spare;
int free; int free, ret;
/* support only ecc hw mode */ /* support only ecc hw mode */
if (nand->ecc.mode != NAND_ECC_HW) { if (nand->ecc.mode != NAND_ECC_HW) {
...@@ -1194,7 +1218,9 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd) ...@@ -1194,7 +1218,9 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
nand->ecc.size = 1024; 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 */ /* calculate oob bytes except ecc parity data */
free = ((nand->ecc.strength * ECC_PARITY_BITS) + 7) >> 3; 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) ...@@ -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", dev_info(dev, "eccsize %d eccstrength %d\n",
nand->ecc.size, nand->ecc.strength); nand->ecc.size, nand->ecc.strength);
...@@ -1271,6 +1297,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, ...@@ -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_byte = mtk_nfc_read_byte;
nand->read_buf = mtk_nfc_read_buf; nand->read_buf = mtk_nfc_read_buf;
nand->cmd_ctrl = mtk_nfc_cmd_ctrl; 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 */ /* set default mode in case dt entry is missing */
nand->ecc.mode = NAND_ECC_HW; nand->ecc.mode = NAND_ECC_HW;
...@@ -1312,7 +1339,10 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, ...@@ -1312,7 +1339,10 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
return -EINVAL; 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_fdm(&chip->fdm, mtd);
mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, 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) ...@@ -1354,12 +1384,39 @@ static int mtk_nfc_nand_chips_init(struct device *dev, struct mtk_nfc *nfc)
return 0; 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) static int mtk_nfc_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct mtk_nfc *nfc; struct mtk_nfc *nfc;
struct resource *res; struct resource *res;
const struct of_device_id *of_nfc_id = NULL;
int ret, irq; int ret, irq;
nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
...@@ -1423,6 +1480,14 @@ static int mtk_nfc_probe(struct platform_device *pdev) ...@@ -1423,6 +1480,14 @@ static int mtk_nfc_probe(struct platform_device *pdev)
goto clk_disable; 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); platform_set_drvdata(pdev, nfc);
ret = mtk_nfc_nand_chips_init(dev, nfc); ret = mtk_nfc_nand_chips_init(dev, nfc);
...@@ -1485,8 +1550,6 @@ static int mtk_nfc_resume(struct device *dev) ...@@ -1485,8 +1550,6 @@ static int mtk_nfc_resume(struct device *dev)
if (ret) if (ret)
return ret; return ret;
mtk_nfc_hw_init(nfc);
/* reset NAND chip if VCC was powered off */ /* reset NAND chip if VCC was powered off */
list_for_each_entry(chip, &nfc->chips, node) { list_for_each_entry(chip, &nfc->chips, node) {
nand = &chip->nand; nand = &chip->nand;
...@@ -1503,12 +1566,6 @@ static int mtk_nfc_resume(struct device *dev) ...@@ -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); static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume);
#endif #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 = { static struct platform_driver mtk_nfc_driver = {
.probe = mtk_nfc_probe, .probe = mtk_nfc_probe,
.remove = mtk_nfc_remove, .remove = mtk_nfc_remove,
......
...@@ -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);
......
此差异已折叠。
此差异已折叠。
...@@ -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;
......
此差异已折叠。
此差异已折叠。
...@@ -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;
......
...@@ -915,6 +915,8 @@ static int spinand_probe(struct spi_device *spi_nand) ...@@ -915,6 +915,8 @@ static int spinand_probe(struct spi_device *spi_nand)
chip->waitfunc = spinand_wait; chip->waitfunc = spinand_wait;
chip->options |= NAND_CACHEPRG; chip->options |= NAND_CACHEPRG;
chip->select_chip = spinand_select_chip; 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); mtd = nand_to_mtd(chip);
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册