From e4c09508545d1c45617ba45391c03c03cbc360b9 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 30 Jun 2008 14:13:28 -0500 Subject: NAND boot: MPC8313ERDB support Note that with older board revisions, NAND boot may only work after a power-on reset, and not after a warm reset. I don't have a newer board to test on; if you have a board with a 33MHz crystal, please let me know if it works after a warm reset. Signed-off-by: Scott Wood --- Makefile | 10 +- board/freescale/mpc8313erdb/config.mk | 6 + board/freescale/mpc8313erdb/mpc8313erdb.c | 32 +++++ board/freescale/mpc8313erdb/sdram.c | 5 +- cpu/mpc83xx/nand_init.c | 112 +++++++++++++++++ cpu/mpc83xx/start.S | 152 +++++++----------------- include/configs/MPC8313ERDB.h | 82 ++++++++++--- include/mpc83xx.h | 2 + include/nand.h | 2 + lib_ppc/time.c | 4 +- nand_spl/board/freescale/mpc8313erdb/Makefile | 101 ++++++++++++++++ nand_spl/board/freescale/mpc8313erdb/u-boot.lds | 52 ++++++++ nand_spl/nand_boot.c | 4 +- nand_spl/nand_boot_fsl_elbc.c | 150 +++++++++++++++++++++++ 14 files changed, 585 insertions(+), 129 deletions(-) create mode 100644 cpu/mpc83xx/nand_init.c create mode 100644 nand_spl/board/freescale/mpc8313erdb/Makefile create mode 100644 nand_spl/board/freescale/mpc8313erdb/u-boot.lds create mode 100644 nand_spl/nand_boot_fsl_elbc.c diff --git a/Makefile b/Makefile index f25750f..ffdd726 100644 --- a/Makefile +++ b/Makefile @@ -1997,8 +1997,11 @@ TASREG_config : unconfig ######################################################################### MPC8313ERDB_33_config \ -MPC8313ERDB_66_config: unconfig +MPC8313ERDB_66_config \ +MPC8313ERDB_NAND_33_config \ +MPC8313ERDB_NAND_66_config: unconfig @mkdir -p $(obj)include + @mkdir -p $(obj)board/freescale/mpc8313erdb @if [ "$(findstring _33_,$@)" ] ; then \ $(XECHO) -n "...33M ..." ; \ echo "#define CFG_33MHZ" >>$(obj)include/config.h ; \ @@ -2006,6 +2009,11 @@ MPC8313ERDB_66_config: unconfig if [ "$(findstring _66_,$@)" ] ; then \ $(XECHO) -n "...66M..." ; \ echo "#define CFG_66MHZ" >>$(obj)include/config.h ; \ + fi ; \ + if [ "$(findstring _NAND_,$@)" ] ; then \ + $(XECHO) -n "...NAND..." ; \ + echo "TEXT_BASE = 0x00100000" > $(obj)/board/freescale/mpc8313erdb/config.tmp ; \ + echo "#define CONFIG_NAND_U_BOOT" >>$(obj)include/config.h ; \ fi ; @$(MKCONFIG) -a MPC8313ERDB ppc mpc83xx mpc8313erdb freescale diff --git a/board/freescale/mpc8313erdb/config.mk b/board/freescale/mpc8313erdb/config.mk index f768264..fd72a14 100644 --- a/board/freescale/mpc8313erdb/config.mk +++ b/board/freescale/mpc8313erdb/config.mk @@ -1 +1,7 @@ +ifndef NAND_SPL +sinclude $(OBJTREE)/board/$(BOARDDIR)/config.tmp +endif + +ifndef TEXT_BASE TEXT_BASE = 0xFE000000 +endif diff --git a/board/freescale/mpc8313erdb/mpc8313erdb.c b/board/freescale/mpc8313erdb/mpc8313erdb.c index 7cbdb7b..ebb703d 100644 --- a/board/freescale/mpc8313erdb/mpc8313erdb.c +++ b/board/freescale/mpc8313erdb/mpc8313erdb.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include DECLARE_GLOBAL_DATA_PTR; @@ -50,6 +52,7 @@ int checkboard(void) return 0; } +#ifndef CONFIG_NAND_SPL static struct pci_region pci_regions[] = { { bus_start: CFG_PCI1_MEM_BASE, @@ -128,3 +131,32 @@ void ft_board_setup(void *blob, bd_t *bd) #endif } #endif +#else /* CONFIG_NAND_SPL */ +void board_init_f(ulong bootflag) +{ + board_early_init_f(); + NS16550_init((NS16550_t)(CFG_IMMR + 0x4500), + CFG_NS16550_CLK / 16 / CONFIG_BAUDRATE); + puts("NAND boot... "); + init_timebase(); + initdram(0); + relocate_code(CFG_NAND_U_BOOT_RELOC + 0x10000, (gd_t *)gd, + CFG_NAND_U_BOOT_RELOC); +} + +void board_init_r(gd_t *gd, ulong dest_addr) +{ + nand_boot(); +} + +void putc(char c) +{ + if (gd->flags & GD_FLG_SILENT) + return; + + if (c == '\n') + NS16550_putc((NS16550_t)(CFG_IMMR + 0x4500), '\r'); + + NS16550_putc((NS16550_t)(CFG_IMMR + 0x4500), c); +} +#endif diff --git a/board/freescale/mpc8313erdb/sdram.c b/board/freescale/mpc8313erdb/sdram.c index afd8b9d..3a6347f 100644 --- a/board/freescale/mpc8313erdb/sdram.c +++ b/board/freescale/mpc8313erdb/sdram.c @@ -58,8 +58,10 @@ static void resume_from_sleep(void) */ static long fixed_sdram(void) { - volatile immap_t *im = (volatile immap_t *)CFG_IMMR; u32 msize = CFG_DDR_SIZE * 1024 * 1024; + +#ifndef CFG_RAMBOOT + volatile immap_t *im = (volatile immap_t *)CFG_IMMR; u32 msize_log2 = __ilog2(msize); im->sysconf.ddrlaw[0].bar = CFG_DDR_SDRAM_BASE >> 12; @@ -100,6 +102,7 @@ static long fixed_sdram(void) /* enable DDR controller */ im->ddr.sdram_cfg |= SDRAM_CFG_MEM_EN; +#endif return msize; } diff --git a/cpu/mpc83xx/nand_init.c b/cpu/mpc83xx/nand_init.c new file mode 100644 index 0000000..e92f230 --- /dev/null +++ b/cpu/mpc83xx/nand_init.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2004-2008 Freescale Semiconductor, Inc. + * + * 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 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 +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Breathe some life into the CPU... + * + * Set up the memory map, + * initialize a bunch of registers, + * initialize the UPM's + */ +void cpu_init_f (volatile immap_t * im) +{ + int i; + + /* Pointer is writable since we allocated a register for it */ + gd = (gd_t *) (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET); + + /* Clear initial global data */ + for (i = 0; i < sizeof(gd_t); i++) + ((char *)gd)[i] = 0; + + /* system performance tweaking */ + +#ifdef CFG_ACR_PIPE_DEP + /* Arbiter pipeline depth */ + im->arbiter.acr = (im->arbiter.acr & ~ACR_PIPE_DEP) | + (CFG_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT); +#endif + +#ifdef CFG_ACR_RPTCNT + /* Arbiter repeat count */ + im->arbiter.acr = (im->arbiter.acr & ~(ACR_RPTCNT)) | + (CFG_ACR_RPTCNT << ACR_RPTCNT_SHIFT); +#endif + +#ifdef CFG_SPCR_OPT + /* Optimize transactions between CSB and other devices */ + im->sysconf.spcr = (im->sysconf.spcr & ~SPCR_OPT) | + (CFG_SPCR_OPT << SPCR_OPT_SHIFT); +#endif + + /* Enable Time Base & Decrimenter (so we will have udelay()) */ + im->sysconf.spcr |= SPCR_TBEN; + + /* DDR control driver register */ +#ifdef CFG_DDRCDR + im->sysconf.ddrcdr = CFG_DDRCDR; +#endif + /* Output buffer impedance register */ +#ifdef CFG_OBIR + im->sysconf.obir = CFG_OBIR; +#endif + + /* + * Memory Controller: + */ + + /* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary + * addresses - these have to be modified later when FLASH size + * has been determined + */ + +#if defined(CFG_NAND_BR_PRELIM) \ + && defined(CFG_NAND_OR_PRELIM) \ + && defined(CFG_NAND_LBLAWBAR_PRELIM) \ + && defined(CFG_NAND_LBLAWAR_PRELIM) + im->lbus.bank[0].br = CFG_NAND_BR_PRELIM; + im->lbus.bank[0].or = CFG_NAND_OR_PRELIM; + im->sysconf.lblaw[0].bar = CFG_NAND_LBLAWBAR_PRELIM; + im->sysconf.lblaw[0].ar = CFG_NAND_LBLAWAR_PRELIM; +#else +#error CFG_NAND_BR_PRELIM, CFG_NAND_OR_PRELIM, CFG_NAND_LBLAWBAR_PRELIM & CFG_NAND_LBLAWAR_PRELIM must be defined +#endif +} + +/* + * Get timebase clock frequency (like cpu_clk in Hz) + */ +unsigned long get_tbclk(void) +{ + return (gd->bus_clk + 3L) / 4L; +} + +void puts(const char *str) +{ + while (*str) + putc(*str++); +} diff --git a/cpu/mpc83xx/start.S b/cpu/mpc83xx/start.S index c182174..16ed494 100644 --- a/cpu/mpc83xx/start.S +++ b/cpu/mpc83xx/start.S @@ -2,7 +2,7 @@ * Copyright (C) 1998 Dan Malek * Copyright (C) 1999 Magnus Damm * Copyright (C) 2000, 2001,2002 Wolfgang Denk - * Copyright Freescale Semiconductor, Inc. 2004, 2006. All rights reserved. + * Copyright Freescale Semiconductor, Inc. 2004, 2006, 2008. * * See file CREDITS for list of people who contributed to this * project. @@ -57,6 +57,10 @@ #define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI) #endif +#if !defined(CONFIG_NAND_SPL) && !defined(CFG_RAMBOOT) +#define CFG_FLASHBOOT +#endif + /* * Set up GOT: Global Offset Table * @@ -64,16 +68,16 @@ */ START_GOT GOT_ENTRY(_GOT2_TABLE_) - GOT_ENTRY(_FIXUP_TABLE_) + GOT_ENTRY(__bss_start) + GOT_ENTRY(_end) +#ifndef CONFIG_NAND_SPL + GOT_ENTRY(_FIXUP_TABLE_) GOT_ENTRY(_start) GOT_ENTRY(_start_of_vectors) GOT_ENTRY(_end_of_vectors) GOT_ENTRY(transfer_to_handler) - - GOT_ENTRY(__init_end) - GOT_ENTRY(_end) - GOT_ENTRY(__bss_start) +#endif END_GOT /* @@ -165,7 +169,7 @@ boot_warm: /* time t 5 */ bl init_e300_core -#ifndef CFG_RAMBOOT +#ifdef CFG_FLASHBOOT /* Inflate flash location so it appears everywhere, calculate */ /* the absolute address in final location of the FLASH, jump */ @@ -181,7 +185,7 @@ in_flash: #if 1 /* Remapping flash with LAW0. */ bl remap_flash_by_law0 #endif -#endif /* CFG_RAMBOOT */ +#endif /* CFG_FLASHBOOT */ /* setup the bats */ bl setup_bats @@ -239,6 +243,7 @@ in_flash: /* run 1st part of board init code (in Flash)*/ bl board_init_f +#ifndef CONFIG_NAND_SPL /* * Vector Table */ @@ -428,6 +433,7 @@ int_return: lwz r1,GPR1(r1) SYNC rfi +#endif /* !CONFIG_NAND_SPL */ /* * This code initialises the E300 processor core @@ -496,88 +502,10 @@ init_e300_core: /* time t 10 */ SYNC mtspr HID2, r3 - /* clear all BAT's */ - /*----------------------------------*/ - - xor r0, r0, r0 - mtspr DBAT0U, r0 - mtspr DBAT0L, r0 - mtspr DBAT1U, r0 - mtspr DBAT1L, r0 - mtspr DBAT2U, r0 - mtspr DBAT2L, r0 - mtspr DBAT3U, r0 - mtspr DBAT3L, r0 - mtspr IBAT0U, r0 - mtspr IBAT0L, r0 - mtspr IBAT1U, r0 - mtspr IBAT1L, r0 - mtspr IBAT2U, r0 - mtspr IBAT2L, r0 - mtspr IBAT3U, r0 - mtspr IBAT3L, r0 - SYNC - - /* invalidate all tlb's - * - * From the 603e User Manual: "The 603e provides the ability to - * invalidate a TLB entry. The TLB Invalidate Entry (tlbie) - * instruction invalidates the TLB entry indexed by the EA, and - * operates on both the instruction and data TLBs simultaneously - * invalidating four TLB entries (both sets in each TLB). The - * index corresponds to bits 15-19 of the EA. To invalidate all - * entries within both TLBs, 32 tlbie instructions should be - * issued, incrementing this field by one each time." - * - * "Note that the tlbia instruction is not implemented on the - * 603e." - * - * bits 15-19 correspond to addresses 0x00000000 to 0x0001F000 - * incrementing by 0x1000 each time. The code below is sort of - * based on code in "flush_tlbs" from arch/ppc/kernel/head.S - * - */ - - li r3, 32 - mtctr r3 - li r3, 0 -1: tlbie r3 - addi r3, r3, 0x1000 - bdnz 1b - SYNC - /* Done! */ /*------------------------------*/ blr - .globl invalidate_bats -invalidate_bats: - /* invalidate BATs */ - mtspr IBAT0U, r0 - mtspr IBAT1U, r0 - mtspr IBAT2U, r0 - mtspr IBAT3U, r0 -#ifdef CONFIG_HIGH_BATS - mtspr IBAT4U, r0 - mtspr IBAT5U, r0 - mtspr IBAT6U, r0 - mtspr IBAT7U, r0 -#endif - isync - mtspr DBAT0U, r0 - mtspr DBAT1U, r0 - mtspr DBAT2U, r0 - mtspr DBAT3U, r0 -#ifdef CONFIG_HIGH_BATS - mtspr DBAT4U, r0 - mtspr DBAT5U, r0 - mtspr DBAT6U, r0 - mtspr DBAT7U, r0 -#endif - isync - sync - blr - /* setup_bats - set them up to some initial state */ .globl setup_bats setup_bats: @@ -590,7 +518,6 @@ setup_bats: ori r3, r3, CFG_IBAT0U@l mtspr IBAT0L, r4 mtspr IBAT0U, r3 - isync /* DBAT 0 */ addis r4, r0, CFG_DBAT0L@h @@ -599,7 +526,6 @@ setup_bats: ori r3, r3, CFG_DBAT0U@l mtspr DBAT0L, r4 mtspr DBAT0U, r3 - isync /* IBAT 1 */ addis r4, r0, CFG_IBAT1L@h @@ -608,7 +534,6 @@ setup_bats: ori r3, r3, CFG_IBAT1U@l mtspr IBAT1L, r4 mtspr IBAT1U, r3 - isync /* DBAT 1 */ addis r4, r0, CFG_DBAT1L@h @@ -617,7 +542,6 @@ setup_bats: ori r3, r3, CFG_DBAT1U@l mtspr DBAT1L, r4 mtspr DBAT1U, r3 - isync /* IBAT 2 */ addis r4, r0, CFG_IBAT2L@h @@ -626,7 +550,6 @@ setup_bats: ori r3, r3, CFG_IBAT2U@l mtspr IBAT2L, r4 mtspr IBAT2U, r3 - isync /* DBAT 2 */ addis r4, r0, CFG_DBAT2L@h @@ -635,7 +558,6 @@ setup_bats: ori r3, r3, CFG_DBAT2U@l mtspr DBAT2L, r4 mtspr DBAT2U, r3 - isync /* IBAT 3 */ addis r4, r0, CFG_IBAT3L@h @@ -644,7 +566,6 @@ setup_bats: ori r3, r3, CFG_IBAT3U@l mtspr IBAT3L, r4 mtspr IBAT3U, r3 - isync /* DBAT 3 */ addis r4, r0, CFG_DBAT3L@h @@ -653,7 +574,6 @@ setup_bats: ori r3, r3, CFG_DBAT3U@l mtspr DBAT3L, r4 mtspr DBAT3U, r3 - isync #ifdef CONFIG_HIGH_BATS /* IBAT 4 */ @@ -663,7 +583,6 @@ setup_bats: ori r3, r3, CFG_IBAT4U@l mtspr IBAT4L, r4 mtspr IBAT4U, r3 - isync /* DBAT 4 */ addis r4, r0, CFG_DBAT4L@h @@ -672,7 +591,6 @@ setup_bats: ori r3, r3, CFG_DBAT4U@l mtspr DBAT4L, r4 mtspr DBAT4U, r3 - isync /* IBAT 5 */ addis r4, r0, CFG_IBAT5L@h @@ -681,7 +599,6 @@ setup_bats: ori r3, r3, CFG_IBAT5U@l mtspr IBAT5L, r4 mtspr IBAT5U, r3 - isync /* DBAT 5 */ addis r4, r0, CFG_DBAT5L@h @@ -690,7 +607,6 @@ setup_bats: ori r3, r3, CFG_DBAT5U@l mtspr DBAT5L, r4 mtspr DBAT5U, r3 - isync /* IBAT 6 */ addis r4, r0, CFG_IBAT6L@h @@ -699,7 +615,6 @@ setup_bats: ori r3, r3, CFG_IBAT6U@l mtspr IBAT6L, r4 mtspr IBAT6U, r3 - isync /* DBAT 6 */ addis r4, r0, CFG_DBAT6L@h @@ -708,7 +623,6 @@ setup_bats: ori r3, r3, CFG_DBAT6U@l mtspr DBAT6L, r4 mtspr DBAT6U, r3 - isync /* IBAT 7 */ addis r4, r0, CFG_IBAT7L@h @@ -717,7 +631,6 @@ setup_bats: ori r3, r3, CFG_IBAT7U@l mtspr IBAT7L, r4 mtspr IBAT7U, r3 - isync /* DBAT 7 */ addis r4, r0, CFG_DBAT7L@h @@ -726,12 +639,28 @@ setup_bats: ori r3, r3, CFG_DBAT7U@l mtspr DBAT7L, r4 mtspr DBAT7U, r3 - isync #endif - /* Invalidate TLBs. - * -> for (val = 0; val < 0x20000; val+=0x1000) - * -> tlbie(val); + isync + + /* invalidate all tlb's + * + * From the 603e User Manual: "The 603e provides the ability to + * invalidate a TLB entry. The TLB Invalidate Entry (tlbie) + * instruction invalidates the TLB entry indexed by the EA, and + * operates on both the instruction and data TLBs simultaneously + * invalidating four TLB entries (both sets in each TLB). The + * index corresponds to bits 15-19 of the EA. To invalidate all + * entries within both TLBs, 32 tlbie instructions should be + * issued, incrementing this field by one each time." + * + * "Note that the tlbia instruction is not implemented on the + * 603e." + * + * bits 15-19 correspond to addresses 0x00000000 to 0x0001F000 + * incrementing by 0x1000 each time. The code below is sort of + * based on code in "flush_tlbs" from arch/ppc/kernel/head.S + * */ lis r3, 0 lis r5, 2 @@ -874,7 +803,7 @@ relocate_code: mr r3, r5 /* Destination Address */ lis r4, CFG_MONITOR_BASE@h /* Source Address */ ori r4, r4, CFG_MONITOR_BASE@l - lwz r5, GOT(__init_end) + lwz r5, GOT(__bss_start) sub r5, r5, r4 li r6, CFG_CACHELINE_SIZE /* Cache Line Size */ @@ -987,6 +916,7 @@ in_ram: stw r0,0(r3) bdnz 1b +#ifndef CONFIG_NAND_SPL /* * Now adjust the fixups and the pointers to the fixups * in case we need to move ourselves again. @@ -1004,6 +934,8 @@ in_ram: stw r0,0(r4) bdnz 3b 4: +#endif + clear_bss: /* * Now clear BSS segment @@ -1037,6 +969,7 @@ clear_bss: mr r4, r10 /* Destination Address */ bl board_init_r +#ifndef CONFIG_NAND_SPL /* * Copy exception vector code to low memory * @@ -1119,6 +1052,7 @@ trap_reloc: stw r0, 4(r7) blr +#endif /* !CONFIG_NAND_SPL */ #ifdef CFG_INIT_RAM_LOCK lock_ram_in_cache: @@ -1142,6 +1076,7 @@ lock_ram_in_cache: sync blr +#ifndef CONFIG_NAND_SPL .globl unlock_ram_in_cache unlock_ram_in_cache: /* invalidate the INIT_RAM section */ @@ -1165,8 +1100,10 @@ unlock_ram_in_cache: mtspr HID0, r3 /* no invalidate, unlock */ sync blr -#endif +#endif /* !CONFIG_NAND_SPL */ +#endif /* CFG_INIT_RAM_LOCK */ +#ifdef CFG_FLASHBOOT map_flash_by_law1: /* When booting from ROM (Flash or EPROM), clear the */ /* Address Mask in OR0 so ROM appears everywhere */ @@ -1245,3 +1182,4 @@ remap_flash_by_law0: stw r4, LBLAWBAR1(r3) stw r4, LBLAWAR1(r3) /* Off LBIU LAW1 */ blr +#endif /* CFG_FLASHBOOT */ diff --git a/include/configs/MPC8313ERDB.h b/include/configs/MPC8313ERDB.h index 3a644d3..37f8cff 100644 --- a/include/configs/MPC8313ERDB.h +++ b/include/configs/MPC8313ERDB.h @@ -63,6 +63,10 @@ #define CFG_IMMR 0xE0000000 +#if defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL) +#define CONFIG_DEFAULT_IMMR CFG_IMMR +#endif + #define CFG_MEMTEST_START 0x00001000 #define CFG_MEMTEST_END 0x07f00000 @@ -173,10 +177,10 @@ #define CFG_FLASH_EMPTY_INFO /* display empty sectors */ #define CFG_FLASH_USE_BUFFER_WRITE /* buffer up multiple bytes */ -#define CFG_BR0_PRELIM (CFG_FLASH_BASE | /* flash Base address */ \ +#define CFG_NOR_BR_PRELIM (CFG_FLASH_BASE | /* flash Base address */ \ (2 << BR_PS_SHIFT) | /* 16 bit port size */ \ BR_V) /* valid */ -#define CFG_OR0_PRELIM ( 0xFF000000 /* 16 MByte */ \ +#define CFG_NOR_OR_PRELIM ( 0xFF800000 /* 8 MByte */ \ | OR_GPCM_XACS \ | OR_GPCM_SCY_9 \ | OR_GPCM_EHTR \ @@ -193,7 +197,7 @@ #define CFG_MONITOR_BASE TEXT_BASE /* start of monitor */ -#if (CFG_MONITOR_BASE < CFG_FLASH_BASE) +#if (CFG_MONITOR_BASE < CFG_FLASH_BASE) && !defined(CONFIG_NAND_SPL) #define CFG_RAMBOOT #endif @@ -220,19 +224,31 @@ #define CFG_LBC_MRTPR 0x20000000 /*TODO */ /* LB refresh timer prescal, 266MHz/32 */ /* drivers/mtd/nand/nand.c */ -#define CFG_NAND_BASE 0xE2800000 /* 0xF0000000 */ +#ifdef CONFIG_NAND_SPL +#define CFG_NAND_BASE 0xFFF00000 +#else +#define CFG_NAND_BASE 0xE2800000 +#endif + #define CFG_MAX_NAND_DEVICE 1 #define NAND_MAX_CHIPS 1 #define CONFIG_MTD_NAND_VERIFY_WRITE #define CONFIG_CMD_NAND 1 #define CONFIG_NAND_FSL_ELBC 1 +#define CFG_NAND_BLOCK_SIZE 16384 + +#define CFG_NAND_U_BOOT_SIZE (512 << 10) +#define CFG_NAND_U_BOOT_DST 0x00100000 +#define CFG_NAND_U_BOOT_START 0x00100100 +#define CFG_NAND_U_BOOT_OFFS 16384 +#define CFG_NAND_U_BOOT_RELOC 0x00010000 -#define CFG_BR1_PRELIM ( CFG_NAND_BASE \ +#define CFG_NAND_BR_PRELIM ( CFG_NAND_BASE \ | (2<> 2; + } + + . = ALIGN(8); + __bss_start = .; + .bss (NOLOAD) : { *(.*bss) } + _end = .; +} +ENTRY(_start) +ASSERT(_end <= 0xfff01000, "NAND bootstrap too big"); diff --git a/nand_spl/nand_boot.c b/nand_spl/nand_boot.c index 5914d04..0f56ba5 100644 --- a/nand_spl/nand_boot.c +++ b/nand_spl/nand_boot.c @@ -235,7 +235,7 @@ void nand_boot(void) struct nand_chip nand_chip; nand_info_t nand_info; int ret; - void (*uboot)(void); + __attribute__((noreturn)) void (*uboot)(void); /* * Init board specific nand support @@ -254,6 +254,6 @@ void nand_boot(void) /* * Jump to U-Boot image */ - uboot = (void (*)(void))CFG_NAND_U_BOOT_START; + uboot = (void *)CFG_NAND_U_BOOT_START; (*uboot)(); } diff --git a/nand_spl/nand_boot_fsl_elbc.c b/nand_spl/nand_boot_fsl_elbc.c new file mode 100644 index 0000000..0d2378e --- /dev/null +++ b/nand_spl/nand_boot_fsl_elbc.c @@ -0,0 +1,150 @@ +/* + * NAND boot for Freescale Enhanced Local Bus Controller, Flash Control Machine + * + * (C) Copyright 2006-2008 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * Copyright (c) 2008 Freescale Semiconductor, Inc. + * Author: Scott Wood + * + * 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 +#include +#include +#include +#include + +#define WINDOW_SIZE 8192 + +static void nand_wait(void) +{ + lbus83xx_t *regs = (lbus83xx_t *)(CFG_IMMR + 0x5000); + + for (;;) { + uint32_t status = in_be32(®s->ltesr); + + if (status == 1) + return; + + if (status & 1) { + puts("read failed (ltesr)\n"); + for (;;); + } + } +} + +static void nand_load(unsigned int offs, int uboot_size, uchar *dst) +{ + lbus83xx_t *regs = (lbus83xx_t *)(CFG_IMMR + 0x5000); + uchar *buf = (uchar *)CFG_NAND_BASE; + int large = in_be32(®s->bank[0].or) & OR_FCM_PGS; + int block_shift = large ? 17 : 14; + int block_size = 1 << block_shift; + int page_size = large ? 2048 : 512; + int bad_marker = large ? page_size + 0 : page_size + 5; + int fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT) | 2; + int pos = 0; + + if (offs & (block_size - 1)) { + puts("bad offset\n"); + for (;;); + } + + if (large) { + fmr |= FMR_ECCM; + out_be32(®s->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) | + (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); + out_be32(®s->fir, + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CA << FIR_OP1_SHIFT) | + (FIR_OP_PA << FIR_OP2_SHIFT) | + (FIR_OP_CW1 << FIR_OP3_SHIFT) | + (FIR_OP_RBW << FIR_OP4_SHIFT)); + } else { + out_be32(®s->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT); + out_be32(®s->fir, + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CA << FIR_OP1_SHIFT) | + (FIR_OP_PA << FIR_OP2_SHIFT) | + (FIR_OP_RBW << FIR_OP3_SHIFT)); + } + + out_be32(®s->fbcr, 0); + clrsetbits_be32(®s->bank[0].br, BR_DECC, BR_DECC_CHK_GEN); + + while (pos < uboot_size) { + int i = 0; + out_be32(®s->fbar, offs >> block_shift); + + do { + int j; + unsigned int page_offs = (offs & (block_size - 1)) << 1; + + out_be32(®s->ltesr, ~0); + out_be32(®s->lteatr, 0); + out_be32(®s->fpar, page_offs); + out_be32(®s->fmr, fmr); + out_be32(®s->lsor, 0); + nand_wait(); + + page_offs %= WINDOW_SIZE; + + /* + * If either of the first two pages are marked bad, + * continue to the next block. + */ + if (i++ < 2 && buf[page_offs + bad_marker] != 0xff) { + puts("skipping\n"); + offs = (offs + block_size) & ~(block_size - 1); + pos &= ~(block_size - 1); + break; + } + + for (j = 0; j < page_size; j++) + dst[pos + j] = buf[page_offs + j]; + + pos += page_size; + offs += page_size; + } while (offs & (block_size - 1)); + } +} + +/* + * 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); + + udelay(1000000); + + /* + * Load U-Boot image from NAND into RAM + */ + nand_load(CFG_NAND_U_BOOT_OFFS, CFG_NAND_U_BOOT_SIZE, + (uchar *)CFG_NAND_U_BOOT_DST); + + /* + * Jump to U-Boot image + */ + puts("transfering control\n"); + uboot = (void *)CFG_NAND_U_BOOT_START; + uboot(); +} -- cgit v1.1