From: Sascha Hauer <s.hauer@pengutronix.de>
To: Barebox List <barebox@lists.infradead.org>
Cc: Johannes Zink <j.zink@pengutronix.de>
Subject: [PATCH 3/7] mtd: nand-mxs: add i.MX7 FCB write support
Date: Fri, 30 Sep 2022 14:15:49 +0200 [thread overview]
Message-ID: <20220930121553.335796-4-s.hauer@pengutronix.de> (raw)
In-Reply-To: <20220930121553.335796-1-s.hauer@pengutronix.de>
From: Johannes Zink <j.zink@pengutronix.de>
The FCB on the i.MX7 is written in BCH62 mode and with randomizer
enabled. This needs special FCB read/write functions. Add them to the
driver.
Signed-off-by: Johannes Zink <j.zink@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_mxs.c | 209 ++++++++++++++++++++++++++++++++-
include/linux/mtd/nand_mxs.h | 4 +
include/soc/imx/imx-nand-bcb.h | 11 ++
3 files changed, 222 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/nand_mxs.c b/drivers/mtd/nand/nand_mxs.c
index 1d0a38dc9e..5faa17a4bd 100644
--- a/drivers/mtd/nand/nand_mxs.c
+++ b/drivers/mtd/nand/nand_mxs.c
@@ -108,6 +108,10 @@
#define GPMI_ECCCTRL_ECC_CMD_OFFSET 13
#define GPMI_ECCCTRL_ECC_CMD_DECODE (0x0 << 13)
#define GPMI_ECCCTRL_ECC_CMD_ENCODE (0x1 << 13)
+#define GPMI_ECCCTRL_RANDOMIZER_ENABLE (1 << 11)
+#define GPMI_ECCCTRL_RANDOMIZER_TYPE0 0
+#define GPMI_ECCCTRL_RANDOMIZER_TYPE1 (1 << 9)
+#define GPMI_ECCCTRL_RANDOMIZER_TYPE2 (2 << 9)
#define GPMI_ECCCTRL_ENABLE_ECC (1 << 12)
#define GPMI_ECCCTRL_BUFFER_MASK_MASK 0x1ff
#define GPMI_ECCCTRL_BUFFER_MASK_OFFSET 0
@@ -138,6 +142,9 @@
#define BCH_FLASHLAYOUT0_ECC0_MASK (0xf << 12)
#define BCH_FLASHLAYOUT0_ECC0_OFFSET 12
#define IMX6_BCH_FLASHLAYOUT0_ECC0_OFFSET 11
+#define BCH_FLASHLAYOUT0_DATA0_SIZE_OFFSET 0
+#define BCH_FLASHLAYOUT0_GF13_0_GF14_1_MASK BIT(10)
+#define BCH_FLASHLAYOUT0_GF13_0_GF14_1_OFFSET 10
#define BCH_FLASH0LAYOUT1 0x00000090
#define BCH_FLASHLAYOUT1_PAGE_SIZE_MASK (0xffff << 16)
@@ -145,6 +152,9 @@
#define BCH_FLASHLAYOUT1_ECCN_MASK (0xf << 12)
#define BCH_FLASHLAYOUT1_ECCN_OFFSET 12
#define IMX6_BCH_FLASHLAYOUT1_ECCN_OFFSET 11
+#define BCH_FLASHLAYOUT1_GF13_0_GF14_1_MASK BIT(10)
+#define BCH_FLASHLAYOUT1_GF13_0_GF14_1_OFFSET 10
+#define BCH_FLASHLAYOUT1_DATAN_SIZE_OFFSET 0
#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4
@@ -752,7 +762,8 @@ static void mxs_nand_config_bch(struct nand_chip *chip, int readlen)
writel(fl1, bch_regs + BCH_FLASH0LAYOUT1);
}
-static int mxs_nand_do_bch_read(struct nand_chip *chip, int channel, int readtotal)
+static int mxs_nand_do_bch_read(struct nand_chip *chip, int channel, int readtotal,
+ bool randomizer, int page)
{
struct mxs_nand_info *nand_info = chip->priv;
struct mxs_dma_desc *d;
@@ -798,6 +809,12 @@ static int mxs_nand_do_bch_read(struct nand_chip *chip, int channel, int readtot
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 (randomizer) {
+ d->cmd.pio_words[2] |= GPMI_ECCCTRL_RANDOMIZER_ENABLE |
+ GPMI_ECCCTRL_RANDOMIZER_TYPE2;
+ d->cmd.pio_words[3] |= (page % 256) << 16;
+ }
+
mxs_dma_desc_append(channel, d);
/* Compile the DMA descriptor - disable the BCH block. */
@@ -874,7 +891,7 @@ static int __mxs_nand_ecc_read_page(struct nand_chip *chip,
mxs_nand_config_bch(chip, readtotal);
- mxs_nand_do_bch_read(chip, channel, readtotal);
+ mxs_nand_do_bch_read(chip, channel, readtotal, false, page);
/* Read DMA completed, now do the mark swapping. */
mxs_nand_swap_block_mark(chip, nand_info->data_buf, nand_info->oob_buf);
@@ -1247,6 +1264,194 @@ static int mxs_nand_block_markbad(struct nand_chip *chip , loff_t ofs)
return 0;
}
+#define BCH62_WRITESIZE 1024
+#define BCH62_OOBSIZE 838
+#define BCH62_PAGESIZE (BCH62_WRITESIZE + BCH62_OOBSIZE)
+
+static void mxs_nand_mode_fcb_62bit(struct mxs_nand_info *nand_info)
+{
+ void __iomem *bch_regs;
+ u32 fl0, fl1;
+
+ bch_regs = nand_info->bch_base;
+
+ /* 8 ecc_chunks */
+ fl0 = 7 << BCH_FLASHLAYOUT0_NBLOCKS_OFFSET;
+ /* 32 bytes for metadata */
+ fl0 |= 32 << BCH_FLASHLAYOUT0_META_SIZE_OFFSET;
+ /* using ECC62 level to be performed */
+ fl0 |= 0x1F << IMX6_BCH_FLASHLAYOUT0_ECC0_OFFSET;
+ /* 0x20 * 4 bytes of the data0 block */
+ fl0 |= 0x20 << BCH_FLASHLAYOUT0_DATA0_SIZE_OFFSET;
+ fl0 |= 0 << BCH_FLASHLAYOUT0_GF13_0_GF14_1_OFFSET;
+ writel(fl0, bch_regs + BCH_FLASH0LAYOUT0);
+
+ /* 1024 for data + 838 for OOB */
+ fl1 = BCH62_PAGESIZE << BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET;
+ /* using ECC62 level to be performed */
+ fl1 |= 0x1f << IMX6_BCH_FLASHLAYOUT1_ECCN_OFFSET;
+ /* 0x20 * 4 bytes of the data0 block */
+ fl1 |= 0x20 << BCH_FLASHLAYOUT1_DATAN_SIZE_OFFSET;
+ fl1 |= 0 << BCH_FLASHLAYOUT1_GF13_0_GF14_1_OFFSET;
+ writel(fl1, bch_regs + BCH_FLASH0LAYOUT1);
+}
+
+int mxs_nand_read_fcb_bch62(unsigned int block, void *buf, size_t size)
+{
+ struct nand_chip *chip;
+ struct mxs_nand_info *nand_info;
+ struct mtd_info *mtd = mxs_nand_mtd;
+ int ret;
+ int page;
+ int flips = 0;
+ uint8_t *status;
+ int i;
+
+ if (!mtd)
+ return -ENODEV;
+
+ chip = mtd_to_nand(mtd);
+ nand_info = chip->priv;
+
+ nand_select_target(chip, 0);
+
+ page = block * (mtd->erasesize / mtd->writesize);
+
+ mxs_nand_mode_fcb_62bit(nand_info);
+
+ nand_read_page_op(chip, page, 0, NULL, 0);
+
+ ret = mxs_nand_do_bch_read(chip, 0, BCH62_PAGESIZE, true, page);
+ if (ret)
+ goto out;
+
+ /* Read DMA completed, now do the mark swapping. */
+ mxs_nand_swap_block_mark(chip, nand_info->data_buf, nand_info->oob_buf);
+
+ /* Loop over status bytes, accumulating ECC status. */
+ status = nand_info->oob_buf + 32;
+
+ for (i = 0; i < 8; i++) {
+ switch (status[i]) {
+ case 0x0:
+ break;
+ case 0xff:
+ /*
+ * A status of 0xff means the chunk is erased, but due to
+ * the randomizer we see this as random data. Explicitly
+ * memset it.
+ */
+ memset(nand_info->data_buf + 0x80 * i, 0xff, 0x80);
+ break;
+ case 0xfe:
+ ret = -EBADMSG;
+ goto out;
+ default:
+ flips += status[0];
+ break;
+ }
+ }
+
+ memcpy(buf, nand_info->data_buf, size);
+
+out:
+ mxs_nand_config_bch(chip, mtd->writesize + mtd->oobsize);
+ nand_deselect_target(chip);
+
+ return ret;
+}
+
+int mxs_nand_write_fcb_bch62(unsigned int block, void *buf, size_t size)
+{
+ struct nand_chip *chip;
+ struct mtd_info *mtd = mxs_nand_mtd;
+ struct mxs_nand_info *nand_info;
+ struct mxs_dma_desc *d;
+ uint32_t channel;
+ int ret = 0;
+ int page;
+
+ if (!mtd)
+ return -ENODEV;
+
+ if (size > BCH62_WRITESIZE)
+ return -EINVAL;
+
+ chip = mtd_to_nand(mtd);
+ nand_info = chip->priv;
+ channel = nand_info->dma_channel_base;
+
+ mxs_nand_mode_fcb_62bit(nand_info);
+
+ nand_select_target(chip, 0);
+
+ page = block * (mtd->erasesize / mtd->writesize);
+
+ nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+ memset(nand_info->data_buf, 0x0, BCH62_WRITESIZE);
+ memcpy(nand_info->data_buf, buf, size);
+
+ /* Handle block mark swapping. */
+ mxs_nand_swap_block_mark(chip, nand_info->data_buf, nand_info->oob_buf);
+
+ /* Compile the DMA descriptor - write data. */
+ d = mxs_nand_get_dma_desc(nand_info);
+ d->cmd.data = MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ |
+ MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END |
+ (6 << MXS_DMA_DESC_PIO_WORDS_OFFSET);
+
+ d->cmd.address = 0;
+
+ d->cmd.pio_words[0] = GPMI_CTRL0_COMMAND_MODE_WRITE |
+ GPMI_CTRL0_WORD_LENGTH |
+ GPMI_CTRL0_ADDRESS_NAND_DATA;
+ d->cmd.pio_words[1] = 0;
+ d->cmd.pio_words[2] = GPMI_ECCCTRL_ENABLE_ECC |
+ GPMI_ECCCTRL_ECC_CMD_ENCODE |
+ GPMI_ECCCTRL_BUFFER_MASK_BCH_PAGE;
+ d->cmd.pio_words[3] = BCH62_PAGESIZE;
+ d->cmd.pio_words[4] = (dma_addr_t)nand_info->data_buf;
+ d->cmd.pio_words[5] = (dma_addr_t)nand_info->oob_buf;
+
+ 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 % 256) << 16;
+
+ mxs_dma_desc_append(channel, d);
+
+ /* Execute the DMA chain. */
+ ret = mxs_dma_go(channel);
+ if (ret) {
+ dev_err(nand_info->dev, "MXS NAND: DMA write error: %d\n", ret);
+ goto out;
+ }
+
+ ret = mxs_nand_wait_for_bch_complete(nand_info);
+ if (ret) {
+ dev_err(nand_info->dev, "MXS NAND: BCH write timeout\n");
+ goto out;
+ }
+
+out:
+ mxs_nand_return_dma_descs(nand_info);
+
+ if (!ret)
+ ret = nand_prog_page_end_op(chip);
+
+ mxs_nand_config_bch(chip, mtd->writesize + mtd->oobsize);
+ nand_deselect_target(chip);
+
+ return ret;
+}
+
/*
* Nominally, the purpose of this function is to look for or create the bad
* block table. In fact, since the we call this function at the very end of
diff --git a/include/linux/mtd/nand_mxs.h b/include/linux/mtd/nand_mxs.h
index 7eda0b8e63..4c1e90d6f0 100644
--- a/include/linux/mtd/nand_mxs.h
+++ b/include/linux/mtd/nand_mxs.h
@@ -28,5 +28,9 @@
*/
int mxs_nand_get_geo(int *ecc_strength, int *bb_mark_bit_offset);
+int mxs_nand_read_fcb_bch62(unsigned int block, void *buf, size_t size);
+int mxs_nand_write_fcb_bch62(unsigned int block, void *buf, size_t size);
+
+struct mtd_info;
#endif /* __NAND_MXS_H */
diff --git a/include/soc/imx/imx-nand-bcb.h b/include/soc/imx/imx-nand-bcb.h
index 6c42d80428..c5481e602e 100644
--- a/include/soc/imx/imx-nand-bcb.h
+++ b/include/soc/imx/imx-nand-bcb.h
@@ -77,6 +77,17 @@ struct fcb_block {
uint32_t DISBBM; /* the flag to enable (1)/disable(0) bi swap */
uint32_t BBMarkerPhysicalOffsetInSpareData; /* The swap position of main area in spare area */
+
+ /* iMX7 only */
+ uint32_t onfi_sync_enable; /* enable Onfi nand sync support */
+ uint32_t onfi_sync_speed; /* Speed for Onfi nand sync mode */
+ uint32_t onfi_sync_nand_data; /* parameters for Onfi nand sync mode timing */
+ uint32_t reserved[6];
+ uint32_t disbbm_search; /* disable bad block search function when reading the firmware, only using DBBT */
+ uint32_t disbbm_search_limit; /* ???randomizer type 2 enable ???*/
+ uint32_t reserved1[15]; /* reserved for future use */
+ uint32_t read_retry_enable; /* enable read retry for DBBT and firmware */
+ uint32_t reserved2[1]; /*reserved, keep at 0 */
};
#endif /* __MACH_IMX_NAND_BCB_H */
--
2.30.2
next prev parent reply other threads:[~2022-09-30 12:17 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-09-30 12:15 [PATCH 0/7] Add i.MX7 NAND boot support Sascha Hauer
2022-09-30 12:15 ` [PATCH 1/7] mtd: nand-mxs: refactor flash layout configuration Sascha Hauer
2022-09-30 12:15 ` [PATCH 2/7] mtd: nand-mxs: Factor out a bch read function Sascha Hauer
2022-09-30 12:15 ` Sascha Hauer [this message]
2022-09-30 12:15 ` [PATCH 4/7] imx-bbu-nand-fcb: isolate i.MX28 specific parts Sascha Hauer
2022-09-30 12:15 ` [PATCH 5/7] imx-bbu-nand-fcb: pass imx_handler further down Sascha Hauer
2022-09-30 12:15 ` [PATCH 6/7] imx-bbu-nand-fcb: add fcb_read/fcb_write function hooks Sascha Hauer
2022-09-30 12:15 ` [PATCH 7/7] imx-bbu-nand-fcb: extend for i.MX7 support Sascha Hauer
2022-09-30 13:21 ` [PATCH 0/7] Add i.MX7 NAND boot support Johannes Zink
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220930121553.335796-4-s.hauer@pengutronix.de \
--to=s.hauer@pengutronix.de \
--cc=barebox@lists.infradead.org \
--cc=j.zink@pengutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox