diff options
Diffstat (limited to 'target/linux/sunxi/patches-4.1/123-mtd-nand-sunxi-add-hw-randomizer-support.patch')
-rw-r--r-- | target/linux/sunxi/patches-4.1/123-mtd-nand-sunxi-add-hw-randomizer-support.patch | 887 |
1 files changed, 0 insertions, 887 deletions
diff --git a/target/linux/sunxi/patches-4.1/123-mtd-nand-sunxi-add-hw-randomizer-support.patch b/target/linux/sunxi/patches-4.1/123-mtd-nand-sunxi-add-hw-randomizer-support.patch deleted file mode 100644 index 4590b8f842..0000000000 --- a/target/linux/sunxi/patches-4.1/123-mtd-nand-sunxi-add-hw-randomizer-support.patch +++ /dev/null @@ -1,887 +0,0 @@ -From ef4bc8ab68979e5c1c30f061c5af1a7d6ec8eb52 Mon Sep 17 00:00:00 2001 -From: Boris Brezillon <boris.brezillon@free-electrons.com> -Date: Tue, 21 Oct 2014 14:40:42 +0200 -Subject: [PATCH] mtd: nand: sunxi: Add HW randomizer support - -Add support for the HW randomizer available on the sunxi nand controller. - -Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - drivers/mtd/nand/sunxi_nand.c | 603 ++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 585 insertions(+), 18 deletions(-) - ---- a/drivers/mtd/nand/sunxi_nand.c -+++ b/drivers/mtd/nand/sunxi_nand.c -@@ -210,10 +210,12 @@ struct sunxi_nand_hw_ecc { - * - * @part: base paritition structure - * @ecc: per-partition ECC info -+ * @rnd: per-partition randomizer info - */ - struct sunxi_nand_part { - struct nand_part part; - struct nand_ecc_ctrl ecc; -+ struct nand_rnd_ctrl rnd; - }; - - static inline struct sunxi_nand_part * -@@ -223,6 +225,29 @@ to_sunxi_nand_part(struct nand_part *par - } - - /* -+ * sunxi NAND randomizer structure: stores NAND randomizer information -+ * -+ * @page: current page -+ * @column: current column -+ * @nseeds: seed table size -+ * @seeds: seed table -+ * @subseeds: pre computed sub seeds -+ * @step: step function -+ * @left: number of remaining bytes in the page -+ * @state: current randomizer state -+ */ -+struct sunxi_nand_hw_rnd { -+ int page; -+ int column; -+ int nseeds; -+ u16 *seeds; -+ u16 *subseeds; -+ u16 (*step)(struct mtd_info *mtd, u16 state, int column, int *left); -+ int left; -+ u16 state; -+}; -+ -+/* - * NAND chip structure: stores NAND chip device related information - * - * @node: used to store NAND chips into a list -@@ -237,6 +262,7 @@ struct sunxi_nand_chip { - struct list_head node; - struct nand_chip nand; - struct mtd_info mtd; -+ void *buffer; - unsigned long clk_rate; - int selected; - int nsels; -@@ -493,6 +519,185 @@ static void sunxi_nfc_write_buf(struct m - } - } - -+static u16 sunxi_nfc_hwrnd_step(struct sunxi_nand_hw_rnd *rnd, u16 state, int count) -+{ -+ state &= 0x7fff; -+ count *= 8; -+ while (count--) -+ state = ((state >> 1) | -+ ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff; -+ -+ return state; -+} -+ -+static u16 sunxi_nfc_hwrnd_single_step(u16 state, int count) -+{ -+ state &= 0x7fff; -+ while (count--) -+ state = ((state >> 1) | -+ ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff; -+ -+ return state; -+} -+ -+static int sunxi_nfc_hwrnd_config(struct mtd_info *mtd, int page, int column, -+ enum nand_rnd_action action) -+{ -+ struct nand_chip *nand = mtd->priv; -+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); -+ struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv; -+ u16 state; -+ -+ if (page < 0 && column < 0) { -+ rnd->page = -1; -+ rnd->column = -1; -+ return 0; -+ } -+ -+ if (column < 0) -+ column = 0; -+ if (page < 0) -+ page = rnd->page; -+ -+ if (page < 0) -+ return -EINVAL; -+ -+ if (page != rnd->page && action == NAND_RND_READ) { -+ int status; -+ -+ status = nand_page_get_status(mtd, page); -+ if (status == NAND_PAGE_STATUS_UNKNOWN) { -+ nand->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1); -+ sunxi_nfc_read_buf(mtd, sunxi_nand->buffer, -+ mtd->writesize + mtd->oobsize); -+ -+ if (nand_page_is_empty(mtd, sunxi_nand->buffer, -+ sunxi_nand->buffer + -+ mtd->writesize)) -+ status = NAND_PAGE_EMPTY; -+ else -+ status = NAND_PAGE_FILLED; -+ -+ nand_page_set_status(mtd, page, status); -+ nand->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1); -+ } -+ } -+ -+ state = rnd->seeds[page % rnd->nseeds]; -+ rnd->page = page; -+ rnd->column = column; -+ -+ if (rnd->step) { -+ rnd->state = rnd->step(mtd, state, column, &rnd->left); -+ } else { -+ rnd->state = sunxi_nfc_hwrnd_step(rnd, state, column % 4096); -+ rnd->left = mtd->oobsize + mtd->writesize - column; -+ } -+ -+ return 0; -+} -+ -+static void sunxi_nfc_hwrnd_write_buf(struct mtd_info *mtd, const uint8_t *buf, -+ int len) -+{ -+ struct nand_chip *nand = mtd->priv; -+ struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); -+ struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv; -+ u32 tmp = readl(nfc->regs + NFC_REG_ECC_CTL); -+ int cnt; -+ int offs = 0; -+ int rndactiv; -+ -+ tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN); -+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL); -+ -+ if (rnd->page < 0) { -+ sunxi_nfc_write_buf(mtd, buf, len); -+ return; -+ } -+ -+ while (len > offs) { -+ cnt = len - offs; -+ if (cnt > 1024) -+ cnt = 1024; -+ -+ rndactiv = nand_rnd_is_activ(mtd, rnd->page, rnd->column, -+ &cnt); -+ if (rndactiv > 0) { -+ writel(tmp | NFC_RANDOM_EN | (rnd->state << 16), -+ nfc->regs + NFC_REG_ECC_CTL); -+ if (rnd->left < cnt) -+ cnt = rnd->left; -+ } -+ -+ sunxi_nfc_write_buf(mtd, buf + offs, cnt); -+ -+ if (rndactiv > 0) -+ writel(tmp & ~NFC_RANDOM_EN, -+ nfc->regs + NFC_REG_ECC_CTL); -+ -+ offs += cnt; -+ if (len <= offs) -+ break; -+ -+ sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_WRITE); -+ } -+} -+ -+static void sunxi_nfc_hwrnd_read_buf(struct mtd_info *mtd, uint8_t *buf, -+ int len) -+{ -+ struct nand_chip *nand = mtd->priv; -+ struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); -+ struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv; -+ u32 tmp = readl(nfc->regs + NFC_REG_ECC_CTL); -+ int cnt; -+ int offs = 0; -+ int rndactiv; -+ -+ tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN); -+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL); -+ -+ if (rnd->page < 0) { -+ sunxi_nfc_read_buf(mtd, buf, len); -+ return; -+ } -+ -+ while (len > offs) { -+ cnt = len - offs; -+ if (cnt > 1024) -+ cnt = 1024; -+ -+ if (nand_page_get_status(mtd, rnd->page) != NAND_PAGE_EMPTY && -+ nand_rnd_is_activ(mtd, rnd->page, rnd->column, &cnt) > 0) -+ rndactiv = 1; -+ else -+ rndactiv = 0; -+ -+ if (rndactiv > 0) { -+ writel(tmp | NFC_RANDOM_EN | (rnd->state << 16), -+ nfc->regs + NFC_REG_ECC_CTL); -+ if (rnd->left < cnt) -+ cnt = rnd->left; -+ } -+ -+ if (buf) -+ sunxi_nfc_read_buf(mtd, buf + offs, cnt); -+ else -+ sunxi_nfc_read_buf(mtd, NULL, cnt); -+ -+ if (rndactiv > 0) -+ writel(tmp & ~NFC_RANDOM_EN, -+ nfc->regs + NFC_REG_ECC_CTL); -+ -+ offs += cnt; -+ if (len <= offs) -+ break; -+ -+ sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_READ); -+ } -+} -+ - static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd) - { - uint8_t ret; -@@ -542,16 +747,43 @@ static int sunxi_nfc_hw_ecc_read_page(st - int oob_required, int page) - { - struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); -+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip); - struct nand_ecc_ctrl *ecc = chip->cur_ecc; - struct nand_ecclayout *layout = ecc->layout; - struct sunxi_nand_hw_ecc *data = ecc->priv; - unsigned int max_bitflips = 0; -+ int status; - int offset; - int ret; - u32 tmp; - int i; - int cnt; - -+ status = nand_page_get_status(mtd, page); -+ if (status == NAND_PAGE_STATUS_UNKNOWN) { -+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1); -+ sunxi_nfc_read_buf(mtd, sunxi_nand->buffer, -+ mtd->writesize + mtd->oobsize); -+ -+ if (nand_page_is_empty(mtd, sunxi_nand->buffer, -+ sunxi_nand->buffer + -+ mtd->writesize)) { -+ status = NAND_PAGE_EMPTY; -+ } else { -+ status = NAND_PAGE_FILLED; -+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1); -+ } -+ -+ nand_page_set_status(mtd, page, status); -+ } -+ -+ if (status == NAND_PAGE_EMPTY) { -+ memset(buf, 0xff, mtd->writesize); -+ if (oob_required) -+ memset(chip->oob_poi, 0xff, mtd->oobsize); -+ return 0; -+ } -+ - tmp = readl(nfc->regs + NFC_REG_ECC_CTL); - tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); - tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | -@@ -560,12 +792,15 @@ static int sunxi_nfc_hw_ecc_read_page(st - writel(tmp, nfc->regs + NFC_REG_ECC_CTL); - - for (i = 0; i < ecc->steps; i++) { -+ bool rndactiv = false; -+ - if (i) - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i * ecc->size, -1); - - offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4; - -- chip->read_buf(mtd, NULL, ecc->size); -+ nand_rnd_config(mtd, page, i * ecc->size, NAND_RND_READ); -+ nand_rnd_read_buf(mtd, NULL, ecc->size); - - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); - -@@ -573,6 +808,25 @@ static int sunxi_nfc_hw_ecc_read_page(st - if (ret) - return ret; - -+ if (i) { -+ cnt = ecc->bytes + 4; -+ if (nand_rnd_is_activ(mtd, page, offset, &cnt) > 0 && -+ cnt == ecc->bytes + 4) -+ rndactiv = true; -+ } else { -+ cnt = ecc->bytes + 2; -+ if (nand_rnd_is_activ(mtd, page, offset + 2, &cnt) > 0 && -+ cnt == ecc->bytes + 2) -+ rndactiv = true; -+ } -+ -+ if (rndactiv) { -+ tmp = readl(nfc->regs + NFC_REG_ECC_CTL); -+ tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION); -+ tmp |= NFC_RANDOM_EN; -+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL); -+ } -+ - tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30); - writel(tmp, nfc->regs + NFC_REG_CMD); - -@@ -583,6 +837,9 @@ static int sunxi_nfc_hw_ecc_read_page(st - memcpy_fromio(buf + (i * ecc->size), - nfc->regs + NFC_RAM0_BASE, ecc->size); - -+ writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN, -+ nfc->regs + NFC_REG_ECC_CTL); -+ - if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) { - mtd->ecc_stats.failed++; - } else { -@@ -598,9 +855,10 @@ static int sunxi_nfc_hw_ecc_read_page(st - if (ret) - return ret; - -+ nand_rnd_config(mtd, -1, offset, NAND_RND_READ); - offset -= mtd->writesize; -- chip->read_buf(mtd, chip->oob_poi + offset, -- ecc->bytes + 4); -+ nand_rnd_read_buf(mtd, chip->oob_poi + offset, -+ ecc->bytes + 4); - } - } - -@@ -610,11 +868,14 @@ static int sunxi_nfc_hw_ecc_read_page(st - offset = mtd->writesize + - ecc->layout->oobfree[ecc->steps].offset; - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); -+ nand_rnd_config(mtd, -1, offset, NAND_RND_READ); - offset -= mtd->writesize; -- chip->read_buf(mtd, chip->oob_poi + offset, cnt); -+ nand_rnd_read_buf(mtd, chip->oob_poi + offset, cnt); - } - } - -+ nand_rnd_config(mtd, -1, -1, NAND_RND_READ); -+ - tmp = readl(nfc->regs + NFC_REG_ECC_CTL); - tmp &= ~NFC_ECC_EN; - -@@ -631,6 +892,7 @@ static int sunxi_nfc_hw_ecc_write_page(s - struct nand_ecc_ctrl *ecc = chip->cur_ecc; - struct nand_ecclayout *layout = ecc->layout; - struct sunxi_nand_hw_ecc *data = ecc->priv; -+ struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv; - int offset; - int ret; - u32 tmp; -@@ -645,17 +907,57 @@ static int sunxi_nfc_hw_ecc_write_page(s - writel(tmp, nfc->regs + NFC_REG_ECC_CTL); - - for (i = 0; i < ecc->steps; i++) { -+ bool rndactiv = false; -+ u8 oob_buf[4]; -+ - if (i) - chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1); - -- chip->write_buf(mtd, buf + (i * ecc->size), ecc->size); -+ nand_rnd_config(mtd, -1, i * ecc->size, NAND_RND_WRITE); -+ nand_rnd_write_buf(mtd, buf + (i * ecc->size), ecc->size); - - offset = layout->eccpos[i * ecc->bytes] - 4 + mtd->writesize; - - /* Fill OOB data in */ -- writel(NFC_BUF_TO_USER_DATA(chip->oob_poi + -- layout->oobfree[i].offset), -- nfc->regs + NFC_REG_USER_DATA_BASE); -+ if (!oob_required) -+ memset(oob_buf, 0xff, 4); -+ else -+ memcpy(oob_buf, -+ chip->oob_poi + layout->oobfree[i].offset, -+ 4); -+ -+ -+ memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4); -+ -+ if (i) { -+ cnt = ecc->bytes + 4; -+ if (rnd && -+ nand_rnd_is_activ(mtd, -1, offset, &cnt) > 0 && -+ cnt == ecc->bytes + 4) -+ rndactiv = true; -+ } else { -+ cnt = ecc->bytes + 2; -+ if (rnd && -+ nand_rnd_is_activ(mtd, -1, offset + 2, &cnt) > 0 && -+ cnt == ecc->bytes + 2) -+ rndactiv = true; -+ } -+ -+ if (rndactiv) { -+ /* pre randomize to generate FF patterns on the NAND */ -+ if (!i) { -+ u16 state = rnd->subseeds[rnd->page % rnd->nseeds]; -+ state = sunxi_nfc_hwrnd_single_step(state, 15); -+ oob_buf[0] ^= state; -+ state = sunxi_nfc_hwrnd_step(rnd, state, 1); -+ oob_buf[1] ^= state; -+ memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4); -+ } -+ tmp = readl(nfc->regs + NFC_REG_ECC_CTL); -+ tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION); -+ tmp |= NFC_RANDOM_EN; -+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL); -+ } - - chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1); - -@@ -669,6 +971,9 @@ static int sunxi_nfc_hw_ecc_write_page(s - ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); - if (ret) - return ret; -+ -+ writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN, -+ nfc->regs + NFC_REG_ECC_CTL); - } - - if (oob_required) { -@@ -677,11 +982,14 @@ static int sunxi_nfc_hw_ecc_write_page(s - offset = mtd->writesize + - ecc->layout->oobfree[i].offset; - chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1); -+ nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE); - offset -= mtd->writesize; -- chip->write_buf(mtd, chip->oob_poi + offset, cnt); -+ nand_rnd_write_buf(mtd, chip->oob_poi + offset, cnt); - } - } - -+ nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE); -+ - tmp = readl(nfc->regs + NFC_REG_ECC_CTL); - tmp &= ~NFC_ECC_EN; - -@@ -690,22 +998,76 @@ static int sunxi_nfc_hw_ecc_write_page(s - return 0; - } - -+static u16 sunxi_nfc_hw_ecc_rnd_steps(struct mtd_info *mtd, u16 state, -+ int column, int *left) -+{ -+ struct nand_chip *chip = mtd->priv; -+ struct nand_ecc_ctrl *ecc = chip->cur_ecc; -+ struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv; -+ int nblks = mtd->writesize / ecc->size; -+ int modsize = ecc->size; -+ int steps; -+ -+ if (column < mtd->writesize) { -+ steps = column % modsize; -+ *left = modsize - steps; -+ } else if (column < mtd->writesize + -+ (nblks * (ecc->bytes + 4))) { -+ column -= mtd->writesize; -+ steps = column % (ecc->bytes + 4); -+ *left = ecc->bytes + 4 - steps; -+ state = rnd->subseeds[rnd->page % rnd->nseeds]; -+ } else { -+ steps = column % 4096; -+ *left = mtd->writesize + mtd->oobsize - column; -+ } -+ -+ return sunxi_nfc_hwrnd_step(rnd, state, steps); -+} -+ - static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, - uint8_t *buf, int oob_required, - int page) - { - struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); -+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip); - struct nand_ecc_ctrl *ecc = chip->cur_ecc; - struct sunxi_nand_hw_ecc *data = ecc->priv; - unsigned int max_bitflips = 0; - uint8_t *oob = chip->oob_poi; - int offset = 0; - int ret; -+ int status; - int cnt; - u32 tmp; - int i; - -+ status = nand_page_get_status(mtd, page); -+ if (status == NAND_PAGE_STATUS_UNKNOWN) { -+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1); -+ sunxi_nfc_read_buf(mtd, sunxi_nand->buffer, -+ mtd->writesize + mtd->oobsize); -+ -+ if (nand_page_is_empty(mtd, sunxi_nand->buffer, -+ sunxi_nand->buffer + -+ mtd->writesize)) { -+ status = NAND_PAGE_EMPTY; -+ } else { -+ status = NAND_PAGE_FILLED; -+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1); -+ } -+ -+ nand_page_set_status(mtd, page, status); -+ } -+ -+ if (status == NAND_PAGE_EMPTY) { -+ memset(buf, 0xff, mtd->writesize); -+ if (oob_required) -+ memset(chip->oob_poi, 0xff, mtd->oobsize); -+ return 0; -+ } -+ - tmp = readl(nfc->regs + NFC_REG_ECC_CTL); - tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); - tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | -@@ -714,7 +1076,17 @@ static int sunxi_nfc_hw_syndrome_ecc_rea - writel(tmp, nfc->regs + NFC_REG_ECC_CTL); - - for (i = 0; i < ecc->steps; i++) { -- chip->read_buf(mtd, NULL, ecc->size); -+ nand_rnd_config(mtd, page, offset, NAND_RND_READ); -+ nand_rnd_read_buf(mtd, NULL, ecc->size); -+ -+ cnt = ecc->bytes + 4; -+ if (nand_rnd_is_activ(mtd, page, offset, &cnt) > 0 && -+ cnt == ecc->bytes + 4) { -+ tmp = readl(nfc->regs + NFC_REG_ECC_CTL); -+ tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION); -+ tmp |= NFC_RANDOM_EN; -+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL); -+ } - - tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30); - writel(tmp, nfc->regs + NFC_REG_CMD); -@@ -727,6 +1099,9 @@ static int sunxi_nfc_hw_syndrome_ecc_rea - buf += ecc->size; - offset += ecc->size; - -+ writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN, -+ nfc->regs + NFC_REG_ECC_CTL); -+ - if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) { - mtd->ecc_stats.failed++; - } else { -@@ -737,7 +1112,8 @@ static int sunxi_nfc_hw_syndrome_ecc_rea - - if (oob_required) { - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); -- chip->read_buf(mtd, oob, ecc->bytes + ecc->prepad); -+ nand_rnd_config(mtd, -1, offset, NAND_RND_READ); -+ nand_rnd_read_buf(mtd, oob, ecc->bytes + ecc->prepad); - oob += ecc->bytes + ecc->prepad; - } - -@@ -748,10 +1124,13 @@ static int sunxi_nfc_hw_syndrome_ecc_rea - cnt = mtd->oobsize - (oob - chip->oob_poi); - if (cnt > 0) { - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); -- chip->read_buf(mtd, oob, cnt); -+ nand_rnd_config(mtd, page, offset, NAND_RND_READ); -+ nand_rnd_read_buf(mtd, oob, cnt); - } - } - -+ nand_rnd_config(mtd, -1, -1, NAND_RND_READ); -+ - writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN, - nfc->regs + NFC_REG_ECC_CTL); - -@@ -766,6 +1145,7 @@ static int sunxi_nfc_hw_syndrome_ecc_wri - struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); - struct nand_ecc_ctrl *ecc = chip->cur_ecc; - struct sunxi_nand_hw_ecc *data = ecc->priv; -+ struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv; - uint8_t *oob = chip->oob_poi; - int offset = 0; - int ret; -@@ -781,13 +1161,24 @@ static int sunxi_nfc_hw_syndrome_ecc_wri - writel(tmp, nfc->regs + NFC_REG_ECC_CTL); - - for (i = 0; i < ecc->steps; i++) { -- chip->write_buf(mtd, buf + (i * ecc->size), ecc->size); -+ nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE); -+ nand_rnd_write_buf(mtd, buf + (i * ecc->size), ecc->size); - offset += ecc->size; - - /* Fill OOB data in */ - writel(NFC_BUF_TO_USER_DATA(oob), - nfc->regs + NFC_REG_USER_DATA_BASE); - -+ cnt = ecc->bytes + 4; -+ if (rnd && -+ nand_rnd_is_activ(mtd, rnd->page, offset, &cnt) > 0 && -+ cnt == ecc->bytes + 4) { -+ tmp = readl(nfc->regs + NFC_REG_ECC_CTL); -+ tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION); -+ tmp |= NFC_RANDOM_EN; -+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL); -+ } -+ - tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR | - (1 << 30); - writel(tmp, nfc->regs + NFC_REG_CMD); -@@ -796,6 +1187,9 @@ static int sunxi_nfc_hw_syndrome_ecc_wri - if (ret) - return ret; - -+ writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN, -+ nfc->regs + NFC_REG_ECC_CTL); -+ - offset += ecc->bytes + ecc->prepad; - oob += ecc->bytes + ecc->prepad; - } -@@ -804,9 +1198,11 @@ static int sunxi_nfc_hw_syndrome_ecc_wri - cnt = mtd->oobsize - (oob - chip->oob_poi); - if (cnt > 0) { - chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1); -- chip->write_buf(mtd, oob, cnt); -+ nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE); -+ nand_rnd_write_buf(mtd, oob, cnt); - } - } -+ nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE); - - tmp = readl(nfc->regs + NFC_REG_ECC_CTL); - tmp &= ~NFC_ECC_EN; -@@ -816,6 +1212,128 @@ static int sunxi_nfc_hw_syndrome_ecc_wri - return 0; - } - -+static u16 sunxi_nfc_hw_syndrome_ecc_rnd_steps(struct mtd_info *mtd, u16 state, -+ int column, int *left) -+{ -+ struct nand_chip *chip = mtd->priv; -+ struct nand_ecc_ctrl *ecc = chip->cur_ecc; -+ struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv; -+ int eccsteps = mtd->writesize / ecc->size; -+ int modsize = ecc->size + ecc->prepad + ecc->bytes; -+ int steps; -+ -+ if (column < (eccsteps * modsize)) { -+ steps = column % modsize; -+ *left = modsize - steps; -+ if (steps >= ecc->size) { -+ steps -= ecc->size; -+ state = rnd->subseeds[rnd->page % rnd->nseeds]; -+ } -+ } else { -+ steps = column % 4096; -+ *left = mtd->writesize + mtd->oobsize - column; -+ } -+ -+ return sunxi_nfc_hwrnd_step(rnd, state, steps); -+} -+ -+static u16 default_seeds[] = {0x4a80}; -+ -+static void sunxi_nand_rnd_ctrl_cleanup(struct nand_rnd_ctrl *rnd) -+{ -+ struct sunxi_nand_hw_rnd *hwrnd = rnd->priv; -+ -+ if (hwrnd->seeds != default_seeds) -+ kfree(hwrnd->seeds); -+ kfree(hwrnd->subseeds); -+ kfree(rnd->layout); -+ kfree(hwrnd); -+} -+ -+static int sunxi_nand_rnd_ctrl_init(struct mtd_info *mtd, -+ struct nand_rnd_ctrl *rnd, -+ struct nand_ecc_ctrl *ecc, -+ struct device_node *np) -+{ -+ struct sunxi_nand_hw_rnd *hwrnd; -+ struct nand_rnd_layout *layout = NULL; -+ int ret; -+ -+ hwrnd = kzalloc(sizeof(*hwrnd), GFP_KERNEL); -+ if (!hwrnd) -+ return -ENOMEM; -+ -+ hwrnd->seeds = default_seeds; -+ hwrnd->nseeds = ARRAY_SIZE(default_seeds); -+ -+ if (of_get_property(np, "nand-randomizer-seeds", &ret)) { -+ hwrnd->nseeds = ret / sizeof(*hwrnd->seeds); -+ hwrnd->seeds = kzalloc(hwrnd->nseeds * sizeof(*hwrnd->seeds), -+ GFP_KERNEL); -+ if (!hwrnd->seeds) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ ret = of_property_read_u16_array(np, "nand-randomizer-seeds", -+ hwrnd->seeds, hwrnd->nseeds); -+ if (ret) -+ goto err; -+ } -+ -+ switch (ecc->mode) { -+ case NAND_ECC_HW_SYNDROME: -+ hwrnd->step = sunxi_nfc_hw_syndrome_ecc_rnd_steps; -+ break; -+ -+ case NAND_ECC_HW: -+ hwrnd->step = sunxi_nfc_hw_ecc_rnd_steps; -+ -+ default: -+ layout = kzalloc(sizeof(*layout) + sizeof(struct nand_rndfree), -+ GFP_KERNEL); -+ if (!layout) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ layout->nranges = 1; -+ layout->ranges[0].offset = mtd->writesize; -+ layout->ranges[0].length = 2; -+ rnd->layout = layout; -+ break; -+ } -+ -+ if (ecc->mode == NAND_ECC_HW_SYNDROME || ecc->mode == NAND_ECC_HW) { -+ int i; -+ -+ hwrnd->subseeds = kzalloc(hwrnd->nseeds * -+ sizeof(*hwrnd->subseeds), -+ GFP_KERNEL); -+ if (!hwrnd->subseeds) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ for (i = 0; i < hwrnd->nseeds; i++) -+ hwrnd->subseeds[i] = sunxi_nfc_hwrnd_step(hwrnd, -+ hwrnd->seeds[i], -+ ecc->size); -+ } -+ -+ rnd->config = sunxi_nfc_hwrnd_config; -+ rnd->read_buf = sunxi_nfc_hwrnd_read_buf; -+ rnd->write_buf = sunxi_nfc_hwrnd_write_buf; -+ rnd->priv = hwrnd; -+ -+ return 0; -+ -+err: -+ kfree(hwrnd); -+ kfree(layout); -+ -+ return ret; -+} -+ - static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, - const struct nand_sdr_timings *timings) - { -@@ -1076,6 +1594,40 @@ static int sunxi_nand_hw_syndrome_ecc_ct - return 0; - } - -+static void sunxi_nand_rnd_cleanup(struct nand_rnd_ctrl *rnd) -+{ -+ switch (rnd->mode) { -+ case NAND_RND_HW: -+ sunxi_nand_rnd_ctrl_cleanup(rnd); -+ break; -+ default: -+ break; -+ } -+} -+ -+static int sunxi_nand_rnd_init(struct mtd_info *mtd, -+ struct nand_rnd_ctrl *rnd, -+ struct nand_ecc_ctrl *ecc, -+ struct device_node *np) -+{ -+ int ret; -+ -+ rnd->mode = NAND_RND_NONE; -+ -+ ret = of_get_nand_rnd_mode(np); -+ if (ret >= 0) -+ rnd->mode = ret; -+ -+ switch (rnd->mode) { -+ case NAND_RND_HW: -+ return sunxi_nand_rnd_ctrl_init(mtd, rnd, ecc, np); -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ - static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc) - { - switch (ecc->mode) { -@@ -1167,7 +1719,14 @@ struct nand_part *sunxi_ofnandpart_parse - if (ret) - goto err; - -+ ret = sunxi_nand_rnd_init(master, &part->rnd, &part->ecc, pp); -+ if (ret) { -+ sunxi_nand_ecc_cleanup(&part->ecc); -+ goto err; -+ } -+ - part->part.ecc = &part->ecc; -+ part->part.rnd = &part->rnd; - - return &part->part; - -@@ -1292,18 +1851,30 @@ static int sunxi_nand_chip_init(struct d - if (ret) - return ret; - -+ chip->buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); -+ if (!chip->buffer) -+ return -ENOMEM; -+ - ret = sunxi_nand_chip_init_timings(chip, np); - if (ret) { - dev_err(dev, "could not configure chip timings: %d\n", ret); - return ret; - } - -+ ret = nand_pst_create(mtd); -+ if (ret) -+ return ret; -+ - ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np); - if (ret) { - dev_err(dev, "ECC init failed: %d\n", ret); - return ret; - } - -+ ret = sunxi_nand_rnd_init(mtd, &nand->rnd, &nand->ecc, np); -+ if (ret) -+ return ret; -+ - ret = nand_scan_tail(mtd); - if (ret) { - dev_err(dev, "nand_scan_tail failed: %d\n", ret); -@@ -1360,6 +1931,8 @@ static void sunxi_nand_chips_cleanup(str - nand_release(&chip->mtd); - sunxi_nand_ecc_cleanup(&chip->nand.ecc); - list_del(&chip->node); -+ sunxi_nand_rnd_cleanup(&chip->nand.rnd); -+ kfree(chip->buffer); - } - } - |