summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2022-11-01 13:37:54 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2022-11-02 12:28:54 +0100
commitf6cf6aff3c895906410c9955db5e161e799a2032 (patch)
treecad3c9641673c8c7db7b05d71e3546bd91f6576a /arch
parent11498dd843e257f45014a94efed5bae8d3c27f77 (diff)
downloadbarebox-f6cf6aff3c895906410c9955db5e161e799a2032.tar.gz
barebox-f6cf6aff3c895906410c9955db5e161e799a2032.tar.xz
ARM: i.MX: xload nand: Implement i.MX7 support
i.MX7 xload NAND support works like on i.MX6, but the FCB is in a different format. The FCB page uses BCH62 ECC, has 8 ECC chunks with 128 bytes each with a resulting total page size of 1862 bytes. Also the page data is written with a pseudo randomizer enabled. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-imx/include/mach/imx7-regs.h1
-rw-r--r--arch/arm/mach-imx/include/mach/xload.h1
-rw-r--r--arch/arm/mach-imx/xload-gpmi-nand.c99
3 files changed, 93 insertions, 8 deletions
diff --git a/arch/arm/mach-imx/include/mach/imx7-regs.h b/arch/arm/mach-imx/include/mach/imx7-regs.h
index 1ee7d86e0e..379be9e062 100644
--- a/arch/arm/mach-imx/include/mach/imx7-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx7-regs.h
@@ -118,6 +118,7 @@
#define MX7_ENET1_BASE_ADDR (MX7_AIPS3_BASE_ADDR + 0x3E0000)
#define MX7_ENET2_BASE_ADDR (MX7_AIPS3_BASE_ADDR + 0x3F0000)
+#define MX7_APBH_BASE 0x33000000
#define MX7_GPMI_BASE 0x33002000
#define MX7_BCH_BASE 0x33004000
diff --git a/arch/arm/mach-imx/include/mach/xload.h b/arch/arm/mach-imx/include/mach/xload.h
index 82bf663c42..ca0055aee2 100644
--- a/arch/arm/mach-imx/include/mach/xload.h
+++ b/arch/arm/mach-imx/include/mach/xload.h
@@ -12,6 +12,7 @@ int imx6_spi_start_image(int instance);
int imx6_esdhc_start_image(int instance);
int imx6_nand_start_image(void);
int imx7_esdhc_start_image(int instance);
+int imx7_nand_start_image(void);
int imx8m_esdhc_load_image(int instance, bool start);
int imx8mn_esdhc_load_image(int instance, bool start);
int imx8mp_esdhc_load_image(int instance, bool start);
diff --git a/arch/arm/mach-imx/xload-gpmi-nand.c b/arch/arm/mach-imx/xload-gpmi-nand.c
index 872adff773..dcef8cda48 100644
--- a/arch/arm/mach-imx/xload-gpmi-nand.c
+++ b/arch/arm/mach-imx/xload-gpmi-nand.c
@@ -14,6 +14,7 @@
#include <linux/mtd/rawnand.h>
#include <soc/imx/gpmi-nand.h>
#include <mach/imx6-regs.h>
+#include <mach/imx7-regs.h>
#include <mach/clock-imx6.h>
#include <dma/apbh-dma.h>
@@ -229,7 +230,7 @@ static uint32_t mxs_nand_aux_status_offset(void)
}
static int mxs_nand_read_page(struct mxs_nand_info *info, int writesize,
- int oobsize, int pagenum, void *databuf, int raw)
+ int oobsize, int pagenum, void *databuf, int raw, bool randomizer)
{
void __iomem *bch_regs = info->bch_base;
unsigned column = 0;
@@ -333,6 +334,12 @@ static int mxs_nand_read_page(struct mxs_nand_info *info, int writesize,
d->pio_words[4] = (dma_addr_t)databuf;
d->pio_words[5] = (dma_addr_t)(databuf + writesize);
+ if (randomizer) {
+ d->pio_words[2] |= GPMI_ECCCTRL_RANDOMIZER_ENABLE |
+ GPMI_ECCCTRL_RANDOMIZER_TYPE2;
+ d->pio_words[3] |= (pagenum % 256) << 16;
+ }
+
/* Compile DMA descriptor - disable the BCH block. */
d = &info->desc[descnum++];
d->data = MXS_DMA_DESC_NAND_WAIT_4_READY |
@@ -841,7 +848,7 @@ static uint32_t calc_chksum(void *buf, size_t size)
return ~chksum;
}
-static int get_fcb(struct mxs_nand_info *info, void *databuf)
+static int imx6_get_fcb(struct mxs_nand_info *info, void *databuf)
{
int i, pagenum, ret;
uint32_t checksum;
@@ -849,13 +856,13 @@ static int get_fcb(struct mxs_nand_info *info, void *databuf)
/* First page read fails, this shouldn't be necessary */
mxs_nand_read_page(info, info->organization.pagesize,
- info->organization.oobsize, 0, databuf, 1);
+ info->organization.oobsize, 0, databuf, 1, false);
for (i = 0; i < 4; i++) {
pagenum = info->organization.pages_per_eraseblock * i;
ret = mxs_nand_read_page(info, info->organization.pagesize,
- info->organization.oobsize, pagenum, databuf, 1);
+ info->organization.oobsize, pagenum, databuf, 1, false);
if (ret)
continue;
@@ -887,6 +894,66 @@ static int get_fcb(struct mxs_nand_info *info, void *databuf)
return -EINVAL;
}
+static int imx7_get_fcb_n(struct mxs_nand_info *info, void *databuf, int num)
+{
+ int ret;
+ int flips = 0;
+ uint8_t *status;
+ int i;
+
+ ret = mxs_nand_read_page(info, BCH62_WRITESIZE, BCH62_OOBSIZE,
+ info->organization.pages_per_eraseblock * num, databuf, 0, true);
+ if (ret)
+ return ret;
+
+ /* Loop over status bytes, accumulating ECC status. */
+ status = databuf + BCH62_WRITESIZE + 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(databuf + 0x80 * i, 0xff, 0x80);
+ break;
+ case 0xfe:
+ return -EBADMSG;
+ default:
+ flips += status[0];
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int imx7_get_fcb(struct mxs_nand_info *info, void *databuf)
+{
+ int i, ret;
+ struct fcb_block *fcb = &info->fcb;
+
+ mxs_nand_mode_fcb_62bit(info->bch_base);
+
+ for (i = 0; i < 4; i++) {
+ ret = imx7_get_fcb_n(info, databuf, i);
+ if (!ret)
+ break;
+ }
+
+ if (ret) {
+ pr_err("Cannot find FCB\n");
+ } else {
+ memcpy(fcb, databuf, sizeof(*fcb));
+ }
+
+ return ret;
+}
+
static int get_dbbt(struct mxs_nand_info *info, void *databuf)
{
int i, ret;
@@ -898,7 +965,7 @@ static int get_dbbt(struct mxs_nand_info *info, void *databuf)
page = startpage + i * info->organization.pages_per_eraseblock;
ret = mxs_nand_read_page(info, info->organization.pagesize,
- info->organization.oobsize, page, databuf, 0);
+ info->organization.oobsize, page, databuf, 0, false);
if (ret)
continue;
@@ -916,7 +983,7 @@ static int get_dbbt(struct mxs_nand_info *info, void *databuf)
return -ENOENT;
ret = mxs_nand_read_page(info, info->organization.pagesize,
- info->organization.oobsize, page + 4, databuf, 0);
+ info->organization.oobsize, page + 4, databuf, 0, false);
if (ret)
continue;
@@ -991,7 +1058,7 @@ static int read_firmware(struct mxs_nand_info *info, int startpage,
}
ret = mxs_nand_read_page(info, pagesize, oobsize,
- curpage, dest, 0);
+ curpage, dest, 0, false);
if (ret) {
pr_debug("Failed to read page %d\n", curpage);
return ret;
@@ -1012,6 +1079,7 @@ struct imx_nand_params {
struct mxs_nand_info info;
struct apbh_dma apbh;
void *sdram;
+ int (*get_fcb)(struct mxs_nand_info *info, void *databuf);
};
static int __maybe_unused imx6_nand_load_image(struct imx_nand_params *params,
@@ -1036,7 +1104,7 @@ static int __maybe_unused imx6_nand_load_image(struct imx_nand_params *params,
if (ret)
return ret;
- ret = get_fcb(info, databuf);
+ ret = params->get_fcb(info, databuf);
if (ret)
return ret;
@@ -1120,6 +1188,7 @@ int imx6_nand_start_image(void)
.apbh.regs = IOMEM(MX6_APBH_BASE_ADDR),
.apbh.id = IMX28_DMA,
.sdram = (void *)MX6_MMDC_PORT01_BASE_ADDR,
+ .get_fcb = imx6_get_fcb,
};
/* Apply ERR007117 workaround */
@@ -1127,3 +1196,17 @@ int imx6_nand_start_image(void)
return imx_nand_start_image(&params);
}
+
+int imx7_nand_start_image(void)
+{
+ static struct imx_nand_params params = {
+ .info.io_base = IOMEM(MX7_GPMI_BASE),
+ .info.bch_base = IOMEM(MX7_BCH_BASE),
+ .apbh.regs = IOMEM(MX7_APBH_BASE),
+ .apbh.id = IMX28_DMA,
+ .sdram = (void *)MX7_DDR_BASE_ADDR,
+ .get_fcb = imx7_get_fcb,
+ };
+
+ return imx_nand_start_image(&params);
+}