summaryrefslogtreecommitdiffstats
path: root/commands/nand.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2008-06-04 09:31:15 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2008-06-06 09:30:32 +0200
commitf3351ebd7864b83b1f5f3cdc7c8a9f9110cb562f (patch)
treed552d362afb4ffd949dba5e758e9e8fbfe73b9a1 /commands/nand.c
parent3cde41fb901f1c6157c7e3e845239b279e5a2cb0 (diff)
downloadbarebox-f3351ebd7864b83b1f5f3cdc7c8a9f9110cb562f.tar.gz
add basic at91sam9260 support. Currently only second stage
bootloader is supported: - No SDRAM initialisation - No UART init / baudrate change
Diffstat (limited to 'commands/nand.c')
-rw-r--r--commands/nand.c205
1 files changed, 205 insertions, 0 deletions
diff --git a/commands/nand.c b/commands/nand.c
new file mode 100644
index 0000000..483441a
--- /dev/null
+++ b/commands/nand.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <fs.h>
+#include <linux/stat.h>
+#include <errno.h>
+#include <malloc.h>
+#include <getopt.h>
+#include <xfuncs.h>
+#include <init.h>
+#include <ioctl.h>
+#include <nand.h>
+#include <linux/mtd/mtd-abi.h>
+
+struct nand_bb {
+ struct device_d device;
+
+ struct device_d *physdev;
+
+ int open;
+
+ struct mtd_info_user info;
+
+ off_t offset;
+};
+
+static ssize_t nand_bb_read(struct device_d *dev, void *buf, size_t count,
+ unsigned long offset, ulong flags)
+{
+ struct nand_bb *bb = dev->priv;
+ int ret;
+
+ printf("%s %d %d\n", __func__, offset, count);
+
+ 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;
+ }
+
+ ret = dev_read(bb->physdev, buf, count, bb->offset, flags);
+ if (ret > 0)
+ bb->offset += ret;
+
+ return ret;
+}
+
+static ssize_t nand_bb_write(struct device_d *dev, const void *buf, size_t count,
+ unsigned long offset, ulong flags)
+{
+ struct nand_bb *bb = dev->priv;
+ int ret;
+
+ printf("%s %d %d\n", __func__, offset, count);
+
+ 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;
+ }
+
+ ret = dev_write(bb->physdev, buf, count, bb->offset, flags);
+ if (ret > 0)
+ bb->offset += ret;
+
+ return ret;
+}
+
+static int nand_bb_open(struct device_d *dev, struct filep *f)
+{
+ struct nand_bb *bb = dev->priv;
+ int ret;
+
+ if (bb->open)
+ return -EBUSY;
+
+ bb->open = 1;
+ bb->offset = 0;
+
+ return 0;
+}
+
+static int nand_bb_close(struct device_d *dev, struct filep *f)
+{
+ struct nand_bb *bb = dev->priv;
+
+ bb->open = 0;
+
+ return 0;
+}
+
+static int nand_bb_probe(struct device_d *dev)
+{
+ struct nand_bb *bb = dev->priv;
+ int ret = 0;
+
+ ret = dev_ioctl(bb->physdev, MEMGETINFO, &bb->info);
+ if (ret < 0)
+ goto out;
+
+ printf("new info: %d\n", bb->info.erasesize);
+
+ return 0;
+out:
+ free(bb);
+ return ret;
+}
+
+static int nand_bb_remove(struct device_d *dev)
+{
+ return 0;
+}
+
+struct driver_d nand_bb_driver = {
+ .name = "nand_bb",
+ .probe = nand_bb_probe,
+ .remove = nand_bb_remove,
+ .open = nand_bb_open,
+ .close = nand_bb_close,
+ .read = nand_bb_read,
+ .write = nand_bb_write,
+};
+
+static int nand_bb_init(void)
+{
+ return register_driver(&nand_bb_driver);
+}
+
+device_initcall(nand_bb_init);
+
+static int do_nand (cmd_tbl_t *cmdtp, int argc, char *argv[])
+{
+ int ret, opt;
+ char *device = NULL;
+ struct device_d *dev;
+ struct nand_bb *bb;
+
+ getopt_reset();
+
+ while((opt = getopt(argc, argv, "m:")) > 0) {
+ switch(opt) {
+ case 'm':
+ device = optarg;
+ break;
+ }
+ }
+
+ if (device) {
+ dev = get_device_by_path(device);
+ if (!dev) {
+ printf("no such device: %s\n", argv[1]);
+ return 1;
+ }
+
+ bb = xzalloc(sizeof(*bb));
+ sprintf(bb->device.id, "%s.bb", dev->id);
+ strcpy(bb->device.name, "nand_bb");
+ bb->device.priv = bb;
+ bb->device.size = dev->size; /* FIXME: Bad blocks? */
+ bb->physdev = dev;
+
+ if (register_device(&bb->device))
+ goto free_out;
+
+ dev_add_child(dev, &bb->device);
+
+ }
+free_out:
+ return 0;
+}
+
+static const __maybe_unused char cmd_nand_help[] =
+"Usage: nand bla\n";
+
+U_BOOT_CMD_START(nand)
+ .maxargs = CONFIG_MAXARGS,
+ .cmd = do_nand,
+ .usage = "",
+ U_BOOT_CMD_HELP(cmd_nand_help)
+U_BOOT_CMD_END