aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2022-12-11 09:40:25 -0500
committerTom Rini <trini@konsulko.com>2022-12-11 09:40:25 -0500
commit7a7b0856ca01f0dadc940f6f1bc6df44129ad9d0 (patch)
tree2bad16f7baf7283e4d8af9c11ad8ef89dd217ecb
parent8f170408774b30aa4ee91b3cc90ba09b564d4651 (diff)
parentfda2253d121f05921e419edffe615c607917792a (diff)
downloadu-boot-7a7b0856ca01f0dadc940f6f1bc6df44129ad9d0.zip
u-boot-7a7b0856ca01f0dadc940f6f1bc6df44129ad9d0.tar.gz
u-boot-7a7b0856ca01f0dadc940f6f1bc6df44129ad9d0.tar.bz2
Merge tag 'u-boot-nand-20221211' of https://source.denx.de/u-boot/custodians/u-boot-nand-flashWIP/11Dec2022
Merge tag 'u-boot-nand-20221211' of https://source.denx.de/u-boot/custodians/u-boot-nand-flash - cmd: nand: Extend nand info to print ecc information - rawnand: omap_gpmc: driver model support (the first patches of the series) - mtd: nand: make Samsung SLC NAND usable again - cmd: mtd: check if a block has to be skipped or erased - spl: spl_legacy: fix invalid offset in SPL_COPY_PAYLOAD_ONLY
-rw-r--r--cmd/mtd.c28
-rw-r--r--cmd/nand.c14
-rw-r--r--common/spl/spl_legacy.c4
-rw-r--r--drivers/mtd/nand/core.c3
-rw-r--r--drivers/mtd/nand/raw/Kconfig2
-rw-r--r--drivers/mtd/nand/raw/mxs_nand_spl.c2
-rw-r--r--drivers/mtd/nand/raw/nand_base.c7
-rw-r--r--drivers/mtd/nand/raw/nand_spl_loaders.c2
-rw-r--r--drivers/mtd/nand/raw/omap_gpmc.c68
-rw-r--r--include/linux/mtd/nand.h1
10 files changed, 81 insertions, 50 deletions
diff --git a/cmd/mtd.c b/cmd/mtd.c
index ad5cc98..eb6e2d6 100644
--- a/cmd/mtd.c
+++ b/cmd/mtd.c
@@ -434,19 +434,31 @@ static int do_mtd_erase(struct cmd_tbl *cmdtp, int flag, int argc,
erase_op.mtd = mtd;
erase_op.addr = off;
erase_op.len = mtd->erasesize;
- erase_op.scrub = scrub;
while (len) {
- ret = mtd_erase(mtd, &erase_op);
+ if (!scrub) {
+ ret = mtd_block_isbad(mtd, erase_op.addr);
+ if (ret < 0) {
+ printf("Failed to get bad block at 0x%08llx\n",
+ erase_op.addr);
+ ret = CMD_RET_FAILURE;
+ goto out_put_mtd;
+ }
- if (ret) {
- /* Abort if its not a bad block error */
- if (ret != -EIO)
- break;
- printf("Skipping bad block at 0x%08llx\n",
- erase_op.addr);
+ if (ret > 0) {
+ printf("Skipping bad block at 0x%08llx\n",
+ erase_op.addr);
+ ret = 0;
+ len -= mtd->erasesize;
+ erase_op.addr += mtd->erasesize;
+ continue;
+ }
}
+ ret = mtd_erase(mtd, &erase_op);
+ if (ret && ret != -EIO)
+ break;
+
len -= mtd->erasesize;
erase_op.addr += mtd->erasesize;
}
diff --git a/cmd/nand.c b/cmd/nand.c
index 5bb4379..9a723f5 100644
--- a/cmd/nand.c
+++ b/cmd/nand.c
@@ -417,12 +417,14 @@ static void nand_print_and_set_info(int idx)
printf("%dx ", chip->numchips);
printf("%s, sector size %u KiB\n",
mtd->name, mtd->erasesize >> 10);
- printf(" Page size %8d b\n", mtd->writesize);
- printf(" OOB size %8d b\n", mtd->oobsize);
- printf(" Erase size %8d b\n", mtd->erasesize);
- printf(" subpagesize %8d b\n", chip->subpagesize);
- printf(" options 0x%08x\n", chip->options);
- printf(" bbt options 0x%08x\n", chip->bbt_options);
+ printf(" Page size %8d b\n", mtd->writesize);
+ printf(" OOB size %8d b\n", mtd->oobsize);
+ printf(" Erase size %8d b\n", mtd->erasesize);
+ printf(" ecc strength %8d bits\n", mtd->ecc_strength);
+ printf(" ecc step size %8d b\n", mtd->ecc_step_size);
+ printf(" subpagesize %8d b\n", chip->subpagesize);
+ printf(" options 0x%08x\n", chip->options);
+ printf(" bbt options 0x%08x\n", chip->bbt_options);
/* Set geometry info */
env_set_hex("nand_writesize", mtd->writesize);
diff --git a/common/spl/spl_legacy.c b/common/spl/spl_legacy.c
index 4c7f446..16851c5 100644
--- a/common/spl/spl_legacy.c
+++ b/common/spl/spl_legacy.c
@@ -106,7 +106,7 @@ int spl_load_legacy_img(struct spl_image_info *spl_image,
* is set
*/
if (spl_image->flags & SPL_COPY_PAYLOAD_ONLY)
- dataptr += sizeof(hdr);
+ dataptr += sizeof(*hdr);
load->read(load, dataptr, spl_image->size,
(void *)(unsigned long)spl_image->load_addr);
@@ -116,7 +116,7 @@ int spl_load_legacy_img(struct spl_image_info *spl_image,
lzma_len = LZMA_LEN;
/* dataptr points to compressed payload */
- dataptr = offset + sizeof(hdr);
+ dataptr = offset + sizeof(*hdr);
debug("LZMA: Decompressing %08lx to %08lx\n",
dataptr, spl_image->load_addr);
diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
index 99c2967..4b9dd6a 100644
--- a/drivers/mtd/nand/core.c
+++ b/drivers/mtd/nand/core.c
@@ -129,7 +129,7 @@ EXPORT_SYMBOL_GPL(nanddev_isreserved);
*
* Return: 0 in case of success, a negative error code otherwise.
*/
-int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos)
+static int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos)
{
unsigned int entry;
@@ -147,7 +147,6 @@ int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos)
return nand->ops->erase(nand, pos);
}
-EXPORT_SYMBOL_GPL(nanddev_erase);
/**
* nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index da2c579..8aaba8b 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -197,7 +197,7 @@ config NAND_LPC32XX_SLC
config NAND_OMAP_GPMC
bool "Support OMAP GPMC NAND controller"
- depends on ARCH_OMAP2PLUS
+ depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || ARCH_K3
help
Enables omap_gpmc.c driver for OMAPx and AMxxxx platforms.
GPMC controller is used for parallel NAND flash devices, and can
diff --git a/drivers/mtd/nand/raw/mxs_nand_spl.c b/drivers/mtd/nand/raw/mxs_nand_spl.c
index ef03b77..3006629 100644
--- a/drivers/mtd/nand/raw/mxs_nand_spl.c
+++ b/drivers/mtd/nand/raw/mxs_nand_spl.c
@@ -257,7 +257,7 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
while (block <= lastblock && size > 0) {
if (!is_badblock(mtd, mtd->erasesize * block, 1)) {
/* Skip bad blocks */
- while (page < nand_page_per_block) {
+ while (page < nand_page_per_block && size) {
int curr_page = nand_page_per_block * block + page;
if (mxs_read_page_ecc(mtd, page_buf, curr_page) < 0) {
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 215b9ba..bc61ad0 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -4171,10 +4171,13 @@ static void nand_manufacturer_detect(struct nand_chip *chip)
* nand_decode_ext_id() otherwise.
*/
if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
- chip->manufacturer.desc->ops->detect)
+ chip->manufacturer.desc->ops->detect) {
+ /* The 3rd id byte holds MLC / multichip data */
+ chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]);
chip->manufacturer.desc->ops->detect(chip);
- else
+ } else {
nand_decode_ext_id(chip);
+ }
}
/*
diff --git a/drivers/mtd/nand/raw/nand_spl_loaders.c b/drivers/mtd/nand/raw/nand_spl_loaders.c
index 4befc75..156b44d 100644
--- a/drivers/mtd/nand/raw/nand_spl_loaders.c
+++ b/drivers/mtd/nand/raw/nand_spl_loaders.c
@@ -23,7 +23,7 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
if (unlikely(page_offset)) {
memmove(dst, dst + page_offset,
CONFIG_SYS_NAND_PAGE_SIZE);
- dst = (void *)((int)dst - page_offset);
+ dst = (void *)(dst - page_offset);
page_offset = 0;
}
dst += CONFIG_SYS_NAND_PAGE_SIZE;
diff --git a/drivers/mtd/nand/raw/omap_gpmc.c b/drivers/mtd/nand/raw/omap_gpmc.c
index 8b9ff4d..69fc09b 100644
--- a/drivers/mtd/nand/raw/omap_gpmc.c
+++ b/drivers/mtd/nand/raw/omap_gpmc.c
@@ -8,7 +8,11 @@
#include <log.h>
#include <asm/io.h>
#include <linux/errno.h>
+
+#ifdef CONFIG_ARCH_OMAP2PLUS
#include <asm/arch/mem.h>
+#endif
+
#include <linux/mtd/omap_gpmc.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/rawnand.h>
@@ -17,6 +21,10 @@
#include <nand.h>
#include <linux/mtd/omap_elm.h>
+#ifndef GPMC_MAX_CS
+#define GPMC_MAX_CS 4
+#endif
+
#define BADBLOCK_MARKER_LENGTH 2
#define SECTOR_BYTES 512
#define ECCCLEAR (0x1 << 8)
@@ -29,7 +37,6 @@ static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
0x97, 0x79, 0xe5, 0x24, 0xb5};
#endif
static uint8_t cs_next;
-static __maybe_unused struct nand_ecclayout omap_ecclayout;
#if defined(CONFIG_NAND_OMAP_GPMC_WSCFG)
static const int8_t wscfg[CONFIG_SYS_MAX_NAND_DEVICE] =
@@ -47,6 +54,7 @@ struct omap_nand_info {
enum omap_ecc ecc_scheme;
uint8_t cs;
uint8_t ws; /* wait status pin (0,1) */
+ void __iomem *fifo;
};
/* We are wasting a bit of memory but al least we are safe */
@@ -342,6 +350,20 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
return 0;
}
+static inline void omap_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct omap_nand_info *info = nand_get_controller_data(chip);
+ u32 alignment = ((uintptr_t)buf | len) & 3;
+
+ if (alignment & 1)
+ readsb(info->fifo, buf, len);
+ else if (alignment & 3)
+ readsw(info->fifo, buf, len >> 1);
+ else
+ readsl(info->fifo, buf, len >> 2);
+}
+
#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH
#define PREFETCH_CONFIG1_CS_SHIFT 24
@@ -407,7 +429,7 @@ static int __read_prefetch_aligned(struct nand_chip *chip, uint32_t *buf, int le
cnt = PREFETCH_STATUS_FIFO_CNT(cnt);
for (i = 0; i < cnt / 4; i++) {
- *buf++ = readl(CONFIG_SYS_NAND_BASE);
+ *buf++ = readl(info->fifo);
len -= 4;
}
} while (len);
@@ -417,29 +439,19 @@ static int __read_prefetch_aligned(struct nand_chip *chip, uint32_t *buf, int le
return 0;
}
-static inline void omap_nand_read(struct mtd_info *mtd, uint8_t *buf, int len)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
- if (chip->options & NAND_BUSWIDTH_16)
- nand_read_buf16(mtd, buf, len);
- else
- nand_read_buf(mtd, buf, len);
-}
-
static void omap_nand_read_prefetch(struct mtd_info *mtd, uint8_t *buf, int len)
{
int ret;
- uint32_t head, tail;
+ uintptr_t head, tail;
struct nand_chip *chip = mtd_to_nand(mtd);
/*
* If the destination buffer is unaligned, start with reading
* the overlap byte-wise.
*/
- head = ((uint32_t) buf) % 4;
+ head = ((uintptr_t)buf) % 4;
if (head) {
- omap_nand_read(mtd, buf, head);
+ omap_nand_read_buf(mtd, buf, head);
buf += head;
len -= head;
}
@@ -453,10 +465,10 @@ static void omap_nand_read_prefetch(struct mtd_info *mtd, uint8_t *buf, int len)
ret = __read_prefetch_aligned(chip, (uint32_t *)buf, len - tail);
if (ret < 0) {
/* fallback in case the prefetch engine is busy */
- omap_nand_read(mtd, buf, len);
+ omap_nand_read_buf(mtd, buf, len);
} else if (tail) {
buf += len - tail;
- omap_nand_read(mtd, buf, tail);
+ omap_nand_read_buf(mtd, buf, tail);
}
}
#endif /* CONFIG_NAND_OMAP_GPMC_PREFETCH */
@@ -740,7 +752,7 @@ static void __maybe_unused omap_free_bch(struct mtd_info *mtd)
static int omap_select_ecc_scheme(struct nand_chip *nand,
enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) {
struct omap_nand_info *info = nand_get_controller_data(nand);
- struct nand_ecclayout *ecclayout = &omap_ecclayout;
+ struct nand_ecclayout *ecclayout = nand->ecc.layout;
int eccsteps = pagesize / SECTOR_BYTES;
int i;
@@ -993,6 +1005,8 @@ int board_nand_init(struct nand_chip *nand)
int32_t gpmc_config = 0;
int cs = cs_next++;
int err = 0;
+ struct omap_nand_info *info;
+
/*
* xloader/Uboot's gpmc configuration would have configured GPMC for
* nand type of memory. The following logic scans and latches on to the
@@ -1021,14 +1035,19 @@ int board_nand_init(struct nand_chip *nand)
nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
- omap_nand_info[cs].control = NULL;
- omap_nand_info[cs].cs = cs;
- omap_nand_info[cs].ws = wscfg[cs];
+
+ info = &omap_nand_info[cs];
+ info->control = NULL;
+ info->cs = cs;
+ info->ws = wscfg[cs];
+ info->fifo = (void __iomem *)CONFIG_SYS_NAND_BASE;
nand_set_controller_data(nand, &omap_nand_info[cs]);
nand->cmd_ctrl = omap_nand_hwcontrol;
nand->options |= NAND_NO_PADDING | NAND_CACHEPRG;
nand->chip_delay = 100;
- nand->ecc.layout = &omap_ecclayout;
+ nand->ecc.layout = kzalloc(sizeof(*nand->ecc.layout), GFP_KERNEL);
+ if (!nand->ecc.layout)
+ return -ENOMEM;
/* configure driver and controller based on NAND device bus-width */
gpmc_config = readl(&gpmc_cfg->cs[cs].config1);
@@ -1054,10 +1073,7 @@ int board_nand_init(struct nand_chip *nand)
#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH
nand->read_buf = omap_nand_read_prefetch;
#else
- if (nand->options & NAND_BUSWIDTH_16)
- nand->read_buf = nand_read_buf16;
- else
- nand->read_buf = nand_read_buf;
+ nand->read_buf = omap_nand_read_buf;
#endif
nand->dev_ready = omap_dev_ready;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 7774c17..aeb38de 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -691,7 +691,6 @@ static inline bool nanddev_io_iter_end(struct nand_device *nand,
bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos);
bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos);
-int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos);
int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos);
/* BBT related functions */