This patch adds the NAND SPL framework needed to boot i.MX31 boards
from NAND.

The patch is based on the work by Maxim Artamonov
<scn1874 at yandex.ru > (which was signed-off-by him).

--

Changes since V3 (original author's latest post):
  * Updated to apply on the main U-boot tree as of 2009-04-02
  * Split the patch into two parts, one with the NAND SPL framework
    and one which activates the NAND boot for the phycore board.
  * Coding style corrections.
---
 cpu/arm1136/start.S                   |   36 +++++--
 include/asm-arm/arch-mx31/mx31-regs.h |   96 +++++++++++++++
 nand_spl/nand_boot_mx31.c             |  204 +++++++++++++++++++++++++++++++++
 3 files changed, 327 insertions(+), 9 deletions(-)
 create mode 100644 nand_spl/nand_boot_mx31.c

diff --git a/cpu/arm1136/start.S b/cpu/arm1136/start.S
index e622338..e87bf99 100644
--- a/cpu/arm1136/start.S
+++ b/cpu/arm1136/start.S
@@ -1,6 +1,9 @@
 /*
  *  armboot - Startup Code for OMP2420/ARM1136 CPU-core
  *
+ *
+ *  Copyright (c) 2008 Maxim Artamonov, <scn1874 at yandex.ru>
+ *
  *  Copyright (c) 2004 Texas Instruments <r-woodru...@ti.com>
  *
  *  Copyright (c) 2001 Marius Gröger <m...@sysgo.de>
@@ -32,6 +35,15 @@
 #include <version.h>
 .globl _start
 _start: b      reset
+#ifdef CONFIG_NAND_SPL
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+#else
 #ifdef CONFIG_ONENAND_IPL
        ldr     pc, _hang
        ldr     pc, _hang
@@ -68,6 +80,7 @@ _irq:                 .word irq
 _fiq:                  .word fiq
 _pad:                  .word 0x12345678 /* now 16*4=64 */
 #endif /* CONFIG_ONENAND_IPL */
+#endif /* CONFIG_NAND_SPL */
 .global _end_vect
 _end_vect:
 
@@ -156,9 +169,9 @@ 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 */
        cmp     r0, r1                  /* don't reloc during debug         */
-#ifndef CONFIG_ONENAND_IPL
+#if !defined(CONFIG_ONENAND_IPL) && !defined(CONFIG_NAND_SPL)
        beq     stack_setup
-#endif /* CONFIG_ONENAND_IPL */
+#endif /* !CONFIG_ONENAND_IPL && !CONFIG_NAND_SPL*/
 
        ldr     r2, _armboot_start
        ldr     r3, _bss_start
@@ -175,7 +188,7 @@ copy_loop:
        /* Set up the stack                                                 */
 stack_setup:
        ldr     r0, _TEXT_BASE          /* upper 128 KiB: relocated uboot   */
-#ifdef CONFIG_ONENAND_IPL
+#if defined(CONFIG_ONENAND_IPL) || defined (CONFIG_NAND_SPL)
        sub     sp, r0, #128            /* leave 32 words for abort-stack   */
 #else
        sub     r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area                   
    */
@@ -184,14 +197,14 @@ stack_setup:
        sub     r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
 #endif
        sub     sp, r0, #12             /* leave 3 words for abort-stack    */
-#endif /* CONFIG_ONENAND_IPL */
+#endif /* CONFIG_ONENAND_IPL || CONFIG_NAND_SPL*/
 
 clear_bss:
        ldr     r0, _bss_start          /* find start of bss segment        */
        ldr     r1, _bss_end            /* stop here                        */
        mov     r2, #0x00000000         /* clear                            */
 
-#ifndef CONFIG_ONENAND_IPL
+#if !defined(CONFIG_ONENAND_IPL) && !defined(CONFIG_NAND_SPL)
 clbss_l:str    r2, [r0]                /* clear loop...                    */
        add     r0, r0, #4
        cmp     r0, r1
@@ -200,12 +213,15 @@ clbss_l:str       r2, [r0]                /* clear 
loop...                    */
 
        ldr     pc, _start_armboot
 
+#ifdef CONFIG_NAND_SPL
+_start_armboot: .word nand_boot
+#else
 #ifdef CONFIG_ONENAND_IPL
 _start_armboot: .word start_oneboot
 #else
 _start_armboot: .word start_armboot
-#endif
-
+#endif /* CONFIG_ONENAND_IPL */
+#endif /* CONFIG_NAND_SPL */
 
 /*
  *************************************************************************
@@ -244,7 +260,7 @@ cpu_init_crit:
        mov     lr, ip          /* restore link */
        mov     pc, lr          /* back to my caller */
 
-#ifndef CONFIG_ONENAND_IPL
+#if !defined(CONFIG_ONENAND_IPL) && !defined(CONFIG_NAND_SPL)
 /*
  *************************************************************************
  *
@@ -357,11 +373,12 @@ cpu_init_crit:
        .macro get_fiq_stack                    @ setup FIQ stack
        ldr     sp, FIQ_STACK_START
        .endm
-#endif /* CONFIG_ONENAND_IPL */
+#endif /* !CONFIG_ONENAND_IPL && !CONFIG_NAND_SPL*/
 
 /*
  * exception handlers
  */
+#ifndef CONFIG_NAND_SPL
 #ifdef CONFIG_ONENAND_IPL
        .align  5
 do_hang:
@@ -436,3 +453,4 @@ arm1136_cache_flush:
                mcr     p15, 0, r1, c7, c5, 0   @ invalidate I cache
                mov     pc, lr                  @ back to caller
 #endif /* CONFIG_ONENAND_IPL */
+#endif /* !CONFIG_NAND_SPL*/
diff --git a/include/asm-arm/arch-mx31/mx31-regs.h 
b/include/asm-arm/arch-mx31/mx31-regs.h
index a8a05c8..45f2ae3 100644
--- a/include/asm-arm/arch-mx31/mx31-regs.h
+++ b/include/asm-arm/arch-mx31/mx31-regs.h
@@ -194,4 +194,100 @@
 #define CS5_BASE       0xB6000000
 #define PCMCIA_MEM_BASE        0xC0000000
 
+/*
+ * NAND controller
+ */
+#define NFC_BASE_ADDR  0xB8000000
+
+/*
+ * Addresses for NFC registers
+ */
+#define NFC_BUF_SIZE            (*((volatile u16 *)(NFC_BASE_ADDR + 0xE00)))
+#define NFC_BUF_ADDR            (*((volatile u16 *)(NFC_BASE_ADDR + 0xE04)))
+#define NFC_FLASH_ADDR          (*((volatile u16 *)(NFC_BASE_ADDR + 0xE06)))
+#define NFC_FLASH_CMD           (*((volatile u16 *)(NFC_BASE_ADDR + 0xE08)))
+#define NFC_CONFIG              (*((volatile u16 *)(NFC_BASE_ADDR + 0xE0A)))
+#define NFC_ECC_STATUS_RESULT   (*((volatile u16 *)(NFC_BASE_ADDR + 0xE0C)))
+#define NFC_RSLTMAIN_AREA       (*((volatile u16 *)(NFC_BASE_ADDR + 0xE0E)))
+#define NFC_RSLTSPARE_AREA      (*((volatile u16 *)(NFC_BASE_ADDR + 0xE10)))
+#define NFC_WRPROT              (*((volatile u16 *)(NFC_BASE_ADDR + 0xE12)))
+#define NFC_UNLOCKSTART_BLKADDR (*((volatile u16 *)(NFC_BASE_ADDR + 0xE14)))
+#define NFC_UNLOCKEND_BLKADDR   (*((volatile u16 *)(NFC_BASE_ADDR + 0xE16)))
+#define NFC_NF_WRPRST           (*((volatile u16 *)(NFC_BASE_ADDR + 0xE18)))
+#define NFC_CONFIG1             (*((volatile u16 *)(NFC_BASE_ADDR + 0xE1A)))
+#define NFC_CONFIG2             (*((volatile u16 *)(NFC_BASE_ADDR + 0xE1C)))
+
+/*
+ * Addresses for NFC RAM BUFFER Main area 0
+ */
+#define MAIN_AREA0        (volatile u16 *)(NFC_BASE_ADDR + 0x000)
+#define MAIN_AREA1        (volatile u16 *)(NFC_BASE_ADDR + 0x200)
+#define MAIN_AREA2        (volatile u16 *)(NFC_BASE_ADDR + 0x400)
+#define MAIN_AREA3        (volatile u16 *)(NFC_BASE_ADDR + 0x600)
+
+/*
+ * Addresses for NFC SPARE BUFFER Spare area 0
+ */
+#define SPARE_AREA0       (volatile u16 *)(NFC_BASE_ADDR + 0x800)
+#define SPARE_AREA1       (volatile u16 *)(NFC_BASE_ADDR + 0x810)
+#define SPARE_AREA2       (volatile u16 *)(NFC_BASE_ADDR + 0x820)
+#define SPARE_AREA3       (volatile u16 *)(NFC_BASE_ADDR + 0x830)
+
+/*
+ * Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register for Command
+ * operation
+ */
+#define NFC_CMD            0x1
+
+/*
+ * Set INT to 0, FADD to 1, rest to 0 in NFC_CONFIG2 Register for Address
+ * operation
+ */
+#define NFC_ADDR           0x2
+
+/*
+ * Set INT to 0, FDI to 1, rest to 0 in NFC_CONFIG2 Register for Input
+ * operation
+ */
+#define NFC_INPUT          0x4
+
+/*
+ * Set INT to 0, FDO to 001, rest to 0 in NFC_CONFIG2 Register for Data
+ * Output operation
+ */
+#define NFC_OUTPUT         0x8
+
+/*
+ * Set INT to 0, FD0 to 010, rest to 0 in NFC_CONFIG2 Register for Read ID
+ * operation
+ */
+#define NFC_ID             0x10
+
+/*
+ * Set INT to 0, FDO to 100, rest to 0 in NFC_CONFIG2 Register for Read
+ * Status operation
+ */
+#define NFC_STATUS         0x20
+
+/*
+ * Set INT to 1, rest to 0 in NFC_CONFIG2 Register for Read Status
+ * operation
+ */
+#define NFC_INT            0x8000
+
+#define NFC_SP_EN           (1 << 2)
+#define NFC_ECC_EN          (1 << 3)
+#define NFC_INT_MSK         (1 << 4)
+#define NFC_BIG             (1 << 5)
+#define NFC_RST             (1 << 6)
+#define NFC_CE              (1 << 7)
+#define NFC_ONE_CYCLE       (1 << 8)
+
+/*
+ * NFMS bit in RCSR register for pagesize of nandflash
+ */
+#define NFMS           (*((volatile u32 *)CCM_RCSR))
+#define NFMS_BIT       30
+
 #endif /* __ASM_ARCH_MX31_REGS_H */
+
diff --git a/nand_spl/nand_boot_mx31.c b/nand_spl/nand_boot_mx31.c
new file mode 100644
index 0000000..a772756
--- /dev/null
+++ b/nand_spl/nand_boot_mx31.c
@@ -0,0 +1,204 @@
+/*
+ * (C) Copyright 2008
+ * Maxim Artamonov, <scn1874 at yandex.ru>
+ * 
+ * (C) Copyright 2006-2008
+ * Stefan Roese, DENX Software Engineering, sr at denx.de.
+ *
+ * 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> 
+#include <nand.h>
+#include <asm-arm/arch/mx31-regs.h>
+
+static void mx31_wait_ready(void)
+{
+       while (1) {
+               if (NFC_CONFIG2 & NFC_INT) {
+                       /* Reset interrupt flag */
+                       NFC_CONFIG2 = NFC_CONFIG2 & (~NFC_INT);
+                       break;
+               }
+       }
+}
+
+static void mx31_nand_init(void)
+{
+       /* unlocking RAM Buff */
+       NFC_CONFIG = 0x2;
+
+       /* hardware ECC checking and correct */
+       NFC_CONFIG1 = NFC_ECC_EN;
+}
+
+static void mx31_nand_command(unsigned short command)
+{
+       NFC_FLASH_CMD = command;
+       NFC_CONFIG2 = NFC_CMD;
+       mx31_wait_ready();
+}
+
+static void mx31_nand_page_address(unsigned int page_address)
+{
+       unsigned int page_count;
+
+       NFC_FLASH_ADDR = 0x00;
+       NFC_CONFIG2 = NFC_ADDR;
+       mx31_wait_ready();
+
+       /* code only for 2kb flash */
+       if (CFG_NAND_PAGE_SIZE == 0x800) {
+               NFC_FLASH_ADDR = 0x00;
+               NFC_CONFIG2 = NFC_ADDR;
+               mx31_wait_ready();
+       }
+
+       page_count = CFG_NAND_CHIP_SIZE / CFG_NAND_PAGE_SIZE;
+
+       if (page_address <= page_count){
+               page_count--; /* transform 0x01000000 to 0x00ffffff */
+               do {
+                       NFC_FLASH_ADDR = (unsigned short)(page_address & 0xff);
+                       NFC_CONFIG2 = NFC_ADDR;
+                       mx31_wait_ready();
+                       page_address = page_address >> 8;
+                       page_count = page_count >> 8;                   
+               } while (page_count);
+       }
+}
+
+static void mx31_nand_data_output(void)
+{
+       int i;
+
+       /*
+        * The NAND controller requires four output commands for
+        * large page devices.
+        */
+       for (i = 0; i < (CFG_NAND_PAGE_SIZE / 512); i++) {
+               NFC_CONFIG1 = NFC_ECC_EN;
+               NFC_BUF_ADDR = i; /* read in i:th buffer */
+               NFC_CONFIG2 = NFC_OUTPUT;
+               mx31_wait_ready();
+       }
+}
+
+static int mx31_nand_check_ecc(void)
+{
+       unsigned short ecc_status_register;
+       
+       ecc_status_register = NFC_ECC_STATUS_RESULT;
+       
+       if (ecc_status_register != 0)
+               return 1; /* error */
+       return 0;
+}
+
+static int mx31_read_page(unsigned int page_address, unsigned char *buf)
+{
+       int i;
+       volatile u32 *p1;
+       volatile u32 *p2;
+       u32 a;
+       
+       mx31_nand_init();
+       NFC_BUF_ADDR = 0; /* read in first 0 buffer */
+       mx31_nand_command(NAND_CMD_READ0);
+       mx31_nand_page_address(page_address);
+       
+       if (CFG_NAND_CHIP_SIZE >= 0x08000000)
+               mx31_nand_command(NAND_CMD_READSTART);
+       
+       mx31_nand_data_output(); /* fill the main buffer 0 */
+       
+       if (mx31_nand_check_ecc()) {
+               while (1) {
+                       /* hang-loop in case of ecc-error */
+               }
+       }
+
+       p1 = (u32 *)MAIN_AREA0;
+       p2 = (u32 *)buf;
+
+       /* main copy loop from NAND-buffer to SDRAM memory */
+       for (i = 0; i < (CFG_NAND_PAGE_SIZE / 4); i++) {                
+               *p2 = *p1;
+               p1++;
+               p2++;
+       }
+       
+       p1 = (u32 *)SPARE_AREA0;
+
+       /* it is hardware specific code for 8-bit 512 B NAND-flash spare area */
+       p1++;
+       a = *p1;
+       a = (a & 0x0000ff00) >> 8;
+
+       if (a != 0xff) /* bad block marker verify */
+               return 1; /* potential bad block */
+       
+       return 0;
+}
+
+static int nand_load(unsigned int from, unsigned int size, unsigned char *buf)
+{
+       int i, bb;
+       
+       mx31_nand_init();
+       
+       /* convert from to page number */
+       from = from / CFG_NAND_PAGE_SIZE;
+
+       i = 0;
+
+       while (i < (size/CFG_NAND_PAGE_SIZE)) {
+               if ((from * CFG_NAND_PAGE_SIZE) >= CFG_NAND_CHIP_SIZE)
+                       return 2; /* memory segment violation */
+
+               bb = mx31_read_page(from, buf);
+
+               /* checking first page of each block */
+               /* if this page has bb marker, then skip whole block */
+               if ((!(from % CFG_NAND_PAGES_PER_BLOCK)) && bb) {
+                       from = from + CFG_NAND_PAGES_PER_BLOCK;
+               }
+               else {
+                       i++;
+                       from++;
+                       buf = buf + CFG_NAND_PAGE_SIZE;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * The main entry for NAND booting. It's necessary that SDRAM is already
+ * configured and available since this code loads the main U-Boot image
+ * from NAND into SDRAM and starts it from there.
+ */
+void nand_boot(void)
+{
+       __attribute__((noreturn)) void (*uboot)(void);
+
+       /* CFG_NAND_U_BOOT_OFFS and CFG_NAND_U_BOOT_SIZE must */
+       /* be aligned to full pages */
+       nand_load(CFG_NAND_U_BOOT_OFFS, CFG_NAND_U_BOOT_SIZE,
+                 (uchar *)CFG_NAND_U_BOOT_DST);
+
+       uboot = (void *)CFG_NAND_U_BOOT_START;
+       uboot();
+}
-- 
1.5.6

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to