9
0
Fork 0

[NAND] continue to make it work. Now works partly on at91sam9260

This commit is contained in:
Sascha Hauer 2008-06-04 09:40:44 +02:00
parent f3351ebd78
commit 3d45abb7c4
6 changed files with 186 additions and 33 deletions

View File

@ -175,6 +175,9 @@ config CMD_FLASH
tristate
prompt "protect/erase"
config CMD_NAND
tristate
prompt "nand"
endmenu

View File

@ -38,3 +38,4 @@ obj-$(CONFIG_CMD_EXPORT) += export.o
obj-$(CONFIG_CMD_PRINTENV) += printenv.o
obj-$(CONFIG_CMD_SAVEENV) += saveenv.o
obj-$(CONFIG_CMD_LOADENV) += loadenv.o
obj-$(CONFIG_CMD_NAND) += nand.o

View File

@ -51,14 +51,16 @@ static ssize_t nand_bb_read(struct device_d *dev, void *buf, size_t count,
printf("%s %d %d\n", __func__, offset, count);
ret = dev_ioctl(bb->physdev, MEMGETBADBLOCK, (void *)bb->offset);
if (ret < 0)
return ret;
do {
ret = dev_ioctl(bb->physdev, MEMGETBADBLOCK, (void *)bb->offset);
if (ret < 0)
return ret;
if (ret) {
printf("block is bad\n");
bb->offset += bb->info.erasesize;
}
if (ret) {
printf("block is bad\n");
bb->offset += bb->info.erasesize;
}
} while (ret);
ret = dev_read(bb->physdev, buf, count, bb->offset, flags);
if (ret > 0)
@ -75,14 +77,16 @@ static ssize_t nand_bb_write(struct device_d *dev, const void *buf, size_t count
printf("%s %d %d\n", __func__, offset, count);
ret = dev_ioctl(bb->physdev, MEMGETBADBLOCK, (void *)bb->offset);
if (ret < 0)
return ret;
do {
ret = dev_ioctl(bb->physdev, MEMGETBADBLOCK, (void *)bb->offset);
if (ret < 0)
return ret;
if (ret) {
printf("block is bad\n");
bb->offset += bb->info.erasesize;
}
if (ret) {
printf("block is bad\n");
bb->offset += bb->info.erasesize;
}
} while (ret);
ret = dev_write(bb->physdev, buf, count, bb->offset, flags);
if (ret > 0)

View File

@ -4,5 +4,4 @@ obj-$(CONFIG_NAND) += nand_bbt.o
obj-$(CONFIG_NAND) += nand.o
obj-$(CONFIG_NAND) += nand_ecc.o
obj-$(CONFIG_NAND) += nand_ids.o
obj-$(CONFIG_NAND) += imx_nand.o
#obj-$(CONFIG_NAND) += nand_util.o

View File

@ -23,58 +23,189 @@
#include <common.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/mtd.h>
#include <init.h>
#include <xfuncs.h>
#include <driver.h>
#include <malloc.h>
#include <ioctl.h>
#include <nand.h>
static ssize_t nand_read(struct device_d *dev, void* buf, size_t count, ulong offset, ulong flags)
{
struct nand_chip *nand = dev->priv;
size_t retlen;
int ret;
char oobuf[NAND_MAX_OOBSIZE];
printf("%s\n", __FUNCTION__);
printf("nand_read: 0x%08x 0x%08x\n", offset, count);
ret = nand->read_ecc(nand, offset, count, &retlen, buf, oobuf, &nand->oobinfo);
ret = nand->read(nand, offset, count, &retlen, buf);
if(ret)
return ret;
return retlen;
}
static ssize_t nand_write(struct device_d* dev, const void* buf, size_t count, ulong offset, ulong flags)
#define NOTALIGNED(x) (x & (nand->oobblock-1)) != 0
static ssize_t nand_write(struct device_d* dev, const void* buf, size_t _count, ulong offset, ulong flags)
{
struct nand_chip *nand = dev->priv;
size_t retlen;
size_t retlen, now;
int ret;
void *wrbuf = NULL;
size_t count = _count;
ret = nand->write_ecc(nand, offset, count, &retlen, buf, NULL, &nand->oobinfo);
if (ret)
return ret;
return retlen;
printf("write: 0x%08x 0x%08x\n", offset, count);
while (count) {
now = count > nand->oobblock ? nand->oobblock : count;
if (NOTALIGNED(now) || NOTALIGNED(offset)) {
printf("not aligned: %d %d\n", nand->oobblock, (offset % nand->oobblock));
wrbuf = xmalloc(nand->oobblock);
memset(wrbuf, 0xff, nand->oobblock);
memcpy(wrbuf + (offset % nand->oobblock), buf, now);
ret = nand->write_ecc(nand, offset & ~(nand->oobblock - 1), nand->oobblock, &retlen, wrbuf,
NULL, &nand->oobinfo);
} else {
ret = nand->write_ecc(nand, offset, now, &retlen, buf,
NULL, &nand->oobinfo);
printf("huhu offset: 0x%08x now: 0x%08x retlen: 0x%08x\n", offset, now, retlen);
}
if (ret)
goto out;
offset += now;
count -= now;
buf += now;
}
out:
if (wrbuf)
free(wrbuf);
return ret ? ret : _count;
}
static int nand_probe (struct device_d *dev)
static int nand_ioctl(struct device_d *dev, int request, void *buf)
{
printf("%s\n", __FUNCTION__);
struct nand_chip *nand = dev->priv;
struct mtd_info_user *info = buf;
switch (request) {
case MEMGETBADBLOCK:
printf("MEMGETBADBLOCK: 0x%08x\n", (off_t)buf);
return nand->block_isbad(nand, (off_t)buf);
case MEMGETINFO:
info->type = nand->type;
info->flags = nand->flags;
info->size = nand->size;
info->erasesize = nand->erasesize;
info->oobsize = nand->oobsize;
/* The below fields are obsolete */
info->ecctype = -1;
info->eccsize = 0;
return 0;
}
return 0;
}
static struct driver_d nand_driver = {
.name = "nand_flash",
.probe = nand_probe,
static ssize_t nand_erase(struct device_d *dev, size_t count, unsigned long offset)
{
struct nand_chip *nand = dev->priv;
struct erase_info erase;
int ret;
memset(&erase, 0, sizeof(erase));
erase.nand = nand;
erase.addr = offset;
erase.len = nand->erasesize;
while (count > 0) {
debug("erase %d %d\n", erase.addr, erase.len);
ret = nand->block_isbad(nand, erase.addr);
if (ret > 0) {
printf("Skipping bad block at 0x%08x\n", erase.addr);
} else {
ret = nand->erase(nand, &erase);
if (ret)
return ret;
}
erase.addr += nand->erasesize;
count -= count > nand->erasesize ? nand->erasesize : count;
}
return 0;
}
static int nand_controller_probe(struct device_d *dev)
{
struct nand_chip *nand;
struct nand_platform_data *pdata = dev->platform_data;
int ret;
nand = xzalloc(sizeof(*nand));
dev->priv = nand;
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)dev->map_base;
nand->hwcontrol = pdata->hwcontrol;
nand->eccmode = pdata->eccmode;
nand->dev_ready = pdata->dev_ready;
nand->chip_delay = pdata->chip_delay;
ret = nand_scan(nand, 1);
if (ret)
goto out;
strcpy(nand->dev.name, "nand_device");
get_free_deviceid(nand->dev.id, "nand");
nand->dev.size = nand->chipsize;
nand->dev.priv = nand;
ret = register_device(&nand->dev);
if (ret)
goto out;
return 0;
out:
free(nand);
return ret;
}
static struct driver_d nand_controller_driver = {
.name = "nand_controller",
.probe = nand_controller_probe,
};
static int nand_device_probe(struct device_d *dev)
{
return 0;
}
static struct driver_d nand_device_driver = {
.name = "nand_device",
.probe = nand_device_probe,
.read = nand_read,
.write = nand_write,
// .erase = nand_erase,
// .protect= nand_protect,
// .memmap = generic_memmap_ro,
.ioctl = nand_ioctl,
.open = dev_open_default,
.close = dev_close_default,
.lseek = dev_lseek_default,
.erase = nand_erase,
// .info = nand_info,
};
static int nand_init(void)
{
return register_driver(&nand_driver);
register_driver(&nand_device_driver);
register_driver(&nand_controller_driver);
return 0;
}
device_initcall(nand_init);

15
include/nand.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef __NAND_H__
#define __NAND_H__
struct nand_chip;
struct nand_platform_data {
void (*hwcontrol)(struct nand_chip *, int cmd);
int eccmode;
int (*dev_ready)(struct nand_chip *);
int chip_delay;
};
#endif /* __NAND_H__ */