flash: add nuc910 nand driver
authorSpencer Oliver <ntfreak@users.sourceforge.net>
Mon, 19 Jul 2010 11:22:18 +0000 (12:22 +0100)
committerSpencer Oliver <ntfreak@users.sourceforge.net>
Mon, 19 Jul 2010 11:22:18 +0000 (12:22 +0100)
This adds a nand driver support for the nuc910 target.
Note that ECC is not currently supported by this driver, although
it is supported by the peripheral.

Signed-off-by: Spencer Oliver <ntfreak@users.sourceforge.net>
src/flash/nand/Makefile.am
src/flash/nand/driver.c
src/flash/nand/nuc910.c [new file with mode: 0644]
src/flash/nand/nuc910.h [new file with mode: 0644]
tcl/board/rsc-w910.cfg

index 259a9cb608edde85e56c0e3991fbeb4ef902127c..8ea7b362dd873d561728920b207bdac0f29edda7 100644 (file)
@@ -27,7 +27,8 @@ NAND_DRIVERS = \
        s3c2440.c \
        s3c2443.c \
        s3c6400.c \
-       at91sam9.c
+       at91sam9.c \
+       nuc910.c
 
 noinst_HEADERS = \
        arm_io.h \
@@ -39,6 +40,7 @@ noinst_HEADERS = \
        mx2.h \
        mx3.h \
        s3c24xx.h \
-       s3c24xx_regs.h
+       s3c24xx_regs.h \
+       nuc910.h
 
 MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
index 597d78a6686d590b665a7950bc916d5b9694e353..522dfa40df961b7b4713e12de905d30c29236e6f 100644 (file)
@@ -40,6 +40,7 @@ extern struct nand_flash_controller s3c6400_nand_controller;
 extern struct nand_flash_controller imx27_nand_flash_controller;
 extern struct nand_flash_controller imx31_nand_flash_controller;
 extern struct nand_flash_controller at91sam9_nand_controller;
+extern struct nand_flash_controller nuc910_nand_controller;
 
 /* extern struct nand_flash_controller boundary_scan_nand_controller; */
 
@@ -57,6 +58,7 @@ static struct nand_flash_controller *nand_flash_controllers[] =
        &imx27_nand_flash_controller,
        &imx31_nand_flash_controller,
        &at91sam9_nand_controller,
+       &nuc910_nand_controller,
 /*     &boundary_scan_nand_controller, */
        NULL
 };
diff --git a/src/flash/nand/nuc910.c b/src/flash/nand/nuc910.c
new file mode 100644 (file)
index 0000000..26d377f
--- /dev/null
@@ -0,0 +1,240 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it 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.                                   *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+/*
+ * NAND controller interface for Nuvoton NUC910
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "nuc910.h"
+#include "arm_io.h"
+#include <target/arm.h>
+
+struct nuc910_nand_controller
+{
+       struct target *target;
+       struct arm_nand_data io;
+};
+
+static int validate_target_state(struct nand_device *nand)
+{
+       struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
+       struct target *target = nuc910_nand->target;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+static int nuc910_nand_command(struct nand_device *nand, uint8_t command)
+{
+       struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
+       struct target *target = nuc910_nand->target;
+       int result;
+
+       if ((result = validate_target_state(nand)) != ERROR_OK)
+               return result;
+
+       target_write_u8(target, NUC910_SMCMD, command);
+       return ERROR_OK;
+}
+
+static int nuc910_nand_address(struct nand_device *nand, uint8_t address)
+{
+       struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
+       struct target *target = nuc910_nand->target;
+       int result;
+
+       if ((result = validate_target_state(nand)) != ERROR_OK)
+               return result;
+
+       target_write_u32(target, NUC910_SMADDR, ((address & 0xff) | NUC910_SMADDR_EOA));
+       return ERROR_OK;
+}
+
+static int nuc910_nand_read(struct nand_device *nand, void *data)
+{
+       struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
+       struct target *target = nuc910_nand->target;
+       int result;
+
+       if ((result = validate_target_state(nand)) != ERROR_OK)
+               return result;
+
+       target_read_u8(target, NUC910_SMDATA, data);
+       return ERROR_OK;
+}
+
+static int nuc910_nand_write(struct nand_device *nand, uint16_t data)
+{
+       struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
+       struct target *target = nuc910_nand->target;
+       int result;
+
+       if ((result = validate_target_state(nand)) != ERROR_OK)
+               return result;
+
+       target_write_u8(target, NUC910_SMDATA, data);
+       return ERROR_OK;
+}
+
+static int nuc910_nand_read_block_data(struct nand_device *nand,
+               uint8_t *data, int data_size)
+{
+       struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
+       int result;
+
+       if ((result = validate_target_state(nand)) != ERROR_OK)
+               return result;
+
+       nuc910_nand->io.chunk_size = nand->page_size;
+
+       /* try the fast way first */
+       result = arm_nandread(&nuc910_nand->io, data, data_size);
+       if (result != ERROR_NAND_NO_BUFFER)
+               return result;
+
+       /* else do it slowly */
+       while (data_size--)
+               nuc910_nand_read(nand, data++);
+
+       return ERROR_OK;
+}
+
+static int nuc910_nand_write_block_data(struct nand_device *nand,
+               uint8_t *data, int data_size)
+{
+       struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
+       int result;
+
+       if ((result = validate_target_state(nand)) != ERROR_OK)
+               return result;
+
+       nuc910_nand->io.chunk_size = nand->page_size;
+
+       /* try the fast way first */
+       result = arm_nandwrite(&nuc910_nand->io, data, data_size);
+       if (result != ERROR_NAND_NO_BUFFER)
+               return result;
+
+       /* else do it slowly */
+       while (data_size--)
+               nuc910_nand_write(nand, *data++);
+
+       return ERROR_OK;
+}
+
+static int nuc910_nand_reset(struct nand_device *nand)
+{
+       return nuc910_nand_command(nand, NAND_CMD_RESET);
+}
+
+static int nuc910_nand_ready(struct nand_device *nand, int timeout)
+{
+       struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
+       struct target *target = nuc910_nand->target;
+       uint32_t status;
+
+       do {
+               target_read_u32(target, NUC910_SMISR, &status);
+               if (status & NUC910_SMISR_RB_) {
+                       return 1;
+               }
+               alive_sleep(1);
+       } while (timeout-- > 0);
+
+       return 0;
+}
+
+NAND_DEVICE_COMMAND_HANDLER(nuc910_nand_device_command)
+{
+       struct nuc910_nand_controller *nuc910_nand;
+
+       nuc910_nand = calloc(1, sizeof(struct nuc910_nand_controller));
+       if (!nuc910_nand) {
+               LOG_ERROR("no memory for nand controller\n");
+               return ERROR_NAND_DEVICE_INVALID;
+       }
+
+       nand->controller_priv = nuc910_nand;
+       nuc910_nand->target = get_target(CMD_ARGV[1]);
+       if (!nuc910_nand->target) {
+               LOG_ERROR("target '%s' not defined", CMD_ARGV[1]);
+               free(nuc910_nand);
+               return ERROR_NAND_DEVICE_INVALID;
+       }
+
+       return ERROR_OK;
+}
+
+static int nuc910_nand_init(struct nand_device *nand)
+{
+       struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
+       struct target *target = nuc910_nand->target;
+       int bus_width = nand->bus_width ? : 8;
+       int result;
+
+       if ((result = validate_target_state(nand)) != ERROR_OK)
+               return result;
+
+       /* nuc910 only supports 8bit */
+       if (bus_width != 8)
+       {
+               LOG_ERROR("nuc910 only supports 8 bit bus width, not %i", bus_width);
+               return ERROR_NAND_OPERATION_NOT_SUPPORTED;
+       }
+
+       /* inform calling code about selected bus width */
+       nand->bus_width = bus_width;
+
+       nuc910_nand->io.target = target;
+       nuc910_nand->io.data = NUC910_SMDATA;
+       nuc910_nand->io.op = ARM_NAND_NONE;
+
+       /* configure nand controller */
+       target_write_u32(target, NUC910_FMICSR, NUC910_FMICSR_SM_EN);
+       target_write_u32(target, NUC910_SMCSR, 0x010000a8);     /* 2048 page size */
+       target_write_u32(target, NUC910_SMTCR, 0x00010204);
+       target_write_u32(target, NUC910_SMIER, 0x00000000);
+
+       return ERROR_OK;
+}
+
+struct nand_flash_controller nuc910_nand_controller =
+{
+       .name = "nuc910",
+       .command = nuc910_nand_command,
+       .address = nuc910_nand_address,
+       .read_data = nuc910_nand_read,
+       .write_data     = nuc910_nand_write,
+       .write_block_data = nuc910_nand_write_block_data,
+       .read_block_data = nuc910_nand_read_block_data,
+       .nand_ready = nuc910_nand_ready,
+       .reset = nuc910_nand_reset,
+       .nand_device_command = nuc910_nand_device_command,
+       .init = nuc910_nand_init,
+};
diff --git a/src/flash/nand/nuc910.h b/src/flash/nand/nuc910.h
new file mode 100644 (file)
index 0000000..644502f
--- /dev/null
@@ -0,0 +1,60 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it 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.                                   *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+/*
+ * NAND controller interface for Nuvoton NUC910
+ */
+
+#ifndef NUC910_H
+#define NUC910_H
+
+#define NUC910_FMICSR  0xB000D000
+#define NUC910_SMCSR   0xB000D0A0
+#define NUC910_SMTCR   0xB000D0A4
+#define NUC910_SMIER   0xB000D0A8
+#define NUC910_SMISR   0xB000D0AC
+#define NUC910_SMCMD   0xB000D0B0
+#define NUC910_SMADDR  0xB000D0B4
+#define NUC910_SMDATA  0xB000D0B8
+
+#define NUC910_SMECC0  0xB000D0BC
+#define NUC910_SMECC1  0xB000D0C0
+#define NUC910_SMECC2  0xB000D0C4
+#define NUC910_SMECC3  0xB000D0C8
+#define NUC910_ECC4ST  0xB000D114
+
+/* Global Control and Status Register (FMICSR) */
+#define NUC910_FMICSR_SM_EN    (1<<3)
+
+/* NAND Flash Address Port Register (SMADDR) */
+#define NUC910_SMADDR_EOA (1<<31)
+
+/* NAND Flash Control and Status Register (SMCSR) */
+#define NUC910_SMCSR_PSIZE     (1<<3)
+#define NUC910_SMCSR_DBW       (1<<4)
+
+/* NAND Flash Interrupt Status Register (SMISR) */
+#define NUC910_SMISR_ECC_IF    (1<<2)
+#define NUC910_SMISR_RB_       (1<<18)
+
+/* ECC4 Correction Status (ECC4ST) */
+
+#endif /* NUC910_H */
+
index eba44f62d4f5aba0a0fa5e844372378158f06fe9..423fb8fd00520e2f881bfbf41df1a4c8e5783723 100644 (file)
@@ -21,6 +21,9 @@ $_TARGETNAME configure -work-area-phys 0x00000000 -work-area-size 0x04000000 -wo
 set _FLASHNAME $_CHIPNAME.flash
 flash bank $_FLASHNAME cfi 0x20000000 0x00200000 2 2 $_TARGETNAME
 
+set _NANDNAME $_CHIPNAME.nand
+nand device $_NANDNAME nuc910 $_TARGETNAME
+
 #
 # Target events
 #

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)