diff options
Diffstat (limited to 'drivers/mtd/onenand')
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 31 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_spl.c | 48 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_uboot.c | 30 |
3 files changed, 83 insertions, 26 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 03deabce10..0e35dc5b88 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -20,6 +20,7 @@ */ #include <common.h> +#include <watchdog.h> #include <linux/compat.h> #include <linux/mtd/mtd.h> #include "linux/mtd/flashchip.h" @@ -467,15 +468,18 @@ static int onenand_read_ecc(struct onenand_chip *this) static int onenand_wait(struct mtd_info *mtd, int state) { struct onenand_chip *this = mtd->priv; - unsigned int flags = ONENAND_INT_MASTER; unsigned int interrupt = 0; unsigned int ctrl; - while (1) { + /* Wait at most 20ms ... */ + u32 timeo = (CONFIG_SYS_HZ * 20) / 1000; + u32 time_start = get_timer(0); + do { + WATCHDOG_RESET(); + if (get_timer(time_start) > timeo) + return -EIO; interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); - if (interrupt & flags) - break; - } + } while ((interrupt & ONENAND_INT_MASTER) == 0); ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); @@ -1154,15 +1158,18 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, static int onenand_bbt_wait(struct mtd_info *mtd, int state) { struct onenand_chip *this = mtd->priv; - unsigned int flags = ONENAND_INT_MASTER; unsigned int interrupt; unsigned int ctrl; - while (1) { + /* Wait at most 20ms ... */ + u32 timeo = (CONFIG_SYS_HZ * 20) / 1000; + u32 time_start = get_timer(0); + do { + WATCHDOG_RESET(); + if (get_timer(time_start) > timeo) + return ONENAND_BBT_READ_FATAL_ERROR; interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); - if (interrupt & flags) - break; - } + } while ((interrupt & ONENAND_INT_MASTER) == 0); /* To get correct interrupt status in timeout case */ interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); @@ -2536,7 +2543,8 @@ static int onenand_chip_probe(struct mtd_info *mtd) this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM); /* Wait reset */ - this->wait(mtd, FL_RESETING); + if (this->wait(mtd, FL_RESETING)) + return -ENXIO; /* Restore system configuration 1 */ this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1); @@ -2649,6 +2657,7 @@ int onenand_probe(struct mtd_info *mtd) mtd->_sync = onenand_sync; mtd->_block_isbad = onenand_block_isbad; mtd->_block_markbad = onenand_block_markbad; + mtd->writebufsize = mtd->writesize; return 0; } diff --git a/drivers/mtd/onenand/onenand_spl.c b/drivers/mtd/onenand/onenand_spl.c index fe6b7d923c..1925f41d8a 100644 --- a/drivers/mtd/onenand/onenand_spl.c +++ b/drivers/mtd/onenand/onenand_spl.c @@ -93,6 +93,54 @@ static int onenand_spl_read_page(uint32_t block, uint32_t page, uint32_t *buf, return 0; } +#ifdef CONFIG_SPL_UBI +/* Temporary storage for non page aligned and non page sized reads. */ +static u8 scratch_buf[PAGE_4K]; + +/** + * onenand_spl_read_block - Read data from physical eraseblock into a buffer + * @block: Number of the physical eraseblock + * @offset: Data offset from the start of @peb + * @len: Data size to read + * @dst: Address of the destination buffer + * + * Notes: + * @offset + @len are not allowed to be larger than a physical + * erase block. No sanity check done for simplicity reasons. + */ +int onenand_spl_read_block(int block, int offset, int len, void *dst) +{ + int page, read, psize; + + psize = onenand_spl_get_geometry(); + /* Calculate the page number */ + page = offset / psize; + /* Offset to the start of a flash page */ + offset = offset % psize; + + while (len) { + /* + * Non page aligned reads go to the scratch buffer. + * Page aligned reads go directly to the destination. + */ + if (offset || len < psize) { + onenand_spl_read_page(block, page, + (uint32_t *)scratch_buf, psize); + read = min(len, psize - offset); + memcpy(dst, scratch_buf + offset, read); + offset = 0; + } else { + onenand_spl_read_page(block, page, dst, psize); + read = psize; + } + page++; + len -= read; + dst += read; + } + return 0; +} +#endif + void onenand_spl_load_image(uint32_t offs, uint32_t size, void *dst) { uint32_t *addr = (uint32_t *)dst; diff --git a/drivers/mtd/onenand/onenand_uboot.c b/drivers/mtd/onenand/onenand_uboot.c index ae60c3bb71..c15ec9df07 100644 --- a/drivers/mtd/onenand/onenand_uboot.c +++ b/drivers/mtd/onenand/onenand_uboot.c @@ -24,33 +24,33 @@ static __attribute__((unused)) char dev_name[] = "onenand0"; void onenand_init(void) { + int err = 0; memset(&onenand_mtd, 0, sizeof(struct mtd_info)); memset(&onenand_chip, 0, sizeof(struct onenand_chip)); onenand_mtd.priv = &onenand_chip; #ifdef CONFIG_USE_ONENAND_BOARD_INIT - /* - * It's used for some board init required - */ - onenand_board_init(&onenand_mtd); + /* It's used for some board init required */ + err = onenand_board_init(&onenand_mtd); #else onenand_chip.base = (void *) CONFIG_SYS_ONENAND_BASE; #endif - onenand_scan(&onenand_mtd, 1); + if (!err && !(onenand_scan(&onenand_mtd, 1))) { - if (onenand_chip.device_id & DEVICE_IS_FLEXONENAND) - puts("Flex-"); - puts("OneNAND: "); - print_size(onenand_chip.chipsize, "\n"); + if (onenand_chip.device_id & DEVICE_IS_FLEXONENAND) + puts("Flex-"); + puts("OneNAND: "); #ifdef CONFIG_MTD_DEVICE - /* - * Add MTD device so that we can reference it later - * via the mtdcore infrastructure (e.g. ubi). - */ - onenand_mtd.name = dev_name; - add_mtd_device(&onenand_mtd); + /* + * Add MTD device so that we can reference it later + * via the mtdcore infrastructure (e.g. ubi). + */ + onenand_mtd.name = dev_name; + add_mtd_device(&onenand_mtd); #endif + } + print_size(onenand_chip.chipsize, "\n"); } |