This patch adds NAND (including boot-from-NAND via steppingstone) support to
the S3C2410 SoC code in u-boot

Signed-off-by: Harald Welte <laforge@openmoko.org>

Index: u-boot/cpu/arm920t/s3c24x0/Makefile
===================================================================
--- u-boot.orig/cpu/arm920t/s3c24x0/Makefile
+++ u-boot/cpu/arm920t/s3c24x0/Makefile
@@ -26,7 +26,7 @@
 LIB	= $(obj)lib$(SOC).a
 
 COBJS	= i2c.o interrupts.o serial.o speed.o \
-	  usb.o
+	  usb.o nand_read.o nand.o
 
 SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
Index: u-boot/cpu/arm920t/s3c24x0/nand.c
===================================================================
--- /dev/null
+++ u-boot/cpu/arm920t/s3c24x0/nand.c
@@ -0,0 +1,224 @@
+/*
+ * (C) Copyright 2006 OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ *
+ * 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
+ */
+
+#include <common.h>
+
+#if 0
+#define DEBUGN	printf
+#else
+#define DEBUGN(x, args ...) {}
+#endif
+
+#if defined(CONFIG_CMD_NAND)
+#if !defined(CFG_NAND_LEGACY)
+
+#include <nand.h>
+#include <s3c2410.h>
+
+#define __REGb(x)	(*(volatile unsigned char *)(x))
+#define __REGi(x)	(*(volatile unsigned int *)(x))
+
+#define	NF_BASE		0x4e000000
+#define	NFCONF		__REGi(NF_BASE + 0x0)
+#define	NFCMD		__REGb(NF_BASE + 0x4)
+#define	NFADDR		__REGb(NF_BASE + 0x8)
+#define	NFDATA		__REGb(NF_BASE + 0xc)
+#define	NFSTAT		__REGb(NF_BASE + 0x10)
+#define NFECC0		__REGb(NF_BASE + 0x14)
+#define NFECC1		__REGb(NF_BASE + 0x15)
+#define NFECC2		__REGb(NF_BASE + 0x16)
+
+#define S3C2410_NFCONF_EN          (1<<15)
+#define S3C2410_NFCONF_512BYTE     (1<<14)
+#define S3C2410_NFCONF_4STEP       (1<<13)
+#define S3C2410_NFCONF_INITECC     (1<<12)
+#define S3C2410_NFCONF_nFCE        (1<<11)
+#define S3C2410_NFCONF_TACLS(x)    ((x)<<8)
+#define S3C2410_NFCONF_TWRPH0(x)   ((x)<<4)
+#define S3C2410_NFCONF_TWRPH1(x)   ((x)<<0)
+
+static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	DEBUGN("hwcontrol(): 0x%02x: ", cmd);
+
+	switch (cmd) {
+	case NAND_CTL_SETNCE:
+		NFCONF &= ~S3C2410_NFCONF_nFCE;
+		DEBUGN("NFCONF=0x%08x\n", NFCONF);
+		break;
+	case NAND_CTL_CLRNCE:
+		NFCONF |= S3C2410_NFCONF_nFCE;
+		DEBUGN("NFCONF=0x%08x\n", NFCONF);
+		break;
+	case NAND_CTL_SETALE:
+		chip->IO_ADDR_W = NF_BASE + 0x8;
+		DEBUGN("SETALE\n");
+		break;
+	case NAND_CTL_SETCLE:
+		chip->IO_ADDR_W = NF_BASE + 0x4;
+		DEBUGN("SETCLE\n");
+		break;
+	default:
+		chip->IO_ADDR_W = NF_BASE + 0xc;
+		break;
+	}
+	return;
+}
+
+static int s3c2410_dev_ready(struct mtd_info *mtd)
+{
+	DEBUGN("dev_ready\n");
+	return (NFSTAT & 0x01);
+}
+
+static void s3c2410_cmdfunc(struct mtd_info *mtd, unsigned cmd,
+			    int column, int page_addr)
+{
+	DEBUGN("cmdfunc(): 0x%02x, col=%d, page=%d\n", cmd, column, page_addr);
+
+	switch (cmd) {
+	case NAND_CMD_READ0:
+	case NAND_CMD_READ1:
+	case NAND_CMD_READOOB:
+		NFCMD = cmd;
+		NFADDR = column & 0xff;
+		NFADDR = page_addr & 0xff;
+		NFADDR = (page_addr >> 8) & 0xff;
+		NFADDR = (page_addr >> 16) & 0xff;
+		break;
+	case NAND_CMD_READID:
+		NFCMD = cmd;
+		NFADDR = 0;
+		break;
+	case NAND_CMD_PAGEPROG:
+		NFCMD = cmd;
+		printf("PAGEPROG not implemented\n");
+		break;
+	case NAND_CMD_ERASE1:
+		NFCMD = cmd;
+		NFADDR = page_addr & 0xff;
+		NFADDR = (page_addr >> 8) & 0xff;
+		NFADDR = (page_addr >> 16) & 0xff;
+		break;
+	case NAND_CMD_ERASE2:
+		NFCMD = cmd;
+		break;
+	case NAND_CMD_SEQIN:
+		printf("SEQIN not implemented\n");
+		break;
+	case NAND_CMD_STATUS:
+		NFCMD = cmd;
+		break;
+	case NAND_CMD_RESET:
+		NFCMD = cmd;
+		break;
+	default:
+		break;
+	}
+
+	while (!s3c2410_dev_ready(mtd));
+}
+
+#ifdef CONFIG_S3C2410_NAND_HWECC
+void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	DEBUGN("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd ,mode);
+	NFCONF |= S3C2410_NFCONF_INITECC;
+}
+
+static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+{
+	ecc_code[0] = NFECC0;
+	ecc_code[1] = NFECC1;
+	ecc_code[2] = NFECC2;
+	DEBUGN("s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n", mtd , ecc_code[0], ecc_code[1], ecc_code[2]);
+
+	return 0;
+}
+
+int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+{
+	if (read_ecc[0] == calc_ecc[0] &&
+	    read_ecc[1] == calc_ecc[1] &&
+	    read_ecc[2] == calc_ecc[2])
+	    	return 0;
+
+	printf("s3c2410_nand_correct_data: not implemented\n");
+	return -1;
+}
+#endif
+
+int board_nand_init(struct nand_chip *nand)
+{
+	u_int32_t cfg;
+	u_int8_t tacls, twrph0, twrph1;
+	S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
+
+	DEBUGN("board_nand_init()\n");
+
+	clk_power->CLKCON |= (1 << 4);
+
+	/* initialize hardware */
+	twrph0 = 3; twrph1 = 0; tacls = 0;
+
+	cfg = S3C2410_NFCONF_EN;
+	cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
+	cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
+	cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
+
+	NFCONF = cfg;
+
+	/* initialize nand_chip data structure */
+	nand->IO_ADDR_R = nand->IO_ADDR_W = 0x4e00000c;
+
+	/* read_buf and write_buf are default */
+	/* read_byte and write_byte are default */
+
+	/* hwcontrol always must be implemented */
+	nand->hwcontrol = s3c2410_hwcontrol;
+
+	nand->dev_ready = s3c2410_dev_ready;
+
+#ifdef CONFIG_S3C2410_NAND_HWECC
+	nand->enable_hwecc = s3c2410_nand_enable_hwecc;
+	nand->calculate_ecc = s3c2410_nand_calculate_ecc;
+	nand->correct_data = s3c2410_nand_correct_data;
+	nand->eccmode = NAND_ECC_HW3_512;
+#else
+	nand->eccmode = NAND_ECC_SOFT;
+#endif
+
+#ifdef CONFIG_S3C2410_NAND_BBT
+	nand->options = NAND_USE_FLASH_BBT;
+#else
+	nand->options = 0;
+#endif
+
+	DEBUGN("end of nand_init\n");
+
+	return 0;
+}
+
+#else
+ #error "U-Boot legacy NAND support not available for S3C2410"
+#endif
+#endif
Index: u-boot/cpu/arm920t/s3c24x0/nand_read.c
===================================================================
--- /dev/null
+++ u-boot/cpu/arm920t/s3c24x0/nand_read.c
@@ -0,0 +1,98 @@
+/*
+ * nand_read.c: Simple NAND read functions for booting from NAND
+ *
+ * This is used by cpu/arm920/start.S assembler code,
+ * and the board-specific linker script must make sure this
+ * file is linked within the first 4kB of NAND flash.
+ *
+ * Taken from GPLv2 licensed vivi bootloader,
+ * Copyright (C) 2002 MIZI Research, Inc.
+ *
+ * Author: Hwang, Chideok <hwang@mizi.com>
+ * Date  : $Date: 2004/02/04 10:37:37 $
+ *
+ * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_S3C2410_NAND_BOOT
+
+#define __REGb(x)	(*(volatile unsigned char *)(x))
+#define __REGi(x)	(*(volatile unsigned int *)(x))
+#define NF_BASE		0x4e000000
+#define NFCONF		__REGi(NF_BASE + 0x0)
+#define NFCMD		__REGb(NF_BASE + 0x4)
+#define NFADDR		__REGb(NF_BASE + 0x8)
+#define NFDATA		__REGb(NF_BASE + 0xc)
+#define NFSTAT		__REGb(NF_BASE + 0x10)
+
+#define BUSY 1
+inline void wait_idle(void)
+{
+	int i;
+
+	while (!(NFSTAT & BUSY))
+		for (i=0; i<10; i++);
+}
+
+#define NAND_SECTOR_SIZE	512
+#define NAND_BLOCK_MASK		(NAND_SECTOR_SIZE - 1)
+#define NAND_PAGE_SIZE		0x4000
+
+/* low level nand read function */
+int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
+{
+	int i, j;
+
+	if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))
+		return -1;	/* invalid alignment */
+
+	/* chip Enable */
+	NFCONF &= ~0x800;
+	for (i=0; i<10; i++);
+
+	for (i=start_addr; i < (start_addr + size);) {
+#ifdef CONFIG_S3C2410_NAND_SKIP_BAD
+		if (start_addr % NAND_PAGE_SIZE == 0) {
+			unsigned char data;
+			NFCMD = 0x50;
+			NFADDR = 517&0xf;
+			NFADDR = (i >> 9) & 0xff;
+			NFADDR = (i >> 17) & 0xff;
+			NFADDR = (i >> 25) & 0xff;
+			wait_idle();
+			data = (NFDATA & 0xff);
+			if (data != 0xff) {
+				/* Bad block */
+				i += NAND_PAGE_SIZE;
+				size += NAND_PAGE_SIZE;
+				continue;
+			}
+		}
+#endif
+		/* READ0 */
+		NFCMD = 0;
+
+		/* Write Address */
+		NFADDR = i & 0xff;
+		NFADDR = (i >> 9) & 0xff;
+		NFADDR = (i >> 17) & 0xff;
+		NFADDR = (i >> 25) & 0xff;
+
+		wait_idle();
+
+		for (j=0; j < NAND_SECTOR_SIZE; j++, i++) {
+			*buf = (NFDATA & 0xff);
+			buf++;
+		}
+	}
+
+	/* chip Disable */
+	NFCONF |= 0x800;	/* chip disable */
+
+	return 0;
+}
+
+#endif /* CONFIG_S3C2410_NAND_BOOT */
Index: u-boot/cpu/arm920t/start.S
===================================================================
--- u-boot.orig/cpu/arm920t/start.S
+++ u-boot/cpu/arm920t/start.S
@@ -5,6 +5,10 @@
  *  Copyright (c) 2002	Alex Züpke <azu@sysgo.de>
  *  Copyright (c) 2002	Gary Jennejohn <gj@denx.de>
  *
+ * S3C2410 NAND portions
+ *  Copyright (c) 2001  MIZI Research, Inc.
+ *  Copyright (c) 2006  OpenMoko, Inc. (Harald Welte <laforge@openmmoko.org>
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -27,6 +31,7 @@
 
 #include <config.h>
 #include <version.h>
+#include <s3c2410.h>
 #if	defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
 #include	<led.h>
 #endif
@@ -246,6 +251,7 @@
 #endif /* CONFIG_BOOTBINFUNC */
 #else
 #ifndef CONFIG_SKIP_RELOCATE_UBOOT
+#ifndef CONFIG_S3C2410_NAND_BOOT
 relocate:				/* relocate U-Boot to RAM	    */
 	adr	r0, _start		/* r0 <- current position of code   */
 	ldr	r1, _TEXT_BASE		/* test if we run from flash or RAM */
@@ -262,6 +268,93 @@
 	stmia	r1!, {r3-r10}		/* copy to   target address [r1]    */
 	cmp	r0, r2			/* until source end addreee [r2]    */
 	ble	copy_loop
+#else /* NAND_BOOT */
+relocate:
+copy_myself:
+	/* mov	r10, lr */
+
+	@ reset NAND
+	mov	r1, #S3C2410_NAND_BASE
+	ldr	r2, =0xf842		@ initial value enable tacls=3,rph0=6,rph1=0
+	str	r2, [r1, #oNFCONF]
+	ldr	r2, [r1, #oNFCONF]
+	bic	r2, r2, #0x800		@ enable chip
+	str	r2, [r1, #oNFCONF]
+	mov	r2, #0xff		@ RESET command
+	strb	r2, [r1, #oNFCMD]
+	mov	r3, #0			@ wait
+1:	add	r3, r3, #0x1
+	cmp	r3, #0xa
+	blt	1b
+2:	ldr	r2, [r1, #oNFSTAT]	@ wait ready
+	tst	r2, #0x1
+	beq	2b
+	ldr	r2, [r1, #oNFCONF]
+	orr	r2, r2, #0x800		@ disable chip
+	str	r2, [r1, #oNFCONF]
+
+#if 0
+	@ get ready to call C functions (for nand_read())
+	ldr	sp, DW_STACK_START	@ setup stack pointer
+	mov	fp, #0			@ no previous frame, so fp=0
+#else
+	ldr	r0, _TEXT_BASE		/* upper 128 KiB: relocated uboot   */
+	sub	r0, r0, #CFG_MALLOC_LEN	/* malloc area                      */
+	sub	r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
+#ifdef CONFIG_USE_IRQ
+	sub	r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
+#endif
+	sub	sp, r0, #12		/* leave 3 words for abort-stack    */
+#endif
+
+	@ copy u-boot to RAM
+	ldr	r0, _TEXT_BASE
+	mov     r1, #0x0
+	mov	r2, #CFG_UBOOT_SIZE
+	bl	nand_read_ll
+
+	tst	r0, #0x0
+	beq	ok_nand_read
+#ifdef CONFIG_DEBUG_LL
+bad_nand_read:
+	ldr	r0, STR_FAIL
+	ldr	r1, SerBase
+	bl	PrintWord
+1:	b	1b		@ infinite loop
+#endif
+
+ok_nand_read:
+#ifdef CONFIG_DEBUG_LL
+	ldr	r0, STR_OK
+	ldr	r1, SerBase
+	bl	PrintWord
+#endif
+
+	@ verify
+	mov	r0, #0
+	@ldr	r1, =0x33f00000
+	ldr	r1, _TEXT_BASE
+	mov	r2, #0x400	@ 4 bytes * 1024 = 4K-bytes
+go_next:
+	ldr	r3, [r0], #4
+	ldr	r4, [r1], #4
+	teq	r3, r4
+	bne	notmatch
+	subs	r2, r2, #4
+	beq	done_nand_read
+	bne	go_next
+notmatch:
+#ifdef CONFIG_DEBUG_LL
+	sub	r0, r0, #4
+	ldr	r1, SerBase
+	bl	PrintHexWord
+	ldr	r0, STR_FAIL
+	ldr	r1, SerBase
+	bl	PrintWord
+#endif
+1:	b	1b
+done_nand_read:
+#endif /* NAND_BOOT */
 #endif	/* CONFIG_SKIP_RELOCATE_UBOOT */
 #endif
 	/* Set up the stack						    */
Index: u-boot/include/s3c2410.h
===================================================================
--- u-boot.orig/include/s3c2410.h
+++ u-boot/include/s3c2410.h
@@ -38,12 +38,6 @@
 #define S3C2410_ECCSIZE		512
 #define S3C2410_ECCBYTES	3
 
-typedef enum {
-	S3C24X0_UART0,
-	S3C24X0_UART1,
-	S3C24X0_UART2
-} S3C24X0_UARTS_NR;
-
 /* S3C2410 device base addresses */
 #define S3C24X0_MEMCTL_BASE		0x48000000
 #define S3C24X0_USB_HOST_BASE		0x49000000
@@ -65,9 +59,23 @@
 #define S3C2410_SDI_BASE		0x5A000000
 
 
+#define oNFCONF			0x00
+#define oNFCMD			0x04
+#define oNFADDR			0x08
+#define oNFDATA			0x0C
+#define oNFSTAT			0x10
+#define oNFECC			0x14
+
+#ifndef __ASSEMBLER__
+
 /* include common stuff */
 #include <s3c24x0.h>
 
+typedef enum {
+	S3C24X0_UART0,
+	S3C24X0_UART1,
+	S3C24X0_UART2
+} S3C24X0_UARTS_NR;
 
 static inline S3C24X0_MEMCTL * S3C24X0_GetBase_MEMCTL(void)
 {
@@ -142,6 +150,7 @@
 	return (S3C2410_SDI * const)S3C2410_SDI_BASE;
 }
 
+#endif
 
 /* ISR */
 #define pISR_RESET		(*(unsigned *)(_ISR_STARTADDRESS+0x0))
