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>
#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(nand_info_t *nand, ulong off, int only_oob, int repeat)
Bartlomiej Sieka
committed
{
int i;
if (repeat)
off = last + nand->writesize;
last = off;
Bartlomiej Sieka
committed
datbuf = memalign(ARCH_DMA_MINALIGN, nand->writesize);
Bartlomiej Sieka
committed
puts("No memory for page buffer\n");
return 1;
}
oobbuf = memalign(ARCH_DMA_MINALIGN, nand->oobsize);
if (!oobbuf) {
puts("No memory for page buffer\n");
ret = 1;
goto free_dat;
}
off &= ~(nand->writesize - 1);
loff_t addr = (loff_t) off;
struct mtd_oob_ops ops;
memset(&ops, 0, sizeof(ops));
ops.datbuf = datbuf;
ops.len = nand->writesize;
ops.ooblen = nand->oobsize;
ops.mode = MTD_OPS_RAW;
i = mtd_read_oob(nand, addr, &ops);
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);
if (!only_oob) {
i = nand->writesize >> 4;
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");
i = nand->oobsize >> 3;
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
}
/* ------------------------------------------------------------------------- */
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
static int set_dev(int dev)
{
if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
!nand_info[dev].name) {
puts("No such device\n");
return -1;
}
if (nand_curr_device == dev)
return 0;
printf("Device %d: %s", dev, nand_info[dev].name);
puts("... is now current device\n");
nand_curr_device = dev;
#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
board_nand_select_device(nand_info[dev].priv, dev);
#endif
return 0;
}
static inline int str2off(const char *p, loff_t *num)
{
char *endptr;
*num = simple_strtoull(p, &endptr, 16);
return *p != '\0' && *endptr == '\0';
}
static inline int str2long(const char *p, ulong *num)
Bartlomiej Sieka
committed
{
char *endptr;
Bartlomiej Sieka
committed
*num = simple_strtoul(p, &endptr, 16);
return *p != '\0' && *endptr == '\0';
Bartlomiej Sieka
committed
static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size,
loff_t *maxsize)
#ifdef CONFIG_CMD_MTDPARTS
struct mtd_device *dev;
struct part_info *part;
u8 pnum;
ret = mtdparts_init();
if (ret)
return ret;
ret = find_dev_and_part(partname, &dev, &pnum, &part);
if (ret)
return ret;
if (dev->id->type != MTD_DEV_TYPE_NAND) {
puts("not a NAND device\n");
return -1;
*off = part->offset;
*size = part->size;
*maxsize = part->size;
*idx = dev->id->num;
ret = set_dev(*idx);
if (ret)
return ret;
return 0;
#else
puts("offset is not a number\n");
return -1;
Bartlomiej Sieka
committed
#endif
Bartlomiej Sieka
committed
static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *size,
loff_t *maxsize)
{
if (!str2off(arg, off))
return get_part(arg, idx, off, size, maxsize);
if (*off >= nand_info[*idx].size) {
puts("Offset exceeds device limit\n");
return -1;
}
Loading
Loading full blame...