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>
*
* Added 16-bit nand support
* (C) 2004 Texas Instruments
Bartlomiej Sieka
committed
Jean-Christophe PLAGNIOL-VILLARD
committed
#ifndef CONFIG_NAND_LEGACY
Bartlomiej Sieka
committed
/*
*
* New NAND support
*
*/
#include <common.h>
Bartlomiej Sieka
committed
#if defined(CONFIG_CMD_NAND)
Bartlomiej Sieka
committed
#include <command.h>
#include <watchdog.h>
#include <malloc.h>
#include <asm/byteorder.h>
#include <jffs2/jffs2.h>
#include <nand.h>
/* parition handling routines */
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(nand_info_t *nand, ulong off, int only_oob)
Bartlomiej Sieka
committed
{
int i;
Bartlomiej Sieka
committed
datbuf = malloc(nand->writesize + nand->oobsize);
oobbuf = malloc(nand->oobsize);
if (!datbuf || !oobbuf) {
Bartlomiej Sieka
committed
puts("No memory for page buffer\n");
return 1;
}
off &= ~(nand->writesize - 1);
loff_t addr = (loff_t) off;
struct mtd_oob_ops ops;
memset(&ops, 0, sizeof(ops));
ops.datbuf = datbuf;
ops.oobbuf = oobbuf; /* must exist, but oob data will be appended to ops.datbuf */
ops.len = nand->writesize;
ops.ooblen = nand->oobsize;
ops.mode = MTD_OOB_RAW;
i = nand->read_oob(nand, addr, &ops);
Bartlomiej Sieka
committed
if (i < 0) {
printf("Error (%d) reading page %08lx\n", i, off);
Bartlomiej Sieka
committed
return 1;
}
printf("Page %08lx dump:\n", off);
i = nand->writesize >> 4;
p = datbuf;
Bartlomiej Sieka
committed
while (i--) {
if (!only_oob)
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
p += 16;
}
puts("OOB:\n");
i = nand->oobsize >> 3;
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;
}
Bartlomiej Sieka
committed
return 0;
}
/* ------------------------------------------------------------------------- */
static inline int str2long(char *p, ulong *num)
Bartlomiej Sieka
committed
{
char *endptr;
Bartlomiej Sieka
committed
*num = simple_strtoul(p, &endptr, 16);
return (*p != '\0' && *endptr == '\0') ? 1 : 0;
}
Bartlomiej Sieka
committed
arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size)
{
int idx = nand_curr_device;
struct mtd_device *dev;
struct part_info *part;
u8 pnum;
if (argc >= 1 && !(str2long(argv[0], off))) {
if ((mtdparts_init() == 0) &&
(find_dev_and_part(argv[0], &dev, &pnum, &part) == 0)) {
if (dev->id->type != MTD_DEV_TYPE_NAND) {
puts("not a NAND device\n");
return -1;
}
*off = part->offset;
if (argc >= 2) {
if (!(str2long(argv[1], (ulong *)size))) {
printf("'%s' is not a number\n", argv[1]);
return -1;
}
if (*size > part->size)
*size = part->size;
} else {
*size = part->size;
}
idx = dev->id->num;
*nand = nand_info[idx];
goto out;
Bartlomiej Sieka
committed
}
Bartlomiej Sieka
committed
#endif
if (argc >= 1) {
if (!(str2long(argv[0], off))) {
printf("'%s' is not a number\n", argv[0]);
return -1;
}
} else {
*off = 0;
}
Bartlomiej Sieka
committed
if (argc >= 2) {
if (!(str2long(argv[1], (ulong *)size))) {
printf("'%s' is not a number\n", argv[1]);
return -1;
}
} else {
*size = nand->size - *off;
Bartlomiej Sieka
committed
}
out:
#endif
printf("device %d ", idx);
if (*size == nand->size)
puts("whole chip\n");
else
printf("offset 0x%lx, size 0x%zx\n", *off, *size);
Bartlomiej Sieka
committed
}
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
static void print_status(ulong start, ulong end, ulong erasesize, int status)
{
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_LOCK) ? "LOCK " : ""),
((status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : ""));
}
static void do_nand_status(nand_info_t *nand)
{
ulong block_start = 0;
ulong off;
int last_status = -1;
struct nand_chip *nand_chip = nand->priv;
/* check the WP bit */
nand_chip->cmdfunc(nand, NAND_CMD_STATUS, -1, -1);
printf("device is %swrite protected\n",
(nand_chip->read_byte(nand) & 0x80 ?
"NOT " : ""));
for (off = 0; off < nand->size; off += nand->erasesize) {
int s = nand_get_lock_status(nand, off);
/* print message only if status has changed */
if (s != last_status && off != 0) {
print_status(block_start, off, nand->erasesize,
last_status);
block_start = off;
}
Loading
Loading full blame...