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 -----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:
commit
7a7b0856ca
10 changed files with 81 additions and 50 deletions
28
cmd/mtd.c
28
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;
|
||||
}
|
||||
|
|
14
cmd/nand.c
14
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue