Newer
Older
/*
* Driver for NAND support, Rick Bronson
* borrowed heavily from:
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
* Ported 'dynenv' to 'nand env.oob' command
* (C) 2010 Nanometrics, Inc.
* 'dynenv' -- Dynamic environment offset in NAND OOB
* (C) Copyright 2006-2007 OpenMoko, Inc.
* Added 16-bit nand support
* (C) 2004 Texas Instruments
* Copyright 2010, 2012 Freescale Semiconductor
* The portions of this file whose copyright is held by Freescale and which
* are not considered a derived work of GPL v2-only code may be distributed
* and/or modified under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
Bartlomiej Sieka
committed
#include <command.h>
Bartlomiej Sieka
committed
#include <watchdog.h>
#include <malloc.h>
#include <asm/byteorder.h>
#include <jffs2/jffs2.h>
#include <nand.h>
int mtdparts_init(void);
int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
int find_dev_and_part(const char *id, struct mtd_device **dev,
u8 *part_num, struct part_info **part);
static int nand_dump(struct mtd_info *mtd, ulong off, int only_oob,
int repeat)
Bartlomiej Sieka
committed
{
int i;
Bartlomiej Sieka
committed
datbuf = memalign(ARCH_DMA_MINALIGN, mtd->writesize);
Bartlomiej Sieka
committed
puts("No memory for page buffer\n");
return 1;
}
oobbuf = memalign(ARCH_DMA_MINALIGN, mtd->oobsize);
if (!oobbuf) {
puts("No memory for page buffer\n");
ret = 1;
goto free_dat;
}
struct mtd_oob_ops ops;
memset(&ops, 0, sizeof(ops));
ops.datbuf = datbuf;
ops.len = mtd->writesize;
ops.ooblen = mtd->oobsize;
Bartlomiej Sieka
committed
if (i < 0) {
printf("Error (%d) reading page %08lx\n", i, off);
ret = 1;
goto free_all;
Bartlomiej Sieka
committed
}
printf("Page %08lx dump:\n", off);
p = datbuf;
while (i--) {
printf("\t%02x %02x %02x %02x %02x %02x %02x %02x"
" %02x %02x %02x %02x %02x %02x %02x %02x\n",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
p[8], p[9], p[10], p[11], p[12], p[13], p[14],
p[15]);
Bartlomiej Sieka
committed
}
Bartlomiej Sieka
committed
puts("OOB:\n");
Bartlomiej Sieka
committed
while (i--) {
printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
Bartlomiej Sieka
committed
p += 8;
}
free_dat:
free(datbuf);
Bartlomiej Sieka
committed
Bartlomiej Sieka
committed
}
/* ------------------------------------------------------------------------- */
static int set_dev(int dev)
{
struct mtd_info *mtd = get_nand_dev_by_index(dev);
if (!mtd)
return -ENODEV;
if (nand_curr_device == dev)
return 0;
printf("Device %d: %s", dev, mtd->name);
puts("... is now current device\n");
nand_curr_device = dev;
#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
board_nand_select_device(mtd->priv, dev);
#endif
return 0;
}
#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
static void print_status(ulong start, ulong end, ulong erasesize, int status)
{
/*
* Micron NAND flash (e.g. MT29F4G08ABADAH4) BLOCK LOCK READ STATUS is
* not the same as others. Instead of bit 1 being lock, it is
* #lock_tight. To make the driver support either format, ignore bit 1
* and use only bit 0 and bit 2.
*/
printf("%08lx - %08lx: %08lx blocks %s%s%s\n",
start,
end - 1,
(end - start) / erasesize,
((status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""),
(!(status & NAND_LOCK_STATUS_UNLOCK) ? "LOCK " : ""),
((status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : ""));
}
static void do_nand_status(struct mtd_info *mtd)
{
ulong block_start = 0;
ulong off;
int last_status = -1;
struct nand_chip *nand_chip = mtd_to_nand(mtd);
nand_chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
printf("device is %swrite protected\n",
(nand_chip->read_byte(mtd) & 0x80 ?
"NOT " : ""));
for (off = 0; off < mtd->size; off += mtd->erasesize) {
int s = nand_get_lock_status(mtd, off);
/* print message only if status has changed */
if (s != last_status && off != 0) {
print_status(block_start, off, mtd->erasesize,
last_status);
block_start = off;
}
last_status = s;
}
/* Print the last block info */
print_status(block_start, off, mtd->erasesize, last_status);
#ifdef CONFIG_ENV_OFFSET_OOB
unsigned long nand_env_oob_offset;
int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[])
{
int ret;
uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
struct mtd_info *mtd = get_nand_dev_by_index(0);
char *cmd = argv[1];
if (CONFIG_SYS_MAX_NAND_DEVICE == 0 || !mtd) {
puts("no devices available\n");
return 1;
}
set_dev(0);
Loading
Loading full blame...