Skip to content

Commit

Permalink
Merge tag 'for-linus-20161008' of git://git.infradead.org/linux-mtd
Browse files Browse the repository at this point in the history
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
  ...
  • Loading branch information
torvalds committed Oct 11, 2016
2 parents 97d2116 + 69db4aa commit 35ff96d
Show file tree
Hide file tree
Showing 28 changed files with 1,263 additions and 459 deletions.
9 changes: 9 additions & 0 deletions Documentation/devicetree/bindings/mtd/nand.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ Optional NAND chip properties:
- nand-ecc-step-size: integer representing the number of data bytes
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
of a controller. Together, they say a controller can correct "{strength} bit
errors per {size} bytes".
Expand Down
6 changes: 6 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -6142,6 +6142,12 @@ M: Zubair Lutfullah Kakakhel <[email protected]>
S: Maintained
F: drivers/dma/dma-jz4780.c

INGENIC JZ4780 NAND DRIVER
M: Harvey Hunt <[email protected]>
L: [email protected]
S: Maintained
F: drivers/mtd/nand/jz4780_*

INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
M: Mimi Zohar <[email protected]>
M: Dmitry Kasatkin <[email protected]>
Expand Down
104 changes: 104 additions & 0 deletions drivers/mtd/mtdcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,110 @@ static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state,
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
* @mtd: pointer to new MTD device info structure
Expand Down
19 changes: 19 additions & 0 deletions drivers/mtd/mtdpart.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,18 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
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,
struct mtd_oob_region *oobregion)
{
Expand Down Expand Up @@ -397,6 +409,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd.oobsize = master->oobsize;
slave->mtd.oobavail = master->oobavail;
slave->mtd.subpage_sft = master->subpage_sft;
slave->mtd.pairing = master->pairing;

slave->mtd.name = name;
slave->mtd.owner = master->owner;
Expand Down Expand Up @@ -463,6 +476,12 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd._block_isbad = part_block_isbad;
if (master->_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->master = master;
slave->offset = part->offset;
Expand Down
12 changes: 6 additions & 6 deletions drivers/mtd/nand/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ config MTD_NAND_AMS_DELTA
Support for NAND flash on Amstrad E3 (Delta).

config MTD_NAND_OMAP2
tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4"
depends on ARCH_OMAP2PLUS
tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
help
Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
platforms.
Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
and Keystone platforms.

config MTD_NAND_OMAP_BCH
depends on MTD_NAND_OMAP2
Expand Down Expand Up @@ -428,7 +428,7 @@ config MTD_NAND_ORION

config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on PPC
depends on FSL_SOC
select FSL_LBC
help
Various Freescale chips, including the 8313, include a NAND Flash
Expand All @@ -438,7 +438,7 @@ config MTD_NAND_FSL_ELBC

config MTD_NAND_FSL_IFC
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 MEMORY
help
Expand Down
3 changes: 1 addition & 2 deletions drivers/mtd/nand/bf5xx_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -761,8 +761,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, info);

spin_lock_init(&info->controller.lock);
init_waitqueue_head(&info->controller.wq);
nand_hw_control_init(&info->controller);

info->device = &pdev->dev;
info->platform = plat;
Expand Down
15 changes: 7 additions & 8 deletions drivers/mtd/nand/brcmnand/brcmnand.c
Original file line number Diff line number Diff line change
Expand Up @@ -1336,7 +1336,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
u32 *flash_cache = (u32 *)ctrl->flash_cache;
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
Expand All @@ -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));

brcmnand_soc_data_bus_unprepare(ctrl->soc);
brcmnand_soc_data_bus_unprepare(ctrl->soc, true);

/* Cleanup from HW quirk: restore SECTOR_SIZE_1K */
if (host->hwcfg.sector_size_1k)
Expand Down Expand Up @@ -1565,12 +1565,12 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
brcmnand_waitfunc(mtd, chip);

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++)
*buf = brcmnand_read_fc(ctrl, j);

brcmnand_soc_data_bus_unprepare(ctrl->soc);
brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
}

if (oob)
Expand Down Expand Up @@ -1815,12 +1815,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);

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++)
brcmnand_write_fc(ctrl, j, *buf);

brcmnand_soc_data_bus_unprepare(ctrl->soc);
brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
} else if (oob) {
for (j = 0; j < FC_WORDS; j++)
brcmnand_write_fc(ctrl, j, 0xffffffff);
Expand Down Expand Up @@ -2370,8 +2370,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)

init_completion(&ctrl->done);
init_completion(&ctrl->dma_done);
spin_lock_init(&ctrl->controller.lock);
init_waitqueue_head(&ctrl->controller.wq);
nand_hw_control_init(&ctrl->controller);
INIT_LIST_HEAD(&ctrl->host_list);

/* NAND register range */
Expand Down
13 changes: 8 additions & 5 deletions drivers/mtd/nand/brcmnand/brcmnand.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,22 @@ struct dev_pm_ops;
struct brcmnand_soc {
bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
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)
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)
soc->prepare_data_bus(soc, false);
soc->prepare_data_bus(soc, false, is_param);
}

static inline u32 brcmnand_readl(void __iomem *addr)
Expand Down
18 changes: 14 additions & 4 deletions drivers/mtd/nand/brcmnand/iproc_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
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 =
container_of(soc, struct iproc_nand_soc, soc);
Expand All @@ -86,10 +87,19 @@ static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)

val = brcmnand_readl(mmio);

if (prepare)
val |= IPROC_NAND_APB_LE_MODE;
else
/*
* 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)
val |= IPROC_NAND_APB_LE_MODE;
else
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);

Expand Down
3 changes: 1 addition & 2 deletions drivers/mtd/nand/docg4.c
Original file line number Diff line number Diff line change
Expand Up @@ -1249,8 +1249,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
nand->controller = &nand->hwcontrol;
spin_lock_init(&nand->controller->lock);
init_waitqueue_head(&nand->controller->wq);
nand_hw_control_init(nand->controller);

/* methods */
nand->cmdfunc = docg4_command;
Expand Down
3 changes: 1 addition & 2 deletions drivers/mtd/nand/fsl_elbc_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -879,8 +879,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
}
elbc_fcm_ctrl->counter++;

spin_lock_init(&elbc_fcm_ctrl->controller.lock);
init_waitqueue_head(&elbc_fcm_ctrl->controller.wq);
nand_hw_control_init(&elbc_fcm_ctrl->controller);
fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
} else {
elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
Expand Down
3 changes: 1 addition & 2 deletions drivers/mtd/nand/fsl_ifc_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -987,8 +987,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
ifc_nand_ctrl->addr = NULL;
fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;

spin_lock_init(&ifc_nand_ctrl->controller.lock);
init_waitqueue_head(&ifc_nand_ctrl->controller.wq);
nand_hw_control_init(&ifc_nand_ctrl->controller);
} else {
ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/mtd/nand/gpmi-nand/gpmi-nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
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;

/*
Expand Down
3 changes: 1 addition & 2 deletions drivers/mtd/nand/jz4780_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,9 +368,8 @@ static int jz4780_nand_probe(struct platform_device *pdev)
nfc->dev = dev;
nfc->num_banks = num_banks;

spin_lock_init(&nfc->controller.lock);
nand_hw_control_init(&nfc->controller);
INIT_LIST_HEAD(&nfc->chips);
init_waitqueue_head(&nfc->controller.wq);

ret = jz4780_nand_init_chips(nfc, pdev);
if (ret) {
Expand Down
Loading

0 comments on commit 35ff96d

Please sign in to comment.