summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/nand/raw/mxs_nand.c116
-rw-r--r--include/mxs_nand.h22
2 files changed, 138 insertions, 0 deletions
diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c
index a41b9620d0..ad7b644886 100644
--- a/drivers/mtd/nand/raw/mxs_nand.c
+++ b/drivers/mtd/nand/raw/mxs_nand.c
@@ -740,6 +740,19 @@ static int mxs_nand_ecc_write_page(struct mtd_info *mtd,
d->cmd.pio_words[4] = (dma_addr_t)nand_info->data_buf;
d->cmd.pio_words[5] = (dma_addr_t)nand_info->oob_buf;
+ if (is_mx7() && nand_info->en_randomizer) {
+ d->cmd.pio_words[2] |= GPMI_ECCCTRL_RANDOMIZER_ENABLE |
+ GPMI_ECCCTRL_RANDOMIZER_TYPE2;
+ /*
+ * Write NAND page number needed to be randomized
+ * to GPMI_ECCCOUNT register.
+ *
+ * The value is between 0-255. For additional details
+ * check 9.6.6.4 of i.MX7D Applications Processor reference
+ */
+ d->cmd.pio_words[3] |= (page % 255) << 16;
+ }
+
mxs_dma_desc_append(channel, d);
/* Flush caches */
@@ -1003,6 +1016,10 @@ int mxs_nand_setup_ecc(struct mtd_info *mtd)
uint32_t tmp;
int ret;
+ nand_info->en_randomizer = 0;
+ nand_info->oobsize = mtd->oobsize;
+ nand_info->writesize = mtd->writesize;
+
ret = mxs_nand_set_geometry(mtd, geo);
if (ret)
return ret;
@@ -1020,6 +1037,7 @@ int mxs_nand_setup_ecc(struct mtd_info *mtd)
tmp |= (geo->gf_len == 14 ? 1 : 0) <<
BCH_FLASHLAYOUT0_GF13_0_GF14_1_OFFSET;
writel(tmp, &bch_regs->hw_bch_flash0layout0);
+ nand_info->bch_flash0layout0 = tmp;
tmp = (mtd->writesize + mtd->oobsize)
<< BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET;
@@ -1028,6 +1046,7 @@ int mxs_nand_setup_ecc(struct mtd_info *mtd)
tmp |= (geo->gf_len == 14 ? 1 : 0) <<
BCH_FLASHLAYOUT1_GF13_0_GF14_1_OFFSET;
writel(tmp, &bch_regs->hw_bch_flash0layout1);
+ nand_info->bch_flash0layout1 = tmp;
/* Set *all* chip selects to use layout 0 */
writel(0, &bch_regs->hw_bch_layoutselect);
@@ -1303,3 +1322,100 @@ err:
free(nand_info);
}
#endif
+
+/*
+ * Read NAND layout for FCB block generation.
+ */
+void mxs_nand_get_layout(struct mtd_info *mtd, struct mxs_nand_layout *l)
+{
+ struct mxs_bch_regs *bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE;
+ u32 tmp;
+
+ tmp = readl(&bch_regs->hw_bch_flash0layout0);
+ l->nblocks = (tmp & BCH_FLASHLAYOUT0_NBLOCKS_MASK) >>
+ BCH_FLASHLAYOUT0_NBLOCKS_OFFSET;
+ l->meta_size = (tmp & BCH_FLASHLAYOUT0_META_SIZE_MASK) >>
+ BCH_FLASHLAYOUT0_META_SIZE_OFFSET;
+
+ tmp = readl(&bch_regs->hw_bch_flash0layout1);
+ l->data0_size = 4 * ((tmp & BCH_FLASHLAYOUT0_DATA0_SIZE_MASK) >>
+ BCH_FLASHLAYOUT0_DATA0_SIZE_OFFSET);
+ l->ecc0 = (tmp & BCH_FLASHLAYOUT0_ECC0_MASK) >>
+ BCH_FLASHLAYOUT0_ECC0_OFFSET;
+ l->datan_size = 4 * ((tmp & BCH_FLASHLAYOUT1_DATAN_SIZE_MASK) >>
+ BCH_FLASHLAYOUT1_DATAN_SIZE_OFFSET);
+ l->eccn = (tmp & BCH_FLASHLAYOUT1_ECCN_MASK) >>
+ BCH_FLASHLAYOUT1_ECCN_OFFSET;
+}
+
+/*
+ * Set BCH to specific layout used by ROM bootloader to read FCB.
+ */
+void mxs_nand_mode_fcb(struct mtd_info *mtd)
+{
+ u32 tmp;
+ struct mxs_bch_regs *bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
+
+ nand_info->en_randomizer = 1;
+
+ mtd->writesize = 1024;
+ mtd->oobsize = 1862 - 1024;
+
+ /* 8 ecc_chunks_*/
+ tmp = 7 << BCH_FLASHLAYOUT0_NBLOCKS_OFFSET;
+ /* 32 bytes for metadata */
+ tmp |= 32 << BCH_FLASHLAYOUT0_META_SIZE_OFFSET;
+ /* using ECC62 level to be performed */
+ tmp |= 0x1F << BCH_FLASHLAYOUT0_ECC0_OFFSET;
+ /* 0x20 * 4 bytes of the data0 block */
+ tmp |= 0x20 << BCH_FLASHLAYOUT0_DATA0_SIZE_OFFSET;
+ tmp |= 0 << BCH_FLASHLAYOUT0_GF13_0_GF14_1_OFFSET;
+ writel(tmp, &bch_regs->hw_bch_flash0layout0);
+
+ /* 1024 for data + 838 for OOB */
+ tmp = 1862 << BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET;
+ /* using ECC62 level to be performed */
+ tmp |= 0x1F << BCH_FLASHLAYOUT1_ECCN_OFFSET;
+ /* 0x20 * 4 bytes of the data0 block */
+ tmp |= 0x20 << BCH_FLASHLAYOUT1_DATAN_SIZE_OFFSET;
+ tmp |= 0 << BCH_FLASHLAYOUT1_GF13_0_GF14_1_OFFSET;
+ writel(tmp, &bch_regs->hw_bch_flash0layout1);
+}
+
+/*
+ * Restore BCH to normal settings.
+ */
+void mxs_nand_mode_normal(struct mtd_info *mtd)
+{
+ struct mxs_bch_regs *bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
+
+ nand_info->en_randomizer = 0;
+
+ mtd->writesize = nand_info->writesize;
+ mtd->oobsize = nand_info->oobsize;
+
+ writel(nand_info->bch_flash0layout0, &bch_regs->hw_bch_flash0layout0);
+ writel(nand_info->bch_flash0layout1, &bch_regs->hw_bch_flash0layout1);
+}
+
+uint32_t mxs_nand_mark_byte_offset(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
+ struct bch_geometry *geo = &nand_info->bch_geometry;
+
+ return geo->block_mark_byte_offset;
+}
+
+uint32_t mxs_nand_mark_bit_offset(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
+ struct bch_geometry *geo = &nand_info->bch_geometry;
+
+ return geo->block_mark_bit_offset;
+}
diff --git a/include/mxs_nand.h b/include/mxs_nand.h
index 4bd65cded9..ada20483d0 100644
--- a/include/mxs_nand.h
+++ b/include/mxs_nand.h
@@ -66,8 +66,30 @@ struct mxs_nand_info {
/* DMA descriptors */
struct mxs_dma_desc **desc;
uint32_t desc_index;
+
+ /* Hardware BCH interface and randomizer */
+ u32 en_randomizer;
+ u32 writesize;
+ u32 oobsize;
+ u32 bch_flash0layout0;
+ u32 bch_flash0layout1;
+};
+
+struct mxs_nand_layout {
+ u32 nblocks;
+ u32 meta_size;
+ u32 data0_size;
+ u32 ecc0;
+ u32 datan_size;
+ u32 eccn;
};
int mxs_nand_init_ctrl(struct mxs_nand_info *nand_info);
int mxs_nand_init_spl(struct nand_chip *nand);
int mxs_nand_setup_ecc(struct mtd_info *mtd);
+
+void mxs_nand_mode_fcb(struct mtd_info *mtd);
+void mxs_nand_mode_normal(struct mtd_info *mtd);
+u32 mxs_nand_mark_byte_offset(struct mtd_info *mtd);
+u32 mxs_nand_mark_bit_offset(struct mtd_info *mtd);
+void mxs_nand_get_layout(struct mtd_info *mtd, struct mxs_nand_layout *l);