summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/raw/nand_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/raw/nand_base.c')
-rw-r--r--drivers/mtd/nand/raw/nand_base.c445
1 files changed, 279 insertions, 166 deletions
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index c24e5e2ba130..45124dbb1835 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -205,6 +205,56 @@ static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
.free = nand_ooblayout_free_lp_hamming,
};
+static int nand_pairing_dist3_get_info(struct mtd_info *mtd, int page,
+ struct mtd_pairing_info *info)
+{
+ int lastpage = (mtd->erasesize / mtd->writesize) - 1;
+ int dist = 3;
+
+ if (page == lastpage)
+ dist = 2;
+
+ if (!page || (page & 1)) {
+ info->group = 0;
+ info->pair = (page + 1) / 2;
+ } else {
+ info->group = 1;
+ info->pair = (page + 1 - dist) / 2;
+ }
+
+ return 0;
+}
+
+static int nand_pairing_dist3_get_wunit(struct mtd_info *mtd,
+ const struct mtd_pairing_info *info)
+{
+ int lastpair = ((mtd->erasesize / mtd->writesize) - 1) / 2;
+ int page = info->pair * 2;
+ int dist = 3;
+
+ if (!info->group && !info->pair)
+ return 0;
+
+ if (info->pair == lastpair && info->group)
+ dist = 2;
+
+ if (!info->group)
+ page--;
+ else if (info->pair)
+ page += dist - 1;
+
+ if (page >= mtd->erasesize / mtd->writesize)
+ return -EINVAL;
+
+ return page;
+}
+
+const struct mtd_pairing_scheme dist3_pairing_scheme = {
+ .ngroups = 2,
+ .get_info = nand_pairing_dist3_get_info,
+ .get_wunit = nand_pairing_dist3_get_wunit,
+};
+
static int check_offs_len(struct nand_chip *chip, loff_t ofs, uint64_t len)
{
int ret = 0;
@@ -225,6 +275,50 @@ static int check_offs_len(struct nand_chip *chip, loff_t ofs, uint64_t len)
}
/**
+ * nand_extract_bits - Copy unaligned bits from one buffer to another one
+ * @dst: destination buffer
+ * @dst_off: bit offset at which the writing starts
+ * @src: source buffer
+ * @src_off: bit offset at which the reading starts
+ * @nbits: number of bits to copy from @src to @dst
+ *
+ * Copy bits from one memory region to another (overlap authorized).
+ */
+void nand_extract_bits(u8 *dst, unsigned int dst_off, const u8 *src,
+ unsigned int src_off, unsigned int nbits)
+{
+ unsigned int tmp, n;
+
+ dst += dst_off / 8;
+ dst_off %= 8;
+ src += src_off / 8;
+ src_off %= 8;
+
+ while (nbits) {
+ n = min3(8 - dst_off, 8 - src_off, nbits);
+
+ tmp = (*src >> src_off) & GENMASK(n - 1, 0);
+ *dst &= ~GENMASK(n - 1 + dst_off, dst_off);
+ *dst |= tmp << dst_off;
+
+ dst_off += n;
+ if (dst_off >= 8) {
+ dst++;
+ dst_off -= 8;
+ }
+
+ src_off += n;
+ if (src_off >= 8) {
+ src++;
+ src_off -= 8;
+ }
+
+ nbits -= n;
+ }
+}
+EXPORT_SYMBOL_GPL(nand_extract_bits);
+
+/**
* nand_select_target() - Select a NAND target (A.K.A. die)
* @chip: NAND chip object
* @cs: the CS line to select. Note that this CS id is always from the chip
@@ -345,6 +439,9 @@ static int nand_block_bad(struct nand_chip *chip, loff_t ofs)
static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
{
+ if (chip->options & NAND_NO_BBM_QUIRK)
+ return 0;
+
if (chip->legacy.block_bad)
return chip->legacy.block_bad(chip, ofs);
@@ -690,7 +787,8 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
*/
timeout_ms = jiffies + msecs_to_jiffies(timeout_ms) + 1;
do {
- ret = nand_read_data_op(chip, &status, sizeof(status), true);
+ ret = nand_read_data_op(chip, &status, sizeof(status), true,
+ false);
if (ret)
break;
@@ -736,8 +834,14 @@ EXPORT_SYMBOL_GPL(nand_soft_waitrdy);
int nand_gpio_waitrdy(struct nand_chip *chip, struct gpio_desc *gpiod,
unsigned long timeout_ms)
{
- /* Wait until R/B pin indicates chip is ready or timeout occurs */
- timeout_ms = jiffies + msecs_to_jiffies(timeout_ms);
+
+ /*
+ * Wait until R/B pin indicates chip is ready or timeout occurs.
+ * +1 below is necessary because if we are now in the last fraction
+ * of jiffy and msecs_to_jiffies is 1 then we will wait only that
+ * small jiffy fraction - possibly leading to false timeout.
+ */
+ timeout_ms = jiffies + msecs_to_jiffies(timeout_ms) + 1;
do {
if (gpiod_get_value_cansleep(gpiod))
return 0;
@@ -770,7 +874,7 @@ void panic_nand_wait(struct nand_chip *chip, unsigned long timeo)
u8 status;
ret = nand_read_data_op(chip, &status, sizeof(status),
- true);
+ true, false);
if (ret)
return;
@@ -1868,6 +1972,8 @@ EXPORT_SYMBOL_GPL(nand_reset_op);
* @buf: buffer used to store the data
* @len: length of the buffer
* @force_8bit: force 8-bit bus access
+ * @check_only: do not actually run the command, only checks if the
+ * controller driver supports it
*
* This function does a raw data read on the bus. Usually used after launching
* another NAND operation like nand_read_page_op().
@@ -1876,7 +1982,7 @@ EXPORT_SYMBOL_GPL(nand_reset_op);
* Returns 0 on success, a negative error code otherwise.
*/
int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
- bool force_8bit)
+ bool force_8bit, bool check_only)
{
if (!len || !buf)
return -EINVAL;
@@ -1889,9 +1995,15 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
instrs[0].ctx.data.force_8bit = force_8bit;
+ if (check_only)
+ return nand_check_op(chip, &op);
+
return nand_exec_op(chip, &op);
}
+ if (check_only)
+ return 0;
+
if (force_8bit) {
u8 *p = buf;
unsigned int i;
@@ -2112,7 +2224,7 @@ static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx)
char *prefix = " ";
unsigned int i;
- pr_debug("executing subop:\n");
+ pr_debug("executing subop (CS%d):\n", ctx->subop.cs);
for (i = 0; i < ctx->ninstrs; i++) {
instr = &ctx->instrs[i];
@@ -2176,6 +2288,7 @@ int nand_op_parser_exec_op(struct nand_chip *chip,
const struct nand_operation *op, bool check_only)
{
struct nand_op_parser_ctx ctx = {
+ .subop.cs = op->cs,
.subop.instrs = op->instrs,
.instrs = op->instrs,
.ninstrs = op->ninstrs,
@@ -2620,7 +2733,7 @@ int nand_read_page_raw(struct nand_chip *chip, uint8_t *buf, int oob_required,
if (oob_required) {
ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize,
- false);
+ false, false);
if (ret)
return ret;
}
@@ -2630,6 +2743,47 @@ int nand_read_page_raw(struct nand_chip *chip, uint8_t *buf, int oob_required,
EXPORT_SYMBOL(nand_read_page_raw);
/**
+ * nand_monolithic_read_page_raw - Monolithic page read in raw mode
+ * @chip: NAND chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * This is a raw page read, ie. without any error detection/correction.
+ * Monolithic means we are requesting all the relevant data (main plus
+ * eventually OOB) to be loaded in the NAND cache and sent over the
+ * bus (from the NAND chip to the NAND controller) in a single
+ * operation. This is an alternative to nand_read_page_raw(), which
+ * first reads the main data, and if the OOB data is requested too,
+ * then reads more data on the bus.
+ */
+int nand_monolithic_read_page_raw(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ unsigned int size = mtd->writesize;
+ u8 *read_buf = buf;
+ int ret;
+
+ if (oob_required) {
+ size += mtd->oobsize;
+
+ if (buf != chip->data_buf)
+ read_buf = nand_get_data_buf(chip);
+ }
+
+ ret = nand_read_page_op(chip, page, 0, read_buf, size);
+ if (ret)
+ return ret;
+
+ if (buf != chip->data_buf)
+ memcpy(buf, read_buf, mtd->writesize);
+
+ return 0;
+}
+EXPORT_SYMBOL(nand_monolithic_read_page_raw);
+
+/**
* nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
* @chip: nand chip info structure
* @buf: buffer to store read data
@@ -2652,7 +2806,7 @@ static int nand_read_page_raw_syndrome(struct nand_chip *chip, uint8_t *buf,
return ret;
for (steps = chip->ecc.steps; steps > 0; steps--) {
- ret = nand_read_data_op(chip, buf, eccsize, false);
+ ret = nand_read_data_op(chip, buf, eccsize, false, false);
if (ret)
return ret;
@@ -2660,14 +2814,14 @@ static int nand_read_page_raw_syndrome(struct nand_chip *chip, uint8_t *buf,
if (chip->ecc.prepad) {
ret = nand_read_data_op(chip, oob, chip->ecc.prepad,
- false);
+ false, false);
if (ret)
return ret;
oob += chip->ecc.prepad;
}
- ret = nand_read_data_op(chip, oob, eccbytes, false);
+ ret = nand_read_data_op(chip, oob, eccbytes, false, false);
if (ret)
return ret;
@@ -2675,7 +2829,7 @@ static int nand_read_page_raw_syndrome(struct nand_chip *chip, uint8_t *buf,
if (chip->ecc.postpad) {
ret = nand_read_data_op(chip, oob, chip->ecc.postpad,
- false);
+ false, false);
if (ret)
return ret;
@@ -2685,7 +2839,7 @@ static int nand_read_page_raw_syndrome(struct nand_chip *chip, uint8_t *buf,
size = mtd->oobsize - (oob - chip->oob_poi);
if (size) {
- ret = nand_read_data_op(chip, oob, size, false);
+ ret = nand_read_data_op(chip, oob, size, false, false);
if (ret)
return ret;
}
@@ -2878,14 +3032,15 @@ static int nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(chip, NAND_ECC_READ);
- ret = nand_read_data_op(chip, p, eccsize, false);
+ ret = nand_read_data_op(chip, p, eccsize, false, false);
if (ret)
return ret;
chip->ecc.calculate(chip, p, &ecc_calc[i]);
}
- ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false);
+ ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false,
+ false);
if (ret)
return ret;
@@ -2921,76 +3076,6 @@ static int nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
}
/**
- * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- * @oob_required: caller requires OOB data read to chip->oob_poi
- * @page: page number to read
- *
- * Hardware ECC for large page chips, require OOB to be read first. For this
- * ECC mode, the write_page method is re-used from ECC_HW. These methods
- * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with
- * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from
- * the data area, by overwriting the NAND manufacturer bad block markings.
- */
-static int nand_read_page_hwecc_oob_first(struct nand_chip *chip, uint8_t *buf,
- int oob_required, int page)
-{
- struct mtd_info *mtd = nand_to_mtd(chip);
- int i, eccsize = chip->ecc.size, ret;
- int eccbytes = chip->ecc.bytes;
- int eccsteps = chip->ecc.steps;
- uint8_t *p = buf;
- uint8_t *ecc_code = chip->ecc.code_buf;
- uint8_t *ecc_calc = chip->ecc.calc_buf;
- unsigned int max_bitflips = 0;
-
- /* Read the OOB area first */
- ret = nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
- if (ret)
- return ret;
-
- ret = nand_read_page_op(chip, page, 0, NULL, 0);
- if (ret)
- return ret;
-
- ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
- chip->ecc.total);
- if (ret)
- return ret;
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- int stat;
-
- chip->ecc.hwctl(chip, NAND_ECC_READ);
-
- ret = nand_read_data_op(chip, p, eccsize, false);
- if (ret)
- return ret;
-
- chip->ecc.calculate(chip, p, &ecc_calc[i]);
-
- stat = chip->ecc.correct(chip, p, &ecc_code[i], NULL);
- if (stat == -EBADMSG &&
- (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
- /* check for empty pages with bitflips */
- stat = nand_check_erased_ecc_chunk(p, eccsize,
- &ecc_code[i], eccbytes,
- NULL, 0,
- chip->ecc.strength);
- }
-
- if (stat < 0) {
- mtd->ecc_stats.failed++;
- } else {
- mtd->ecc_stats.corrected += stat;
- max_bitflips = max_t(unsigned int, max_bitflips, stat);
- }
- }
- return max_bitflips;
-}
-
-/**
* nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
* @chip: nand chip info structure
* @buf: buffer to store read data
@@ -3021,13 +3106,13 @@ static int nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf,
chip->ecc.hwctl(chip, NAND_ECC_READ);
- ret = nand_read_data_op(chip, p, eccsize, false);
+ ret = nand_read_data_op(chip, p, eccsize, false, false);
if (ret)
return ret;
if (chip->ecc.prepad) {
ret = nand_read_data_op(chip, oob, chip->ecc.prepad,
- false);
+ false, false);
if (ret)
return ret;
@@ -3036,7 +3121,7 @@ static int nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf,
chip->ecc.hwctl(chip, NAND_ECC_READSYN);
- ret = nand_read_data_op(chip, oob, eccbytes, false);
+ ret = nand_read_data_op(chip, oob, eccbytes, false, false);
if (ret)
return ret;
@@ -3046,7 +3131,7 @@ static int nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf,
if (chip->ecc.postpad) {
ret = nand_read_data_op(chip, oob, chip->ecc.postpad,
- false);
+ false, false);
if (ret)
return ret;
@@ -3074,7 +3159,7 @@ static int nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf,
/* Calculate remaining oob bytes */
i = mtd->oobsize - (oob - chip->oob_poi);
if (i) {
- ret = nand_read_data_op(chip, oob, i, false);
+ ret = nand_read_data_op(chip, oob, i, false, false);
if (ret)
return ret;
}
@@ -3166,7 +3251,7 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from,
uint32_t max_oobsize = mtd_oobavail(mtd, ops);
uint8_t *bufpoi, *oob, *buf;
- int use_bufpoi;
+ int use_bounce_buf;
unsigned int max_bitflips = 0;
int retry_mode = 0;
bool ecc_fail = false;
@@ -3184,25 +3269,25 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from,
oob_required = oob ? 1 : 0;
while (1) {
- unsigned int ecc_failures = mtd->ecc_stats.failed;
+ struct mtd_ecc_stats ecc_stats = mtd->ecc_stats;
bytes = min(mtd->writesize - col, readlen);
aligned = (bytes == mtd->writesize);
if (!aligned)
- use_bufpoi = 1;
- else if (chip->options & NAND_USE_BOUNCE_BUFFER)
- use_bufpoi = !virt_addr_valid(buf) ||
- !IS_ALIGNED((unsigned long)buf,
- chip->buf_align);
+ use_bounce_buf = 1;
+ else if (chip->options & NAND_USES_DMA)
+ use_bounce_buf = !virt_addr_valid(buf) ||
+ !IS_ALIGNED((unsigned long)buf,
+ chip->buf_align);
else
- use_bufpoi = 0;
+ use_bounce_buf = 0;
/* Is the current page in the buffer? */
if (realpage != chip->pagecache.page || oob) {
- bufpoi = use_bufpoi ? chip->data_buf : buf;
+ bufpoi = use_bounce_buf ? chip->data_buf : buf;
- if (use_bufpoi && aligned)
+ if (use_bounce_buf && aligned)
pr_debug("%s: using read bounce buffer for buf@%p\n",
__func__, buf);
@@ -3223,16 +3308,19 @@ read_retry:
ret = chip->ecc.read_page(chip, bufpoi,
oob_required, page);
if (ret < 0) {
- if (use_bufpoi)
+ if (use_bounce_buf)
/* Invalidate page cache */
chip->pagecache.page = -1;
break;
}
- /* Transfer not aligned data */
- if (use_bufpoi) {
+ /*
+ * Copy back the data in the initial buffer when reading
+ * partial pages or when a bounce buffer is required.
+ */
+ if (use_bounce_buf) {
if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
- !(mtd->ecc_stats.failed - ecc_failures) &&
+ !(mtd->ecc_stats.failed - ecc_stats.failed) &&
(ops->mode != MTD_OPS_RAW)) {
chip->pagecache.page = realpage;
chip->pagecache.bitflips = ret;
@@ -3240,7 +3328,7 @@ read_retry:
/* Invalidate page cache */
chip->pagecache.page = -1;
}
- memcpy(buf, chip->data_buf + col, bytes);
+ memcpy(buf, bufpoi + col, bytes);
}
if (unlikely(oob)) {
@@ -3255,7 +3343,7 @@ read_retry:
nand_wait_readrdy(chip);
- if (mtd->ecc_stats.failed - ecc_failures) {
+ if (mtd->ecc_stats.failed - ecc_stats.failed) {
if (retry_mode + 1 < chip->read_retries) {
retry_mode++;
ret = nand_setup_read_retry(chip,
@@ -3263,8 +3351,8 @@ read_retry:
if (ret < 0)
break;
- /* Reset failures; retry */
- mtd->ecc_stats.failed = ecc_failures;
+ /* Reset ecc_stats; retry */
+ mtd->ecc_stats = ecc_stats;
goto read_retry;
} else {
/* No more retry modes; real failure */
@@ -3373,7 +3461,7 @@ static int nand_read_oob_syndrome(struct nand_chip *chip, int page)
sndrnd = 1;
toread = min_t(int, length, chunk);
- ret = nand_read_data_op(chip, bufpoi, toread, false);
+ ret = nand_read_data_op(chip, bufpoi, toread, false, false);
if (ret)
return ret;
@@ -3381,7 +3469,7 @@ static int nand_read_oob_syndrome(struct nand_chip *chip, int page)
length -= toread;
}
if (length > 0) {
- ret = nand_read_data_op(chip, bufpoi, length, false);
+ ret = nand_read_data_op(chip, bufpoi, length, false, false);
if (ret)
return ret;
}
@@ -3634,6 +3722,42 @@ int nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
EXPORT_SYMBOL(nand_write_page_raw);
/**
+ * nand_monolithic_write_page_raw - Monolithic page write in raw mode
+ * @chip: NAND chip info structure
+ * @buf: data buffer to write
+ * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
+ *
+ * This is a raw page write, ie. without any error detection/correction.
+ * Monolithic means we are requesting all the relevant data (main plus
+ * eventually OOB) to be sent over the bus and effectively programmed
+ * into the NAND chip arrays in a single operation. This is an
+ * alternative to nand_write_page_raw(), which first sends the main
+ * data, then eventually send the OOB data by latching more data
+ * cycles on the NAND bus, and finally sends the program command to
+ * synchronyze the NAND chip cache.
+ */
+int nand_monolithic_write_page_raw(struct nand_chip *chip, const u8 *buf,
+ int oob_required, int page)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ unsigned int size = mtd->writesize;
+ u8 *write_buf = (u8 *)buf;
+
+ if (oob_required) {
+ size += mtd->oobsize;
+
+ if (buf != chip->data_buf) {
+ write_buf = nand_get_data_buf(chip);
+ memcpy(write_buf, buf, mtd->writesize);
+ }
+ }
+
+ return nand_prog_page_op(chip, page, 0, write_buf, size);
+}
+EXPORT_SYMBOL(nand_monolithic_write_page_raw);
+
+/**
* nand_write_page_raw_syndrome - [INTERN] raw page write function
* @chip: nand chip info structure
* @buf: data buffer
@@ -4012,20 +4136,23 @@ static int nand_do_write_ops(struct nand_chip *chip, loff_t to,
while (1) {
int bytes = mtd->writesize;
uint8_t *wbuf = buf;
- int use_bufpoi;
+ int use_bounce_buf;
int part_pagewr = (column || writelen < mtd->writesize);
if (part_pagewr)
- use_bufpoi = 1;
- else if (chip->options & NAND_USE_BOUNCE_BUFFER)
- use_bufpoi = !virt_addr_valid(buf) ||
- !IS_ALIGNED((unsigned long)buf,
- chip->buf_align);
+ use_bounce_buf = 1;
+ else if (chip->options & NAND_USES_DMA)
+ use_bounce_buf = !virt_addr_valid(buf) ||
+ !IS_ALIGNED((unsigned long)buf,
+ chip->buf_align);
else
- use_bufpoi = 0;
+ use_bounce_buf = 0;
- /* Partial page write?, or need to use bounce buffer */
- if (use_bufpoi) {
+ /*
+ * Copy the data from the initial buffer when doing partial page
+ * writes or when a bounce buffer is required.
+ */
+ if (use_bounce_buf) {
pr_debug("%s: using write bounce buffer for buf@%p\n",
__func__, buf);
if (part_pagewr)
@@ -4883,7 +5010,6 @@ static const char * const nand_ecc_modes[] = {
[NAND_ECC_SOFT] = "soft",
[NAND_ECC_HW] = "hw",
[NAND_ECC_HW_SYNDROME] = "hw_syndrome",
- [NAND_ECC_HW_OOB_FIRST] = "hw_oob_first",
[NAND_ECC_ON_DIE] = "on-die",
};
@@ -4896,14 +5022,14 @@ static int of_get_nand_ecc_mode(struct device_node *np)
if (err < 0)
return err;
- for (i = 0; i < ARRAY_SIZE(nand_ecc_modes); i++)
+ for (i = NAND_ECC_NONE; i < ARRAY_SIZE(nand_ecc_modes); i++)
if (!strcasecmp(pm, nand_ecc_modes[i]))
return i;
/*
* For backward compatibility we support few obsoleted values that don't
- * have their mappings into nand_ecc_modes_t anymore (they were merged
- * with other enums).
+ * have their mappings into the nand_ecc_mode enum anymore (they were
+ * merged with other enums).
*/
if (!strcasecmp(pm, "soft_bch"))
return NAND_ECC_SOFT;
@@ -4917,17 +5043,20 @@ static const char * const nand_ecc_algos[] = {
[NAND_ECC_RS] = "rs",
};
-static int of_get_nand_ecc_algo(struct device_node *np)
+static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
{
+ enum nand_ecc_algo ecc_algo;
const char *pm;
- int err, i;
+ int err;
err = of_property_read_string(np, "nand-ecc-algo", &pm);
if (!err) {
- for (i = NAND_ECC_HAMMING; i < ARRAY_SIZE(nand_ecc_algos); i++)
- if (!strcasecmp(pm, nand_ecc_algos[i]))
- return i;
- return -ENODEV;
+ for (ecc_algo = NAND_ECC_HAMMING;
+ ecc_algo < ARRAY_SIZE(nand_ecc_algos);
+ ecc_algo++) {
+ if (!strcasecmp(pm, nand_ecc_algos[ecc_algo]))
+ return ecc_algo;
+ }
}
/*
@@ -4935,15 +5064,14 @@ static int of_get_nand_ecc_algo(struct device_node *np)
* for some obsoleted values that were specifying ECC algorithm.
*/
err = of_property_read_string(np, "nand-ecc-mode", &pm);
- if (err < 0)
- return err;
-
- if (!strcasecmp(pm, "soft"))
- return NAND_ECC_HAMMING;
- else if (!strcasecmp(pm, "soft_bch"))
- return NAND_ECC_BCH;
+ if (!err) {
+ if (!strcasecmp(pm, "soft"))
+ return NAND_ECC_HAMMING;
+ else if (!strcasecmp(pm, "soft_bch"))
+ return NAND_ECC_BCH;
+ }
- return -ENODEV;
+ return NAND_ECC_UNKNOWN;
}
static int of_get_nand_ecc_step_size(struct device_node *np)
@@ -4988,7 +5116,8 @@ static bool of_get_nand_on_flash_bbt(struct device_node *np)
static int nand_dt_init(struct nand_chip *chip)
{
struct device_node *dn = nand_get_flash_node(chip);
- int ecc_mode, ecc_algo, ecc_strength, ecc_step;
+ enum nand_ecc_algo ecc_algo;
+ int ecc_mode, ecc_strength, ecc_step;
if (!dn)
return 0;
@@ -5010,7 +5139,7 @@ static int nand_dt_init(struct nand_chip *chip)
if (ecc_mode >= 0)
chip->ecc.mode = ecc_mode;
- if (ecc_algo >= 0)
+ if (ecc_algo != NAND_ECC_UNKNOWN)
chip->ecc.algo = ecc_algo;
if (ecc_strength >= 0)
@@ -5140,8 +5269,10 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip)
ecc->read_page = nand_read_page_swecc;
ecc->read_subpage = nand_read_subpage;
ecc->write_page = nand_write_page_swecc;
- ecc->read_page_raw = nand_read_page_raw;
- ecc->write_page_raw = nand_write_page_raw;
+ if (!ecc->read_page_raw)
+ ecc->read_page_raw = nand_read_page_raw;
+ if (!ecc->write_page_raw)
+ ecc->write_page_raw = nand_write_page_raw;
ecc->read_oob = nand_read_oob_std;
ecc->write_oob = nand_write_oob_std;
if (!ecc->size)
@@ -5163,8 +5294,10 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip)
ecc->read_page = nand_read_page_swecc;
ecc->read_subpage = nand_read_subpage;
ecc->write_page = nand_write_page_swecc;
- ecc->read_page_raw = nand_read_page_raw;
- ecc->write_page_raw = nand_write_page_raw;
+ if (!ecc->read_page_raw)
+ ecc->read_page_raw = nand_read_page_raw;
+ if (!ecc->write_page_raw)
+ ecc->write_page_raw = nand_write_page_raw;
ecc->read_oob = nand_read_oob_std;
ecc->write_oob = nand_write_oob_std;
@@ -5628,16 +5761,6 @@ static int nand_scan_tail(struct nand_chip *chip)
*/
switch (ecc->mode) {
- case NAND_ECC_HW_OOB_FIRST:
- /* Similar to NAND_ECC_HW, but a separate read_page handle */
- if (!ecc->calculate || !ecc->correct || !ecc->hwctl) {
- WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
- ret = -EINVAL;
- goto err_nand_manuf_cleanup;
- }
- if (!ecc->read_page)
- ecc->read_page = nand_read_page_hwecc_oob_first;
- fallthrough;
case NAND_ECC_HW:
/* Use standard hwecc read page function? */
if (!ecc->read_page)
@@ -5781,8 +5904,10 @@ static int nand_scan_tail(struct nand_chip *chip)
/* ECC sanity check: warn if it's too weak */
if (!nand_ecc_strength_good(chip))
- pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
- mtd->name);
+ pr_warn("WARNING: %s: the ECC used on your system (%db/%dB) is too weak compared to the one required by the NAND chip (%db/%dB)\n",
+ mtd->name, chip->ecc.strength, chip->ecc.size,
+ chip->base.eccreq.strength,
+ chip->base.eccreq.step_size);
/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
@@ -5975,18 +6100,6 @@ void nand_cleanup(struct nand_chip *chip)
EXPORT_SYMBOL_GPL(nand_cleanup);
-/**
- * nand_release - [NAND Interface] Unregister the MTD device and free resources
- * held by the NAND device
- * @chip: NAND chip object
- */
-void nand_release(struct nand_chip *chip)
-{
- mtd_device_unregister(nand_to_mtd(chip));
- nand_cleanup(chip);
-}
-EXPORT_SYMBOL_GPL(nand_release);
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");