From patchwork Fri Jun 5 11:52:39 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roy Spliet X-Patchwork-Id: 481160 X-Patchwork-Delegate: scottwood@freescale.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 16A2E140218 for ; Fri, 5 Jun 2015 21:54:04 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 99B974B6A7; Fri, 5 Jun 2015 13:53:38 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 723Qv3Qt5kdQ; Fri, 5 Jun 2015 13:53:38 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id DE2C74B65B; Fri, 5 Jun 2015 13:53:19 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 67AA94B699 for ; Fri, 5 Jun 2015 13:53:13 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id f1BEwbU8nNMk for ; Fri, 5 Jun 2015 13:53:13 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-wi0-f179.google.com (mail-wi0-f179.google.com [209.85.212.179]) by theia.denx.de (Postfix) with ESMTPS id 828A54B69D for ; Fri, 5 Jun 2015 13:53:02 +0200 (CEST) Received: by wibut5 with SMTP id ut5so18592746wib.1 for ; Fri, 05 Jun 2015 04:53:02 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:from:to:cc:subject:date:message-id :in-reply-to:references:content-type; bh=G8tihF+JGCi9K82zOkfYZkTXwAyQvzkZNhgD7wWBw7I=; b=FsYYVT2/93hOv/TLdIp7hHNxaMHJpVNwRhOHzHQMNNprHipt3PjUQl4zw6NDHnTD+3 4oE8H24iXARxbQB6DJ3Lhe9swa1AcmtZ83CQXLFlDAeYK75pbFUhHhF/kImJqrB4RO5P 1KWlZSMet12D9gtMu47oa989FCboaISAeVCFOmM8AdlmIaTw4fYZHJcTg6gYXh5km8lD fHelahp4Zv0QwTwrW+7I2qE3yguGau4EuwQ0jREcggOKTCkV3J9210ph1OQ5UTJqWqW5 EDa5T/S8UjFqREbfNfLFNcG5SDj/HxPJcUoKRA1Yt45ynx5wagObsufFEhIwx7wkO9tC e0Mw== X-Gm-Message-State: ALoCoQnKjXv+oplafcimnYo4nryQX8aQRvpm2qd8R3WO+lTqUxyRNfM7QZklvv7eGQ/EsaLsLRak12Aiwgcz3tOtskeera+xYj3aTpiRz9qIGgc865843OxmJ5xjW1vYmnyvbql5zz7S MIME-Version: 1.0 X-Received: by 10.194.193.71 with SMTP id hm7mr5976610wjc.40.1433505181902; Fri, 05 Jun 2015 04:53:01 -0700 (PDT) Received: from Seven.fritz.box (a83-163-237-212.adsl.xs4all.nl. [83.163.237.212]) by mx.google.com with ESMTPSA id d3sm2949692wic.1.2015.06.05.04.52.59 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 05 Jun 2015 04:53:00 -0700 (PDT) From: Roy Spliet To: U-Boot Mailinglist , Sunxi Mailinglist Date: Fri, 5 Jun 2015 13:52:39 +0200 Message-Id: <1433505164-24112-7-git-send-email-r.spliet@ultimaker.com> X-Mailer: git-send-email 2.4.2 In-Reply-To: <1433505164-24112-1-git-send-email-r.spliet@ultimaker.com> References: <1433505164-24112-1-git-send-email-r.spliet@ultimaker.com> Cc: Daniel Kochmanski , Roy Spliet , Ian Campbell Subject: [U-Boot] [RFC 06/11] mtd/nand: Add randomisation layer X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Based on BBrezillons work, minus per-partition support. Changes to support that would be quite invasive while it hasn't been solved yet for Linux. Signed-off-by: Roy Spliet --- drivers/mtd/nand/nand_base.c | 255 ++++++++++++++++++++++++++++++++++--------- include/linux/mtd/nand.h | 96 ++++++++++++++++ 2 files changed, 299 insertions(+), 52 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 83586cc..5196c0c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1185,6 +1185,62 @@ EXPORT_SYMBOL(nand_lock); #endif /** + * nand_rnd_is_activ - check wether a region of a NAND page requires NAND + * randomizer to be disabled + * @mtd: mtd info + * @page: NAND page + * @column: offset within the page + * @len: len of the region + * + * Returns 1 if the randomizer should be enabled, 0 if not, or -ERR in case of + * error. + * + * In case of success len will contain the size of the region: + * - if the requested region fits in a NAND random region len will not change + * - else len will be replaced by the available length within the NAND random + * region + */ +int nand_rnd_is_activ(struct mtd_info *mtd, int page, int column, int *len) +{ + struct nand_chip *chip = mtd->priv; + struct nand_rnd_layout *layout = chip->rnd.layout; + struct nand_rndfree *range; + int ret = 1; + int tmp; + int i; + + if (!len || *len < 0 || column < 0 || + column + *len > mtd->writesize + mtd->oobsize) + return -EINVAL; + + if (layout) { + for (i = 0; i < layout->nranges; i++) { + range = &layout->ranges[i]; + if (column + *len <= range->offset) { + break; + } else if (column >= range->offset + range->length) { + continue; + } else if (column < range->offset) { + tmp = range->offset - column; + if (*len > tmp) + *len = tmp; + break; + } else { + tmp = range->offset + range->length - column; + if (*len > tmp) + *len = tmp; + ret = 0; + break; + } + + } + } + + return ret; +} +EXPORT_SYMBOL(nand_rnd_is_activ); + +/** * nand_page_is_empty - check wether a NAND page contains only FFs * @mtd: mtd info * @data: data buffer @@ -1329,9 +1385,13 @@ EXPORT_SYMBOL(nand_pst_create); static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { - chip->read_buf(mtd, buf, mtd->writesize); - if (oob_required) - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + nand_rnd_config(mtd, page, 0, NAND_RND_READ); + nand_rnd_read_buf(mtd, buf, mtd->writesize); + if (oob_required){ + nand_rnd_config(mtd, page, mtd->writesize, NAND_RND_READ); + nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize); + } + nand_rnd_config(mtd, -1, -1, NAND_RND_READ); return 0; } @@ -1352,29 +1412,40 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; uint8_t *oob = chip->oob_poi; - int steps, size; + int steps, size, column = 0; for (steps = chip->ecc.steps; steps > 0; steps--) { - chip->read_buf(mtd, buf, eccsize); + nand_rnd_config(mtd, page, column, NAND_RND_READ); + nand_rnd_read_buf(mtd, buf, eccsize); buf += eccsize; + column += eccsize; if (chip->ecc.prepad) { - chip->read_buf(mtd, oob, chip->ecc.prepad); + nand_rnd_config(mtd, page, column, NAND_RND_READ); + nand_rnd_read_buf(mtd, oob, chip->ecc.prepad); oob += chip->ecc.prepad; + column += chip->ecc.prepad; } - chip->read_buf(mtd, oob, eccbytes); + nand_rnd_config(mtd, page, column, NAND_RND_READ); + nand_rnd_read_buf(mtd, oob, eccbytes); oob += eccbytes; + column += eccbytes; if (chip->ecc.postpad) { - chip->read_buf(mtd, oob, chip->ecc.postpad); + nand_rnd_config(mtd, page, column, NAND_RND_READ); + nand_rnd_read_buf(mtd, oob, chip->ecc.postpad); oob += chip->ecc.postpad; + column += chip->ecc.postpad; } } size = mtd->oobsize - (oob - chip->oob_poi); - if (size) - chip->read_buf(mtd, oob, size); + if (size) { + nand_rnd_config(mtd, page, column, NAND_RND_READ); + nand_rnd_read_buf(mtd, oob, size); + } + nand_rnd_config(mtd, -1, -1, NAND_RND_READ); return 0; } @@ -1462,7 +1533,8 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1); p = bufpoi + data_col_addr; - chip->read_buf(mtd, p, datafrag_len); + nand_rnd_config(mtd, -1, data_col_addr, NAND_RND_READ); + nand_rnd_read_buf(mtd, p, datafrag_len); /* Calculate ECC */ for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) @@ -1481,7 +1553,8 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, } if (gaps) { chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + nand_rnd_config(mtd, -1, mtd->writesize, NAND_RND_READ); + nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize); } else { /* * Send the command to read the particular ECC bytes take care @@ -1496,7 +1569,8 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1); - chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); + nand_rnd_config(mtd, -1, mtd->writesize + aligned_pos, NAND_RND_READ); + nand_rnd_read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); } for (i = 0; i < eccfrag_len; i++) @@ -1515,6 +1589,8 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, max_bitflips = max_t(unsigned int, max_bitflips, stat); } } + nand_rnd_config(mtd, -1, -1, NAND_RND_READ); + return max_bitflips; } @@ -1539,13 +1615,17 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *ecc_code = chip->buffers->ecccode; uint32_t *eccpos = chip->ecc.layout->eccpos; unsigned int max_bitflips = 0; + int column = 0; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); + nand_rnd_config(mtd, page, column, NAND_RND_READ); + nand_rnd_read_buf(mtd, p, eccsize); chip->ecc.calculate(mtd, p, &ecc_calc[i]); + column += eccsize; } - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + nand_rnd_config(mtd, page, column, NAND_RND_READ); + nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize); for (i = 0; i < chip->ecc.total; i++) ecc_code[i] = chip->oob_poi[eccpos[i]]; @@ -1564,6 +1644,8 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, max_bitflips = max_t(unsigned int, max_bitflips, stat); } } + nand_rnd_config(mtd, -1, -1, NAND_RND_READ); + return max_bitflips; } @@ -1592,11 +1674,14 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, uint32_t *eccpos = chip->ecc.layout->eccpos; uint8_t *ecc_calc = chip->buffers->ecccalc; unsigned int max_bitflips = 0; + int column = 0; /* Read the OOB area first */ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + nand_rnd_config(mtd, page, mtd->writesize, NAND_RND_READ); + nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize); chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + column = 0; for (i = 0; i < chip->ecc.total; i++) ecc_code[i] = chip->oob_poi[eccpos[i]]; @@ -1605,7 +1690,8 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, int stat; chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); + nand_rnd_config(mtd, page, column, NAND_RND_READ); + nand_rnd_read_buf(mtd, p, eccsize); chip->ecc.calculate(mtd, p, &ecc_calc[i]); stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); @@ -1616,6 +1702,8 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, max_bitflips = max_t(unsigned int, max_bitflips, stat); } } + nand_rnd_config(mtd, -1, -1, NAND_RND_READ); + return max_bitflips; } @@ -1639,20 +1727,26 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *p = buf; uint8_t *oob = chip->oob_poi; unsigned int max_bitflips = 0; + int column = 0; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { int stat; chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); + nand_rnd_config(mtd, page, column, NAND_RND_READ); + nand_rnd_read_buf(mtd, p, eccsize); + column += eccsize; if (chip->ecc.prepad) { - chip->read_buf(mtd, oob, chip->ecc.prepad); + nand_rnd_config(mtd, page, column, NAND_RND_READ); + nand_rnd_read_buf(mtd, oob, chip->ecc.prepad); oob += chip->ecc.prepad; } chip->ecc.hwctl(mtd, NAND_ECC_READSYN); - chip->read_buf(mtd, oob, eccbytes); + nand_rnd_config(mtd, page, column, NAND_RND_READ); + nand_rnd_read_buf(mtd, oob, eccbytes); + column += eccbytes; stat = chip->ecc.correct(mtd, p, oob, NULL); if (stat < 0) { @@ -1665,15 +1759,20 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, oob += eccbytes; if (chip->ecc.postpad) { - chip->read_buf(mtd, oob, chip->ecc.postpad); + nand_rnd_config(mtd, page, column, NAND_RND_READ); + nand_rnd_read_buf(mtd, oob, chip->ecc.postpad); + column += chip->ecc.postpad; oob += chip->ecc.postpad; } } /* Calculate remaining oob bytes */ i = mtd->oobsize - (oob - chip->oob_poi); - if (i) - chip->read_buf(mtd, oob, i); + if (i) { + nand_rnd_config(mtd, page, column, NAND_RND_READ); + nand_rnd_read_buf(mtd, oob, i); + } + nand_rnd_config(mtd, -1, -1, NAND_RND_READ); return max_bitflips; } @@ -1685,9 +1784,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, * @ops: oob ops structure * @len: size of oob to transfer */ -static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, +static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob, struct mtd_oob_ops *ops, size_t len) { + struct nand_chip *chip = mtd->priv; + switch (ops->mode) { case MTD_OPS_PLACE_OOB: @@ -1804,6 +1905,7 @@ read_retry: * Now read the page into the buffer. Absent an error, * the read methods return max bitflips per ecc step. */ + nand_rnd_config(mtd, page, -1, NAND_RND_READ); if (unlikely(ops->mode == MTD_OPS_RAW)) ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, oob_required, @@ -1816,6 +1918,8 @@ read_retry: else ret = chip->ecc.read_page(mtd, chip, bufpoi, oob_required, page); + nand_rnd_config(mtd, -1, -1, NAND_RND_READ); + if (ret < 0) { if (!aligned) /* Invalidate page cache */ @@ -1843,7 +1947,7 @@ read_retry: int toread = min(oobreadlen, max_oobsize); if (toread) { - oob = nand_transfer_oob(chip, + oob = nand_transfer_oob(mtd, oob, ops, toread); oobreadlen -= toread; } @@ -1960,7 +2064,9 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page) { chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + nand_rnd_config(mtd, page, mtd->writesize, NAND_RND_READ); + nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize); + nand_rnd_config(mtd, -1, -1, NAND_RND_READ); return 0; } @@ -1979,7 +2085,7 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; int eccsize = chip->ecc.size; uint8_t *bufpoi = buf; - int i, toread, sndrnd = 0, pos; + int i, toread, sndrnd = 0, pos = eccsize; chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page); for (i = 0; i < chip->ecc.steps; i++) { @@ -1992,12 +2098,17 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, } else sndrnd = 1; toread = min_t(int, length, chunk); - chip->read_buf(mtd, bufpoi, toread); + nand_rnd_config(mtd, page, pos, NAND_RND_READ); + nand_rnd_read_buf(mtd, bufpoi, toread); bufpoi += toread; length -= toread; } - if (length > 0) - chip->read_buf(mtd, bufpoi, length); + if (length > 0){ + pos = mtd->writesize + mtd->oobsize - length; + nand_rnd_config(mtd, page, pos, NAND_RND_READ); + nand_rnd_read_buf(mtd, bufpoi, length); + } + nand_rnd_config(mtd, -1, -1, NAND_RND_READ); return 0; } @@ -2016,7 +2127,9 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int length = mtd->oobsize; chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); - chip->write_buf(mtd, buf, length); + nand_rnd_config(mtd, page, mtd->writesize, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, buf, length); + nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE); /* Send command to program the OOB data */ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); @@ -2071,12 +2184,18 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, } else sndcmd = 1; len = min_t(int, length, chunk); - chip->write_buf(mtd, bufpoi, len); + nand_rnd_config(mtd, page, pos, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, bufpoi, len); bufpoi += len; length -= len; } - if (length > 0) - chip->write_buf(mtd, bufpoi, length); + + if (length > 0){ + pos = mtd->writesize + mtd->oobsize - length; + nand_rnd_config(mtd, page, pos, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, bufpoi, length); + } + nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE); chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); status = chip->waitfunc(mtd, chip); @@ -2147,7 +2266,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, break; len = min(len, readlen); - buf = nand_transfer_oob(chip, buf, ops, len); + buf = nand_transfer_oob(mtd, buf, ops, len); if (chip->options & NAND_NEED_READRDY) { /* Apply delay or wait for ready/busy pin */ @@ -2265,29 +2384,39 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd, int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; uint8_t *oob = chip->oob_poi; - int steps, size; + int steps, size, column = 0; for (steps = chip->ecc.steps; steps > 0; steps--) { - chip->write_buf(mtd, buf, eccsize); + nand_rnd_config(mtd, -1, column, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, buf, eccsize); buf += eccsize; + column += eccsize; if (chip->ecc.prepad) { - chip->write_buf(mtd, oob, chip->ecc.prepad); + nand_rnd_config(mtd, -1, column, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, oob, chip->ecc.prepad); oob += chip->ecc.prepad; + column += chip->ecc.prepad; } - chip->write_buf(mtd, oob, eccbytes); + nand_rnd_config(mtd, -1, column, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, oob, eccbytes); oob += eccbytes; + column += eccbytes; if (chip->ecc.postpad) { - chip->write_buf(mtd, oob, chip->ecc.postpad); + nand_rnd_config(mtd, -1, column, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, oob, chip->ecc.postpad); oob += chip->ecc.postpad; + column += chip->ecc.postpad; } } size = mtd->oobsize - (oob - chip->oob_poi); - if (size) - chip->write_buf(mtd, oob, size); + if (size) { + nand_rnd_config(mtd, -1, column, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, oob, size); + } return 0; } @@ -2334,17 +2463,21 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *ecc_calc = chip->buffers->ecccalc; const uint8_t *p = buf; uint32_t *eccpos = chip->ecc.layout->eccpos; + int column = 0; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { chip->ecc.hwctl(mtd, NAND_ECC_WRITE); - chip->write_buf(mtd, p, eccsize); + nand_rnd_config(mtd, -1, column, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, p, eccsize); chip->ecc.calculate(mtd, p, &ecc_calc[i]); + column += eccsize; } for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + nand_rnd_config(mtd, -1, column, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, chip->oob_poi, mtd->oobsize); return 0; } @@ -2380,7 +2513,10 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd, chip->ecc.hwctl(mtd, NAND_ECC_WRITE); /* write data (untouched subpages already masked by 0xFF) */ - chip->write_buf(mtd, buf, ecc_size); + nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, buf, ecc_size); + offset += ecc_size; + /* mask ECC of un-touched subpages by padding 0xFF */ if ((step < start_step) || (step > end_step)) @@ -2405,7 +2541,8 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd, chip->oob_poi[eccpos[i]] = ecc_calc[i]; /* write OOB buffer to NAND device */ - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, chip->oob_poi, mtd->oobsize); return 0; } @@ -2430,31 +2567,42 @@ static int nand_write_page_syndrome(struct mtd_info *mtd, int eccsteps = chip->ecc.steps; const uint8_t *p = buf; uint8_t *oob = chip->oob_poi; + int column = 0; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { chip->ecc.hwctl(mtd, NAND_ECC_WRITE); - chip->write_buf(mtd, p, eccsize); + nand_rnd_config(mtd, -1, column, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, p, eccsize); + column += eccsize; if (chip->ecc.prepad) { - chip->write_buf(mtd, oob, chip->ecc.prepad); + nand_rnd_config(mtd, -1, column, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, oob, chip->ecc.prepad); oob += chip->ecc.prepad; + column += chip->ecc.prepad; } chip->ecc.calculate(mtd, p, oob); - chip->write_buf(mtd, oob, eccbytes); + nand_rnd_config(mtd, -1, column, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, oob, eccbytes); oob += eccbytes; + column += eccbytes; if (chip->ecc.postpad) { - chip->write_buf(mtd, oob, chip->ecc.postpad); + nand_rnd_config(mtd, -1, column, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, oob, chip->ecc.postpad); oob += chip->ecc.postpad; + column += chip->ecc.postpad; } } /* Calculate remaining oob bytes */ i = mtd->oobsize - (oob - chip->oob_poi); - if (i) - chip->write_buf(mtd, oob, i); + if (i) { + nand_rnd_config(mtd, -1, column, NAND_RND_WRITE); + nand_rnd_write_buf(mtd, oob, i); + } return 0; } @@ -2485,6 +2633,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + nand_rnd_config(mtd, page, 0, NAND_RND_WRITE); if (unlikely(raw)) status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required); @@ -2494,6 +2643,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, else status = chip->ecc.write_page(mtd, chip, buf, oob_required); + nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE); + if (status < 0) return status; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index ef6a783..6465a52 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -565,6 +565,64 @@ void nand_page_set_status(struct mtd_info *mtd, int page, int nand_pst_create(struct mtd_info *mtd); +/* + * Constants for randomizer modes + */ +typedef enum { + NAND_RND_NONE, + NAND_RND_SOFT, + NAND_RND_HW, +} nand_rnd_modes_t; + +/* + * Constants for randomizer actions + */ +enum nand_rnd_action { + NAND_RND_NO_ACTION, + NAND_RND_READ, + NAND_RND_WRITE, +}; + +/** + * struct nand_rndfree - Structure defining a NAND page region where the + * randomizer should be disabled + * @offset: range offset + * @length: range length + */ +struct nand_rndfree { + u32 offset; + u32 length; +}; + +/** + * struct nand_rnd_layout - Structure defining rndfree regions + * @nranges: number of ranges + * @ranges: array defining the rndfree regions + */ +struct nand_rnd_layout { + int nranges; + struct nand_rndfree ranges[0]; +}; + +/** + * struct nand_rnd_ctrl - Randomizer Control structure + * @mode: Randomizer mode + * @config: function to prepare the randomizer (i.e.: set the appropriate + * seed/init value). + * @read_buf: function that read from the NAND and descramble the retrieved + * data. + * @write_buf: function that scramble data before writing it to the NAND. + */ +struct nand_rnd_ctrl { + nand_rnd_modes_t mode; + struct nand_rnd_layout *layout; + void *priv; + int (*config)(struct mtd_info *mtd, int page, int column, + enum nand_rnd_action action); + void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); + void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); +}; + /** * struct nand_buffers - buffer structure for read/write * @ecccalc: buffer pointer for calculated ECC, size is oobsize. @@ -763,6 +821,8 @@ struct nand_chip { struct nand_buffers *buffers; struct nand_hw_control hwcontrol; + struct nand_rnd_ctrl rnd; + uint8_t *bbt; struct nand_bbt_descr *bbt_td; struct nand_bbt_descr *bbt_md; @@ -894,6 +954,42 @@ extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf); +static inline int nand_rnd_config(struct mtd_info *mtd, int page, int column, + enum nand_rnd_action action) +{ + struct nand_chip *chip = mtd->priv; + + if (chip->rnd.config) + return chip->rnd.config(mtd, page, column, action); + + return 0; +} + +static inline void nand_rnd_write_buf(struct mtd_info *mtd, const uint8_t *buf, + int len) +{ + struct nand_chip *chip = mtd->priv; + + if (chip->rnd.write_buf) + chip->rnd.write_buf(mtd, buf, len); + else + chip->write_buf(mtd, buf, len); +} + +static inline void nand_rnd_read_buf(struct mtd_info *mtd, uint8_t *buf, + int len) +{ + struct nand_chip *chip = mtd->priv; + + if (chip->rnd.read_buf) + chip->rnd.read_buf(mtd, buf, len); + else + chip->read_buf(mtd, buf, len); +} + +int nand_rnd_is_activ(struct mtd_info *mtd, int page, int column, int *len); + + #ifdef __UBOOT__ /* * Constants for oob configuration