Commit 35ff96df authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MTD updates from Brian Norris:
 "I've not been very active this cycle, so these are mostly from Boris,
  for the NAND flash subsystem.

  NAND:

   - Add the infrastructure to automate NAND timings configuration

   - Provide a generic DT property to maximize ECC strength

   - Some refactoring in the core bad block table handling, to help with
     improving some of the logic in error cases.

   - Minor cleanups and fixes

  MTD:

   - Add APIs for handling page pairing; this is necessary for reliably
     supporting MLC and TLC NAND flash, where paired-page disturbance
     affects reliability. Upper layers (e.g., UBI) should make use of
     these in the near future"

* tag 'for-linus-20161008' of git://git.infradead.org/linux-mtd: (35 commits)
  mtd: nand: fix trivial spelling error
  mtdpart: Propagate _get/put_device()
  mtd: nand: Provide nand_cleanup() function to free NAND related resources
  mtd: Kill the OF_MTD Kconfig option
  mtd: nand: mxc: Test CONFIG_OF instead of CONFIG_OF_MTD
  mtd: nand: Fix nand_command_lp() for 8bits opcodes
  mtd: nand: sunxi: Support ECC maximization
  mtd: nand: Support maximizing ECC when using software BCH
  mtd: nand: Add an option to maximize the ECC strength
  mtd: nand: mxc: Add timing setup for v2 controllers
  mtd: nand: mxc: implement onfi get/set features
  mtd: nand: sunxi: switch from manual to automated timing config
  mtd: nand: automate NAND timings selection
  mtd: nand: Expose data interface for ONFI mode 0
  mtd: nand: Add function to convert ONFI mode to data_interface
  mtd: nand: convert ONFI mode into data interface
  mtd: nand: Introduce nand_data_interface
  mtd: nand: Create a NAND reset function
  mtd: nand: remove unnecessary 'extern' from function declarations
  MAINTAINERS: Add maintainer entry for Ingenic JZ4780 NAND driver
  ...
parents 97d21167 69db4aa4
...@@ -35,6 +35,15 @@ Optional NAND chip properties: ...@@ -35,6 +35,15 @@ Optional NAND chip properties:
- nand-ecc-step-size: integer representing the number of data bytes - nand-ecc-step-size: integer representing the number of data bytes
that are covered by a single ECC step. that are covered by a single ECC step.
- nand-ecc-maximize: boolean used to specify that you want to maximize ECC
strength. The maximum ECC strength is both controller and
chip dependent. The controller side has to select the ECC
config providing the best strength and taking the OOB area
size constraint into account.
This is particularly useful when only the in-band area is
used by the upper layers, and you want to make your NAND
as reliable as possible.
The ECC strength and ECC step size properties define the correction capability The ECC strength and ECC step size properties define the correction capability
of a controller. Together, they say a controller can correct "{strength} bit of a controller. Together, they say a controller can correct "{strength} bit
errors per {size} bytes". errors per {size} bytes".
......
...@@ -6142,6 +6142,12 @@ M: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> ...@@ -6142,6 +6142,12 @@ M: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
S: Maintained S: Maintained
F: drivers/dma/dma-jz4780.c F: drivers/dma/dma-jz4780.c
INGENIC JZ4780 NAND DRIVER
M: Harvey Hunt <harveyhuntnexus@gmail.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/nand/jz4780_*
INTEGRITY MEASUREMENT ARCHITECTURE (IMA) INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
M: Mimi Zohar <zohar@linux.vnet.ibm.com> M: Mimi Zohar <zohar@linux.vnet.ibm.com>
M: Dmitry Kasatkin <dmitry.kasatkin@gmail.com> M: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
......
...@@ -375,6 +375,110 @@ static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state, ...@@ -375,6 +375,110 @@ static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state,
return NOTIFY_DONE; return NOTIFY_DONE;
} }
/**
* mtd_wunit_to_pairing_info - get pairing information of a wunit
* @mtd: pointer to new MTD device info structure
* @wunit: write unit we are interested in
* @info: returned pairing information
*
* Retrieve pairing information associated to the wunit.
* This is mainly useful when dealing with MLC/TLC NANDs where pages can be
* paired together, and where programming a page may influence the page it is
* paired with.
* The notion of page is replaced by the term wunit (write-unit) to stay
* consistent with the ->writesize field.
*
* The @wunit argument can be extracted from an absolute offset using
* mtd_offset_to_wunit(). @info is filled with the pairing information attached
* to @wunit.
*
* From the pairing info the MTD user can find all the wunits paired with
* @wunit using the following loop:
*
* for (i = 0; i < mtd_pairing_groups(mtd); i++) {
* info.pair = i;
* mtd_pairing_info_to_wunit(mtd, &info);
* ...
* }
*/
int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit,
struct mtd_pairing_info *info)
{
int npairs = mtd_wunit_per_eb(mtd) / mtd_pairing_groups(mtd);
if (wunit < 0 || wunit >= npairs)
return -EINVAL;
if (mtd->pairing && mtd->pairing->get_info)
return mtd->pairing->get_info(mtd, wunit, info);
info->group = 0;
info->pair = wunit;
return 0;
}
EXPORT_SYMBOL_GPL(mtd_wunit_to_pairing_info);
/**
* mtd_wunit_to_pairing_info - get wunit from pairing information
* @mtd: pointer to new MTD device info structure
* @info: pairing information struct
*
* Returns a positive number representing the wunit associated to the info
* struct, or a negative error code.
*
* This is the reverse of mtd_wunit_to_pairing_info(), and can help one to
* iterate over all wunits of a given pair (see mtd_wunit_to_pairing_info()
* doc).
*
* It can also be used to only program the first page of each pair (i.e.
* page attached to group 0), which allows one to use an MLC NAND in
* software-emulated SLC mode:
*
* info.group = 0;
* npairs = mtd_wunit_per_eb(mtd) / mtd_pairing_groups(mtd);
* for (info.pair = 0; info.pair < npairs; info.pair++) {
* wunit = mtd_pairing_info_to_wunit(mtd, &info);
* mtd_write(mtd, mtd_wunit_to_offset(mtd, blkoffs, wunit),
* mtd->writesize, &retlen, buf + (i * mtd->writesize));
* }
*/
int mtd_pairing_info_to_wunit(struct mtd_info *mtd,
const struct mtd_pairing_info *info)
{
int ngroups = mtd_pairing_groups(mtd);
int npairs = mtd_wunit_per_eb(mtd) / ngroups;
if (!info || info->pair < 0 || info->pair >= npairs ||
info->group < 0 || info->group >= ngroups)
return -EINVAL;
if (mtd->pairing && mtd->pairing->get_wunit)
return mtd->pairing->get_wunit(mtd, info);
return info->pair;
}
EXPORT_SYMBOL_GPL(mtd_pairing_info_to_wunit);
/**
* mtd_pairing_groups - get the number of pairing groups
* @mtd: pointer to new MTD device info structure
*
* Returns the number of pairing groups.
*
* This number is usually equal to the number of bits exposed by a single
* cell, and can be used in conjunction with mtd_pairing_info_to_wunit()
* to iterate over all pages of a given pair.
*/
int mtd_pairing_groups(struct mtd_info *mtd)
{
if (!mtd->pairing || !mtd->pairing->ngroups)
return 1;
return mtd->pairing->ngroups;
}
EXPORT_SYMBOL_GPL(mtd_pairing_groups);
/** /**
* add_mtd_device - register an MTD device * add_mtd_device - register an MTD device
* @mtd: pointer to new MTD device info structure * @mtd: pointer to new MTD device info structure
......
...@@ -317,6 +317,18 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -317,6 +317,18 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
return res; return res;
} }
static int part_get_device(struct mtd_info *mtd)
{
struct mtd_part *part = mtd_to_part(mtd);
return part->master->_get_device(part->master);
}
static void part_put_device(struct mtd_info *mtd)
{
struct mtd_part *part = mtd_to_part(mtd);
part->master->_put_device(part->master);
}
static int part_ooblayout_ecc(struct mtd_info *mtd, int section, static int part_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion) struct mtd_oob_region *oobregion)
{ {
...@@ -397,6 +409,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, ...@@ -397,6 +409,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd.oobsize = master->oobsize; slave->mtd.oobsize = master->oobsize;
slave->mtd.oobavail = master->oobavail; slave->mtd.oobavail = master->oobavail;
slave->mtd.subpage_sft = master->subpage_sft; slave->mtd.subpage_sft = master->subpage_sft;
slave->mtd.pairing = master->pairing;
slave->mtd.name = name; slave->mtd.name = name;
slave->mtd.owner = master->owner; slave->mtd.owner = master->owner;
...@@ -463,6 +476,12 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, ...@@ -463,6 +476,12 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd._block_isbad = part_block_isbad; slave->mtd._block_isbad = part_block_isbad;
if (master->_block_markbad) if (master->_block_markbad)
slave->mtd._block_markbad = part_block_markbad; slave->mtd._block_markbad = part_block_markbad;
if (master->_get_device)
slave->mtd._get_device = part_get_device;
if (master->_put_device)
slave->mtd._put_device = part_put_device;
slave->mtd._erase = part_erase; slave->mtd._erase = part_erase;
slave->master = master; slave->master = master;
slave->offset = part->offset; slave->offset = part->offset;
......
...@@ -88,11 +88,11 @@ config MTD_NAND_AMS_DELTA ...@@ -88,11 +88,11 @@ config MTD_NAND_AMS_DELTA
Support for NAND flash on Amstrad E3 (Delta). Support for NAND flash on Amstrad E3 (Delta).
config MTD_NAND_OMAP2 config MTD_NAND_OMAP2
tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4" tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
depends on ARCH_OMAP2PLUS depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
help help
Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4 Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
platforms. and Keystone platforms.
config MTD_NAND_OMAP_BCH config MTD_NAND_OMAP_BCH
depends on MTD_NAND_OMAP2 depends on MTD_NAND_OMAP2
...@@ -428,7 +428,7 @@ config MTD_NAND_ORION ...@@ -428,7 +428,7 @@ config MTD_NAND_ORION
config MTD_NAND_FSL_ELBC config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers" tristate "NAND support for Freescale eLBC controllers"
depends on PPC depends on FSL_SOC
select FSL_LBC select FSL_LBC
help help
Various Freescale chips, including the 8313, include a NAND Flash Various Freescale chips, including the 8313, include a NAND Flash
...@@ -438,7 +438,7 @@ config MTD_NAND_FSL_ELBC ...@@ -438,7 +438,7 @@ config MTD_NAND_FSL_ELBC
config MTD_NAND_FSL_IFC config MTD_NAND_FSL_IFC
tristate "NAND support for Freescale IFC controller" tristate "NAND support for Freescale IFC controller"
depends on MTD_NAND && (FSL_SOC || ARCH_LAYERSCAPE) depends on FSL_SOC || ARCH_LAYERSCAPE
select FSL_IFC select FSL_IFC
select MEMORY select MEMORY
help help
......
...@@ -761,8 +761,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev) ...@@ -761,8 +761,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info); platform_set_drvdata(pdev, info);
spin_lock_init(&info->controller.lock); nand_hw_control_init(&info->controller);
init_waitqueue_head(&info->controller.wq);
info->device = &pdev->dev; info->device = &pdev->dev;
info->platform = plat; info->platform = plat;
......
...@@ -1336,7 +1336,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command, ...@@ -1336,7 +1336,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
u32 *flash_cache = (u32 *)ctrl->flash_cache; u32 *flash_cache = (u32 *)ctrl->flash_cache;
int i; int i;
brcmnand_soc_data_bus_prepare(ctrl->soc); brcmnand_soc_data_bus_prepare(ctrl->soc, true);
/* /*
* Must cache the FLASH_CACHE now, since changes in * Must cache the FLASH_CACHE now, since changes in
...@@ -1349,7 +1349,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command, ...@@ -1349,7 +1349,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
*/ */
flash_cache[i] = be32_to_cpu(brcmnand_read_fc(ctrl, i)); flash_cache[i] = be32_to_cpu(brcmnand_read_fc(ctrl, i));
brcmnand_soc_data_bus_unprepare(ctrl->soc); brcmnand_soc_data_bus_unprepare(ctrl->soc, true);
/* Cleanup from HW quirk: restore SECTOR_SIZE_1K */ /* Cleanup from HW quirk: restore SECTOR_SIZE_1K */
if (host->hwcfg.sector_size_1k) if (host->hwcfg.sector_size_1k)
...@@ -1565,12 +1565,12 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1565,12 +1565,12 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
brcmnand_waitfunc(mtd, chip); brcmnand_waitfunc(mtd, chip);
if (likely(buf)) { if (likely(buf)) {
brcmnand_soc_data_bus_prepare(ctrl->soc); brcmnand_soc_data_bus_prepare(ctrl->soc, false);
for (j = 0; j < FC_WORDS; j++, buf++) for (j = 0; j < FC_WORDS; j++, buf++)
*buf = brcmnand_read_fc(ctrl, j); *buf = brcmnand_read_fc(ctrl, j);
brcmnand_soc_data_bus_unprepare(ctrl->soc); brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
} }
if (oob) if (oob)
...@@ -1815,12 +1815,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1815,12 +1815,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
if (buf) { if (buf) {
brcmnand_soc_data_bus_prepare(ctrl->soc); brcmnand_soc_data_bus_prepare(ctrl->soc, false);
for (j = 0; j < FC_WORDS; j++, buf++) for (j = 0; j < FC_WORDS; j++, buf++)
brcmnand_write_fc(ctrl, j, *buf); brcmnand_write_fc(ctrl, j, *buf);
brcmnand_soc_data_bus_unprepare(ctrl->soc); brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
} else if (oob) { } else if (oob) {
for (j = 0; j < FC_WORDS; j++) for (j = 0; j < FC_WORDS; j++)
brcmnand_write_fc(ctrl, j, 0xffffffff); brcmnand_write_fc(ctrl, j, 0xffffffff);
...@@ -2370,8 +2370,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) ...@@ -2370,8 +2370,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
init_completion(&ctrl->done); init_completion(&ctrl->done);
init_completion(&ctrl->dma_done); init_completion(&ctrl->dma_done);
spin_lock_init(&ctrl->controller.lock); nand_hw_control_init(&ctrl->controller);
init_waitqueue_head(&ctrl->controller.wq);
INIT_LIST_HEAD(&ctrl->host_list); INIT_LIST_HEAD(&ctrl->host_list);
/* NAND register range */ /* NAND register range */
......
...@@ -23,19 +23,22 @@ struct dev_pm_ops; ...@@ -23,19 +23,22 @@ struct dev_pm_ops;
struct brcmnand_soc { struct brcmnand_soc {
bool (*ctlrdy_ack)(struct brcmnand_soc *soc); bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en); void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare); void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
bool is_param);
}; };
static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc) static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc,
bool is_param)
{ {
if (soc && soc->prepare_data_bus) if (soc && soc->prepare_data_bus)
soc->prepare_data_bus(soc, true); soc->prepare_data_bus(soc, true, is_param);
} }
static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc) static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc,
bool is_param)
{ {
if (soc && soc->prepare_data_bus) if (soc && soc->prepare_data_bus)
soc->prepare_data_bus(soc, false); soc->prepare_data_bus(soc, false, is_param);
} }
static inline u32 brcmnand_readl(void __iomem *addr) static inline u32 brcmnand_readl(void __iomem *addr)
......
...@@ -74,7 +74,8 @@ static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en) ...@@ -74,7 +74,8 @@ static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
spin_unlock_irqrestore(&priv->idm_lock, flags); spin_unlock_irqrestore(&priv->idm_lock, flags);
} }
static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare) static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare,
bool is_param)
{ {
struct iproc_nand_soc *priv = struct iproc_nand_soc *priv =
container_of(soc, struct iproc_nand_soc, soc); container_of(soc, struct iproc_nand_soc, soc);
...@@ -86,10 +87,19 @@ static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare) ...@@ -86,10 +87,19 @@ static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
val = brcmnand_readl(mmio); val = brcmnand_readl(mmio);
/*
* In the case of BE or when dealing with NAND data, alway configure
* the APB bus to LE mode before accessing the FIFO and back to BE mode
* after the access is done
*/
if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) || !is_param) {
if (prepare) if (prepare)
val |= IPROC_NAND_APB_LE_MODE; val |= IPROC_NAND_APB_LE_MODE;
else else
val &= ~IPROC_NAND_APB_LE_MODE; val &= ~IPROC_NAND_APB_LE_MODE;
} else { /* when in LE accessing the parameter page, keep APB in BE */
val &= ~IPROC_NAND_APB_LE_MODE;
}
brcmnand_writel(val, mmio); brcmnand_writel(val, mmio);
......
...@@ -1249,8 +1249,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd) ...@@ -1249,8 +1249,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE; nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA; nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
nand->controller = &nand->hwcontrol; nand->controller = &nand->hwcontrol;
spin_lock_init(&nand->controller->lock); nand_hw_control_init(nand->controller);
init_waitqueue_head(&nand->controller->wq);
/* methods */ /* methods */
nand->cmdfunc = docg4_command; nand->cmdfunc = docg4_command;
......
...@@ -879,8 +879,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev) ...@@ -879,8 +879,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
} }
elbc_fcm_ctrl->counter++; elbc_fcm_ctrl->counter++;
spin_lock_init(&elbc_fcm_ctrl->controller.lock); nand_hw_control_init(&elbc_fcm_ctrl->controller);
init_waitqueue_head(&elbc_fcm_ctrl->controller.wq);
fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl; fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
} else { } else {
elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand; elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
......
...@@ -987,8 +987,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev) ...@@ -987,8 +987,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
ifc_nand_ctrl->addr = NULL; ifc_nand_ctrl->addr = NULL;
fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl; fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
spin_lock_init(&ifc_nand_ctrl->controller.lock); nand_hw_control_init(&ifc_nand_ctrl->controller);
init_waitqueue_head(&ifc_nand_ctrl->controller.wq);
} else { } else {
ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand; ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
} }
......
...@@ -318,7 +318,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this) ...@@ -318,7 +318,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
return -EINVAL; return -EINVAL;
} }
geo->page_size = mtd->writesize + mtd->oobsize; geo->page_size = mtd->writesize + geo->metadata_size +
(geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
geo->payload_size = mtd->writesize; geo->payload_size = mtd->writesize;
/* /*
......
...@@ -368,9 +368,8 @@ static int jz4780_nand_probe(struct platform_device *pdev) ...@@ -368,9 +368,8 @@ static int jz4780_nand_probe(struct platform_device *pdev)
nfc->dev = dev; nfc->dev = dev;
nfc->num_banks = num_banks; nfc->num_banks = num_banks;
spin_lock_init(&nfc->controller.lock); nand_hw_control_init(&nfc->controller);
INIT_LIST_HEAD(&nfc->chips); INIT_LIST_HEAD(&nfc->chips);
init_waitqueue_head(&nfc->controller.wq);
ret = jz4780_nand_init_chips(nfc, pdev); ret = jz4780_nand_init_chips(nfc, pdev);
if (ret) { if (ret) {
......
...@@ -152,6 +152,9 @@ struct mxc_nand_devtype_data { ...@@ -152,6 +152,9 @@ struct mxc_nand_devtype_data {
void (*select_chip)(struct mtd_info *mtd, int chip); void (*select_chip)(struct mtd_info *mtd, int chip);
int (*correct_data)(struct mtd_info *mtd, u_char *dat, int (*correct_data)(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc); u_char *read_ecc, u_char *calc_ecc);
int (*setup_data_interface)(struct mtd_info *mtd,
const struct nand_data_interface *conf,
bool check_only);
/* /*
* On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
...@@ -1012,6 +1015,82 @@ static void preset_v1(struct mtd_info *mtd) ...@@ -1012,6 +1015,82 @@ static void preset_v1(struct mtd_info *mtd)
writew(0x4, NFC_V1_V2_WRPROT); writew(0x4, NFC_V1_V2_WRPROT);
} }
static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd,
const struct nand_data_interface *conf,
bool check_only)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
int tRC_min_ns, tRC_ps, ret;
unsigned long rate, rate_round;
const struct nand_sdr_timings *timings;
u16 config1;
timings = nand_get_sdr_timings(conf);
if (IS_ERR(timings))
return -ENOTSUPP;
config1 = readw(NFC_V1_V2_CONFIG1);
tRC_min_ns = timings->tRC_min / 1000;
rate = 1000000000 / tRC_min_ns;
/*
* For tRC < 30ns we have to use EDO mode. In this case the controller
* does one access per clock cycle. Otherwise the controller does one
* access in two clock cycles, thus we have to double the rate to the
* controller.
*/
if (tRC_min_ns < 30) {
rate_round = clk_round_rate(host->clk, rate);
config1 |= NFC_V2_CONFIG1_ONE_CYCLE;
tRC_ps = 1000000000 / (rate_round / 1000);
} else {
rate *= 2;
rate_round = clk_round_rate(host->clk, rate);
config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE;
tRC_ps = 1000000000 / (rate_round / 1000 / 2);
}
/*
* The timing values compared against are from the i.MX25 Automotive
* datasheet, Table 50. NFC Timing Parameters
*/
if (timings->tCLS_min > tRC_ps - 1000 ||
timings->tCLH_min > tRC_ps - 2000 ||
timings->tCS_min > tRC_ps - 1000 ||
timings->tCH_min > tRC_ps - 2000 ||
timings->tWP_min > tRC_ps - 1500 ||
timings->tALS_min > tRC_ps ||
timings->tALH_min > tRC_ps - 3000 ||
timings->tDS_min > tRC_ps ||
timings->tDH_min > tRC_ps - 5000 ||
timings->tWC_min > 2 * tRC_ps ||
timings->tWH_min > tRC_ps - 2500 ||
timings->tRR_min > 6 * tRC_ps ||
timings->tRP_min > 3 * tRC_ps / 2 ||
timings->tRC_min > 2 * tRC_ps ||
timings->tREH_min > (tRC_ps / 2) - 2500) {
dev_dbg(host->dev, "Timing out of bounds\n");
return -EINVAL;
}
if (check_only)
return 0;
ret = clk_set_rate(host->clk, rate);
if (ret)
return ret;
writew(config1, NFC_V1_V2_CONFIG1);
dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round,
config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" :
"normal");
return 0;
}
static void preset_v2(struct mtd_info *mtd) static void preset_v2(struct mtd_info *mtd)
{ {
struct nand_chip *nand_chip = mtd_to_nand(mtd); struct nand_chip *nand_chip = mtd_to_nand(mtd);
...@@ -1239,6 +1318,57 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, ...@@ -1239,6 +1318,57 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
} }
} }
static int mxc_nand_onfi_set_features(struct mtd_info *mtd,
struct nand_chip *chip, int addr,
u8 *subfeature_param)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
int i;
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
host->buf_start = 0;
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
chip->write_byte(mtd, subfeature_param[i]);
memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
mxc_do_addr_cycle(mtd, addr, -1);
host->devtype_data->send_page(mtd, NFC_INPUT);
return 0;
}
static int mxc_nand_onfi_get_features(struct mtd_info *mtd,
struct nand_chip *chip, int addr,
u8 *subfeature_param)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
int i;
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
mxc_do_addr_cycle(mtd, addr, -1);
host->devtype_data->send_page(mtd, NFC_OUTPUT);
memcpy32_fromio(host->data_buf, host->main_area0, 512);
host->buf_start = 0;
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
*subfeature_param++ = chip->read_byte(mtd);
return 0;
}
/* /*
* The generic flash bbt decriptors overlap with our ecc * The generic flash bbt decriptors overlap with our ecc
* hardware, so define some i.MX specific ones. * hardware, so define some i.MX specific ones.
...@@ -1327,6 +1457,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { ...@@ -1327,6 +1457,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
.ooblayout = &mxc_v2_ooblayout_ops, .ooblayout = &mxc_v2_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v2, .select_chip = mxc_nand_select_chip_v2,
.correct_data = mxc_nand_correct_data_v2_v3, .correct_data = mxc_nand_correct_data_v2_v3,
.setup_data_interface = mxc_nand_v2_setup_data_interface,
.irqpending_quirk = 0, .irqpending_quirk = 0,
.needs_ip = 0, .needs_ip = 0,
.regs_offset = 0x1e00, .regs_offset = 0x1e00,
...@@ -1434,7 +1565,7 @@ static const struct platform_device_id mxcnd_devtype[] = { ...@@ -1434,7 +1565,7 @@ static const struct platform_device_id mxcnd_devtype[] = {
}; };
MODULE_DEVICE_TABLE(platform, mxcnd_devtype); MODULE_DEVICE_TABLE(platform, mxcnd_devtype);
#ifdef CONFIG_OF_MTD #ifdef CONFIG_OF
static const struct of_device_id mxcnd_dt_ids[] = { static const struct of_device_id mxcnd_dt_ids[] = {
{ {
.compatible = "fsl,imx21-nand", .compatible = "fsl,imx21-nand",
...@@ -1513,6 +1644,8 @@ static int mxcnd_probe(struct platform_device *pdev) ...@@ -1513,6 +1644,8 @@ static int mxcnd_probe(struct platform_device *pdev)
this->read_word = mxc_nand_read_word; this->read_word = mxc_nand_read_word;
this->write_buf = mxc_nand_write_buf; this->write_buf = mxc_nand_write_buf;
this->read_buf = mxc_nand_read_buf; this->read_buf = mxc_nand_read_buf;
this->onfi_set_features = mxc_nand_onfi_set_features;
this->onfi_get_features = mxc_nand_onfi_get_features;
host->clk = devm_clk_get(&pdev->dev, NULL); host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk)) if (IS_ERR(host->clk))
...@@ -1533,6 +1666,8 @@ static int mxcnd_probe(struct platform_device *pdev) ...@@ -1533,6 +1666,8 @@ static int mxcnd_probe(struct platform_device *pdev)
if (err < 0) if (err < 0)
return err; return err;
this->setup_data_interface = host->devtype_data->setup_data_interface;
if (host->devtype_data->needs_ip) { if (host->devtype_data->needs_ip) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->regs_ip = devm_ioremap_resource(&pdev->dev, res); host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
......
...@@ -745,6 +745,9 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, ...@@ -745,6 +745,9 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
column >>= 1; column >>= 1;
chip->cmd_ctrl(mtd, column, ctrl); chip->cmd_ctrl(mtd, column, ctrl);
ctrl &= ~NAND_CTRL_CHANGE; ctrl &= ~NAND_CTRL_CHANGE;
/* Only output a single addr cycle for 8bits opcodes. */
if (!nand_opcode_8bits(command))
chip->cmd_ctrl(mtd, column >> 8, ctrl); chip->cmd_ctrl(mtd, column >> 8, ctrl);
} }
if (page_addr != -1) { if (page_addr != -1) {
...@@ -947,6 +950,172 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) ...@@ -947,6 +950,172 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
return status; return status;
} }
/**
* nand_reset_data_interface - Reset data interface and timings
* @chip: The NAND chip
*
* Reset the Data interface and timings to ONFI mode 0.
*
* Returns 0 for success or negative error code otherwise.
*/
static int nand_reset_data_interface(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_data_interface *conf;
int ret;
if (!chip->setup_data_interface)
return 0;
/*
* The ONFI specification says:
* "
* To transition from NV-DDR or NV-DDR2 to the SDR data
* interface, the host shall use the Reset (FFh) command
* using SDR timing mode 0. A device in any timing mode is
* required to recognize Reset (FFh) command issued in SDR
* timing mode 0.
* "
*
* Configure the data interface in SDR mode and set the
* timings to timing mode 0.
*/
conf = nand_get_default_data_interface();
ret = chip->setup_data_interface(mtd, conf, false);
if (ret)
pr_err("Failed to configure data interface to SDR timing mode 0\n");
return ret;
}
/**
* nand_setup_data_interface - Setup the best data interface and timings
* @chip: The NAND chip
*
* Find and configure the best data interface and NAND timings supported by
* the chip and the driver.
* First tries to retrieve supported timing modes from ONFI information,
* and if the NAND chip does not support ONFI, relies on the
* ->onfi_timing_mode_default specified in the nand_ids table.
*
* Returns 0 for success or negative error code otherwise.
*/
static int nand_setup_data_interface(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
if (!chip->setup_data_interface || !chip->data_interface)
return 0;
/*
* Ensure the timing mode has been changed on the chip side
* before changing timings on the controller side.
*/
if (chip->onfi_version) {
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
chip->onfi_timing_mode_default,
};
ret = chip->onfi_set_features(mtd, chip,
ONFI_FEATURE_ADDR_TIMING_MODE,
tmode_param);
if (ret)
goto err;
}
ret = chip->setup_data_interface(mtd, chip->data_interface, false);
err:
return ret;
}
/**
* nand_init_data_interface - find the best data interface and timings
* @chip: The NAND chip
*
* Find the best data interface and NAND timings supported by the chip
* and the driver.
* First tries to retrieve supported timing modes from ONFI information,
* and if the NAND chip does not support ONFI, relies on the
* ->onfi_timing_mode_default specified in the nand_ids table. After this
* function nand_chip->data_interface is initialized with the best timing mode
* available.
*
* Returns 0 for success or negative error code otherwise.
*/
static int nand_init_data_interface(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int modes, mode, ret;
if (!chip->setup_data_interface)
return 0;
/*
* First try to identify the best timings from ONFI parameters and
* if the NAND does not support ONFI, fallback to the default ONFI
* timing mode.
*/
modes = onfi_get_async_timing_mode(chip);
if (modes == ONFI_TIMING_MODE_UNKNOWN) {
if (!chip->onfi_timing_mode_default)
return 0;
modes = GENMASK(chip->onfi_timing_mode_default, 0);
}
chip->data_interface = kzalloc(sizeof(*chip->data_interface),
GFP_KERNEL);
if (!chip->data_interface)
return -ENOMEM;
for (mode = fls(modes) - 1; mode >= 0; mode--) {
ret = onfi_init_data_interface(chip, chip->data_interface,
NAND_SDR_IFACE, mode);
if (ret)
continue;
ret = chip->setup_data_interface(mtd, chip->data_interface,
true);
if (!ret) {
chip->onfi_timing_mode_default = mode;
break;
}
}
return 0;
}
static void nand_release_data_interface(struct nand_chip *chip)
{
kfree(chip->data_interface);
}
/**
* nand_reset - Reset and initialize a NAND device
* @chip: The NAND chip
*
* Returns 0 for success or negative error code otherwise
*/
int nand_reset(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
ret = nand_reset_data_interface(chip);
if (ret)
return ret;
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
ret = nand_setup_data_interface(chip);
if (ret)
return ret;
return 0;
}
/** /**
* __nand_unlock - [REPLACEABLE] unlocks specified locked blocks * __nand_unlock - [REPLACEABLE] unlocks specified locked blocks
* @mtd: mtd info * @mtd: mtd info
...@@ -1025,7 +1194,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -1025,7 +1194,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
* some operation can also clear the bit 7 of status register * some operation can also clear the bit 7 of status register
* eg. erase/program a locked block * eg. erase/program a locked block
*/ */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset(chip);
/* Check, if it is write protected */ /* Check, if it is write protected */
if (nand_check_wp(mtd)) { if (nand_check_wp(mtd)) {
...@@ -1084,7 +1253,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -1084,7 +1253,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
* some operation can also clear the bit 7 of status register * some operation can also clear the bit 7 of status register
* eg. erase/program a locked block * eg. erase/program a locked block
*/ */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset(chip);
/* Check, if it is write protected */ /* Check, if it is write protected */
if (nand_check_wp(mtd)) { if (nand_check_wp(mtd)) {
...@@ -2162,7 +2331,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -2162,7 +2331,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
static int nand_read_oob(struct mtd_info *mtd, loff_t from, static int nand_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops) struct mtd_oob_ops *ops)
{ {
int ret = -ENOTSUPP; int ret;
ops->retlen = 0; ops->retlen = 0;
...@@ -2173,24 +2342,18 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -2173,24 +2342,18 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
return -EINVAL; return -EINVAL;
} }
nand_get_device(mtd, FL_READING); if (ops->mode != MTD_OPS_PLACE_OOB &&
ops->mode != MTD_OPS_AUTO_OOB &&
switch (ops->mode) { ops->mode != MTD_OPS_RAW)
case MTD_OPS_PLACE_OOB: return -ENOTSUPP;
case MTD_OPS_AUTO_OOB:
case MTD_OPS_RAW:
break;
default: nand_get_device(mtd, FL_READING);
goto out;
}
if (!ops->datbuf) if (!ops->datbuf)
ret = nand_do_read_oob(mtd, from, ops); ret = nand_do_read_oob(mtd, from, ops);
else else
ret = nand_do_read_ops(mtd, from, ops); ret = nand_do_read_ops(mtd, from, ops);
out:
nand_release_device(mtd); nand_release_device(mtd);
return ret; return ret;
} }
...@@ -2788,7 +2951,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, ...@@ -2788,7 +2951,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
* if we don't do this. I have no clue why, but I seem to have 'fixed' * if we don't do this. I have no clue why, but I seem to have 'fixed'
* it in the doc2000 driver in August 1999. dwmw2. * it in the doc2000 driver in August 1999. dwmw2.
*/ */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset(chip);
/* Check, if it is write protected */ /* Check, if it is write protected */
if (nand_check_wp(mtd)) { if (nand_check_wp(mtd)) {
...@@ -3191,8 +3354,7 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) ...@@ -3191,8 +3354,7 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
if (!chip->controller) { if (!chip->controller) {
chip->controller = &chip->hwcontrol; chip->controller = &chip->hwcontrol;
spin_lock_init(&chip->controller->lock); nand_hw_control_init(chip->controller);
init_waitqueue_head(&chip->controller->wq);
} }
} }
...@@ -3829,7 +3991,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, ...@@ -3829,7 +3991,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
* after power-up. * after power-up.
*/ */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset(chip);
/* Send the command for reading device ID */ /* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
...@@ -4113,6 +4275,9 @@ static int nand_dt_init(struct nand_chip *chip) ...@@ -4113,6 +4275,9 @@ static int nand_dt_init(struct nand_chip *chip)
if (ecc_step > 0) if (ecc_step > 0)
chip->ecc.size = ecc_step; chip->ecc.size = ecc_step;
if (of_property_read_bool(dn, "nand-ecc-maximize"))
chip->ecc.options |= NAND_ECC_MAXIMIZE;
return 0; return 0;
} }
...@@ -4141,6 +4306,15 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, ...@@ -4141,6 +4306,15 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
if (!mtd->name && mtd->dev.parent) if (!mtd->name && mtd->dev.parent)
mtd->name = dev_name(mtd->dev.parent); mtd->name = dev_name(mtd->dev.parent);
if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) {
/*
* Default functions assigned for chip_select() and
* cmdfunc() both expect cmd_ctrl() to be populated,
* so we need to check that that's the case
*/
pr_err("chip.cmd_ctrl() callback is not provided");
return -EINVAL;
}
/* Set the default functions */ /* Set the default functions */
nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16); nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
...@@ -4155,13 +4329,17 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, ...@@ -4155,13 +4329,17 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
return PTR_ERR(type); return PTR_ERR(type);
} }
ret = nand_init_data_interface(chip);
if (ret)
return ret;
chip->select_chip(mtd, -1); chip->select_chip(mtd, -1);
/* Check for a chip array */ /* Check for a chip array */
for (i = 1; i < maxchips; i++) { for (i = 1; i < maxchips; i++) {
chip->select_chip(mtd, i); chip->select_chip(mtd, i);
/* See comment in nand_get_flash_type for reset */ /* See comment in nand_get_flash_type for reset */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset(chip);
/* Send the command for reading device ID */ /* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */ /* Read manufacturer and device IDs */
...@@ -4221,6 +4399,7 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd) ...@@ -4221,6 +4399,7 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
ecc->write_page_raw = nand_write_page_raw; ecc->write_page_raw = nand_write_page_raw;
ecc->read_oob = nand_read_oob_std; ecc->read_oob = nand_read_oob_std;
ecc->write_oob = nand_write_oob_std; ecc->write_oob = nand_write_oob_std;
/* /*
* Board driver should supply ecc.size and ecc.strength * Board driver should supply ecc.size and ecc.strength
* values to select how many bits are correctable. * values to select how many bits are correctable.
...@@ -4243,6 +4422,25 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd) ...@@ -4243,6 +4422,25 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
} }
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
}
/*
* We can only maximize ECC config when the default layout is
* used, otherwise we don't know how many bytes can really be
* used.
*/
if (mtd->ooblayout == &nand_ooblayout_lp_ops &&
ecc->options & NAND_ECC_MAXIMIZE) {
int steps, bytes;
/* Always prefer 1k blocks over 512bytes ones */
ecc->size = 1024;
steps = mtd->writesize / ecc->size;
/* Reserve 2 bytes for the BBM */
bytes = (mtd->oobsize - 2) / steps;
ecc->strength = bytes * 8 / fls(8 * ecc->size);
} }
/* See nand_bch_init() for details. */ /* See nand_bch_init() for details. */
...@@ -4601,18 +4799,16 @@ int nand_scan(struct mtd_info *mtd, int maxchips) ...@@ -4601,18 +4799,16 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
EXPORT_SYMBOL(nand_scan); EXPORT_SYMBOL(nand_scan);
/** /**
* nand_release - [NAND Interface] Free resources held by the NAND device * nand_cleanup - [NAND Interface] Free resources held by the NAND device
* @mtd: MTD device structure * @chip: NAND chip object
*/ */
void nand_release(struct mtd_info *mtd) void nand_cleanup(struct nand_chip *chip)
{ {
struct nand_chip *chip = mtd_to_nand(mtd);
if (chip->ecc.mode == NAND_ECC_SOFT && if (chip->ecc.mode == NAND_ECC_SOFT &&
chip->ecc.algo == NAND_ECC_BCH) chip->ecc.algo == NAND_ECC_BCH)
nand_bch_free((struct nand_bch_control *)chip->ecc.priv); nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
mtd_device_unregister(mtd); nand_release_data_interface(chip);
/* Free bad block table memory */ /* Free bad block table memory */
kfree(chip->bbt); kfree(chip->bbt);
...@@ -4624,6 +4820,18 @@ void nand_release(struct mtd_info *mtd) ...@@ -4624,6 +4820,18 @@ void nand_release(struct mtd_info *mtd)
& NAND_BBT_DYNAMICSTRUCT) & NAND_BBT_DYNAMICSTRUCT)
kfree(chip->badblock_pattern); kfree(chip->badblock_pattern);
} }
EXPORT_SYMBOL_GPL(nand_cleanup);
/**
* nand_release - [NAND Interface] Unregister the MTD device and free resources
* held by the NAND device
* @mtd: MTD device structure
*/
void nand_release(struct mtd_info *mtd)
{
mtd_device_unregister(mtd);
nand_cleanup(mtd_to_nand(mtd));
}
EXPORT_SYMBOL_GPL(nand_release); EXPORT_SYMBOL_GPL(nand_release);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -604,6 +604,100 @@ static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf, ...@@ -604,6 +604,100 @@ static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
search_bbt(mtd, buf, md); search_bbt(mtd, buf, md);
} }
/**
* get_bbt_block - Get the first valid eraseblock suitable to store a BBT
* @this: the NAND device
* @td: the BBT description
* @md: the mirror BBT descriptor
* @chip: the CHIP selector
*
* This functions returns a positive block number pointing a valid eraseblock
* suitable to store a BBT (i.e. in the range reserved for BBT), or -ENOSPC if
* all blocks are already used of marked bad. If td->pages[chip] was already
* pointing to a valid block we re-use it, otherwise we search for the next
* valid one.
*/
static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
struct nand_bbt_descr *md, int chip)
{
int startblock, dir, page, numblocks, i;
/*
* There was already a version of the table, reuse the page. This
* applies for absolute placement too, as we have the page number in
* td->pages.
*/
if (td->pages[chip] != -1)
return td->pages[chip] >>
(this->bbt_erase_shift - this->page_shift);
numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
if (!(td->options & NAND_BBT_PERCHIP))
numblocks *= this->numchips;
/*
* Automatic placement of the bad block table. Search direction
* top -> down?
*/
if (td->options & NAND_BBT_LASTBLOCK) {
startblock = numblocks * (chip + 1) - 1;
dir = -1;
} else {
startblock = chip * numblocks;
dir = 1;
}
for (i = 0; i < td->maxblocks; i++) {
int block = startblock + dir * i;
/* Check, if the block is bad */
switch (bbt_get_entry(this, block)) {
case BBT_BLOCK_WORN:
case BBT_BLOCK_FACTORY_BAD:
continue;
}
page = block << (this->bbt_erase_shift - this->page_shift);
/* Check, if the block is used by the mirror table */
if (!md || md->pages[chip] != page)
return block;
}
return -ENOSPC;
}
/**
* mark_bbt_block_bad - Mark one of the block reserved for BBT bad
* @this: the NAND device
* @td: the BBT description
* @chip: the CHIP selector
* @block: the BBT block to mark
*
* Blocks reserved for BBT can become bad. This functions is an helper to mark
* such blocks as bad. It takes care of updating the in-memory BBT, marking the
* block as bad using a bad block marker and invalidating the associated
* td->pages[] entry.
*/
static void mark_bbt_block_bad(struct nand_chip *this,
struct nand_bbt_descr *td,
int chip, int block)
{
struct mtd_info *mtd = nand_to_mtd(this);
loff_t to;
int res;
bbt_mark_entry(this, block, BBT_BLOCK_WORN);
to = (loff_t)block << this->bbt_erase_shift;
res = this->block_markbad(mtd, to);
if (res)
pr_warn("nand_bbt: error %d while marking block %d bad\n",
res, block);
td->pages[chip] = -1;
}
/** /**
* write_bbt - [GENERIC] (Re)write the bad block table * write_bbt - [GENERIC] (Re)write the bad block table
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -621,7 +715,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, ...@@ -621,7 +715,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_chip *this = mtd_to_nand(mtd); struct nand_chip *this = mtd_to_nand(mtd);
struct erase_info einfo; struct erase_info einfo;
int i, res, chip = 0; int i, res, chip = 0;
int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; int bits, page, offs, numblocks, sft, sftmsk;
int nrchips, pageoffs, ooboffs; int nrchips, pageoffs, ooboffs;
uint8_t msk[4]; uint8_t msk[4];
uint8_t rcode = td->reserved_block_code; uint8_t rcode = td->reserved_block_code;
...@@ -652,46 +746,21 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, ...@@ -652,46 +746,21 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
} }
/* Loop through the chips */ /* Loop through the chips */
for (; chip < nrchips; chip++) { while (chip < nrchips) {
/* int block;
* There was already a version of the table, reuse the page
* This applies for absolute placement too, as we have the block = get_bbt_block(this, td, md, chip);
* page nr. in td->pages. if (block < 0) {
*/ pr_err("No space left to write bad block table\n");
if (td->pages[chip] != -1) { res = block;
page = td->pages[chip]; goto outerr;
goto write;
} }
/* /*
* Automatic placement of the bad block table. Search direction * get_bbt_block() returns a block number, shift the value to
* top -> down? * get a page number.
*/ */
if (td->options & NAND_BBT_LASTBLOCK) { page = block << (this->bbt_erase_shift - this->page_shift);
startblock = numblocks * (chip + 1) - 1;
dir = -1;
} else {
startblock = chip * numblocks;
dir = 1;
}
for (i = 0; i < td->maxblocks; i++) {
int block = startblock + dir * i;
/* Check, if the block is bad */
switch (bbt_get_entry(this, block)) {
case BBT_BLOCK_WORN:
case BBT_BLOCK_FACTORY_BAD:
continue;
}
page = block <<
(this->bbt_erase_shift - this->page_shift);
/* Check, if the block is used by the mirror table */
if (!md || md->pages[chip] != page)
goto write;
}
pr_err("No space left to write bad block table\n");
return -ENOSPC;
write:
/* Set up shift count and masks for the flash table */ /* Set up shift count and masks for the flash table */
bits = td->options & NAND_BBT_NRBITS_MSK; bits = td->options & NAND_BBT_NRBITS_MSK;
...@@ -787,20 +856,28 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, ...@@ -787,20 +856,28 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
einfo.addr = to; einfo.addr = to;
einfo.len = 1 << this->bbt_erase_shift; einfo.len = 1 << this->bbt_erase_shift;
res = nand_erase_nand(mtd, &einfo, 1); res = nand_erase_nand(mtd, &einfo, 1);
if (res < 0) if (res < 0) {
goto outerr; pr_warn("nand_bbt: error while erasing BBT block %d\n",
res);
mark_bbt_block_bad(this, td, chip, block);
continue;
}
res = scan_write_bbt(mtd, to, len, buf, res = scan_write_bbt(mtd, to, len, buf,
td->options & NAND_BBT_NO_OOB ? NULL : td->options & NAND_BBT_NO_OOB ? NULL :
&buf[len]); &buf[len]);
if (res < 0) if (res < 0) {
goto outerr; pr_warn("nand_bbt: error while writing BBT block %d\n",
res);
mark_bbt_block_bad(this, td, chip, block);
continue;
}
pr_info("Bad block table written to 0x%012llx, version 0x%02X\n", pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
(unsigned long long)to, td->version[chip]); (unsigned long long)to, td->version[chip]);
/* Mark it as used */ /* Mark it as used */
td->pages[chip] = page; td->pages[chip++] = page;
} }
return 0; return 0;
......
...@@ -13,10 +13,12 @@ ...@@ -13,10 +13,12 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/mtd/nand.h> #include <linux/mtd/nand.h>
static const struct nand_sdr_timings onfi_sdr_timings[] = { static const struct nand_data_interface onfi_sdr_timings[] = {
/* Mode 0 */ /* Mode 0 */
{ {
.tADL_min = 200000, .type = NAND_SDR_IFACE,
.timings.sdr = {
.tADL_min = 400000,
.tALH_min = 20000, .tALH_min = 20000,
.tALS_min = 50000, .tALS_min = 50000,
.tAR_min = 25000, .tAR_min = 25000,
...@@ -42,18 +44,21 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = { ...@@ -42,18 +44,21 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = {
.tRHZ_max = 200000, .tRHZ_max = 200000,
.tRLOH_min = 0, .tRLOH_min = 0,
.tRP_min = 50000, .tRP_min = 50000,
.tRR_min = 40000,
.tRST_max = 250000000000ULL, .tRST_max = 250000000000ULL,
.tWB_max = 200000, .tWB_max = 200000,
.tRR_min = 40000,
.tWC_min = 100000, .tWC_min = 100000,
.tWH_min = 30000, .tWH_min = 30000,
.tWHR_min = 120000, .tWHR_min = 120000,
.tWP_min = 50000, .tWP_min = 50000,
.tWW_min = 100000, .tWW_min = 100000,
}, },
},
/* Mode 1 */ /* Mode 1 */
{ {
.tADL_min = 100000, .type = NAND_SDR_IFACE,
.timings.sdr = {
.tADL_min = 400000,
.tALH_min = 10000, .tALH_min = 10000,
.tALS_min = 25000, .tALS_min = 25000,
.tAR_min = 10000, .tAR_min = 10000,
...@@ -88,9 +93,12 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = { ...@@ -88,9 +93,12 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = {
.tWP_min = 25000, .tWP_min = 25000,
.tWW_min = 100000, .tWW_min = 100000,
}, },
},
/* Mode 2 */ /* Mode 2 */
{ {
.tADL_min = 100000, .type = NAND_SDR_IFACE,
.timings.sdr = {
.tADL_min = 400000,
.tALH_min = 10000, .tALH_min = 10000,
.tALS_min = 15000, .tALS_min = 15000,
.tAR_min = 10000, .tAR_min = 10000,
...@@ -125,9 +133,12 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = { ...@@ -125,9 +133,12 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = {
.tWP_min = 17000, .tWP_min = 17000,
.tWW_min = 100000, .tWW_min = 100000,
}, },
},
/* Mode 3 */ /* Mode 3 */
{ {
.tADL_min = 100000, .type = NAND_SDR_IFACE,
.timings.sdr = {
.tADL_min = 400000,
.tALH_min = 5000, .tALH_min = 5000,
.tALS_min = 10000, .tALS_min = 10000,
.tAR_min = 10000, .tAR_min = 10000,
...@@ -162,9 +173,12 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = { ...@@ -162,9 +173,12 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = {
.tWP_min = 15000, .tWP_min = 15000,
.tWW_min = 100000, .tWW_min = 100000,
}, },
},
/* Mode 4 */ /* Mode 4 */
{ {
.tADL_min = 70000, .type = NAND_SDR_IFACE,
.timings.sdr = {
.tADL_min = 400000,
.tALH_min = 5000, .tALH_min = 5000,
.tALS_min = 10000, .tALS_min = 10000,
.tAR_min = 10000, .tAR_min = 10000,
...@@ -199,9 +213,12 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = { ...@@ -199,9 +213,12 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = {
.tWP_min = 12000, .tWP_min = 12000,
.tWW_min = 100000, .tWW_min = 100000,
}, },
},
/* Mode 5 */ /* Mode 5 */
{ {
.tADL_min = 70000, .type = NAND_SDR_IFACE,
.timings.sdr = {
.tADL_min = 400000,
.tALH_min = 5000, .tALH_min = 5000,
.tALS_min = 10000, .tALS_min = 10000,
.tAR_min = 10000, .tAR_min = 10000,
...@@ -236,6 +253,7 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = { ...@@ -236,6 +253,7 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = {
.tWP_min = 10000, .tWP_min = 10000,
.tWW_min = 100000, .tWW_min = 100000,
}, },
},
}; };
/** /**
...@@ -248,6 +266,46 @@ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode) ...@@ -248,6 +266,46 @@ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings)) if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
return &onfi_sdr_timings[mode]; return &onfi_sdr_timings[mode].timings.sdr;
} }
EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings); EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
/**
* onfi_init_data_interface - [NAND Interface] Initialize a data interface from
* given ONFI mode
* @iface: The data interface to be initialized
* @mode: The ONFI timing mode
*/
int onfi_init_data_interface(struct nand_chip *chip,
struct nand_data_interface *iface,
enum nand_data_interface_type type,
int timing_mode)
{
if (type != NAND_SDR_IFACE)
return -EINVAL;
if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
return -EINVAL;
*iface = onfi_sdr_timings[timing_mode];
/*
* TODO: initialize timings that cannot be deduced from timing mode:
* tR, tPROG, tCCS, ...
* These information are part of the ONFI parameter page.
*/
return 0;
}
EXPORT_SYMBOL(onfi_init_data_interface);
/**
* nand_get_default_data_interface - [NAND Interface] Retrieve NAND
* data interface for mode 0. This is used as default timing after
* reset.
*/
const struct nand_data_interface *nand_get_default_data_interface(void)
{
return &onfi_sdr_timings[0];
}
EXPORT_SYMBOL(nand_get_default_data_interface);
...@@ -218,8 +218,7 @@ static int ndfc_probe(struct platform_device *ofdev) ...@@ -218,8 +218,7 @@ static int ndfc_probe(struct platform_device *ofdev)
ndfc = &ndfc_ctrl[cs]; ndfc = &ndfc_ctrl[cs];
ndfc->chip_select = cs; ndfc->chip_select = cs;
spin_lock_init(&ndfc->ndfc_control.lock); nand_hw_control_init(&ndfc->ndfc_control);
init_waitqueue_head(&ndfc->ndfc_control.wq);
ndfc->ofdev = ofdev; ndfc->ofdev = ofdev;
dev_set_drvdata(&ofdev->dev, ndfc); dev_set_drvdata(&ofdev->dev, ndfc);
......
...@@ -1810,8 +1810,7 @@ static int alloc_nand_resource(struct platform_device *pdev) ...@@ -1810,8 +1810,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
chip->cmdfunc = nand_cmdfunc; chip->cmdfunc = nand_cmdfunc;
} }
spin_lock_init(&chip->controller->lock); nand_hw_control_init(chip->controller);
init_waitqueue_head(&chip->controller->wq);
info->clk = devm_clk_get(&pdev->dev, NULL); info->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk)) { if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed to get nand clock\n"); dev_err(&pdev->dev, "failed to get nand clock\n");
......
...@@ -1957,8 +1957,7 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) ...@@ -1957,8 +1957,7 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
INIT_LIST_HEAD(&nandc->desc_list); INIT_LIST_HEAD(&nandc->desc_list);
INIT_LIST_HEAD(&nandc->host_list); INIT_LIST_HEAD(&nandc->host_list);
spin_lock_init(&nandc->controller.lock); nand_hw_control_init(&nandc->controller);
init_waitqueue_head(&nandc->controller.wq);
return 0; return 0;
} }
......
...@@ -180,7 +180,7 @@ struct s3c2410_nand_info { ...@@ -180,7 +180,7 @@ struct s3c2410_nand_info {
enum s3c_cpu_type cpu_type; enum s3c_cpu_type cpu_type;
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_ARM_S3C24XX_CPUFREQ
struct notifier_block freq_transition; struct notifier_block freq_transition;
#endif #endif
}; };
...@@ -701,7 +701,7 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, ...@@ -701,7 +701,7 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
/* cpufreq driver support */ /* cpufreq driver support */
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_ARM_S3C24XX_CPUFREQ
static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb, static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb,
unsigned long val, void *data) unsigned long val, void *data)
...@@ -977,8 +977,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) ...@@ -977,8 +977,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info); platform_set_drvdata(pdev, info);
spin_lock_init(&info->controller.lock); nand_hw_control_init(&info->controller);
init_waitqueue_head(&info->controller.wq);
/* get the clock source and enable it */ /* get the clock source and enable it */
......
...@@ -397,7 +397,7 @@ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf, ...@@ -397,7 +397,7 @@ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
struct dma_chan *chan; struct dma_chan *chan;
enum dma_transfer_direction tr_dir; enum dma_transfer_direction tr_dir;
dma_addr_t dma_addr; dma_addr_t dma_addr;
dma_cookie_t cookie = -EINVAL; dma_cookie_t cookie;
uint32_t reg; uint32_t reg;
int ret; int ret;
...@@ -423,6 +423,12 @@ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf, ...@@ -423,6 +423,12 @@ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
desc->callback = flctl_dma_complete; desc->callback = flctl_dma_complete;
desc->callback_param = flctl; desc->callback_param = flctl;
cookie = dmaengine_submit(desc); cookie = dmaengine_submit(desc);
if (dma_submit_error(cookie)) {
ret = dma_submit_error(cookie);
dev_warn(&flctl->pdev->dev,
"DMA submit failed, falling back to PIO\n");
goto out;
}
dma_async_issue_pending(chan); dma_async_issue_pending(chan);
} else { } else {
......
...@@ -1572,14 +1572,22 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration, ...@@ -1572,14 +1572,22 @@ 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_nand_chip_set_timings(struct sunxi_nand_chip *chip, static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd,
const struct nand_sdr_timings *timings) const struct nand_data_interface *conf,
bool check_only)
{ {
struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller); struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
const struct nand_sdr_timings *timings;
u32 min_clk_period = 0; u32 min_clk_period = 0;
s32 tWB, tADL, tWHR, tRHW, tCAD; s32 tWB, tADL, tWHR, tRHW, tCAD;
long real_clk_rate; long real_clk_rate;
timings = nand_get_sdr_timings(conf);
if (IS_ERR(timings))
return -ENOTSUPP;
/* T1 <=> tCLS */ /* T1 <=> tCLS */
if (timings->tCLS_min > min_clk_period) if (timings->tCLS_min > min_clk_period)
min_clk_period = timings->tCLS_min; min_clk_period = timings->tCLS_min;
...@@ -1679,6 +1687,9 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, ...@@ -1679,6 +1687,9 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
return tRHW; return tRHW;
} }
if (check_only)
return 0;
/* /*
* TODO: according to ONFI specs this value only applies for DDR NAND, * TODO: according to ONFI specs this value only applies for DDR NAND,
* but Allwinner seems to set this to 0x7. Mimic them for now. * but Allwinner seems to set this to 0x7. Mimic them for now.
...@@ -1712,44 +1723,6 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, ...@@ -1712,44 +1723,6 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
return 0; return 0;
} }
static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
struct device_node *np)
{
struct mtd_info *mtd = nand_to_mtd(&chip->nand);
const struct nand_sdr_timings *timings;
int ret;
int mode;
mode = onfi_get_async_timing_mode(&chip->nand);
if (mode == ONFI_TIMING_MODE_UNKNOWN) {
mode = chip->nand.onfi_timing_mode_default;
} else {
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {};
int i;
mode = fls(mode) - 1;
if (mode < 0)
mode = 0;
feature[0] = mode;
for (i = 0; i < chip->nsels; i++) {
chip->nand.select_chip(mtd, i);
ret = chip->nand.onfi_set_features(mtd, &chip->nand,
ONFI_FEATURE_ADDR_TIMING_MODE,
feature);
chip->nand.select_chip(mtd, -1);
if (ret)
return ret;
}
}
timings = onfi_async_timing_mode_to_sdr_timings(mode);
if (IS_ERR(timings))
return PTR_ERR(timings);
return sunxi_nand_chip_set_timings(chip, timings);
}
static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section, static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion) struct mtd_oob_region *oobregion)
{ {
...@@ -1814,6 +1787,35 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, ...@@ -1814,6 +1787,35 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
int ret; int ret;
int i; int i;
if (ecc->options & NAND_ECC_MAXIMIZE) {
int bytes;
ecc->size = 1024;
nsectors = mtd->writesize / ecc->size;
/* Reserve 2 bytes for the BBM */
bytes = (mtd->oobsize - 2) / nsectors;
/* 4 non-ECC bytes are added before each ECC bytes section */
bytes -= 4;
/* and bytes has to be even. */
if (bytes % 2)
bytes--;
ecc->strength = bytes * 8 / fls(8 * ecc->size);
for (i = 0; i < ARRAY_SIZE(strengths); i++) {
if (strengths[i] > ecc->strength)
break;
}
if (!i)
ecc->strength = 0;
else
ecc->strength = strengths[i - 1];
}
if (ecc->size != 512 && ecc->size != 1024) if (ecc->size != 512 && ecc->size != 1024)
return -EINVAL; return -EINVAL;
...@@ -1975,7 +1977,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc, ...@@ -1975,7 +1977,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
struct device_node *np) struct device_node *np)
{ {
const struct nand_sdr_timings *timings;
struct sunxi_nand_chip *chip; struct sunxi_nand_chip *chip;
struct mtd_info *mtd; struct mtd_info *mtd;
struct nand_chip *nand; struct nand_chip *nand;
...@@ -2065,25 +2066,11 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, ...@@ -2065,25 +2066,11 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
nand->read_buf = sunxi_nfc_read_buf; nand->read_buf = sunxi_nfc_read_buf;
nand->write_buf = sunxi_nfc_write_buf; nand->write_buf = sunxi_nfc_write_buf;
nand->read_byte = sunxi_nfc_read_byte; nand->read_byte = sunxi_nfc_read_byte;
nand->setup_data_interface = sunxi_nfc_setup_data_interface;
mtd = nand_to_mtd(nand); mtd = nand_to_mtd(nand);
mtd->dev.parent = dev; mtd->dev.parent = dev;
timings = onfi_async_timing_mode_to_sdr_timings(0);
if (IS_ERR(timings)) {
ret = PTR_ERR(timings);
dev_err(dev,
"could not retrieve timings for ONFI mode 0: %d\n",
ret);
return ret;
}
ret = sunxi_nand_chip_set_timings(chip, timings);
if (ret) {
dev_err(dev, "could not configure chip timings: %d\n", ret);
return ret;
}
ret = nand_scan_ident(mtd, nsels, NULL); ret = nand_scan_ident(mtd, nsels, NULL);
if (ret) if (ret)
return ret; return ret;
...@@ -2096,12 +2083,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, ...@@ -2096,12 +2083,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
nand->options |= NAND_SUBPAGE_READ; nand->options |= NAND_SUBPAGE_READ;
ret = sunxi_nand_chip_init_timings(chip, np);
if (ret) {
dev_err(dev, "could not configure chip timings: %d\n", ret);
return ret;
}
ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np); ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
if (ret) { if (ret) {
dev_err(dev, "ECC init failed: %d\n", ret); dev_err(dev, "ECC init failed: %d\n", ret);
...@@ -2175,8 +2156,7 @@ static int sunxi_nfc_probe(struct platform_device *pdev) ...@@ -2175,8 +2156,7 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
nfc->dev = dev; nfc->dev = dev;
spin_lock_init(&nfc->controller.lock); nand_hw_control_init(&nfc->controller);
init_waitqueue_head(&nfc->controller.wq);
INIT_LIST_HEAD(&nfc->chips); INIT_LIST_HEAD(&nfc->chips);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
......
...@@ -303,8 +303,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) ...@@ -303,8 +303,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n", dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
(gbusclk + 500000) / 1000000, hold, spw); (gbusclk + 500000) / 1000000, hold, spw);
spin_lock_init(&drvdata->hw_control.lock); nand_hw_control_init(&drvdata->hw_control);
init_waitqueue_head(&drvdata->hw_control.wq);
platform_set_drvdata(dev, drvdata); platform_set_drvdata(dev, drvdata);
txx9ndfmc_initialize(dev); txx9ndfmc_initialize(dev);
......
...@@ -90,10 +90,6 @@ config OF_PCI_IRQ ...@@ -90,10 +90,6 @@ config OF_PCI_IRQ
help help
OpenFirmware PCI IRQ routing helpers OpenFirmware PCI IRQ routing helpers
config OF_MTD
depends on MTD
def_bool y
config OF_RESERVED_MEM config OF_RESERVED_MEM
depends on OF_EARLY_FLATTREE depends on OF_EARLY_FLATTREE
bool bool
......
...@@ -127,6 +127,82 @@ struct mtd_ooblayout_ops { ...@@ -127,6 +127,82 @@ struct mtd_ooblayout_ops {
struct mtd_oob_region *oobfree); struct mtd_oob_region *oobfree);
}; };
/**
* struct mtd_pairing_info - page pairing information
*
* @pair: pair id
* @group: group id
*
* The term "pair" is used here, even though TLC NANDs might group pages by 3
* (3 bits in a single cell). A pair should regroup all pages that are sharing
* the same cell. Pairs are then indexed in ascending order.
*
* @group is defining the position of a page in a given pair. It can also be
* seen as the bit position in the cell: page attached to bit 0 belongs to
* group 0, page attached to bit 1 belongs to group 1, etc.
*
* Example:
* The H27UCG8T2BTR-BC datasheet describes the following pairing scheme:
*
* group-0 group-1
*
* pair-0 page-0 page-4
* pair-1 page-1 page-5
* pair-2 page-2 page-8
* ...
* pair-127 page-251 page-255
*
*
* Note that the "group" and "pair" terms were extracted from Samsung and
* Hynix datasheets, and might be referenced under other names in other
* datasheets (Micron is describing this concept as "shared pages").
*/
struct mtd_pairing_info {
int pair;
int group;
};
/**
* struct mtd_pairing_scheme - page pairing scheme description
*
* @ngroups: number of groups. Should be related to the number of bits
* per cell.
* @get_info: converts a write-unit (page number within an erase block) into
* mtd_pairing information (pair + group). This function should
* fill the info parameter based on the wunit index or return
* -EINVAL if the wunit parameter is invalid.
* @get_wunit: converts pairing information into a write-unit (page) number.
* This function should return the wunit index pointed by the
* pairing information described in the info argument. It should
* return -EINVAL, if there's no wunit corresponding to the
* passed pairing information.
*
* See mtd_pairing_info documentation for a detailed explanation of the
* pair and group concepts.
*
* The mtd_pairing_scheme structure provides a generic solution to represent
* NAND page pairing scheme. Instead of exposing two big tables to do the
* write-unit <-> (pair + group) conversions, we ask the MTD drivers to
* implement the ->get_info() and ->get_wunit() functions.
*
* MTD users will then be able to query these information by using the
* mtd_pairing_info_to_wunit() and mtd_wunit_to_pairing_info() helpers.
*
* @ngroups is here to help MTD users iterating over all the pages in a
* given pair. This value can be retrieved by MTD users using the
* mtd_pairing_groups() helper.
*
* Examples are given in the mtd_pairing_info_to_wunit() and
* mtd_wunit_to_pairing_info() documentation.
*/
struct mtd_pairing_scheme {
int ngroups;
int (*get_info)(struct mtd_info *mtd, int wunit,
struct mtd_pairing_info *info);
int (*get_wunit)(struct mtd_info *mtd,
const struct mtd_pairing_info *info);
};
struct module; /* only needed for owner field in mtd_info */ struct module; /* only needed for owner field in mtd_info */
struct mtd_info { struct mtd_info {
...@@ -188,6 +264,9 @@ struct mtd_info { ...@@ -188,6 +264,9 @@ struct mtd_info {
/* OOB layout description */ /* OOB layout description */
const struct mtd_ooblayout_ops *ooblayout; const struct mtd_ooblayout_ops *ooblayout;
/* NAND pairing scheme, only provided for MLC/TLC NANDs */
const struct mtd_pairing_scheme *pairing;
/* the ecc step size. */ /* the ecc step size. */
unsigned int ecc_step_size; unsigned int ecc_step_size;
...@@ -296,6 +375,12 @@ static inline void mtd_set_ooblayout(struct mtd_info *mtd, ...@@ -296,6 +375,12 @@ static inline void mtd_set_ooblayout(struct mtd_info *mtd,
mtd->ooblayout = ooblayout; mtd->ooblayout = ooblayout;
} }
static inline void mtd_set_pairing_scheme(struct mtd_info *mtd,
const struct mtd_pairing_scheme *pairing)
{
mtd->pairing = pairing;
}
static inline void mtd_set_of_node(struct mtd_info *mtd, static inline void mtd_set_of_node(struct mtd_info *mtd,
struct device_node *np) struct device_node *np)
{ {
...@@ -312,6 +397,11 @@ static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops) ...@@ -312,6 +397,11 @@ static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
} }
int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit,
struct mtd_pairing_info *info);
int mtd_pairing_info_to_wunit(struct mtd_info *mtd,
const struct mtd_pairing_info *info);
int mtd_pairing_groups(struct mtd_info *mtd);
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr); int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
void **virt, resource_size_t *phys); void **virt, resource_size_t *phys);
...@@ -397,6 +487,23 @@ static inline uint32_t mtd_mod_by_ws(uint64_t sz, struct mtd_info *mtd) ...@@ -397,6 +487,23 @@ static inline uint32_t mtd_mod_by_ws(uint64_t sz, struct mtd_info *mtd)
return do_div(sz, mtd->writesize); return do_div(sz, mtd->writesize);
} }
static inline int mtd_wunit_per_eb(struct mtd_info *mtd)
{
return mtd->erasesize / mtd->writesize;
}
static inline int mtd_offset_to_wunit(struct mtd_info *mtd, loff_t offs)
{
return mtd_div_by_ws(mtd_mod_by_eb(offs, mtd), mtd);
}
static inline loff_t mtd_wunit_to_offset(struct mtd_info *mtd, loff_t base,
int wunit)
{
return base + (wunit * mtd->writesize);
}
static inline int mtd_has_oob(const struct mtd_info *mtd) static inline int mtd_has_oob(const struct mtd_info *mtd)
{ {
return mtd->_read_oob && mtd->_write_oob; return mtd->_read_oob && mtd->_write_oob;
......
...@@ -29,26 +29,26 @@ struct nand_flash_dev; ...@@ -29,26 +29,26 @@ struct nand_flash_dev;
struct device_node; struct device_node;
/* Scan and identify a NAND device */ /* Scan and identify a NAND device */
extern int nand_scan(struct mtd_info *mtd, int max_chips); int nand_scan(struct mtd_info *mtd, int max_chips);
/* /*
* Separate phases of nand_scan(), allowing board driver to intervene * Separate phases of nand_scan(), allowing board driver to intervene
* and override command or ECC setup according to flash type. * and override command or ECC setup according to flash type.
*/ */
extern int nand_scan_ident(struct mtd_info *mtd, int max_chips, int nand_scan_ident(struct mtd_info *mtd, int max_chips,
struct nand_flash_dev *table); struct nand_flash_dev *table);
extern int nand_scan_tail(struct mtd_info *mtd); int nand_scan_tail(struct mtd_info *mtd);
/* Free resources held by the NAND device */ /* Unregister the MTD device and free resources held by the NAND device */
extern void nand_release(struct mtd_info *mtd); void nand_release(struct mtd_info *mtd);
/* Internal helper for board drivers which need to override command function */ /* Internal helper for board drivers which need to override command function */
extern void nand_wait_ready(struct mtd_info *mtd); void nand_wait_ready(struct mtd_info *mtd);
/* locks all blocks present in the device */ /* locks all blocks present in the device */
extern int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
/* unlocks specified locked blocks */ /* unlocks specified locked blocks */
extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
/* The maximum number of NAND chips in an array */ /* The maximum number of NAND chips in an array */
#define NAND_MAX_CHIPS 8 #define NAND_MAX_CHIPS 8
...@@ -141,6 +141,7 @@ enum nand_ecc_algo { ...@@ -141,6 +141,7 @@ enum nand_ecc_algo {
* pages and you want to rely on the default implementation. * pages and you want to rely on the default implementation.
*/ */
#define NAND_ECC_GENERIC_ERASED_CHECK BIT(0) #define NAND_ECC_GENERIC_ERASED_CHECK BIT(0)
#define NAND_ECC_MAXIMIZE BIT(1)
/* Bit mask for flags passed to do_nand_read_ecc */ /* Bit mask for flags passed to do_nand_read_ecc */
#define NAND_GET_DEVICE 0x80 #define NAND_GET_DEVICE 0x80
...@@ -460,6 +461,13 @@ struct nand_hw_control { ...@@ -460,6 +461,13 @@ struct nand_hw_control {
wait_queue_head_t wq; wait_queue_head_t wq;
}; };
static inline void nand_hw_control_init(struct nand_hw_control *nfc)
{
nfc->active = NULL;
spin_lock_init(&nfc->lock);
init_waitqueue_head(&nfc->wq);
}
/** /**
* struct nand_ecc_ctrl - Control structure for ECC * struct nand_ecc_ctrl - Control structure for ECC
* @mode: ECC mode * @mode: ECC mode
...@@ -565,6 +573,123 @@ struct nand_buffers { ...@@ -565,6 +573,123 @@ struct nand_buffers {
uint8_t *databuf; uint8_t *databuf;
}; };
/**
* struct nand_sdr_timings - SDR NAND chip timings
*
* This struct defines the timing requirements of a SDR NAND chip.
* These information can be found in every NAND datasheets and the timings
* meaning are described in the ONFI specifications:
* www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing
* Parameters)
*
* All these timings are expressed in picoseconds.
*
* @tALH_min: ALE hold time
* @tADL_min: ALE to data loading time
* @tALS_min: ALE setup time
* @tAR_min: ALE to RE# delay
* @tCEA_max: CE# access time
* @tCEH_min:
* @tCH_min: CE# hold time
* @tCHZ_max: CE# high to output hi-Z
* @tCLH_min: CLE hold time
* @tCLR_min: CLE to RE# delay
* @tCLS_min: CLE setup time
* @tCOH_min: CE# high to output hold
* @tCS_min: CE# setup time
* @tDH_min: Data hold time
* @tDS_min: Data setup time
* @tFEAT_max: Busy time for Set Features and Get Features
* @tIR_min: Output hi-Z to RE# low
* @tITC_max: Interface and Timing Mode Change time
* @tRC_min: RE# cycle time
* @tREA_max: RE# access time
* @tREH_min: RE# high hold time
* @tRHOH_min: RE# high to output hold
* @tRHW_min: RE# high to WE# low
* @tRHZ_max: RE# high to output hi-Z
* @tRLOH_min: RE# low to output hold
* @tRP_min: RE# pulse width
* @tRR_min: Ready to RE# low (data only)
* @tRST_max: Device reset time, measured from the falling edge of R/B# to the
* rising edge of R/B#.
* @tWB_max: WE# high to SR[6] low
* @tWC_min: WE# cycle time
* @tWH_min: WE# high hold time
* @tWHR_min: WE# high to RE# low
* @tWP_min: WE# pulse width
* @tWW_min: WP# transition to WE# low
*/
struct nand_sdr_timings {
u32 tALH_min;
u32 tADL_min;
u32 tALS_min;
u32 tAR_min;
u32 tCEA_max;
u32 tCEH_min;
u32 tCH_min;
u32 tCHZ_max;
u32 tCLH_min;
u32 tCLR_min;
u32 tCLS_min;
u32 tCOH_min;
u32 tCS_min;
u32 tDH_min;
u32 tDS_min;
u32 tFEAT_max;
u32 tIR_min;
u32 tITC_max;
u32 tRC_min;
u32 tREA_max;
u32 tREH_min;
u32 tRHOH_min;
u32 tRHW_min;
u32 tRHZ_max;
u32 tRLOH_min;
u32 tRP_min;
u32 tRR_min;
u64 tRST_max;
u32 tWB_max;
u32 tWC_min;
u32 tWH_min;
u32 tWHR_min;
u32 tWP_min;
u32 tWW_min;
};
/**
* enum nand_data_interface_type - NAND interface timing type
* @NAND_SDR_IFACE: Single Data Rate interface
*/
enum nand_data_interface_type {
NAND_SDR_IFACE,
};
/**
* struct nand_data_interface - NAND interface timing
* @type: type of the timing
* @timings: The timing, type according to @type
*/
struct nand_data_interface {
enum nand_data_interface_type type;
union {
struct nand_sdr_timings sdr;
} timings;
};
/**
* nand_get_sdr_timings - get SDR timing from data interface
* @conf: The data interface
*/
static inline const struct nand_sdr_timings *
nand_get_sdr_timings(const struct nand_data_interface *conf)
{
if (conf->type != NAND_SDR_IFACE)
return ERR_PTR(-EINVAL);
return &conf->timings.sdr;
}
/** /**
* struct nand_chip - NAND Private Flash Chip Data * struct nand_chip - NAND Private Flash Chip Data
* @mtd: MTD device registered to the MTD framework * @mtd: MTD device registered to the MTD framework
...@@ -627,10 +752,9 @@ struct nand_buffers { ...@@ -627,10 +752,9 @@ struct nand_buffers {
* also from the datasheet. It is the recommended ECC step * also from the datasheet. It is the recommended ECC step
* size, if known; if unknown, set to zero. * size, if known; if unknown, set to zero.
* @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is
* either deduced from the datasheet if the NAND * set to the actually used ONFI mode if the chip is
* chip is not ONFI compliant or set to 0 if it is * ONFI compliant or deduced from the datasheet if
* (an ONFI chip is always configured in mode 0 * the NAND chip is not ONFI compliant.
* after a NAND reset)
* @numchips: [INTERN] number of physical chips * @numchips: [INTERN] number of physical chips
* @chipsize: [INTERN] the size of one chip for multichip arrays * @chipsize: [INTERN] the size of one chip for multichip arrays
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
...@@ -650,6 +774,7 @@ struct nand_buffers { ...@@ -650,6 +774,7 @@ struct nand_buffers {
* @read_retries: [INTERN] the number of read retry modes supported * @read_retries: [INTERN] the number of read retry modes supported
* @onfi_set_features: [REPLACEABLE] set the features for ONFI nand * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
* @onfi_get_features: [REPLACEABLE] get the features for ONFI nand * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
* @setup_data_interface: [OPTIONAL] setup the data interface and timing
* @bbt: [INTERN] bad block table pointer * @bbt: [INTERN] bad block table pointer
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash * @bbt_td: [REPLACEABLE] bad block table descriptor for flash
* lookup. * lookup.
...@@ -696,6 +821,10 @@ struct nand_chip { ...@@ -696,6 +821,10 @@ struct nand_chip {
int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
int feature_addr, uint8_t *subfeature_para); int feature_addr, uint8_t *subfeature_para);
int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode); int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);
int (*setup_data_interface)(struct mtd_info *mtd,
const struct nand_data_interface *conf,
bool check_only);
int chip_delay; int chip_delay;
unsigned int options; unsigned int options;
...@@ -725,6 +854,8 @@ struct nand_chip { ...@@ -725,6 +854,8 @@ struct nand_chip {
struct nand_jedec_params jedec_params; struct nand_jedec_params jedec_params;
}; };
struct nand_data_interface *data_interface;
int read_retries; int read_retries;
flstate_t state; flstate_t state;
...@@ -893,13 +1024,13 @@ struct nand_manufacturers { ...@@ -893,13 +1024,13 @@ struct nand_manufacturers {
extern struct nand_flash_dev nand_flash_ids[]; extern struct nand_flash_dev nand_flash_ids[];
extern struct nand_manufacturers nand_manuf_ids[]; extern struct nand_manufacturers nand_manuf_ids[];
extern int nand_default_bbt(struct mtd_info *mtd); int nand_default_bbt(struct mtd_info *mtd);
extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs); int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
extern int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs); int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt); int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
int allowbbt); int allowbbt);
extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, uint8_t *buf); size_t *retlen, uint8_t *buf);
/** /**
...@@ -988,6 +1119,11 @@ static inline int onfi_get_sync_timing_mode(struct nand_chip *chip) ...@@ -988,6 +1119,11 @@ static inline int onfi_get_sync_timing_mode(struct nand_chip *chip)
return le16_to_cpu(chip->onfi_params.src_sync_timing_mode); return le16_to_cpu(chip->onfi_params.src_sync_timing_mode);
} }
int onfi_init_data_interface(struct nand_chip *chip,
struct nand_data_interface *iface,
enum nand_data_interface_type type,
int timing_mode);
/* /*
* Check if it is a SLC nand. * Check if it is a SLC nand.
* The !nand_is_slc() can be used to check the MLC/TLC nand chips. * The !nand_is_slc() can be used to check the MLC/TLC nand chips.
...@@ -1023,57 +1159,10 @@ static inline int jedec_feature(struct nand_chip *chip) ...@@ -1023,57 +1159,10 @@ static inline int jedec_feature(struct nand_chip *chip)
: 0; : 0;
} }
/*
* struct nand_sdr_timings - SDR NAND chip timings
*
* This struct defines the timing requirements of a SDR NAND chip.
* These informations can be found in every NAND datasheets and the timings
* meaning are described in the ONFI specifications:
* www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing
* Parameters)
*
* All these timings are expressed in picoseconds.
*/
struct nand_sdr_timings {
u32 tALH_min;
u32 tADL_min;
u32 tALS_min;
u32 tAR_min;
u32 tCEA_max;
u32 tCEH_min;
u32 tCH_min;
u32 tCHZ_max;
u32 tCLH_min;
u32 tCLR_min;
u32 tCLS_min;
u32 tCOH_min;
u32 tCS_min;
u32 tDH_min;
u32 tDS_min;
u32 tFEAT_max;
u32 tIR_min;
u32 tITC_max;
u32 tRC_min;
u32 tREA_max;
u32 tREH_min;
u32 tRHOH_min;
u32 tRHW_min;
u32 tRHZ_max;
u32 tRLOH_min;
u32 tRP_min;
u32 tRR_min;
u64 tRST_max;
u32 tWB_max;
u32 tWC_min;
u32 tWH_min;
u32 tWHR_min;
u32 tWP_min;
u32 tWW_min;
};
/* get timing characteristics from ONFI timing mode. */ /* get timing characteristics from ONFI timing mode. */
const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode); const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
/* get data interface from ONFI timing mode 0, used after reset. */
const struct nand_data_interface *nand_get_default_data_interface(void);
int nand_check_erased_ecc_chunk(void *data, int datalen, int nand_check_erased_ecc_chunk(void *data, int datalen,
void *ecc, int ecclen, void *ecc, int ecclen,
...@@ -1093,4 +1182,11 @@ int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page); ...@@ -1093,4 +1182,11 @@ int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
/* Default read_oob syndrome implementation */ /* Default read_oob syndrome implementation */
int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
int page); int page);
/* Reset and initialize a NAND device */
int nand_reset(struct nand_chip *chip);
/* Free resources held by the NAND device */
void nand_cleanup(struct nand_chip *chip);
#endif /* __LINUX_MTD_NAND_H */ #endif /* __LINUX_MTD_NAND_H */
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