Commit 6a138027 authored by Richard Weinberger's avatar Richard Weinberger

Merge tag 'nand/for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux into mtd/next

Core changes:
* Drop useless 'depends on' in Kconfig
* Add an extra level in the Kconfig hierarchy
* Trivial spellings
* Dynamic allocation of the interface configurations
* Dropping the default ONFI timing mode
* Various cleanup (types, structures, naming, comments)
* Hide the chip->data_interface indirection
* Add the generic rb-gpios property
* Add the ->choose_interface_config() hook
* Introduce nand_choose_best_sdr_timings()
* Use default values for tPROG_max and tBERS_max
* Avoid redefining tR_max and tCCS_min
* Add a helper to find the closest ONFI mode
* bcm63xx MTD parsers: simplify CFE detection

Raw NAND controller drivers changes:
* fsl-upm: Deprecation of specific DT properties
* fsl_upm: Driver rework and cleanup in favor of ->exec_op()
* Ingenic: Cleanup ARRAY_SIZE() vs sizeof() use
* brcmnand: ECC error handling on EDU transfers
* brcmnand: Don't default to EDU transfers
* qcom: Set BAM mode only if not set already
* qcom: Avoid write to unavailable register
* gpio: Driver rework in favor of ->exec_op()
* tango: ->exec_op() conversion
* mtk: ->exec_op() conversion

Raw NAND chip drivers changes:
* toshiba: Implement ->choose_interface_config() for TH58NVG2S3HBAI4
* toshiba: Implement ->choose_interface_config() for TC58NVG0S3E
* toshiba: Implement ->choose_interface_config() for TC58TEG5DCLTA00
* hynix: Implement ->choose_interface_config() for H27UCG8T2ATR-BC
parents 0c84b7fc da151e34
...@@ -7,14 +7,16 @@ Required properties: ...@@ -7,14 +7,16 @@ Required properties:
- fsl,upm-cmd-offset : UPM pattern offset for the command latch. - fsl,upm-cmd-offset : UPM pattern offset for the command latch.
Optional properties: Optional properties:
- fsl,upm-wait-flags : add chip-dependent short delays after running the
UPM pattern (0x1), after writing a data byte (0x2) or after
writing out a buffer (0x4).
- fsl,upm-addr-line-cs-offsets : address offsets for multi-chip support. - fsl,upm-addr-line-cs-offsets : address offsets for multi-chip support.
The corresponding address lines are used to select the chip. The corresponding address lines are used to select the chip.
- gpios : may specify optional GPIOs connected to the Ready-Not-Busy pins - gpios : may specify optional GPIOs connected to the Ready-Not-Busy pins
(R/B#). For multi-chip devices, "n" GPIO definitions are required (R/B#). For multi-chip devices, "n" GPIO definitions are required
according to the number of chips. according to the number of chips.
Deprecated properties:
- fsl,upm-wait-flags : add chip-dependent short delays after running the
UPM pattern (0x1), after writing a data byte (0x2) or after
writing out a buffer (0x4).
- chip-delay : chip dependent delay for transferring data from array to - chip-delay : chip dependent delay for transferring data from array to
read registers (tR). Required if property "gpios" is not used read registers (tR). Required if property "gpios" is not used
(R/B# pins not connected). (R/B# pins not connected).
...@@ -52,8 +54,6 @@ upm@3,0 { ...@@ -52,8 +54,6 @@ upm@3,0 {
fsl,upm-cmd-offset = <0x08>; fsl,upm-cmd-offset = <0x08>;
/* Multi-chip NAND device */ /* Multi-chip NAND device */
fsl,upm-addr-line-cs-offsets = <0x0 0x200>; fsl,upm-addr-line-cs-offsets = <0x0 0x200>;
fsl,upm-wait-flags = <0x5>;
chip-delay = <25>; // in micro-seconds
nand@0 { nand@0 {
#address-cells = <1>; #address-cells = <1>;
......
...@@ -114,6 +114,13 @@ patternProperties: ...@@ -114,6 +114,13 @@ patternProperties:
description: description:
Contains the native Ready/Busy IDs. Contains the native Ready/Busy IDs.
rb-gpios:
description:
Contains one or more GPIO descriptor (the numper of descriptor
depends on the number of R/B pins exposed by the flash) for the
Ready/Busy pins. Active state refers to the NAND ready state and
should be set to GPIOD_ACTIVE_HIGH unless the signal is inverted.
required: required:
- reg - reg
......
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
menu "NAND"
config MTD_NAND_CORE config MTD_NAND_CORE
tristate tristate
source "drivers/mtd/nand/onenand/Kconfig" source "drivers/mtd/nand/onenand/Kconfig"
source "drivers/mtd/nand/raw/Kconfig" source "drivers/mtd/nand/raw/Kconfig"
source "drivers/mtd/nand/spi/Kconfig" source "drivers/mtd/nand/spi/Kconfig"
endmenu
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
menuconfig MTD_ONENAND menuconfig MTD_ONENAND
tristate "OneNAND Device Support" tristate "OneNAND Device Support"
depends on MTD
depends on HAS_IOMEM depends on HAS_IOMEM
help help
This enables support for accessing all type of OneNAND flash This enables support for accessing all type of OneNAND flash
......
...@@ -12,7 +12,6 @@ config MTD_NAND_ECC_SW_HAMMING_SMC ...@@ -12,7 +12,6 @@ config MTD_NAND_ECC_SW_HAMMING_SMC
menuconfig MTD_RAW_NAND menuconfig MTD_RAW_NAND
tristate "Raw/Parallel NAND Device Support" tristate "Raw/Parallel NAND Device Support"
depends on MTD
select MTD_NAND_CORE select MTD_NAND_CORE
select MTD_NAND_ECC_SW_HAMMING select MTD_NAND_ECC_SW_HAMMING
help help
......
...@@ -191,8 +191,8 @@ static int gpio_nand_exec_op(struct nand_chip *this, ...@@ -191,8 +191,8 @@ static int gpio_nand_exec_op(struct nand_chip *this,
return ret; return ret;
} }
static int gpio_nand_setup_data_interface(struct nand_chip *this, int csline, static int gpio_nand_setup_interface(struct nand_chip *this, int csline,
const struct nand_data_interface *cf) const struct nand_interface_config *cf)
{ {
struct gpio_nand *priv = nand_get_controller_data(this); struct gpio_nand *priv = nand_get_controller_data(this);
const struct nand_sdr_timings *sdr = nand_get_sdr_timings(cf); const struct nand_sdr_timings *sdr = nand_get_sdr_timings(cf);
...@@ -217,7 +217,7 @@ static int gpio_nand_setup_data_interface(struct nand_chip *this, int csline, ...@@ -217,7 +217,7 @@ static int gpio_nand_setup_data_interface(struct nand_chip *this, int csline,
static const struct nand_controller_ops gpio_nand_ops = { static const struct nand_controller_ops gpio_nand_ops = {
.exec_op = gpio_nand_exec_op, .exec_op = gpio_nand_exec_op,
.setup_data_interface = gpio_nand_setup_data_interface, .setup_interface = gpio_nand_setup_interface,
}; };
/* /*
......
...@@ -854,8 +854,8 @@ static int anfc_exec_op(struct nand_chip *chip, ...@@ -854,8 +854,8 @@ static int anfc_exec_op(struct nand_chip *chip,
return nand_op_parser_exec_op(chip, &anfc_op_parser, op, check_only); return nand_op_parser_exec_op(chip, &anfc_op_parser, op, check_only);
} }
static int anfc_setup_data_interface(struct nand_chip *chip, int target, static int anfc_setup_interface(struct nand_chip *chip, int target,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
struct anand *anand = to_anand(chip); struct anand *anand = to_anand(chip);
struct arasan_nfc *nfc = to_anfc(chip->controller); struct arasan_nfc *nfc = to_anfc(chip->controller);
...@@ -1083,7 +1083,7 @@ static void anfc_detach_chip(struct nand_chip *chip) ...@@ -1083,7 +1083,7 @@ static void anfc_detach_chip(struct nand_chip *chip)
static const struct nand_controller_ops anfc_ops = { static const struct nand_controller_ops anfc_ops = {
.exec_op = anfc_exec_op, .exec_op = anfc_exec_op,
.setup_data_interface = anfc_setup_data_interface, .setup_interface = anfc_setup_interface,
.attach_chip = anfc_attach_chip, .attach_chip = anfc_attach_chip,
.detach_chip = anfc_detach_chip, .detach_chip = anfc_detach_chip,
}; };
......
...@@ -200,8 +200,8 @@ struct atmel_nand_controller_ops { ...@@ -200,8 +200,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 nand_chip *chip); int (*ecc_init)(struct nand_chip *chip);
int (*setup_data_interface)(struct atmel_nand *nand, int csline, int (*setup_interface)(struct atmel_nand *nand, int csline,
const struct nand_data_interface *conf); const struct nand_interface_config *conf);
}; };
struct atmel_nand_controller_caps { struct atmel_nand_controller_caps {
...@@ -1168,7 +1168,7 @@ static int atmel_hsmc_nand_ecc_init(struct nand_chip *chip) ...@@ -1168,7 +1168,7 @@ static int atmel_hsmc_nand_ecc_init(struct nand_chip *chip)
} }
static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand, static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
const struct nand_data_interface *conf, const struct nand_interface_config *conf,
struct atmel_smc_cs_conf *smcconf) struct atmel_smc_cs_conf *smcconf)
{ {
u32 ncycles, totalcycles, timeps, mckperiodps; u32 ncycles, totalcycles, timeps, mckperiodps;
...@@ -1397,9 +1397,9 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand, ...@@ -1397,9 +1397,9 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
return 0; return 0;
} }
static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand, static int atmel_smc_nand_setup_interface(struct atmel_nand *nand,
int csline, int csline,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
struct atmel_nand_controller *nc; struct atmel_nand_controller *nc;
struct atmel_smc_cs_conf smcconf; struct atmel_smc_cs_conf smcconf;
...@@ -1422,9 +1422,9 @@ static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand, ...@@ -1422,9 +1422,9 @@ static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand,
return 0; return 0;
} }
static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand, static int atmel_hsmc_nand_setup_interface(struct atmel_nand *nand,
int csline, int csline,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
struct atmel_hsmc_nand_controller *nc; struct atmel_hsmc_nand_controller *nc;
struct atmel_smc_cs_conf smcconf; struct atmel_smc_cs_conf smcconf;
...@@ -1452,8 +1452,8 @@ static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand, ...@@ -1452,8 +1452,8 @@ static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
return 0; return 0;
} }
static int atmel_nand_setup_data_interface(struct nand_chip *chip, int csline, static int atmel_nand_setup_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc; struct atmel_nand_controller *nc;
...@@ -1464,7 +1464,7 @@ static int atmel_nand_setup_data_interface(struct nand_chip *chip, int csline, ...@@ -1464,7 +1464,7 @@ static int atmel_nand_setup_data_interface(struct nand_chip *chip, int csline,
(csline < 0 && csline != NAND_DATA_IFACE_CHECK_ONLY)) (csline < 0 && csline != NAND_DATA_IFACE_CHECK_ONLY))
return -EINVAL; return -EINVAL;
return nc->caps->ops->setup_data_interface(nand, csline, conf); return nc->caps->ops->setup_interface(nand, csline, conf);
} }
static void atmel_nand_init(struct atmel_nand_controller *nc, static void atmel_nand_init(struct atmel_nand_controller *nc,
...@@ -1483,7 +1483,7 @@ static void atmel_nand_init(struct atmel_nand_controller *nc, ...@@ -1483,7 +1483,7 @@ static void atmel_nand_init(struct atmel_nand_controller *nc,
chip->legacy.write_buf = atmel_nand_write_buf; chip->legacy.write_buf = atmel_nand_write_buf;
chip->legacy.select_chip = atmel_nand_select_chip; chip->legacy.select_chip = atmel_nand_select_chip;
if (!nc->mck || !nc->caps->ops->setup_data_interface) if (!nc->mck || !nc->caps->ops->setup_interface)
chip->options |= NAND_KEEP_TIMINGS; chip->options |= NAND_KEEP_TIMINGS;
/* Some NANDs require a longer delay than the default one (20us). */ /* Some NANDs require a longer delay than the default one (20us). */
...@@ -1956,7 +1956,7 @@ static int atmel_nand_attach_chip(struct nand_chip *chip) ...@@ -1956,7 +1956,7 @@ static int atmel_nand_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops atmel_nand_controller_ops = { static const struct nand_controller_ops atmel_nand_controller_ops = {
.attach_chip = atmel_nand_attach_chip, .attach_chip = atmel_nand_attach_chip,
.setup_data_interface = atmel_nand_setup_data_interface, .setup_interface = atmel_nand_setup_interface,
}; };
static int atmel_nand_controller_init(struct atmel_nand_controller *nc, static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
...@@ -2318,7 +2318,7 @@ static const struct atmel_nand_controller_ops atmel_hsmc_nc_ops = { ...@@ -2318,7 +2318,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, .setup_interface = atmel_hsmc_nand_setup_interface,
}; };
static const struct atmel_nand_controller_caps atmel_sama5_nc_caps = { static const struct atmel_nand_controller_caps atmel_sama5_nc_caps = {
...@@ -2375,10 +2375,10 @@ atmel_smc_nand_controller_remove(struct atmel_nand_controller *nc) ...@@ -2375,10 +2375,10 @@ atmel_smc_nand_controller_remove(struct atmel_nand_controller *nc)
/* /*
* The SMC reg layout of at91rm9200 is completely different which prevents us * The SMC reg layout of at91rm9200 is completely different which prevents us
* from re-using atmel_smc_nand_setup_data_interface() for the * from re-using atmel_smc_nand_setup_interface() for the
* ->setup_data_interface() hook. * ->setup_interface() hook.
* At this point, there's no support for the at91rm9200 SMC IP, so we leave * At this point, there's no support for the at91rm9200 SMC IP, so we leave
* ->setup_data_interface() unassigned. * ->setup_interface() unassigned.
*/ */
static const struct atmel_nand_controller_ops at91rm9200_nc_ops = { static const struct atmel_nand_controller_ops at91rm9200_nc_ops = {
.probe = atmel_smc_nand_controller_probe, .probe = atmel_smc_nand_controller_probe,
...@@ -2399,7 +2399,7 @@ static const struct atmel_nand_controller_ops atmel_smc_nc_ops = { ...@@ -2399,7 +2399,7 @@ static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
.remove = atmel_smc_nand_controller_remove, .remove = atmel_smc_nand_controller_remove,
.ecc_init = atmel_nand_ecc_init, .ecc_init = atmel_nand_ecc_init,
.nand_init = atmel_smc_nand_init, .nand_init = atmel_smc_nand_init,
.setup_data_interface = atmel_smc_nand_setup_data_interface, .setup_interface = atmel_smc_nand_setup_interface,
}; };
static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = { static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = {
......
...@@ -1918,6 +1918,22 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, ...@@ -1918,6 +1918,22 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
edu_writel(ctrl, EDU_STOP, 0); /* force stop */ edu_writel(ctrl, EDU_STOP, 0); /* force stop */
edu_readl(ctrl, EDU_STOP); edu_readl(ctrl, EDU_STOP);
if (!ret && edu_cmd == EDU_CMD_READ) {
u64 err_addr = 0;
/*
* check for ECC errors here, subpage ECC errors are
* retained in ECC error address register
*/
err_addr = brcmnand_get_uncorrecc_addr(ctrl);
if (!err_addr) {
err_addr = brcmnand_get_correcc_addr(ctrl);
if (err_addr)
ret = -EUCLEAN;
} else
ret = -EBADMSG;
}
return ret; return ret;
} }
...@@ -2124,6 +2140,7 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2124,6 +2140,7 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
u64 err_addr = 0; u64 err_addr = 0;
int err; int err;
bool retry = true; bool retry = true;
bool edu_err = false;
dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf); dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
...@@ -2141,6 +2158,10 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2141,6 +2158,10 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
else else
return -EIO; return -EIO;
} }
if (has_edu(ctrl) && err_addr)
edu_err = true;
} else { } else {
if (oob) if (oob)
memset(oob, 0x99, mtd->oobsize); memset(oob, 0x99, mtd->oobsize);
...@@ -2188,6 +2209,11 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2188,6 +2209,11 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
if (mtd_is_bitflip(err)) { if (mtd_is_bitflip(err)) {
unsigned int corrected = brcmnand_count_corrected(ctrl); unsigned int corrected = brcmnand_count_corrected(ctrl);
/* in case of EDU correctable error we read again using PIO */
if (edu_err)
err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
oob, &err_addr);
dev_dbg(ctrl->dev, "corrected error at 0x%llx\n", dev_dbg(ctrl->dev, "corrected error at 0x%llx\n",
(unsigned long long)err_addr); (unsigned long long)err_addr);
mtd->ecc_stats.corrected += corrected; mtd->ecc_stats.corrected += corrected;
...@@ -3023,8 +3049,9 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) ...@@ -3023,8 +3049,9 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
if (ret < 0) if (ret < 0)
goto err; goto err;
/* set edu transfer function to call */ if (has_edu(ctrl))
ctrl->dma_trans = brcmnand_edu_trans; /* set edu transfer function to call */
ctrl->dma_trans = brcmnand_edu_trans;
} }
/* Disable automatic device ID config, direct addressing */ /* Disable automatic device ID config, direct addressing */
......
...@@ -2303,8 +2303,8 @@ static inline u32 calc_tdvw(u32 trp_cnt, u32 clk_period, u32 trhoh_min, ...@@ -2303,8 +2303,8 @@ static inline u32 calc_tdvw(u32 trp_cnt, u32 clk_period, u32 trhoh_min,
} }
static int static int
cadence_nand_setup_data_interface(struct nand_chip *chip, int chipnr, cadence_nand_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
const struct nand_sdr_timings *sdr; const struct nand_sdr_timings *sdr;
struct cdns_nand_ctrl *cdns_ctrl = to_cdns_nand_ctrl(chip->controller); struct cdns_nand_ctrl *cdns_ctrl = to_cdns_nand_ctrl(chip->controller);
...@@ -2690,7 +2690,7 @@ static int cadence_nand_attach_chip(struct nand_chip *chip) ...@@ -2690,7 +2690,7 @@ static int cadence_nand_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops cadence_nand_controller_ops = { static const struct nand_controller_ops cadence_nand_controller_ops = {
.attach_chip = cadence_nand_attach_chip, .attach_chip = cadence_nand_attach_chip,
.exec_op = cadence_nand_exec_op, .exec_op = cadence_nand_exec_op,
.setup_data_interface = cadence_nand_setup_data_interface, .setup_interface = cadence_nand_setup_interface,
}; };
static int cadence_nand_chip_init(struct cdns_nand_ctrl *cdns_ctrl, static int cadence_nand_chip_init(struct cdns_nand_ctrl *cdns_ctrl,
......
...@@ -761,8 +761,8 @@ static int denali_write_page(struct nand_chip *chip, const u8 *buf, ...@@ -761,8 +761,8 @@ static int denali_write_page(struct nand_chip *chip, const u8 *buf,
return denali_page_xfer(chip, (void *)buf, mtd->writesize, page, true); return denali_page_xfer(chip, (void *)buf, mtd->writesize, page, true);
} }
static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, static int denali_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
static const unsigned int data_setup_on_host = 10000; static const unsigned int data_setup_on_host = 10000;
struct denali_controller *denali = to_denali_controller(chip); struct denali_controller *denali = to_denali_controller(chip);
...@@ -1173,7 +1173,7 @@ static int denali_exec_op(struct nand_chip *chip, ...@@ -1173,7 +1173,7 @@ static int denali_exec_op(struct nand_chip *chip,
static const struct nand_controller_ops denali_controller_ops = { static const struct nand_controller_ops denali_controller_ops = {
.attach_chip = denali_attach_chip, .attach_chip = denali_attach_chip,
.exec_op = denali_exec_op, .exec_op = denali_exec_op,
.setup_data_interface = denali_setup_data_interface, .setup_interface = denali_setup_interface,
}; };
int denali_chip_init(struct denali_controller *denali, int denali_chip_init(struct denali_controller *denali,
...@@ -1230,7 +1230,7 @@ int denali_chip_init(struct denali_controller *denali, ...@@ -1230,7 +1230,7 @@ int denali_chip_init(struct denali_controller *denali,
chip->buf_align = 16; chip->buf_align = 16;
} }
/* clk rate info is needed for setup_data_interface */ /* clk rate info is needed for setup_interface */
if (!denali->clk_rate || !denali->clk_x_rate) if (!denali->clk_rate || !denali->clk_x_rate)
chip->options |= NAND_KEEP_TIMINGS; chip->options |= NAND_KEEP_TIMINGS;
......
This diff is collapsed.
...@@ -327,8 +327,8 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host, ...@@ -327,8 +327,8 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
return 0; return 0;
} }
static int fsmc_setup_data_interface(struct nand_chip *nand, int csline, static int fsmc_setup_interface(struct nand_chip *nand, int csline,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
struct fsmc_nand_data *host = nand_to_fsmc(nand); struct fsmc_nand_data *host = nand_to_fsmc(nand);
struct fsmc_nand_timings tims; struct fsmc_nand_timings tims;
...@@ -951,7 +951,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand) ...@@ -951,7 +951,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand)
static const struct nand_controller_ops fsmc_nand_controller_ops = { static const struct nand_controller_ops fsmc_nand_controller_ops = {
.attach_chip = fsmc_nand_attach_chip, .attach_chip = fsmc_nand_attach_chip,
.exec_op = fsmc_exec_op, .exec_op = fsmc_exec_op,
.setup_data_interface = fsmc_setup_data_interface, .setup_interface = fsmc_setup_interface,
}; };
/** /**
......
...@@ -25,8 +25,11 @@ ...@@ -25,8 +25,11 @@
#include <linux/mtd/nand-gpio.h> #include <linux/mtd/nand-gpio.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/delay.h>
struct gpiomtd { struct gpiomtd {
struct nand_controller base;
void __iomem *io;
void __iomem *io_sync; void __iomem *io_sync;
struct nand_chip nand_chip; struct nand_chip nand_chip;
struct gpio_nand_platdata plat; struct gpio_nand_platdata plat;
...@@ -69,34 +72,99 @@ static void gpio_nand_dosync(struct gpiomtd *gpiomtd) ...@@ -69,34 +72,99 @@ static void gpio_nand_dosync(struct gpiomtd *gpiomtd)
static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {} static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {}
#endif #endif
static void gpio_nand_cmd_ctrl(struct nand_chip *chip, int cmd, static int gpio_nand_exec_instr(struct nand_chip *chip,
unsigned int ctrl) const struct nand_op_instr *instr)
{ {
struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip)); struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip));
unsigned int i;
gpio_nand_dosync(gpiomtd); switch (instr->type) {
case NAND_OP_CMD_INSTR:
gpio_nand_dosync(gpiomtd);
gpiod_set_value(gpiomtd->cle, 1);
gpio_nand_dosync(gpiomtd);
writeb(instr->ctx.cmd.opcode, gpiomtd->io);
gpio_nand_dosync(gpiomtd);
gpiod_set_value(gpiomtd->cle, 0);
return 0;
case NAND_OP_ADDR_INSTR:
gpio_nand_dosync(gpiomtd);
gpiod_set_value(gpiomtd->ale, 1);
gpio_nand_dosync(gpiomtd);
for (i = 0; i < instr->ctx.addr.naddrs; i++)
writeb(instr->ctx.addr.addrs[i], gpiomtd->io);
gpio_nand_dosync(gpiomtd);
gpiod_set_value(gpiomtd->ale, 0);
return 0;
case NAND_OP_DATA_IN_INSTR:
gpio_nand_dosync(gpiomtd);
if ((chip->options & NAND_BUSWIDTH_16) &&
!instr->ctx.data.force_8bit)
ioread16_rep(gpiomtd->io, instr->ctx.data.buf.in,
instr->ctx.data.len / 2);
else
ioread8_rep(gpiomtd->io, instr->ctx.data.buf.in,
instr->ctx.data.len);
return 0;
if (ctrl & NAND_CTRL_CHANGE) { case NAND_OP_DATA_OUT_INSTR:
if (gpiomtd->nce)
gpiod_set_value(gpiomtd->nce, !(ctrl & NAND_NCE));
gpiod_set_value(gpiomtd->cle, !!(ctrl & NAND_CLE));
gpiod_set_value(gpiomtd->ale, !!(ctrl & NAND_ALE));
gpio_nand_dosync(gpiomtd); gpio_nand_dosync(gpiomtd);
if ((chip->options & NAND_BUSWIDTH_16) &&
!instr->ctx.data.force_8bit)
iowrite16_rep(gpiomtd->io, instr->ctx.data.buf.out,
instr->ctx.data.len / 2);
else
iowrite8_rep(gpiomtd->io, instr->ctx.data.buf.out,
instr->ctx.data.len);
return 0;
case NAND_OP_WAITRDY_INSTR:
if (!gpiomtd->rdy)
return nand_soft_waitrdy(chip, instr->ctx.waitrdy.timeout_ms);
return nand_gpio_waitrdy(chip, gpiomtd->rdy,
instr->ctx.waitrdy.timeout_ms);
default:
return -EINVAL;
} }
if (cmd == NAND_CMD_NONE)
return;
writeb(cmd, gpiomtd->nand_chip.legacy.IO_ADDR_W); return 0;
gpio_nand_dosync(gpiomtd);
} }
static int gpio_nand_devready(struct nand_chip *chip) static int gpio_nand_exec_op(struct nand_chip *chip,
const struct nand_operation *op,
bool check_only)
{ {
struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip)); struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip));
unsigned int i;
int ret = 0;
if (check_only)
return 0;
return gpiod_get_value(gpiomtd->rdy); gpio_nand_dosync(gpiomtd);
gpiod_set_value(gpiomtd->nce, 0);
for (i = 0; i < op->ninstrs; i++) {
ret = gpio_nand_exec_instr(chip, &op->instrs[i]);
if (ret)
break;
if (op->instrs[i].delay_ns)
ndelay(op->instrs[i].delay_ns);
}
gpio_nand_dosync(gpiomtd);
gpiod_set_value(gpiomtd->nce, 1);
return ret;
} }
static const struct nand_controller_ops gpio_nand_ops = {
.exec_op = gpio_nand_exec_op,
};
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id gpio_nand_id_table[] = { static const struct of_device_id gpio_nand_id_table[] = {
{ .compatible = "gpio-control-nand" }, { .compatible = "gpio-control-nand" },
...@@ -225,9 +293,9 @@ static int gpio_nand_probe(struct platform_device *pdev) ...@@ -225,9 +293,9 @@ static int gpio_nand_probe(struct platform_device *pdev)
chip = &gpiomtd->nand_chip; chip = &gpiomtd->nand_chip;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
chip->legacy.IO_ADDR_R = devm_ioremap_resource(dev, res); gpiomtd->io = devm_ioremap_resource(dev, res);
if (IS_ERR(chip->legacy.IO_ADDR_R)) if (IS_ERR(gpiomtd->io))
return PTR_ERR(chip->legacy.IO_ADDR_R); return PTR_ERR(gpiomtd->io);
res = gpio_nand_get_io_sync(pdev); res = gpio_nand_get_io_sync(pdev);
if (res) { if (res) {
...@@ -269,17 +337,15 @@ static int gpio_nand_probe(struct platform_device *pdev) ...@@ -269,17 +337,15 @@ static int gpio_nand_probe(struct platform_device *pdev)
ret = PTR_ERR(gpiomtd->rdy); ret = PTR_ERR(gpiomtd->rdy);
goto out_ce; goto out_ce;
} }
/* Using RDY pin */
if (gpiomtd->rdy) nand_controller_init(&gpiomtd->base);
chip->legacy.dev_ready = gpio_nand_devready; gpiomtd->base.ops = &gpio_nand_ops;
nand_set_flash_node(chip, pdev->dev.of_node); nand_set_flash_node(chip, pdev->dev.of_node);
chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING; chip->ecc.algo = NAND_ECC_HAMMING;
chip->options = gpiomtd->plat.options; chip->options = gpiomtd->plat.options;
chip->legacy.chip_delay = gpiomtd->plat.chip_delay; chip->controller = &gpiomtd->base;
chip->legacy.cmd_ctrl = gpio_nand_cmd_ctrl;
mtd = nand_to_mtd(chip); mtd = nand_to_mtd(chip);
mtd->dev.parent = dev; mtd->dev.parent = dev;
......
...@@ -736,8 +736,8 @@ static void gpmi_nfc_apply_timings(struct gpmi_nand_data *this) ...@@ -736,8 +736,8 @@ static void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
udelay(dll_wait_time_us); udelay(dll_wait_time_us);
} }
static int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr, static int gpmi_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
struct gpmi_nand_data *this = nand_get_controller_data(chip); struct gpmi_nand_data *this = nand_get_controller_data(chip);
const struct nand_sdr_timings *sdr; const struct nand_sdr_timings *sdr;
...@@ -2400,7 +2400,7 @@ static int gpmi_nfc_exec_op(struct nand_chip *chip, ...@@ -2400,7 +2400,7 @@ static int gpmi_nfc_exec_op(struct nand_chip *chip,
static const struct nand_controller_ops gpmi_nand_controller_ops = { static const struct nand_controller_ops gpmi_nand_controller_ops = {
.attach_chip = gpmi_nand_attach_chip, .attach_chip = gpmi_nand_attach_chip,
.setup_data_interface = gpmi_setup_data_interface, .setup_interface = gpmi_setup_interface,
.exec_op = gpmi_nfc_exec_op, .exec_op = gpmi_nfc_exec_op,
}; };
......
...@@ -90,8 +90,8 @@ static int jz4740_ecc_calculate(struct ingenic_ecc *ecc, ...@@ -90,8 +90,8 @@ static int jz4740_ecc_calculate(struct ingenic_ecc *ecc,
* If the written data is completely 0xff, we also want to write 0xff as * If the written data is completely 0xff, we also want to write 0xff as
* ECC, otherwise we will get in trouble when doing subpage writes. * ECC, otherwise we will get in trouble when doing subpage writes.
*/ */
if (memcmp(ecc_code, empty_block_ecc, ARRAY_SIZE(empty_block_ecc)) == 0) if (memcmp(ecc_code, empty_block_ecc, sizeof(empty_block_ecc)) == 0)
memset(ecc_code, 0xff, ARRAY_SIZE(empty_block_ecc)); memset(ecc_code, 0xff, sizeof(empty_block_ecc));
return 0; return 0;
} }
......
...@@ -53,12 +53,12 @@ struct nand_manufacturer_ops { ...@@ -53,12 +53,12 @@ struct nand_manufacturer_ops {
}; };
/** /**
* struct nand_manufacturer - NAND Flash Manufacturer structure * struct nand_manufacturer_desc - NAND Flash Manufacturer descriptor
* @name: Manufacturer name * @name: Manufacturer name
* @id: manufacturer ID code of device. * @id: manufacturer ID code of device.
* @ops: manufacturer operations * @ops: manufacturer operations
*/ */
struct nand_manufacturer { struct nand_manufacturer_desc {
int id; int id;
char *name; char *name;
const struct nand_manufacturer_ops *ops; const struct nand_manufacturer_ops *ops;
...@@ -79,14 +79,21 @@ extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops; ...@@ -79,14 +79,21 @@ extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops;
extern const struct mtd_pairing_scheme dist3_pairing_scheme; extern const struct mtd_pairing_scheme dist3_pairing_scheme;
/* Core functions */ /* Core functions */
const struct nand_manufacturer *nand_get_manufacturer(u8 id); const struct nand_manufacturer_desc *nand_get_manufacturer_desc(u8 id);
int nand_bbm_get_next_page(struct nand_chip *chip, int page); int nand_bbm_get_next_page(struct nand_chip *chip, int page);
int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs); int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs);
int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
int allowbbt); int allowbbt);
int onfi_fill_data_interface(struct nand_chip *chip, void onfi_fill_interface_config(struct nand_chip *chip,
enum nand_data_interface_type type, struct nand_interface_config *iface,
int timing_mode); enum nand_interface_type type,
unsigned int timing_mode);
unsigned int
onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings);
int nand_choose_best_sdr_timings(struct nand_chip *chip,
struct nand_interface_config *iface,
struct nand_sdr_timings *spec_timings);
const struct nand_interface_config *nand_get_reset_interface_config(void);
int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param); int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param); int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf, int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf,
...@@ -130,10 +137,10 @@ static inline int nand_exec_op(struct nand_chip *chip, ...@@ -130,10 +137,10 @@ static inline int nand_exec_op(struct nand_chip *chip,
return chip->controller->ops->exec_op(chip, op, false); return chip->controller->ops->exec_op(chip, op, false);
} }
static inline bool nand_has_setup_data_iface(struct nand_chip *chip) static inline bool nand_controller_can_setup_interface(struct nand_chip *chip)
{ {
if (!chip->controller || !chip->controller->ops || if (!chip->controller || !chip->controller->ops ||
!chip->controller->ops->setup_data_interface) !chip->controller->ops->setup_interface)
return false; return false;
if (chip->options & NAND_KEEP_TIMINGS) if (chip->options & NAND_KEEP_TIMINGS)
......
...@@ -1096,6 +1096,8 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip, ...@@ -1096,6 +1096,8 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
const u8 *oob_buf, bool raw, const u8 *oob_buf, bool raw,
int page) int page)
{ {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip); struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller); struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout; const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
...@@ -1141,7 +1143,7 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip, ...@@ -1141,7 +1143,7 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
return ret; return ret;
ret = marvell_nfc_wait_op(chip, ret = marvell_nfc_wait_op(chip,
PSEC_TO_MSEC(chip->data_interface.timings.sdr.tPROG_max)); PSEC_TO_MSEC(sdr->tPROG_max));
return ret; return ret;
} }
...@@ -1562,6 +1564,8 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip, ...@@ -1562,6 +1564,8 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
const u8 *buf, const u8 *buf,
int oob_required, int page) int oob_required, int page)
{ {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout; const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
const u8 *data = buf; const u8 *data = buf;
...@@ -1598,8 +1602,7 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip, ...@@ -1598,8 +1602,7 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
marvell_nfc_wait_ndrun(chip); marvell_nfc_wait_ndrun(chip);
} }
ret = marvell_nfc_wait_op(chip, ret = marvell_nfc_wait_op(chip, PSEC_TO_MSEC(sdr->tPROG_max));
PSEC_TO_MSEC(chip->data_interface.timings.sdr.tPROG_max));
marvell_nfc_disable_hw_ecc(chip); marvell_nfc_disable_hw_ecc(chip);
...@@ -2305,9 +2308,8 @@ static struct nand_bbt_descr bbt_mirror_descr = { ...@@ -2305,9 +2308,8 @@ static struct nand_bbt_descr bbt_mirror_descr = {
.pattern = bbt_mirror_pattern .pattern = bbt_mirror_pattern
}; };
static int marvell_nfc_setup_data_interface(struct nand_chip *chip, int chipnr, static int marvell_nfc_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface const struct nand_interface_config *conf)
*conf)
{ {
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip); struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller); struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
...@@ -2508,7 +2510,7 @@ static int marvell_nand_attach_chip(struct nand_chip *chip) ...@@ -2508,7 +2510,7 @@ static int marvell_nand_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops marvell_nand_controller_ops = { static const struct nand_controller_ops marvell_nand_controller_ops = {
.attach_chip = marvell_nand_attach_chip, .attach_chip = marvell_nand_attach_chip,
.exec_op = marvell_nfc_exec_op, .exec_op = marvell_nfc_exec_op,
.setup_data_interface = marvell_nfc_setup_data_interface, .setup_interface = marvell_nfc_setup_interface,
}; };
static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc, static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
...@@ -2644,7 +2646,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc, ...@@ -2644,7 +2646,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
/* /*
* Save a reference value for timing registers before * Save a reference value for timing registers before
* ->setup_data_interface() is called. * ->setup_interface() is called.
*/ */
marvell_nand->ndtr0 = readl_relaxed(nfc->regs + NDTR0); marvell_nand->ndtr0 = readl_relaxed(nfc->regs + NDTR0);
marvell_nand->ndtr1 = readl_relaxed(nfc->regs + NDTR1); marvell_nand->ndtr1 = readl_relaxed(nfc->regs + NDTR1);
......
...@@ -573,10 +573,10 @@ static int meson_nfc_write_buf(struct nand_chip *nand, u8 *buf, int len) ...@@ -573,10 +573,10 @@ static int meson_nfc_write_buf(struct nand_chip *nand, u8 *buf, int len)
static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand, static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand,
int page, bool in) int page, bool in)
{ {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(nand));
struct mtd_info *mtd = nand_to_mtd(nand); struct mtd_info *mtd = nand_to_mtd(nand);
struct meson_nfc *nfc = nand_get_controller_data(nand); struct meson_nfc *nfc = nand_get_controller_data(nand);
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&nand->data_interface);
u32 *addrs = nfc->cmdfifo.rw.addrs; u32 *addrs = nfc->cmdfifo.rw.addrs;
u32 cs = nfc->param.chip_select; u32 cs = nfc->param.chip_select;
u32 cmd0, cmd_num, row_start; u32 cmd0, cmd_num, row_start;
...@@ -626,9 +626,9 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand, ...@@ -626,9 +626,9 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand,
static int meson_nfc_write_page_sub(struct nand_chip *nand, static int meson_nfc_write_page_sub(struct nand_chip *nand,
int page, int raw) int page, int raw)
{ {
struct mtd_info *mtd = nand_to_mtd(nand);
const struct nand_sdr_timings *sdr = const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&nand->data_interface); nand_get_sdr_timings(nand_get_interface_config(nand));
struct mtd_info *mtd = nand_to_mtd(nand);
struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand); struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
struct meson_nfc *nfc = nand_get_controller_data(nand); struct meson_nfc *nfc = nand_get_controller_data(nand);
int data_len, info_len; int data_len, info_len;
...@@ -1097,8 +1097,8 @@ static int meson_chip_buffer_init(struct nand_chip *nand) ...@@ -1097,8 +1097,8 @@ static int meson_chip_buffer_init(struct nand_chip *nand)
} }
static static
int meson_nfc_setup_data_interface(struct nand_chip *nand, int csline, int meson_nfc_setup_interface(struct nand_chip *nand, int csline,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand); struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
const struct nand_sdr_timings *timings; const struct nand_sdr_timings *timings;
...@@ -1222,7 +1222,7 @@ static int meson_nand_attach_chip(struct nand_chip *nand) ...@@ -1222,7 +1222,7 @@ static int meson_nand_attach_chip(struct nand_chip *nand)
static const struct nand_controller_ops meson_nand_controller_ops = { static const struct nand_controller_ops meson_nand_controller_ops = {
.attach_chip = meson_nand_attach_chip, .attach_chip = meson_nand_attach_chip,
.detach_chip = meson_nand_detach_chip, .detach_chip = meson_nand_detach_chip,
.setup_data_interface = meson_nfc_setup_data_interface, .setup_interface = meson_nfc_setup_interface,
.exec_op = meson_nfc_exec_op, .exec_op = meson_nfc_exec_op,
}; };
......
...@@ -387,44 +387,6 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd) ...@@ -387,44 +387,6 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
return 0; return 0;
} }
static void mtk_nfc_select_chip(struct nand_chip *nand, int chip)
{
struct mtk_nfc *nfc = nand_get_controller_data(nand);
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
if (chip < 0)
return;
mtk_nfc_hw_runtime_config(nand_to_mtd(nand));
nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
}
static int mtk_nfc_dev_ready(struct nand_chip *nand)
{
struct mtk_nfc *nfc = nand_get_controller_data(nand);
if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
return 0;
return 1;
}
static void mtk_nfc_cmd_ctrl(struct nand_chip *chip, int dat,
unsigned int ctrl)
{
struct mtk_nfc *nfc = nand_get_controller_data(chip);
if (ctrl & NAND_ALE) {
mtk_nfc_send_address(nfc, dat);
} else if (ctrl & NAND_CLE) {
mtk_nfc_hw_reset(nfc);
nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG);
mtk_nfc_send_command(nfc, dat);
}
}
static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc) static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
{ {
int rc; int rc;
...@@ -501,8 +463,76 @@ static void mtk_nfc_write_buf(struct nand_chip *chip, const u8 *buf, int len) ...@@ -501,8 +463,76 @@ static void mtk_nfc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
mtk_nfc_write_byte(chip, buf[i]); mtk_nfc_write_byte(chip, buf[i]);
} }
static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline, static int mtk_nfc_exec_instr(struct nand_chip *chip,
const struct nand_data_interface *conf) const struct nand_op_instr *instr)
{
struct mtk_nfc *nfc = nand_get_controller_data(chip);
unsigned int i;
u32 status;
switch (instr->type) {
case NAND_OP_CMD_INSTR:
mtk_nfc_send_command(nfc, instr->ctx.cmd.opcode);
return 0;
case NAND_OP_ADDR_INSTR:
for (i = 0; i < instr->ctx.addr.naddrs; i++)
mtk_nfc_send_address(nfc, instr->ctx.addr.addrs[i]);
return 0;
case NAND_OP_DATA_IN_INSTR:
mtk_nfc_read_buf(chip, instr->ctx.data.buf.in,
instr->ctx.data.len);
return 0;
case NAND_OP_DATA_OUT_INSTR:
mtk_nfc_write_buf(chip, instr->ctx.data.buf.out,
instr->ctx.data.len);
return 0;
case NAND_OP_WAITRDY_INSTR:
return readl_poll_timeout(nfc->regs + NFI_STA, status,
status & STA_BUSY, 20,
instr->ctx.waitrdy.timeout_ms);
default:
break;
}
return -EINVAL;
}
static void mtk_nfc_select_target(struct nand_chip *nand, unsigned int cs)
{
struct mtk_nfc *nfc = nand_get_controller_data(nand);
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
mtk_nfc_hw_runtime_config(nand_to_mtd(nand));
nfi_writel(nfc, mtk_nand->sels[cs], NFI_CSEL);
}
static int mtk_nfc_exec_op(struct nand_chip *chip,
const struct nand_operation *op,
bool check_only)
{
struct mtk_nfc *nfc = nand_get_controller_data(chip);
unsigned int i;
int ret = 0;
if (check_only)
return 0;
mtk_nfc_hw_reset(nfc);
nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG);
mtk_nfc_select_target(chip, op->cs);
for (i = 0; i < op->ninstrs; i++) {
ret = mtk_nfc_exec_instr(chip, &op->instrs[i]);
if (ret)
break;
}
return ret;
}
static int mtk_nfc_setup_interface(struct nand_chip *chip, int csline,
const struct nand_interface_config *conf)
{ {
struct mtk_nfc *nfc = nand_get_controller_data(chip); struct mtk_nfc *nfc = nand_get_controller_data(chip);
const struct nand_sdr_timings *timings; const struct nand_sdr_timings *timings;
...@@ -803,6 +833,7 @@ static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -803,6 +833,7 @@ static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
u32 reg; u32 reg;
int ret; int ret;
mtk_nfc_select_target(chip, chip->cur_cs);
nand_prog_page_begin_op(chip, page, 0, NULL, 0); nand_prog_page_begin_op(chip, page, 0, NULL, 0);
if (!raw) { if (!raw) {
...@@ -920,6 +951,7 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -920,6 +951,7 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
u8 *buf; u8 *buf;
int rc; int rc;
mtk_nfc_select_target(chip, chip->cur_cs);
start = data_offs / chip->ecc.size; start = data_offs / chip->ecc.size;
end = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size); end = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
...@@ -1325,7 +1357,8 @@ static int mtk_nfc_attach_chip(struct nand_chip *chip) ...@@ -1325,7 +1357,8 @@ static int mtk_nfc_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops mtk_nfc_controller_ops = { static const struct nand_controller_ops mtk_nfc_controller_ops = {
.attach_chip = mtk_nfc_attach_chip, .attach_chip = mtk_nfc_attach_chip,
.setup_data_interface = mtk_nfc_setup_data_interface, .setup_interface = mtk_nfc_setup_interface,
.exec_op = mtk_nfc_exec_op,
}; };
static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
...@@ -1381,13 +1414,6 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, ...@@ -1381,13 +1414,6 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
nand_set_controller_data(nand, nfc); nand_set_controller_data(nand, nfc);
nand->options |= NAND_USES_DMA | NAND_SUBPAGE_READ; nand->options |= NAND_USES_DMA | NAND_SUBPAGE_READ;
nand->legacy.dev_ready = mtk_nfc_dev_ready;
nand->legacy.select_chip = mtk_nfc_select_chip;
nand->legacy.write_byte = mtk_nfc_write_byte;
nand->legacy.write_buf = mtk_nfc_write_buf;
nand->legacy.read_byte = mtk_nfc_read_byte;
nand->legacy.read_buf = mtk_nfc_read_buf;
nand->legacy.cmd_ctrl = mtk_nfc_cmd_ctrl;
/* 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;
......
...@@ -137,8 +137,8 @@ struct mxc_nand_devtype_data { ...@@ -137,8 +137,8 @@ struct mxc_nand_devtype_data {
u32 (*get_ecc_status)(struct mxc_nand_host *); u32 (*get_ecc_status)(struct mxc_nand_host *);
const struct mtd_ooblayout_ops *ooblayout; const struct mtd_ooblayout_ops *ooblayout;
void (*select_chip)(struct nand_chip *chip, int cs); void (*select_chip)(struct nand_chip *chip, int cs);
int (*setup_data_interface)(struct nand_chip *chip, int csline, int (*setup_interface)(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf); const struct nand_interface_config *conf);
void (*enable_hwecc)(struct nand_chip *chip, bool enable); void (*enable_hwecc)(struct nand_chip *chip, bool enable);
/* /*
...@@ -1139,8 +1139,8 @@ static void preset_v1(struct mtd_info *mtd) ...@@ -1139,8 +1139,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 nand_chip *chip, int csline, static int mxc_nand_v2_setup_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
struct mxc_nand_host *host = nand_get_controller_data(chip); struct mxc_nand_host *host = nand_get_controller_data(chip);
int tRC_min_ns, tRC_ps, ret; int tRC_min_ns, tRC_ps, ret;
...@@ -1432,7 +1432,7 @@ static int mxc_nand_get_features(struct nand_chip *chip, int addr, ...@@ -1432,7 +1432,7 @@ static int mxc_nand_get_features(struct nand_chip *chip, int addr,
} }
/* /*
* The generic flash bbt decriptors overlap with our ecc * The generic flash bbt descriptors overlap with our ecc
* hardware, so define some i.MX specific ones. * hardware, so define some i.MX specific ones.
*/ */
static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
...@@ -1521,7 +1521,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { ...@@ -1521,7 +1521,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
.get_ecc_status = get_ecc_status_v2, .get_ecc_status = get_ecc_status_v2,
.ooblayout = &mxc_v2_ooblayout_ops, .ooblayout = &mxc_v2_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v2, .select_chip = mxc_nand_select_chip_v2,
.setup_data_interface = mxc_nand_v2_setup_data_interface, .setup_interface = mxc_nand_v2_setup_interface,
.enable_hwecc = mxc_nand_enable_hwecc_v1_v2, .enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
.irqpending_quirk = 0, .irqpending_quirk = 0,
.needs_ip = 0, .needs_ip = 0,
...@@ -1738,17 +1738,17 @@ static int mxcnd_attach_chip(struct nand_chip *chip) ...@@ -1738,17 +1738,17 @@ static int mxcnd_attach_chip(struct nand_chip *chip)
return 0; return 0;
} }
static int mxcnd_setup_data_interface(struct nand_chip *chip, int chipnr, static int mxcnd_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
struct mxc_nand_host *host = nand_get_controller_data(chip); struct mxc_nand_host *host = nand_get_controller_data(chip);
return host->devtype_data->setup_data_interface(chip, chipnr, conf); return host->devtype_data->setup_interface(chip, chipnr, conf);
} }
static const struct nand_controller_ops mxcnd_controller_ops = { static const struct nand_controller_ops mxcnd_controller_ops = {
.attach_chip = mxcnd_attach_chip, .attach_chip = mxcnd_attach_chip,
.setup_data_interface = mxcnd_setup_data_interface, .setup_interface = mxcnd_setup_interface,
}; };
static int mxcnd_probe(struct platform_device *pdev) static int mxcnd_probe(struct platform_device *pdev)
...@@ -1809,7 +1809,7 @@ static int mxcnd_probe(struct platform_device *pdev) ...@@ -1809,7 +1809,7 @@ static int mxcnd_probe(struct platform_device *pdev)
if (err < 0) if (err < 0)
return err; return err;
if (!host->devtype_data->setup_data_interface) if (!host->devtype_data->setup_interface)
this->options |= NAND_KEEP_TIMINGS; this->options |= NAND_KEEP_TIMINGS;
if (host->devtype_data->needs_ip) { if (host->devtype_data->needs_ip) {
......
...@@ -451,8 +451,8 @@ static int mxic_nfc_exec_op(struct nand_chip *chip, ...@@ -451,8 +451,8 @@ static int mxic_nfc_exec_op(struct nand_chip *chip,
return ret; return ret;
} }
static int mxic_nfc_setup_data_interface(struct nand_chip *chip, int chipnr, static int mxic_nfc_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip); struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
const struct nand_sdr_timings *sdr; const struct nand_sdr_timings *sdr;
...@@ -480,7 +480,7 @@ static int mxic_nfc_setup_data_interface(struct nand_chip *chip, int chipnr, ...@@ -480,7 +480,7 @@ static int mxic_nfc_setup_data_interface(struct nand_chip *chip, int chipnr,
static const struct nand_controller_ops mxic_nand_controller_ops = { static const struct nand_controller_ops mxic_nand_controller_ops = {
.exec_op = mxic_nfc_exec_op, .exec_op = mxic_nfc_exec_op,
.setup_data_interface = mxic_nfc_setup_data_interface, .setup_interface = mxic_nfc_setup_interface,
}; };
static int mxic_nfc_probe(struct platform_device *pdev) static int mxic_nfc_probe(struct platform_device *pdev)
......
This diff is collapsed.
...@@ -1226,7 +1226,7 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd) ...@@ -1226,7 +1226,7 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)
return -ENOMEM; return -ENOMEM;
/* /*
* If no primary table decriptor is given, scan the device to build a * If no primary table descriptor is given, scan the device to build a
* memory based bad block table. * memory based bad block table.
*/ */
if (!td) { if (!td) {
......
...@@ -337,7 +337,7 @@ static int hynix_mlc_1xnm_rr_init(struct nand_chip *chip, ...@@ -337,7 +337,7 @@ static int hynix_mlc_1xnm_rr_init(struct nand_chip *chip,
rr->nregs = nregs; rr->nregs = nregs;
rr->regs = hynix_1xnm_mlc_read_retry_regs; rr->regs = hynix_1xnm_mlc_read_retry_regs;
hynix->read_retry = rr; hynix->read_retry = rr;
chip->setup_read_retry = hynix_nand_setup_read_retry; chip->ops.setup_read_retry = hynix_nand_setup_read_retry;
chip->read_retries = nmodes; chip->read_retries = nmodes;
out: out:
...@@ -673,6 +673,15 @@ static void hynix_nand_cleanup(struct nand_chip *chip) ...@@ -673,6 +673,15 @@ static void hynix_nand_cleanup(struct nand_chip *chip)
nand_set_manufacturer_data(chip, NULL); nand_set_manufacturer_data(chip, NULL);
} }
static int
h27ucg8t2atrbc_choose_interface_config(struct nand_chip *chip,
struct nand_interface_config *iface)
{
onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 4);
return nand_choose_best_sdr_timings(chip, iface, NULL);
}
static int hynix_nand_init(struct nand_chip *chip) static int hynix_nand_init(struct nand_chip *chip)
{ {
struct hynix_nand *hynix; struct hynix_nand *hynix;
...@@ -689,6 +698,11 @@ static int hynix_nand_init(struct nand_chip *chip) ...@@ -689,6 +698,11 @@ static int hynix_nand_init(struct nand_chip *chip)
nand_set_manufacturer_data(chip, hynix); nand_set_manufacturer_data(chip, hynix);
if (!strncmp("H27UCG8T2ATR-BC", chip->parameters.model,
sizeof("H27UCG8T2ATR-BC") - 1))
chip->ops.choose_interface_config =
h27ucg8t2atrbc_choose_interface_config;
ret = hynix_nand_rr_init(chip); ret = hynix_nand_rr_init(chip);
if (ret) if (ret)
hynix_nand_cleanup(chip); hynix_nand_cleanup(chip);
......
...@@ -28,8 +28,7 @@ struct nand_flash_dev nand_flash_ids[] = { ...@@ -28,8 +28,7 @@ struct nand_flash_dev nand_flash_ids[] = {
*/ */
{"TC58NVG0S3E 1G 3.3V 8-bit", {"TC58NVG0S3E 1G 3.3V 8-bit",
{ .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} }, { .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} },
SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512), SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512), },
2 },
{"TC58NVG2S0F 4G 3.3V 8-bit", {"TC58NVG2S0F 4G 3.3V 8-bit",
{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} }, { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) }, SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
...@@ -51,7 +50,10 @@ struct nand_flash_dev nand_flash_ids[] = { ...@@ -51,7 +50,10 @@ struct nand_flash_dev nand_flash_ids[] = {
{"H27UCG8T2ATR-BC 64G 3.3V 8-bit", {"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} }, { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640, SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
NAND_ECC_INFO(40, SZ_1K), 4 }, NAND_ECC_INFO(40, SZ_1K) },
{"TH58NVG2S3HBAI4 4G 3.3V 8-bit",
{ .id = {0x98, 0xdc, 0x91, 0x15, 0x76} },
SZ_2K, SZ_512, SZ_128K, 0, 5, 128, NAND_ECC_INFO(8, SZ_512) },
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
...@@ -166,7 +168,7 @@ struct nand_flash_dev nand_flash_ids[] = { ...@@ -166,7 +168,7 @@ struct nand_flash_dev nand_flash_ids[] = {
}; };
/* Manufacturer IDs */ /* Manufacturer IDs */
static const struct nand_manufacturer nand_manufacturers[] = { static const struct nand_manufacturer_desc nand_manufacturer_descs[] = {
{NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops}, {NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
{NAND_MFR_ATO, "ATO"}, {NAND_MFR_ATO, "ATO"},
{NAND_MFR_EON, "Eon"}, {NAND_MFR_EON, "Eon"},
...@@ -186,20 +188,20 @@ static const struct nand_manufacturer nand_manufacturers[] = { ...@@ -186,20 +188,20 @@ static const struct nand_manufacturer nand_manufacturers[] = {
}; };
/** /**
* nand_get_manufacturer - Get manufacturer information from the manufacturer * nand_get_manufacturer_desc - Get manufacturer information from the
* ID * manufacturer ID
* @id: manufacturer ID * @id: manufacturer ID
* *
* Returns a pointer a nand_manufacturer object if the manufacturer is defined * Returns a nand_manufacturer_desc object if the manufacturer is defined
* in the NAND manufacturers database, NULL otherwise. * in the NAND manufacturers database, NULL otherwise.
*/ */
const struct nand_manufacturer *nand_get_manufacturer(u8 id) const struct nand_manufacturer_desc *nand_get_manufacturer_desc(u8 id)
{ {
int i; int i;
for (i = 0; i < ARRAY_SIZE(nand_manufacturers); i++) for (i = 0; i < ARRAY_SIZE(nand_manufacturer_descs); i++)
if (nand_manufacturers[i].id == id) if (nand_manufacturer_descs[i].id == id)
return &nand_manufacturers[i]; return &nand_manufacturer_descs[i];
return NULL; return NULL;
} }
...@@ -354,6 +354,9 @@ static void nand_command(struct nand_chip *chip, unsigned int command, ...@@ -354,6 +354,9 @@ static void nand_command(struct nand_chip *chip, unsigned int command,
static void nand_ccs_delay(struct nand_chip *chip) static void nand_ccs_delay(struct nand_chip *chip)
{ {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
/* /*
* The controller already takes care of waiting for tCCS when the RNDIN * The controller already takes care of waiting for tCCS when the RNDIN
* or RNDOUT command is sent, return directly. * or RNDOUT command is sent, return directly.
...@@ -365,8 +368,8 @@ static void nand_ccs_delay(struct nand_chip *chip) ...@@ -365,8 +368,8 @@ static void nand_ccs_delay(struct nand_chip *chip)
* Wait tCCS_min if it is correctly defined, otherwise wait 500ns * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
* (which should be safe for all NANDs). * (which should be safe for all NANDs).
*/ */
if (nand_has_setup_data_iface(chip)) if (nand_controller_can_setup_interface(chip))
ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000); ndelay(sdr->tCCS_min / 1000);
else else
ndelay(500); ndelay(500);
} }
......
...@@ -130,7 +130,7 @@ static void macronix_nand_onfi_init(struct nand_chip *chip) ...@@ -130,7 +130,7 @@ static void macronix_nand_onfi_init(struct nand_chip *chip)
return; return;
chip->read_retries = MACRONIX_NUM_READ_RETRY_MODES; chip->read_retries = MACRONIX_NUM_READ_RETRY_MODES;
chip->setup_read_retry = macronix_nand_setup_read_retry; chip->ops.setup_read_retry = macronix_nand_setup_read_retry;
if (p->supports_set_get_features) { if (p->supports_set_get_features) {
bitmap_set(p->set_feature_list, bitmap_set(p->set_feature_list,
...@@ -242,8 +242,8 @@ static void macronix_nand_block_protection_support(struct nand_chip *chip) ...@@ -242,8 +242,8 @@ static void macronix_nand_block_protection_support(struct nand_chip *chip)
bitmap_set(chip->parameters.set_feature_list, bitmap_set(chip->parameters.set_feature_list,
ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1); ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1);
chip->lock_area = mxic_nand_lock; chip->ops.lock_area = mxic_nand_lock;
chip->unlock_area = mxic_nand_unlock; chip->ops.unlock_area = mxic_nand_unlock;
} }
static int nand_power_down_op(struct nand_chip *chip) static int nand_power_down_op(struct nand_chip *chip)
...@@ -312,8 +312,8 @@ static void macronix_nand_deep_power_down_support(struct nand_chip *chip) ...@@ -312,8 +312,8 @@ static void macronix_nand_deep_power_down_support(struct nand_chip *chip)
if (i < 0) if (i < 0)
return; return;
chip->suspend = mxic_nand_suspend; chip->ops.suspend = mxic_nand_suspend;
chip->resume = mxic_nand_resume; chip->ops.resume = mxic_nand_resume;
} }
static int macronix_nand_init(struct nand_chip *chip) static int macronix_nand_init(struct nand_chip *chip)
......
...@@ -84,7 +84,7 @@ static int micron_nand_onfi_init(struct nand_chip *chip) ...@@ -84,7 +84,7 @@ static int micron_nand_onfi_init(struct nand_chip *chip)
struct nand_onfi_vendor_micron *micron = (void *)p->onfi->vendor; struct nand_onfi_vendor_micron *micron = (void *)p->onfi->vendor;
chip->read_retries = micron->read_retry_options; chip->read_retries = micron->read_retry_options;
chip->setup_read_retry = micron_nand_setup_read_retry; chip->ops.setup_read_retry = micron_nand_setup_read_retry;
} }
if (p->supports_set_get_features) { if (p->supports_set_get_features) {
......
...@@ -12,7 +12,14 @@ ...@@ -12,7 +12,14 @@
#define ONFI_DYN_TIMING_MAX U16_MAX #define ONFI_DYN_TIMING_MAX U16_MAX
static const struct nand_data_interface onfi_sdr_timings[] = { /*
* For non-ONFI chips we use the highest possible value for tPROG and tBERS.
* tR and tCCS will take the default values precised in the ONFI specification
* for timing mode 0, respectively 200us and 500ns.
*
* These four values are tweaked to be more accurate in the case of ONFI chips.
*/
static const struct nand_interface_config onfi_sdr_timings[] = {
/* Mode 0 */ /* Mode 0 */
{ {
.type = NAND_SDR_IFACE, .type = NAND_SDR_IFACE,
...@@ -20,6 +27,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { ...@@ -20,6 +27,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
.timings.sdr = { .timings.sdr = {
.tCCS_min = 500000, .tCCS_min = 500000,
.tR_max = 200000000, .tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tADL_min = 400000, .tADL_min = 400000,
.tALH_min = 20000, .tALH_min = 20000,
.tALS_min = 50000, .tALS_min = 50000,
...@@ -63,6 +72,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { ...@@ -63,6 +72,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
.timings.sdr = { .timings.sdr = {
.tCCS_min = 500000, .tCCS_min = 500000,
.tR_max = 200000000, .tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tADL_min = 400000, .tADL_min = 400000,
.tALH_min = 10000, .tALH_min = 10000,
.tALS_min = 25000, .tALS_min = 25000,
...@@ -106,6 +117,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { ...@@ -106,6 +117,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
.timings.sdr = { .timings.sdr = {
.tCCS_min = 500000, .tCCS_min = 500000,
.tR_max = 200000000, .tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tADL_min = 400000, .tADL_min = 400000,
.tALH_min = 10000, .tALH_min = 10000,
.tALS_min = 15000, .tALS_min = 15000,
...@@ -149,6 +162,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { ...@@ -149,6 +162,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
.timings.sdr = { .timings.sdr = {
.tCCS_min = 500000, .tCCS_min = 500000,
.tR_max = 200000000, .tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tADL_min = 400000, .tADL_min = 400000,
.tALH_min = 5000, .tALH_min = 5000,
.tALS_min = 10000, .tALS_min = 10000,
...@@ -192,6 +207,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { ...@@ -192,6 +207,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
.timings.sdr = { .timings.sdr = {
.tCCS_min = 500000, .tCCS_min = 500000,
.tR_max = 200000000, .tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tADL_min = 400000, .tADL_min = 400000,
.tALH_min = 5000, .tALH_min = 5000,
.tALS_min = 10000, .tALS_min = 10000,
...@@ -235,6 +252,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { ...@@ -235,6 +252,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
.timings.sdr = { .timings.sdr = {
.tCCS_min = 500000, .tCCS_min = 500000,
.tR_max = 200000000, .tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tADL_min = 400000, .tADL_min = 400000,
.tALH_min = 5000, .tALH_min = 5000,
.tALS_min = 10000, .tALS_min = 10000,
...@@ -273,23 +292,79 @@ static const struct nand_data_interface onfi_sdr_timings[] = { ...@@ -273,23 +292,79 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
}, },
}; };
/* All NAND chips share the same reset data interface: SDR mode 0 */
const struct nand_interface_config *nand_get_reset_interface_config(void)
{
return &onfi_sdr_timings[0];
}
/**
* onfi_find_closest_sdr_mode - Derive the closest ONFI SDR timing mode given a
* set of timings
* @spec_timings: the timings to challenge
*/
unsigned int
onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings)
{
const struct nand_sdr_timings *onfi_timings;
int mode;
for (mode = ARRAY_SIZE(onfi_sdr_timings) - 1; mode > 0; mode--) {
onfi_timings = &onfi_sdr_timings[mode].timings.sdr;
if (spec_timings->tCCS_min <= onfi_timings->tCCS_min &&
spec_timings->tADL_min <= onfi_timings->tADL_min &&
spec_timings->tALH_min <= onfi_timings->tALH_min &&
spec_timings->tALS_min <= onfi_timings->tALS_min &&
spec_timings->tAR_min <= onfi_timings->tAR_min &&
spec_timings->tCEH_min <= onfi_timings->tCEH_min &&
spec_timings->tCH_min <= onfi_timings->tCH_min &&
spec_timings->tCLH_min <= onfi_timings->tCLH_min &&
spec_timings->tCLR_min <= onfi_timings->tCLR_min &&
spec_timings->tCLS_min <= onfi_timings->tCLS_min &&
spec_timings->tCOH_min <= onfi_timings->tCOH_min &&
spec_timings->tCS_min <= onfi_timings->tCS_min &&
spec_timings->tDH_min <= onfi_timings->tDH_min &&
spec_timings->tDS_min <= onfi_timings->tDS_min &&
spec_timings->tIR_min <= onfi_timings->tIR_min &&
spec_timings->tRC_min <= onfi_timings->tRC_min &&
spec_timings->tREH_min <= onfi_timings->tREH_min &&
spec_timings->tRHOH_min <= onfi_timings->tRHOH_min &&
spec_timings->tRHW_min <= onfi_timings->tRHW_min &&
spec_timings->tRLOH_min <= onfi_timings->tRLOH_min &&
spec_timings->tRP_min <= onfi_timings->tRP_min &&
spec_timings->tRR_min <= onfi_timings->tRR_min &&
spec_timings->tWC_min <= onfi_timings->tWC_min &&
spec_timings->tWH_min <= onfi_timings->tWH_min &&
spec_timings->tWHR_min <= onfi_timings->tWHR_min &&
spec_timings->tWP_min <= onfi_timings->tWP_min &&
spec_timings->tWW_min <= onfi_timings->tWW_min)
return mode;
}
return 0;
}
/** /**
* onfi_fill_data_interface - [NAND Interface] Initialize a data interface from * onfi_fill_interface_config - Initialize an interface config from a given
* given ONFI mode * ONFI mode
* @mode: The ONFI timing mode * @chip: The NAND chip
* @iface: The interface configuration to fill
* @type: The interface type
* @timing_mode: The ONFI timing mode
*/ */
int onfi_fill_data_interface(struct nand_chip *chip, void onfi_fill_interface_config(struct nand_chip *chip,
enum nand_data_interface_type type, struct nand_interface_config *iface,
int timing_mode) enum nand_interface_type type,
unsigned int timing_mode)
{ {
struct nand_data_interface *iface = &chip->data_interface;
struct onfi_params *onfi = chip->parameters.onfi; struct onfi_params *onfi = chip->parameters.onfi;
if (type != NAND_SDR_IFACE) if (WARN_ON(type != NAND_SDR_IFACE))
return -EINVAL; return;
if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings)) if (WARN_ON(timing_mode >= ARRAY_SIZE(onfi_sdr_timings)))
return -EINVAL; return;
*iface = onfi_sdr_timings[timing_mode]; *iface = onfi_sdr_timings[timing_mode];
...@@ -308,22 +383,5 @@ int onfi_fill_data_interface(struct nand_chip *chip, ...@@ -308,22 +383,5 @@ int onfi_fill_data_interface(struct nand_chip *chip,
/* nanoseconds -> picoseconds */ /* nanoseconds -> picoseconds */
timings->tCCS_min = 1000UL * onfi->tCCS; timings->tCCS_min = 1000UL * onfi->tCCS;
} else {
struct nand_sdr_timings *timings = &iface->timings.sdr;
/*
* For non-ONFI chips we use the highest possible value for
* tPROG and tBERS. tR and tCCS will take the default values
* precised in the ONFI specification for timing mode 0,
* respectively 200us and 500ns.
*/
/* microseconds -> picoseconds */
timings->tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX;
timings->tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX;
timings->tR_max = 200000000;
timings->tCCS_min = 500000;
} }
return 0;
} }
...@@ -33,7 +33,7 @@ static int toshiba_nand_benand_read_eccstatus_op(struct nand_chip *chip, ...@@ -33,7 +33,7 @@ static int toshiba_nand_benand_read_eccstatus_op(struct nand_chip *chip,
if (nand_has_exec_op(chip)) { if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr = const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface); nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = { struct nand_op_instr instrs[] = {
NAND_OP_CMD(TOSHIBA_NAND_CMD_ECC_STATUS_READ, NAND_OP_CMD(TOSHIBA_NAND_CMD_ECC_STATUS_READ,
PSEC_TO_NSEC(sdr->tADL_min)), PSEC_TO_NSEC(sdr->tADL_min)),
...@@ -194,17 +194,79 @@ static void toshiba_nand_decode_id(struct nand_chip *chip) ...@@ -194,17 +194,79 @@ static void toshiba_nand_decode_id(struct nand_chip *chip)
} }
} }
static int
tc58teg5dclta00_choose_interface_config(struct nand_chip *chip,
struct nand_interface_config *iface)
{
onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 5);
return nand_choose_best_sdr_timings(chip, iface, NULL);
}
static int
tc58nvg0s3e_choose_interface_config(struct nand_chip *chip,
struct nand_interface_config *iface)
{
onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 2);
return nand_choose_best_sdr_timings(chip, iface, NULL);
}
static int
th58nvg2s3hbai4_choose_interface_config(struct nand_chip *chip,
struct nand_interface_config *iface)
{
struct nand_sdr_timings *sdr = &iface->timings.sdr;
/* Start with timings from the closest timing mode, mode 4. */
onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 4);
/* Patch timings that differ from mode 4. */
sdr->tALS_min = 12000;
sdr->tCHZ_max = 20000;
sdr->tCLS_min = 12000;
sdr->tCOH_min = 0;
sdr->tDS_min = 12000;
sdr->tRHOH_min = 25000;
sdr->tRHW_min = 30000;
sdr->tRHZ_max = 60000;
sdr->tWHR_min = 60000;
/* Patch timings not part of onfi timing mode. */
sdr->tPROG_max = 700000000;
sdr->tBERS_max = 5000000000;
return nand_choose_best_sdr_timings(chip, iface, sdr);
}
static int tc58teg5dclta00_init(struct nand_chip *chip) static int tc58teg5dclta00_init(struct nand_chip *chip)
{ {
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
chip->onfi_timing_mode_default = 5; chip->ops.choose_interface_config =
&tc58teg5dclta00_choose_interface_config;
chip->options |= NAND_NEED_SCRAMBLING; chip->options |= NAND_NEED_SCRAMBLING;
mtd_set_pairing_scheme(mtd, &dist3_pairing_scheme); mtd_set_pairing_scheme(mtd, &dist3_pairing_scheme);
return 0; return 0;
} }
static int tc58nvg0s3e_init(struct nand_chip *chip)
{
chip->ops.choose_interface_config =
&tc58nvg0s3e_choose_interface_config;
return 0;
}
static int th58nvg2s3hbai4_init(struct nand_chip *chip)
{
chip->ops.choose_interface_config =
&th58nvg2s3hbai4_choose_interface_config;
return 0;
}
static int toshiba_nand_init(struct nand_chip *chip) static int toshiba_nand_init(struct nand_chip *chip)
{ {
if (nand_is_slc(chip)) if (nand_is_slc(chip))
...@@ -217,6 +279,12 @@ static int toshiba_nand_init(struct nand_chip *chip) ...@@ -217,6 +279,12 @@ static int toshiba_nand_init(struct nand_chip *chip)
if (!strcmp("TC58TEG5DCLTA00", chip->parameters.model)) if (!strcmp("TC58TEG5DCLTA00", chip->parameters.model))
tc58teg5dclta00_init(chip); tc58teg5dclta00_init(chip);
if (!strncmp("TC58NVG0S3E", chip->parameters.model,
sizeof("TC58NVG0S3E") - 1))
tc58nvg0s3e_init(chip);
if (!strncmp("TH58NVG2S3HBAI4", chip->parameters.model,
sizeof("TH58NVG2S3HBAI4") - 1))
th58nvg2s3hbai4_init(chip);
return 0; return 0;
} }
......
...@@ -459,11 +459,13 @@ struct qcom_nand_host { ...@@ -459,11 +459,13 @@ struct qcom_nand_host {
* among different NAND controllers. * among different NAND controllers.
* @ecc_modes - ecc mode for NAND * @ecc_modes - ecc mode for NAND
* @is_bam - whether NAND controller is using BAM * @is_bam - whether NAND controller is using BAM
* @is_qpic - whether NAND CTRL is part of qpic IP
* @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
*/ */
struct qcom_nandc_props { struct qcom_nandc_props {
u32 ecc_modes; u32 ecc_modes;
bool is_bam; bool is_bam;
bool is_qpic;
u32 dev_cmd_reg_start; u32 dev_cmd_reg_start;
}; };
...@@ -2774,14 +2776,24 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) ...@@ -2774,14 +2776,24 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
u32 nand_ctrl; u32 nand_ctrl;
/* kill onenand */ /* kill onenand */
nandc_write(nandc, SFLASHC_BURST_CFG, 0); if (!nandc->props->is_qpic)
nandc_write(nandc, SFLASHC_BURST_CFG, 0);
nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD), nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
NAND_DEV_CMD_VLD_VAL); NAND_DEV_CMD_VLD_VAL);
/* enable ADM or BAM DMA */ /* enable ADM or BAM DMA */
if (nandc->props->is_bam) { if (nandc->props->is_bam) {
nand_ctrl = nandc_read(nandc, NAND_CTRL); nand_ctrl = nandc_read(nandc, NAND_CTRL);
nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN);
/*
*NAND_CTRL is an operational registers, and CPU
* access to operational registers are read only
* in BAM mode. So update the NAND_CTRL register
* only if it is not in BAM mode. In most cases BAM
* mode will be enabled in bootloader
*/
if (!(nand_ctrl & BAM_MODE_EN))
nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN);
} else { } else {
nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN); nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN);
} }
...@@ -3035,12 +3047,14 @@ static const struct qcom_nandc_props ipq806x_nandc_props = { ...@@ -3035,12 +3047,14 @@ static const struct qcom_nandc_props ipq806x_nandc_props = {
static const struct qcom_nandc_props ipq4019_nandc_props = { static const struct qcom_nandc_props ipq4019_nandc_props = {
.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
.is_bam = true, .is_bam = true,
.is_qpic = true,
.dev_cmd_reg_start = 0x0, .dev_cmd_reg_start = 0x0,
}; };
static const struct qcom_nandc_props ipq8074_nandc_props = { static const struct qcom_nandc_props ipq8074_nandc_props = {
.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
.is_bam = true, .is_bam = true,
.is_qpic = true,
.dev_cmd_reg_start = 0x7000, .dev_cmd_reg_start = 0x7000,
}; };
......
...@@ -808,8 +808,8 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, ...@@ -808,8 +808,8 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
return -ENODEV; return -ENODEV;
} }
static int s3c2410_nand_setup_data_interface(struct nand_chip *chip, int csline, static int s3c2410_nand_setup_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
...@@ -999,7 +999,7 @@ static int s3c2410_nand_attach_chip(struct nand_chip *chip) ...@@ -999,7 +999,7 @@ static int s3c2410_nand_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops s3c24xx_nand_controller_ops = { static const struct nand_controller_ops s3c24xx_nand_controller_ops = {
.attach_chip = s3c2410_nand_attach_chip, .attach_chip = s3c2410_nand_attach_chip,
.setup_data_interface = s3c2410_nand_setup_data_interface, .setup_interface = s3c2410_nand_setup_interface,
}; };
static const struct of_device_id s3c24xx_nand_dt_ids[] = { static const struct of_device_id s3c24xx_nand_dt_ids[] = {
......
...@@ -1277,7 +1277,7 @@ static int stm32_fmc2_nfc_waitrdy(struct nand_chip *chip, ...@@ -1277,7 +1277,7 @@ static int stm32_fmc2_nfc_waitrdy(struct nand_chip *chip,
dev_warn(nfc->dev, "Waitrdy timeout\n"); dev_warn(nfc->dev, "Waitrdy timeout\n");
/* Wait tWB before R/B# signal is low */ /* Wait tWB before R/B# signal is low */
timings = nand_get_sdr_timings(&chip->data_interface); timings = nand_get_sdr_timings(nand_get_interface_config(chip));
ndelay(PSEC_TO_NSEC(timings->tWB_max)); ndelay(PSEC_TO_NSEC(timings->tWB_max));
/* R/B# signal is low, clear high level flag */ /* R/B# signal is low, clear high level flag */
...@@ -1517,7 +1517,7 @@ static void stm32_fmc2_nfc_calc_timings(struct nand_chip *chip, ...@@ -1517,7 +1517,7 @@ static void stm32_fmc2_nfc_calc_timings(struct nand_chip *chip,
} }
static int stm32_fmc2_nfc_setup_interface(struct nand_chip *chip, int chipnr, static int stm32_fmc2_nfc_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
const struct nand_sdr_timings *sdrt; const struct nand_sdr_timings *sdrt;
...@@ -1735,7 +1735,7 @@ static int stm32_fmc2_nfc_attach_chip(struct nand_chip *chip) ...@@ -1735,7 +1735,7 @@ static int stm32_fmc2_nfc_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops stm32_fmc2_nfc_controller_ops = { static const struct nand_controller_ops stm32_fmc2_nfc_controller_ops = {
.attach_chip = stm32_fmc2_nfc_attach_chip, .attach_chip = stm32_fmc2_nfc_attach_chip,
.exec_op = stm32_fmc2_nfc_exec_op, .exec_op = stm32_fmc2_nfc_exec_op,
.setup_data_interface = stm32_fmc2_nfc_setup_interface, .setup_interface = stm32_fmc2_nfc_setup_interface,
}; };
static int stm32_fmc2_nfc_parse_child(struct stm32_fmc2_nfc *nfc, static int stm32_fmc2_nfc_parse_child(struct stm32_fmc2_nfc *nfc,
......
...@@ -1376,8 +1376,8 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration, ...@@ -1376,8 +1376,8 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
#define sunxi_nand_lookup_timing(l, p, c) \ #define sunxi_nand_lookup_timing(l, p, c) \
_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c) _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
static int sunxi_nfc_setup_data_interface(struct nand_chip *nand, int csline, static int sunxi_nfc_setup_interface(struct nand_chip *nand, int csline,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
...@@ -1920,7 +1920,7 @@ static int sunxi_nfc_exec_op(struct nand_chip *nand, ...@@ -1920,7 +1920,7 @@ static int sunxi_nfc_exec_op(struct nand_chip *nand,
static const struct nand_controller_ops sunxi_nand_controller_ops = { static const struct nand_controller_ops sunxi_nand_controller_ops = {
.attach_chip = sunxi_nand_attach_chip, .attach_chip = sunxi_nand_attach_chip,
.setup_data_interface = sunxi_nfc_setup_data_interface, .setup_interface = sunxi_nfc_setup_interface,
.exec_op = sunxi_nfc_exec_op, .exec_op = sunxi_nfc_exec_op,
}; };
......
...@@ -113,59 +113,80 @@ struct tango_chip { ...@@ -113,59 +113,80 @@ struct tango_chip {
#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3)) #define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
static void tango_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl) static void tango_select_target(struct nand_chip *chip, unsigned int cs)
{ {
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
struct tango_chip *tchip = to_tango_chip(chip); struct tango_chip *tchip = to_tango_chip(chip);
if (ctrl & NAND_CLE) writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
writeb_relaxed(dat, tchip->base + PBUS_CMD); writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
if (ctrl & NAND_ALE) writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
writeb_relaxed(dat, tchip->base + PBUS_ADDR); writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
} }
static int tango_dev_ready(struct nand_chip *chip) static int tango_waitrdy(struct nand_chip *chip, unsigned int timeout_ms)
{ {
struct tango_nfc *nfc = to_tango_nfc(chip->controller); struct tango_nfc *nfc = to_tango_nfc(chip->controller);
u32 status;
return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY; return readl_relaxed_poll_timeout(nfc->pbus_base + PBUS_CS_CTRL,
status, status & PBUS_IORDY, 20,
timeout_ms);
} }
static u8 tango_read_byte(struct nand_chip *chip) static int tango_exec_instr(struct nand_chip *chip,
const struct nand_op_instr *instr)
{ {
struct tango_chip *tchip = to_tango_chip(chip); struct tango_chip *tchip = to_tango_chip(chip);
unsigned int i;
return readb_relaxed(tchip->base + PBUS_DATA); switch (instr->type) {
} case NAND_OP_CMD_INSTR:
writeb_relaxed(instr->ctx.cmd.opcode, tchip->base + PBUS_CMD);
static void tango_read_buf(struct nand_chip *chip, u8 *buf, int len) return 0;
{ case NAND_OP_ADDR_INSTR:
struct tango_chip *tchip = to_tango_chip(chip); for (i = 0; i < instr->ctx.addr.naddrs; i++)
writeb_relaxed(instr->ctx.addr.addrs[i],
tchip->base + PBUS_ADDR);
return 0;
case NAND_OP_DATA_IN_INSTR:
ioread8_rep(tchip->base + PBUS_DATA, instr->ctx.data.buf.in,
instr->ctx.data.len);
return 0;
case NAND_OP_DATA_OUT_INSTR:
iowrite8_rep(tchip->base + PBUS_DATA, instr->ctx.data.buf.out,
instr->ctx.data.len);
return 0;
case NAND_OP_WAITRDY_INSTR:
return tango_waitrdy(chip,
instr->ctx.waitrdy.timeout_ms);
default:
break;
}
ioread8_rep(tchip->base + PBUS_DATA, buf, len); return -EINVAL;
} }
static void tango_write_buf(struct nand_chip *chip, const u8 *buf, int len) static int tango_exec_op(struct nand_chip *chip,
const struct nand_operation *op,
bool check_only)
{ {
struct tango_chip *tchip = to_tango_chip(chip); unsigned int i;
int ret = 0;
iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
}
static void tango_select_chip(struct nand_chip *chip, int idx) if (check_only)
{ return 0;
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
struct tango_chip *tchip = to_tango_chip(chip);
if (idx < 0) tango_select_target(chip, op->cs);
return; /* No "chip unselect" function */ for (i = 0; i < op->ninstrs; i++) {
ret = tango_exec_instr(chip, &op->instrs[i]);
if (ret)
break;
}
writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1); return ret;
writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
} }
/* /*
...@@ -279,6 +300,7 @@ static int tango_read_page(struct nand_chip *chip, u8 *buf, ...@@ -279,6 +300,7 @@ static int tango_read_page(struct nand_chip *chip, u8 *buf,
struct tango_nfc *nfc = to_tango_nfc(chip->controller); struct tango_nfc *nfc = to_tango_nfc(chip->controller);
int err, res, len = mtd->writesize; int err, res, len = mtd->writesize;
tango_select_target(chip, chip->cur_cs);
if (oob_required) if (oob_required)
chip->ecc.read_oob(chip, page); chip->ecc.read_oob(chip, page);
...@@ -300,22 +322,30 @@ static int tango_write_page(struct nand_chip *chip, const u8 *buf, ...@@ -300,22 +322,30 @@ static int tango_write_page(struct nand_chip *chip, const u8 *buf,
{ {
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
struct tango_nfc *nfc = to_tango_nfc(chip->controller); struct tango_nfc *nfc = to_tango_nfc(chip->controller);
int err, status, len = mtd->writesize; const struct nand_sdr_timings *timings;
int err, len = mtd->writesize;
u8 status;
/* Calling tango_write_oob() would send PAGEPROG twice */ /* Calling tango_write_oob() would send PAGEPROG twice */
if (oob_required) if (oob_required)
return -ENOTSUPP; return -ENOTSUPP;
tango_select_target(chip, chip->cur_cs);
writel_relaxed(0xffffffff, nfc->mem_base + METADATA); writel_relaxed(0xffffffff, nfc->mem_base + METADATA);
err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page); err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page);
if (err) if (err)
return err; return err;
status = chip->legacy.waitfunc(chip); timings = nand_get_sdr_timings(nand_get_interface_config(chip));
if (status & NAND_STATUS_FAIL) err = tango_waitrdy(chip, PSEC_TO_MSEC(timings->tR_max));
return -EIO; if (err)
return err;
return 0; err = nand_status_op(chip, &status);
if (err)
return err;
return (status & NAND_STATUS_FAIL) ? -EIO : 0;
} }
static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos) static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
...@@ -326,7 +356,9 @@ static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos) ...@@ -326,7 +356,9 @@ static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
/* skip over "len" bytes */ /* skip over "len" bytes */
nand_change_read_column_op(chip, *pos, NULL, 0, false); nand_change_read_column_op(chip, *pos, NULL, 0, false);
} else { } else {
tango_read_buf(chip, *buf, len); struct tango_chip *tchip = to_tango_chip(chip);
ioread8_rep(tchip->base + PBUS_DATA, *buf, len);
*buf += len; *buf += len;
} }
} }
...@@ -339,7 +371,9 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos) ...@@ -339,7 +371,9 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
/* skip over "len" bytes */ /* skip over "len" bytes */
nand_change_write_column_op(chip, *pos, NULL, 0, false); nand_change_write_column_op(chip, *pos, NULL, 0, false);
} else { } else {
tango_write_buf(chip, *buf, len); struct tango_chip *tchip = to_tango_chip(chip);
iowrite8_rep(tchip->base + PBUS_DATA, *buf, len);
*buf += len; *buf += len;
} }
} }
...@@ -420,6 +454,7 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob) ...@@ -420,6 +454,7 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
static int tango_read_page_raw(struct nand_chip *chip, u8 *buf, static int tango_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page) int oob_required, int page)
{ {
tango_select_target(chip, chip->cur_cs);
nand_read_page_op(chip, page, 0, NULL, 0); nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, buf, chip->oob_poi); raw_read(chip, buf, chip->oob_poi);
return 0; return 0;
...@@ -428,6 +463,7 @@ static int tango_read_page_raw(struct nand_chip *chip, u8 *buf, ...@@ -428,6 +463,7 @@ static int tango_read_page_raw(struct nand_chip *chip, u8 *buf,
static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf, static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf,
int oob_required, int page) int oob_required, int page)
{ {
tango_select_target(chip, chip->cur_cs);
nand_prog_page_begin_op(chip, page, 0, NULL, 0); nand_prog_page_begin_op(chip, page, 0, NULL, 0);
raw_write(chip, buf, chip->oob_poi); raw_write(chip, buf, chip->oob_poi);
return nand_prog_page_end_op(chip); return nand_prog_page_end_op(chip);
...@@ -435,6 +471,7 @@ static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf, ...@@ -435,6 +471,7 @@ static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf,
static int tango_read_oob(struct nand_chip *chip, int page) static int tango_read_oob(struct nand_chip *chip, int page)
{ {
tango_select_target(chip, chip->cur_cs);
nand_read_page_op(chip, page, 0, NULL, 0); nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, NULL, chip->oob_poi); raw_read(chip, NULL, chip->oob_poi);
return 0; return 0;
...@@ -442,6 +479,7 @@ static int tango_read_oob(struct nand_chip *chip, int page) ...@@ -442,6 +479,7 @@ static int tango_read_oob(struct nand_chip *chip, int page)
static int tango_write_oob(struct nand_chip *chip, int page) static int tango_write_oob(struct nand_chip *chip, int page)
{ {
tango_select_target(chip, chip->cur_cs);
nand_prog_page_begin_op(chip, page, 0, NULL, 0); nand_prog_page_begin_op(chip, page, 0, NULL, 0);
raw_write(chip, NULL, chip->oob_poi); raw_write(chip, NULL, chip->oob_poi);
return nand_prog_page_end_op(chip); return nand_prog_page_end_op(chip);
...@@ -477,7 +515,7 @@ static u32 to_ticks(int kHz, int ps) ...@@ -477,7 +515,7 @@ static u32 to_ticks(int kHz, int ps)
} }
static int tango_set_timings(struct nand_chip *chip, int csline, static int tango_set_timings(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf); const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
struct tango_nfc *nfc = to_tango_nfc(chip->controller); struct tango_nfc *nfc = to_tango_nfc(chip->controller);
...@@ -527,7 +565,8 @@ static int tango_attach_chip(struct nand_chip *chip) ...@@ -527,7 +565,8 @@ static int tango_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops tango_controller_ops = { static const struct nand_controller_ops tango_controller_ops = {
.attach_chip = tango_attach_chip, .attach_chip = tango_attach_chip,
.setup_data_interface = tango_set_timings, .setup_interface = tango_set_timings,
.exec_op = tango_exec_op,
}; };
static int chip_init(struct device *dev, struct device_node *np) static int chip_init(struct device *dev, struct device_node *np)
...@@ -562,12 +601,6 @@ static int chip_init(struct device *dev, struct device_node *np) ...@@ -562,12 +601,6 @@ static int chip_init(struct device *dev, struct device_node *np)
ecc = &chip->ecc; ecc = &chip->ecc;
mtd = nand_to_mtd(chip); mtd = nand_to_mtd(chip);
chip->legacy.read_byte = tango_read_byte;
chip->legacy.write_buf = tango_write_buf;
chip->legacy.read_buf = tango_read_buf;
chip->legacy.select_chip = tango_select_chip;
chip->legacy.cmd_ctrl = tango_cmd_ctrl;
chip->legacy.dev_ready = tango_dev_ready;
chip->options = NAND_USES_DMA | chip->options = NAND_USES_DMA |
NAND_NO_SUBPAGE_WRITE | NAND_NO_SUBPAGE_WRITE |
NAND_WAIT_TCCS; NAND_WAIT_TCCS;
......
...@@ -813,8 +813,8 @@ static void tegra_nand_setup_timing(struct tegra_nand_controller *ctrl, ...@@ -813,8 +813,8 @@ static void tegra_nand_setup_timing(struct tegra_nand_controller *ctrl,
writel_relaxed(reg, ctrl->regs + TIMING_2); writel_relaxed(reg, ctrl->regs + TIMING_2);
} }
static int tegra_nand_setup_data_interface(struct nand_chip *chip, int csline, static int tegra_nand_setup_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf) const struct nand_interface_config *conf)
{ {
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
const struct nand_sdr_timings *timings; const struct nand_sdr_timings *timings;
...@@ -1053,7 +1053,7 @@ static int tegra_nand_attach_chip(struct nand_chip *chip) ...@@ -1053,7 +1053,7 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops tegra_nand_controller_ops = { static const struct nand_controller_ops tegra_nand_controller_ops = {
.attach_chip = &tegra_nand_attach_chip, .attach_chip = &tegra_nand_attach_chip,
.exec_op = tegra_nand_exec_op, .exec_op = tegra_nand_exec_op,
.setup_data_interface = tegra_nand_setup_data_interface, .setup_interface = tegra_nand_setup_interface,
}; };
static int tegra_nand_chips_init(struct device *dev, static int tegra_nand_chips_init(struct device *dev,
......
...@@ -22,6 +22,11 @@ ...@@ -22,6 +22,11 @@
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/of.h> #include <linux/of.h>
#ifdef CONFIG_MIPS
#include <asm/bootinfo.h>
#include <asm/fw/cfe/cfe_api.h>
#endif /* CONFIG_MIPS */
#define BCM963XX_CFE_BLOCK_SIZE SZ_64K /* always at least 64KiB */ #define BCM963XX_CFE_BLOCK_SIZE SZ_64K /* always at least 64KiB */
#define BCM963XX_CFE_MAGIC_OFFSET 0x4e0 #define BCM963XX_CFE_MAGIC_OFFSET 0x4e0
...@@ -32,28 +37,15 @@ ...@@ -32,28 +37,15 @@
#define STR_NULL_TERMINATE(x) \ #define STR_NULL_TERMINATE(x) \
do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0) do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0)
static int bcm63xx_detect_cfe(struct mtd_info *master) static inline int bcm63xx_detect_cfe(void)
{ {
char buf[9]; int ret = 0;
int ret;
size_t retlen;
ret = mtd_read(master, BCM963XX_CFE_VERSION_OFFSET, 5, &retlen, #ifdef CONFIG_MIPS
(void *)buf); ret = (fw_arg3 == CFE_EPTSEAL);
buf[retlen] = 0; #endif /* CONFIG_MIPS */
if (ret) return ret;
return ret;
if (strncmp("cfe-v", buf, 5) == 0)
return 0;
/* very old CFE's do not have the cfe-v string, so check for magic */
ret = mtd_read(master, BCM963XX_CFE_MAGIC_OFFSET, 8, &retlen,
(void *)buf);
buf[retlen] = 0;
return strncmp("CFE1CFE1", buf, 8);
} }
static int bcm63xx_read_nvram(struct mtd_info *master, static int bcm63xx_read_nvram(struct mtd_info *master,
...@@ -138,7 +130,7 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, ...@@ -138,7 +130,7 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
struct bcm963xx_nvram *nvram = NULL; struct bcm963xx_nvram *nvram = NULL;
int ret; int ret;
if (bcm63xx_detect_cfe(master)) if (!bcm63xx_detect_cfe())
return -EINVAL; return -EINVAL;
nvram = vzalloc(sizeof(*nvram)); nvram = vzalloc(sizeof(*nvram));
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
struct nand_device;
/** /**
* struct nand_memory_organization - Memory organization structure * struct nand_memory_organization - Memory organization structure
* @bits_per_cell: number of bits per NAND cell * @bits_per_cell: number of bits per NAND cell
...@@ -114,11 +116,11 @@ struct nand_page_io_req { ...@@ -114,11 +116,11 @@ struct nand_page_io_req {
}; };
/** /**
* struct nand_ecc_req - NAND ECC requirements * struct nand_ecc_props - NAND ECC properties
* @strength: ECC strength * @strength: ECC strength
* @step_size: ECC step/block size * @step_size: Number of bytes per step
*/ */
struct nand_ecc_req { struct nand_ecc_props {
unsigned int strength; unsigned int strength;
unsigned int step_size; unsigned int step_size;
}; };
...@@ -133,8 +135,6 @@ struct nand_bbt { ...@@ -133,8 +135,6 @@ struct nand_bbt {
unsigned long *cache; unsigned long *cache;
}; };
struct nand_device;
/** /**
* struct nand_ops - NAND operations * struct nand_ops - NAND operations
* @erase: erase a specific block. No need to check if the block is bad before * @erase: erase a specific block. No need to check if the block is bad before
...@@ -179,7 +179,7 @@ struct nand_ops { ...@@ -179,7 +179,7 @@ struct nand_ops {
struct nand_device { struct nand_device {
struct mtd_info mtd; struct mtd_info mtd;
struct nand_memory_organization memorg; struct nand_memory_organization memorg;
struct nand_ecc_req eccreq; struct nand_ecc_props eccreq;
struct nand_row_converter rowconv; struct nand_row_converter rowconv;
struct nand_bbt bbt; struct nand_bbt bbt;
const struct nand_ops *ops; const struct nand_ops *ops;
......
This diff is collapsed.
...@@ -309,7 +309,7 @@ struct spinand_info { ...@@ -309,7 +309,7 @@ struct spinand_info {
struct spinand_devid devid; struct spinand_devid devid;
u32 flags; u32 flags;
struct nand_memory_organization memorg; struct nand_memory_organization memorg;
struct nand_ecc_req eccreq; struct nand_ecc_props eccreq;
struct spinand_ecc_info eccinfo; struct spinand_ecc_info eccinfo;
struct { struct {
const struct spinand_op_variants *read_cache; const struct spinand_op_variants *read_cache;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment