- 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
 -----BEGIN PGP SIGNATURE-----
 
 iQJYBAABCgBCFiEE6GOTDNYiFygVXvMmQBtB6IWRjvEFAmOVqHYkHGRhcmlvLmJp
 bmFjY2hpQGFtYXJ1bGFzb2x1dGlvbnMuY29tAAoJEEAbQeiFkY7x8kIQAKpksSrJ
 vv+TS9nL5Xcn4pHMsZ+OAkCBeUGHEYAsYW6akSvFqcN3UCgFpyz2xGMNNlurHVjy
 YL1e/qSXrBZ3U+kem8xjT5ceU8ZBBNZrRN9pR+2VwCxGEjeA4YgaRN8CIwXUf1QD
 hSJs4jr3MvIm5Mioabsk1Y9AoRMDH4IHkNvg6ATV6fIwTMrcjj6ztiSSalSx8iyK
 p1s8r+0Y+q8mU/XQCEG3RwaAkTASXsDSAQMZSKHk+hqji3sooprfqj+x6fifue2L
 zPA0YOUWHyBdcDJeVuETNBhGjN/vtI06qkrvdtrFtjWhTC2mmKcesrH4q85m8O9Z
 XdsYNdr6pWVZslO28We57h2gIC7uolPEQ6+QMc3E0ks9O4CDnucX52ZBPkHXqFfW
 SZOzwgB1CqDrCVHPM2RVAIUNSIKyBil9/30op+CYoxT9kBFuKNOwWJtqQzzIzUtE
 k9N/VkL/mGHjGT8n0mKTRRnIpQx6yruDIAY1gaOLUDlMDLwTy6AiCaT87wlNxgCS
 LypU+qd6VwUcRTMIk8amQSrT8uSzV9K4A7AWZAWAels6So9hrVvviPpO0RMp9kJT
 sn8IDL3HL1xGv28I1EiYv2+R/U8NW89KvttmMeB7ANGXBSkS+8NuIiMFTeKCgwAW
 V0FSmdeqVBE0CMJQiJotOgFQ4uP7cd6wjQU7
 =73Md
 -----END PGP SIGNATURE-----

Merge tag 'u-boot-nand-20221211' of https://source.denx.de/u-boot/custodians/u-boot-nand-flash

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
This commit is contained in:
Tom Rini 2022-12-11 09:40:25 -05:00
commit 7a7b0856ca
10 changed files with 81 additions and 50 deletions

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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) {

View file

@ -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);
}
}
/*

View file

@ -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;

View file

@ -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;

View file

@ -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 */