Merge tag 'nand/for-4.10' of github.com:linux-nand/linux
From Boris Brezillon: """ This pull request contains the following notable changes: - new tango NAND controller driver - new ox820 NAND controller driver - addition of a new full-ID entry in the nand_ids table - rework of the s3c240 driver to support DT - extension of the nand_sdr_timings to expose tCCS, tPROG and tR - addition of a new flag to ask the core to wait for tCCS when sending a RNDIN/RNDOUT command - addition of a new flag to ask the core to let the controller driver send the READ/PROGPAGE command This pull request also contains minor fixes/cleanup/cosmetic changes: - properly support 512 ECC step size in the sunxi driver - improve the error messages in the pxa probe path - fix module autoload in the omap2 driver - cleanup of several nand drivers to return nand_scan{_tail}() error code instead of returning -EIO - various cleanups in the denali driver - cleanups in the ooblayout handling (MTD core) - fix an error check in nandsim """
This commit is contained in:
@@ -709,6 +709,25 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
|
||||
nand_wait_ready(mtd);
|
||||
}
|
||||
|
||||
static void nand_ccs_delay(struct nand_chip *chip)
|
||||
{
|
||||
/*
|
||||
* The controller already takes care of waiting for tCCS when the RNDIN
|
||||
* or RNDOUT command is sent, return directly.
|
||||
*/
|
||||
if (!(chip->options & NAND_WAIT_TCCS))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Wait tCCS_min if it is correctly defined, otherwise wait 500ns
|
||||
* (which should be safe for all NANDs).
|
||||
*/
|
||||
if (chip->data_interface && chip->data_interface->timings.sdr.tCCS_min)
|
||||
ndelay(chip->data_interface->timings.sdr.tCCS_min / 1000);
|
||||
else
|
||||
ndelay(500);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_command_lp - [DEFAULT] Send command to NAND large page device
|
||||
* @mtd: MTD device structure
|
||||
@@ -773,10 +792,13 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
|
||||
case NAND_CMD_ERASE1:
|
||||
case NAND_CMD_ERASE2:
|
||||
case NAND_CMD_SEQIN:
|
||||
case NAND_CMD_RNDIN:
|
||||
case NAND_CMD_STATUS:
|
||||
return;
|
||||
|
||||
case NAND_CMD_RNDIN:
|
||||
nand_ccs_delay(chip);
|
||||
return;
|
||||
|
||||
case NAND_CMD_RESET:
|
||||
if (chip->dev_ready)
|
||||
break;
|
||||
@@ -795,6 +817,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
|
||||
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
|
||||
chip->cmd_ctrl(mtd, NAND_CMD_NONE,
|
||||
NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
nand_ccs_delay(chip);
|
||||
return;
|
||||
|
||||
case NAND_CMD_READ0:
|
||||
@@ -1946,7 +1970,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||
__func__, buf);
|
||||
|
||||
read_retry:
|
||||
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
|
||||
if (nand_standard_page_accessors(&chip->ecc))
|
||||
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
|
||||
|
||||
/*
|
||||
* Now read the page into the buffer. Absent an error,
|
||||
@@ -2634,7 +2659,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
else
|
||||
subpage = 0;
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
|
||||
if (nand_standard_page_accessors(&chip->ecc))
|
||||
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
|
||||
|
||||
if (unlikely(raw))
|
||||
status = chip->ecc.write_page_raw(mtd, chip, buf,
|
||||
@@ -2657,7 +2683,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
|
||||
if (!cached || !NAND_HAS_CACHEPROG(chip)) {
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
|
||||
if (nand_standard_page_accessors(&chip->ecc))
|
||||
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
|
||||
status = chip->waitfunc(mtd, chip);
|
||||
/*
|
||||
* See if operation failed and additional status checks are
|
||||
@@ -3985,10 +4012,9 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
/*
|
||||
* Get the flash and manufacturer id and lookup if the type is supported.
|
||||
*/
|
||||
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
int *maf_id, int *dev_id,
|
||||
struct nand_flash_dev *type)
|
||||
static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int *maf_id, int *dev_id,
|
||||
struct nand_flash_dev *type)
|
||||
{
|
||||
int busw;
|
||||
int i, maf_idx;
|
||||
@@ -4026,7 +4052,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||
if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
|
||||
pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
|
||||
*maf_id, *dev_id, id_data[0], id_data[1]);
|
||||
return ERR_PTR(-ENODEV);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!type)
|
||||
@@ -4053,7 +4079,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||
}
|
||||
|
||||
if (!type->name)
|
||||
return ERR_PTR(-ENODEV);
|
||||
return -ENODEV;
|
||||
|
||||
if (!mtd->name)
|
||||
mtd->name = type->name;
|
||||
@@ -4098,7 +4124,7 @@ ident_done:
|
||||
pr_warn("bus width %d instead %d bit\n",
|
||||
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
|
||||
busw ? 16 : 8);
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nand_decode_bbm_options(mtd, chip, id_data);
|
||||
@@ -4140,7 +4166,7 @@ ident_done:
|
||||
pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
|
||||
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
|
||||
mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
|
||||
return type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const nand_ecc_modes[] = {
|
||||
@@ -4306,7 +4332,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
|
||||
{
|
||||
int i, nand_maf_id, nand_dev_id;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nand_flash_dev *type;
|
||||
int ret;
|
||||
|
||||
ret = nand_dt_init(chip);
|
||||
@@ -4329,14 +4354,12 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
|
||||
nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
|
||||
|
||||
/* Read the flash type */
|
||||
type = nand_get_flash_type(mtd, chip, &nand_maf_id,
|
||||
&nand_dev_id, table);
|
||||
|
||||
if (IS_ERR(type)) {
|
||||
ret = nand_get_flash_type(mtd, chip, &nand_maf_id, &nand_dev_id, table);
|
||||
if (ret) {
|
||||
if (!(chip->options & NAND_SCAN_SILENT_NODEV))
|
||||
pr_warn("No NAND device found\n");
|
||||
chip->select_chip(mtd, -1);
|
||||
return PTR_ERR(type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize the ->data_interface field. */
|
||||
@@ -4515,6 +4538,26 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
|
||||
return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
|
||||
}
|
||||
|
||||
static bool invalid_ecc_page_accessors(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
|
||||
if (nand_standard_page_accessors(ecc))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND
|
||||
* controller driver implements all the page accessors because
|
||||
* default helpers are not suitable when the core does not
|
||||
* send the READ0/PAGEPROG commands.
|
||||
*/
|
||||
return (!ecc->read_page || !ecc->write_page ||
|
||||
!ecc->read_page_raw || !ecc->write_page_raw ||
|
||||
(NAND_HAS_SUBPAGE_READ(chip) && !ecc->read_subpage) ||
|
||||
(NAND_HAS_SUBPAGE_WRITE(chip) && !ecc->write_subpage &&
|
||||
ecc->hwctl && ecc->calculate));
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_scan_tail - [NAND Interface] Scan for the NAND device
|
||||
* @mtd: MTD device structure
|
||||
@@ -4535,6 +4578,11 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
!(chip->bbt_options & NAND_BBT_USE_FLASH)))
|
||||
return -EINVAL;
|
||||
|
||||
if (invalid_ecc_page_accessors(chip)) {
|
||||
pr_err("Invalid ECC page accessors setup\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(chip->options & NAND_OWN_BUFFERS)) {
|
||||
nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
|
||||
+ mtd->oobsize * 3, GFP_KERNEL);
|
||||
|
Reference in New Issue
Block a user