This patch adds NAND (including boot-from-NAND via steppingstone) support to the S3C2410 SoC code in u-boot Signed-off-by: Harald Welte Index: u-boot/cpu/arm920t/s3c24x0/Makefile =================================================================== --- u-boot.orig/cpu/arm920t/s3c24x0/Makefile 2007-02-28 03:47:44.000000000 +0100 +++ u-boot/cpu/arm920t/s3c24x0/Makefile 2007-03-01 14:29:32.000000000 +0100 @@ -26,7 +26,7 @@ LIB = $(obj)lib$(SOC).a COBJS = i2c.o interrupts.o serial.o speed.o \ - usb_ohci.o + usb_ohci.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 1970-01-01 00:00:00.000000000 +0000 +++ u-boot/cpu/arm920t/s3c24x0/nand.c 2007-03-01 14:30:27.000000000 +0100 @@ -0,0 +1,225 @@ +/* + * (C) Copyright 2006 OpenMoko, Inc. + * Author: Harald Welte + * + * 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 + +#if 0 +#define DEBUGN printf +#else +#define DEBUGN(x, args ...) {} +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_NAND) +#if !defined(CFG_NAND_LEGACY) + +#include +#include + +#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; + //NFCONF = 0xf842; + + /* 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 1970-01-01 00:00:00.000000000 +0000 +++ u-boot/cpu/arm920t/s3c24x0/nand_read.c 2007-02-28 03:51:24.000000000 +0100 @@ -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 + * Date : $Date: 2004/02/04 10:37:37 $ + * + * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc. + * Author: Harald Welte + */ + +#include + +#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 2007-02-28 03:47:44.000000000 +0100 +++ u-boot/cpu/arm920t/start.S 2007-03-01 14:29:22.000000000 +0100 @@ -5,6 +5,10 @@ * Copyright (c) 2002 Alex Züpke * Copyright (c) 2002 Gary Jennejohn * + * S3C2410 NAND portions + * Copyright (c) 2001 MIZI Research, Inc. + * Copyright (c) 2006 OpenMoko, Inc. (Harald Welte + * * See file CREDITS for list of people who contributed to this * project. * @@ -27,6 +31,7 @@ #include #include +#include /* @@ -161,6 +166,7 @@ #endif #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 */ @@ -177,6 +183,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 */ /* Set up the stack */ Index: u-boot/include/s3c2410.h =================================================================== --- u-boot.orig/include/s3c2410.h 2007-02-28 03:51:24.000000000 +0100 +++ u-boot/include/s3c2410.h 2007-03-01 14:29:22.000000000 +0100 @@ -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 +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))