[U-Boot] [PATCH 0/4] Voipac PXA270 OneNAND SPL

Convert OneNAND IPL to SPL framework and make Voipac PXA270 board use it.
This series triggers some checkpatch warnings: * Warnings in start.S due to length of line. Since I reused the start.S from other CPU (arm1136), I'd rather investigate if it'd be possible to create one common start.S for armv5? * Warnings due to used externs. pxa_dram_init() will be cleaned up in a subsequent series in all boards.
Marek Vasut (4): PXA: Drop Voipac PXA270 OneNAND IPL PXA: Rework start.S to be closer to other ARMs OneNAND: Add simple OneNAND SPL PXA: Adapt Voipac PXA270 to OneNAND SPL
arch/arm/cpu/pxa/cpu.c | 16 + arch/arm/cpu/pxa/start.S | 382 +++++++++----------------- board/vpac270/Makefile | 6 + board/vpac270/onenand.c | 136 +++++++++ board/vpac270/vpac270.c | 2 + drivers/mtd/onenand/Makefile | 4 + drivers/mtd/onenand/onenand_spl.c | 130 +++++++++ include/configs/vpac270.h | 25 ++- include/onenand_uboot.h | 18 ++ onenand_ipl/board/vpac270/Makefile | 79 ------ onenand_ipl/board/vpac270/config.mk | 1 - onenand_ipl/board/vpac270/u-boot.onenand.lds | 51 ---- onenand_ipl/board/vpac270/vpac270.c | 42 --- spl/Makefile | 1 + 14 files changed, 469 insertions(+), 424 deletions(-) create mode 100644 board/vpac270/onenand.c create mode 100644 drivers/mtd/onenand/onenand_spl.c delete mode 100644 onenand_ipl/board/vpac270/Makefile delete mode 100644 onenand_ipl/board/vpac270/config.mk delete mode 100644 onenand_ipl/board/vpac270/u-boot.onenand.lds delete mode 100644 onenand_ipl/board/vpac270/vpac270.c
Cc: Albert ARIBAUD albert.u.boot@aribaud.net

This OneNAND IPL will be replaced by OneNAND SPL.
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net --- onenand_ipl/board/vpac270/Makefile | 79 -------------------------- onenand_ipl/board/vpac270/config.mk | 1 - onenand_ipl/board/vpac270/u-boot.onenand.lds | 51 ----------------- onenand_ipl/board/vpac270/vpac270.c | 42 -------------- 4 files changed, 0 insertions(+), 173 deletions(-) delete mode 100644 onenand_ipl/board/vpac270/Makefile delete mode 100644 onenand_ipl/board/vpac270/config.mk delete mode 100644 onenand_ipl/board/vpac270/u-boot.onenand.lds delete mode 100644 onenand_ipl/board/vpac270/vpac270.c
diff --git a/onenand_ipl/board/vpac270/Makefile b/onenand_ipl/board/vpac270/Makefile deleted file mode 100644 index f850ddd..0000000 --- a/onenand_ipl/board/vpac270/Makefile +++ /dev/null @@ -1,79 +0,0 @@ - -include $(TOPDIR)/config.mk -include $(TOPDIR)/board/$(BOARDDIR)/config.mk - -LDSCRIPT= $(TOPDIR)/onenand_ipl/board/$(BOARDDIR)/u-boot.onenand.lds -LDFLAGS = -Bstatic -T $(onenandobj)u-boot.lds -Ttext $(CONFIG_SYS_TEXT_BASE) $(PLATFORM_LDFLAGS) -AFLAGS += -DCONFIG_SPL_BUILD -DCONFIG_ONENAND_IPL -CFLAGS += -DCONFIG_SPL_BUILD -DCONFIG_ONENAND_IPL -OBJCFLAGS += --gap-fill=0x00 - -SOBJS += start.o -COBJS := vpac270.o -COBJS += onenand_read.o -COBJS += onenand_boot.o - -SRCS := $(addprefix $(obj),$(SOBJS:.o=.S) $(COBJS:.o=.c)) -OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) -__OBJS := $(SOBJS) $(COBJS) -LNDIR := $(OBJTREE)/onenand_ipl/board/$(BOARDDIR) - -onenandobj := $(OBJTREE)/onenand_ipl/ - -ALL = $(onenandobj)onenand-ipl $(onenandobj)onenand-ipl.bin $(onenandobj)onenand-ipl-2k.bin - -all: $(obj).depend $(ALL) - -$(onenandobj)onenand-ipl-2k.bin: $(onenandobj)onenand-ipl - $(OBJCOPY) ${OBJCFLAGS} --pad-to=0x0800 -O binary $< $@ - -$(onenandobj)onenand-ipl.bin: $(onenandobj)onenand-ipl - $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ - -$(onenandobj)onenand-ipl: $(OBJS) $(onenandobj)u-boot.lds - cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \ - -Map $@.map -o $@ - -$(onenandobj)u-boot.lds: $(LDSCRIPT) - $(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -P - <$^ >$@ - -# create symbolic links from common files - -# from cpu directory -$(obj)start.S: - @rm -f $@ - ln -s $(SRCTREE)/$(CPUDIR)/start.S $@ - -# from onenand_ipl directory -$(obj)onenand_ipl.h: - @rm -f $@ - ln -s $(SRCTREE)/onenand_ipl/onenand_ipl.h $@ - -$(obj)onenand_boot.c: $(obj)onenand_ipl.h - @rm -f $@ - ln -s $(SRCTREE)/onenand_ipl/onenand_boot.c $@ - -$(obj)onenand_read.c: $(obj)onenand_ipl.h - @rm -f $@ - ln -s $(SRCTREE)/onenand_ipl/onenand_read.c $@ - -ifneq ($(OBJTREE), $(SRCTREE)) -$(obj)vpac270.c: - @rm -f $@ - ln -s $(SRCTREE)/onenand_ipl/board/$(BOARDDIR)/vpac270.c $@ -endif - -######################################################################### - -$(obj)%.o: $(obj)%.S - $(CC) $(AFLAGS) -c -o $@ $< - -$(obj)%.o: $(obj)$.c - $(CC) $(CFLAGS) -c -o $@ $< - -# defines $(obj).depend target -include $(SRCTREE)/rules.mk - -sinclude $(obj).depend - -######################################################################### diff --git a/onenand_ipl/board/vpac270/config.mk b/onenand_ipl/board/vpac270/config.mk deleted file mode 100644 index 752836d..0000000 --- a/onenand_ipl/board/vpac270/config.mk +++ /dev/null @@ -1 +0,0 @@ -CONFIG_SYS_TEXT_BASE = 0x5c03fc00 diff --git a/onenand_ipl/board/vpac270/u-boot.onenand.lds b/onenand_ipl/board/vpac270/u-boot.onenand.lds deleted file mode 100644 index b5b2646..0000000 --- a/onenand_ipl/board/vpac270/u-boot.onenand.lds +++ /dev/null @@ -1,51 +0,0 @@ -/* - * (C) Copyright 2000 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * 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 - */ - -OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") -OUTPUT_ARCH(arm) -ENTRY(_start) -SECTIONS -{ - . = 0x00000000; - - . = ALIGN(4); - .text : - { - start.o (.text) - *(.text) - } - - . = ALIGN(4); - .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } - - . = ALIGN(4); - .data : { *(.data) } - - . = ALIGN(4); - .got : { *(.got) } - - . = ALIGN(4); - __bss_start = .; - .bss : { *(.bss) . = ALIGN(4); } - __bss_end__ = .; -} diff --git a/onenand_ipl/board/vpac270/vpac270.c b/onenand_ipl/board/vpac270/vpac270.c deleted file mode 100644 index a1eb331..0000000 --- a/onenand_ipl/board/vpac270/vpac270.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * (C) Copyright 2004 - * Robert Whaley, Applied Data Systems, Inc. rwhaley@applieddata.net - * - * (C) Copyright 2002 - * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Marius Groeger mgroeger@sysgo.de - * - * 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 <common.h> -#include <asm/arch/hardware.h> - -int board_init (void) -{ - return 0; -} - -int s_init(int skip) -{ - return 0; -}

The start.S on PXA was very obscure. This reworks it back to be close to arm1136 start.S and others.
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net --- arch/arm/cpu/pxa/cpu.c | 16 ++ arch/arm/cpu/pxa/start.S | 382 ++++++++++++++++----------------------------- 2 files changed, 152 insertions(+), 246 deletions(-)
diff --git a/arch/arm/cpu/pxa/cpu.c b/arch/arm/cpu/pxa/cpu.c index df351c7..c48b2ef 100644 --- a/arch/arm/cpu/pxa/cpu.c +++ b/arch/arm/cpu/pxa/cpu.c @@ -328,3 +328,19 @@ void i2c_clk_enable(void) writel(readl(CKEN) | CKEN14_I2C, CKEN); #endif } + +void reset_cpu(ulong ignored) __attribute__((noreturn)); + +void reset_cpu(ulong ignored) +{ + uint32_t tmp; + + setbits_le32(OWER, OWER_WME); + + tmp = readl(OSCR); + tmp += 0x1000; + writel(tmp, OSMR3); + + for (;;) + ; +} diff --git a/arch/arm/cpu/pxa/start.S b/arch/arm/cpu/pxa/start.S index 6191a73..46f7ac0 100644 --- a/arch/arm/cpu/pxa/start.S +++ b/arch/arm/cpu/pxa/start.S @@ -1,14 +1,20 @@ /* - * armboot - Startup Code for XScale + * armboot - Startup Code for XScale CPU-core * * Copyright (C) 1998 Dan Malek dmalek@jlc.net * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se> * Copyright (C) 2000 Wolfgang Denk wd@denx.de * Copyright (C) 2001 Alex Zuepke azu@sysgo.de + * Copyright (C) 2001 Marius Groger mag@sysgo.de + * Copyright (C) 2002 Alex Zupke azu@sysgo.de + * Copyright (C) 2002 Gary Jennejohn garyj@denx.de * Copyright (C) 2002 Kyle Harris kharris@nexus-tech.net - * Copyright (C) 2003 Robert Schwebel r.schwebel@pengutronix.de * Copyright (C) 2003 Kai-Uwe Bloem kai-uwe.bloem@auerswald.de - * Copyright (c) 2010 Marek Vasut marek.vasut@gmail.com + * Copyright (C) 2003 Kshitij kshitij@ti.com + * Copyright (C) 2003 Richard Woodruff r-woodruff2@ti.com + * Copyright (C) 2003 Robert Schwebel r.schwebel@pengutronix.de + * Copyright (C) 2004 Texas Instruments r-woodruff2@ti.com + * Copyright (C) 2010 Marek Vasut marek.vasut@gmail.com * * See file CREDITS for list of people who contributed to this * project. @@ -32,15 +38,6 @@ #include <asm-offsets.h> #include <config.h> #include <version.h> -#include <asm/arch/pxa-regs.h> - -/* takes care the CP15 update has taken place */ -.macro CPWAIT reg -mrc p15,0,\reg,c2,c0,0 -mov \reg,\reg -sub pc,pc,#4 -.endm - .globl _start _start: b reset #ifdef CONFIG_SPL_BUILD @@ -77,26 +74,38 @@ _data_abort: .word data_abort _not_used: .word not_used _irq: .word irq _fiq: .word fiq +_pad: .word 0x12345678 /* now 16*4=64 */ #endif /* CONFIG_SPL_BUILD */ +.global _end_vect +_end_vect:
.balignl 16,0xdeadbeef - - /* + ************************************************************************* + * * Startup Code (reset vector) * - * do important init only if we don't start from RAM! - * - relocate armboot to RAM - * - setup stack - * - jump to second stage + * do important init only if we don't start from memory! + * setup Memory and board specific bits prior to relocation. + * relocate armboot to ram + * setup stack + * + ************************************************************************* */
.globl _TEXT_BASE _TEXT_BASE: +#ifdef CONFIG_SPL_BUILD + .word CONFIG_SPL_TEXT_BASE +#else .word CONFIG_SYS_TEXT_BASE +#endif
/* * These are defined in the board-specific linker script. + * Subtracting _start from them lets the linker put their + * relative position in the executable instead of leaving + * them null. */ .globl _bss_start_ofs _bss_start_ofs: @@ -120,9 +129,8 @@ IRQ_STACK_START: .globl FIQ_STACK_START FIQ_STACK_START: .word 0x0badc0de -#endif /* CONFIG_USE_IRQ */ +#endif
-#ifndef CONFIG_SPL_BUILD /* IRQ stack memory (calculated at run-time) + 8 bytes */ .globl IRQ_STACK_START_IN IRQ_STACK_START_IN: @@ -141,91 +149,15 @@ reset: orr r0,r0,#0xd3 msr cpsr,r0
- /* - * Enable MMU to use DCache as DRAM - */ - /* Domain access -- enable for all CPs */ - ldr r0, =0x0000ffff - mcr p15, 0, r0, c3, c0, 0 - - /* Point TTBR to MMU table */ - ldr r0, =mmu_table - adr r2, _start - orr r0, r2 - mcr p15, 0, r0, c2, c0, 0 - -/* !!! Hereby, check if the code is running from SRAM !!! */ -/* If the code is running from SRAM, alias SRAM to 0x0 to simulate NOR. The code - * is linked to 0x0 too, so this makes things easier. */ - cmp r2, #0x5c000000 - - ldreq r1, [r0] - orreq r1, r2 - streq r1, [r0] - - /* Kick in MMU, ICache, DCache, BTB */ - mrc p15, 0, r0, c1, c0, 0 - bic r0, #0x1b00 - bic r0, #0x0087 - orr r0, #0x1800 - orr r0, #0x0005 - mcr p15, 0, r0, c1, c0, 0 - CPWAIT r0 - - /* Unlock Icache, Dcache */ - mcr p15, 0, r0, c9, c1, 1 - mcr p15, 0, r0, c9, c2, 1 - - /* Flush Icache, Dcache, BTB */ - mcr p15, 0, r0, c7, c7, 0 - - /* Unlock I-TLB, D-TLB */ - mcr p15, 0, r0, c10, c4, 1 - mcr p15, 0, r0, c10, c8, 1 - - /* Flush TLB */ - mcr p15, 0, r0, c8, c7, 0 - /* Allocate 4096 bytes of Dcache as RAM */ - - /* Drain pending loads and stores */ - mcr p15, 0, r0, c7, c10, 4 - - mov r4, #0x00 - mov r5, #0x00 - mov r2, #0x01 - mcr p15, 0, r0, c9, c2, 0 - CPWAIT r0 - - /* 128 lines reserved (128 x 32bytes = 4096 bytes total) */ - mov r0, #128 - mov r1, #0xa0000000 -alloc: - mcr p15, 0, r1, c7, c2, 5 - /* Drain pending loads and stores */ - mcr p15, 0, r0, c7, c10, 4 - strd r4, [r1], #8 - strd r4, [r1], #8 - strd r4, [r1], #8 - strd r4, [r1], #8 - subs r0, #0x01 - bne alloc - /* Drain pending loads and stores */ - mcr p15, 0, r0, c7, c10, 4 - mov r2, #0x00 - mcr p15, 0, r2, c9, c2, 0 - CPWAIT r0 - - /* Jump to 0x0 ( + offset) if running from SRAM */ - adr r0, zerojmp - bic r0, #0x5c000000 - mov pc, r0 -zerojmp: +#ifndef CONFIG_SKIP_LOWLEVEL_INIT + bl cpu_init_crit +#endif
/* Set stackpointer in internal RAM to call board_init_f */ call_board_init_f: ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ - ldr r0,=0x00000000 + ldr r0, =0x00000000 bl board_init_f
/*------------------------------------------------------------------------------*/ @@ -254,13 +186,11 @@ stack_setup: ldr r3, _bss_start_ofs add r2, r0, r3 /* r2 <- source end address */
- stmfd sp!, {r0-r12} copy_loop: - ldmia r0!, {r3-r5, r7-r11} /* copy from source address [r0] */ - stmia r1!, {r3-r5, r7-r11} /* copy to target address [r1] */ + ldmia r0!, {r9-r10} /* copy from source address [r0] */ + stmia r1!, {r9-r10} /* copy to target address [r1] */ cmp r0, r2 /* until source end address [r2] */ blo copy_loop - ldmfd sp!, {r0-r12}
#ifndef CONFIG_SPL_BUILD /* @@ -275,13 +205,13 @@ copy_loop: ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */ add r3, r3, r0 /* r3 <- rel dyn end in FLASH */ fixloop: - ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */ - add r0, r9 /* r0 <- location to fix up in RAM */ + ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */ + add r0, r0, r9 /* r0 <- location to fix up in RAM */ ldr r1, [r2, #4] and r7, r1, #0xff - cmp r7, #23 /* relative fixup? */ + cmp r7, #23 /* relative fixup? */ beq fixrel - cmp r7, #2 /* absolute fixup? */ + cmp r7, #2 /* absolute fixup? */ beq fixabs /* ignore unknown type of fixup */ b fixnext @@ -298,10 +228,10 @@ fixrel: add r1, r1, r9 fixnext: str r1, [r0] - add r2, r2, #8 /* each rel.dyn entry is 8 bytes */ + add r2, r2, #8 /* each rel.dyn entry is 8 bytes */ cmp r2, r3 blo fixloop -#endif /* #ifndef CONFIG_SPL_BUILD */ +#endif
clear_bss: #ifndef CONFIG_SPL_BUILD @@ -322,15 +252,16 @@ clbss_l:str r2, [r0] /* clear loop... */ * We are done. Do not return, instead branch to second part of board * initialization, now running from RAM. */ -#ifdef CONFIG_ONENAND_IPL - ldr r0, _start_oneboot_ofs +#ifdef CONFIG_ONENAND_SPL + ldr r0, _onenand_boot_ofs mov pc, r0
-_start_oneboot_ofs - : .word start_oneboot +_onenand_boot_ofs: + .word onenand_boot #else +jump_2_ram: ldr r0, _board_init_r_ofs - adr r1, _start + ldr r1, _TEXT_BASE add lr, r0, r1 add lr, lr, r9 /* setup parameters for board_init_r */ @@ -341,7 +272,7 @@ _start_oneboot_ofs
_board_init_r_ofs: .word board_init_r - _start -#endif /* CONFIG_ONENAND_IPL */ +#endif
_rel_dyn_start_ofs: .word __rel_dyn_start - _start @@ -350,42 +281,49 @@ _rel_dyn_end_ofs: _dynsym_start_ofs: .word __dynsym_start - _start
-#else /* CONFIG_SPL_BUILD */ - -/****************************************************************************/ -/* */ -/* the actual reset code for OneNAND IPL */ -/* */ -/****************************************************************************/ - -#ifndef CONFIG_PXA27X -#error OneNAND IPL is not supported on PXA25x and 26x due to lack of SRAM -#endif - -reset: - /* Set CPU to SVC32 mode */ - mrs r0,cpsr - bic r0,r0,#0x1f - orr r0,r0,#0x13 - msr cpsr,r0 - - /* Point stack at the end of SRAM and leave 32 words for abort-stack */ - ldr sp, =0x5c03ff80 +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ +#ifndef CONFIG_SKIP_LOWLEVEL_INIT +cpu_init_crit: + /* + * flush v4 I/D caches + */ + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 /* Invalidate I+D+BTB caches */ + mcr p15, 0, r0, c8, c7, 0 /* Invalidate Unified TLB */
- /* Start OneNAND IPL */ - ldr pc, =start_oneboot + /* + * disable MMU stuff and caches + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) + bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) + orr r0, r0, #0x00000002 @ set bit 2 (A) Align + orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache + mcr p15, 0, r0, c1, c0, 0
-#endif /* CONFIG_SPL_BUILD */ + mov pc, lr /* back to my caller */ +#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
#ifndef CONFIG_SPL_BUILD -/****************************************************************************/ -/* */ -/* Interrupt handling */ -/* */ -/****************************************************************************/ - -/* IRQ stack frame */ - +/* + ************************************************************************* + * + * Interrupt handling + * + ************************************************************************* + */ +@ +@ IRQ stack frame. +@ #define S_FRAME_SIZE 72
#define S_OLD_R0 68 @@ -409,37 +347,36 @@ reset: #define S_R0 0
#define MODE_SVC 0x13 +#define I_BIT 0x80
- /* use bad_save_user_regs for abort/prefetch/undef/swi ... */ +/* + * use bad_save_user_regs for abort/prefetch/undef/swi ... + * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling + */
.macro bad_save_user_regs - sub sp, sp, #S_FRAME_SIZE - stmia sp, {r0 - r12} /* Calling r0-r12 */ - add r8, sp, #S_PC + sub sp, sp, #S_FRAME_SIZE @ carve out a frame on current user stack + stmia sp, {r0 - r12} @ Save user registers (now in svc mode) r0-r12
- ldr r2, IRQ_STACK_START_IN - ldmia r2, {r2 - r4} /* get pc, cpsr, old_r0 */ - add r0, sp, #S_FRAME_SIZE /* restore sp_SVC */ + ldr r2, IRQ_STACK_START_IN @ set base 2 words into abort stack + ldmia r2, {r2 - r3} @ get values for "aborted" pc and cpsr (into parm regs) + add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack
add r5, sp, #S_SP mov r1, lr - stmia r5, {r0 - r4} /* save sp_SVC, lr_SVC, pc, cpsr, old_r */ - mov r0, sp + stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr + mov r0, sp @ save current stack into r0 (param register) .endm
- - /* use irq_save_user_regs / irq_restore_user_regs for */ - /* IRQ/FIQ handling */ - .macro irq_save_user_regs sub sp, sp, #S_FRAME_SIZE - stmia sp, {r0 - r12} /* Calling r0-r12 */ - add r8, sp, #S_PC - stmdb r8, {sp, lr}^ /* Calling SP, LR */ - str lr, [r8, #0] /* Save calling PC */ + stmia sp, {r0 - r12} @ Calling r0-r12 + add r8, sp, #S_PC @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good. + stmdb r8, {sp, lr}^ @ Calling SP, LR + str lr, [r8, #0] @ Save calling PC mrs r6, spsr - str r6, [r8, #4] /* Save CPSR */ - str r0, [r8, #8] /* Save OLD_R0 */ + str r6, [r8, #4] @ Save CPSR + str r0, [r8, #8] @ Save OLD_R0 mov r0, sp .endm
@@ -452,16 +389,28 @@ reset: .endm
.macro get_bad_stack - ldr r13, IRQ_STACK_START_IN @ setup our mode stack + ldr r13, IRQ_STACK_START_IN @ setup our mode stack (enter in banked mode)
- str lr, [r13] @ save caller lr / spsr - mrs lr, spsr - str lr, [r13, #4] + str lr, [r13] @ save caller lr in position 0 of saved stack + mrs lr, spsr @ get the spsr + str lr, [r13, #4] @ save spsr in position 1 of saved stack
mov r13, #MODE_SVC @ prepare SVC-Mode - msr spsr_c, r13 - mov lr, pc - movs pc, lr + @ msr spsr_c, r13 + msr spsr, r13 @ switch modes, make sure moves will execute + mov lr, pc @ capture return pc + movs pc, lr @ jump to next instruction & switch modes. + .endm + + .macro get_bad_stack_swi + sub r13, r13, #4 @ space on current stack for scratch reg. + str r0, [r13] @ save R0's value. + ldr r0, IRQ_STACK_START_IN @ get data regions start + str lr, [r0] @ save caller lr in position 0 of saved stack + mrs r0, spsr @ get the spsr + str lr, [r0, #4] @ save spsr in position 1 of saved stack + ldr r0, [r13] @ restore r0 + add r13, r13, #4 @ pop stack entry .endm
.macro get_irq_stack @ setup IRQ stack @@ -471,21 +420,17 @@ reset: .macro get_fiq_stack @ setup FIQ stack ldr sp, FIQ_STACK_START .endm -#endif /* CONFIG_SPL_BUILD - - -/****************************************************************************/ -/* */ -/* exception handlers */ -/* */ -/****************************************************************************/ +#endif /* CONFIG_SPL_BUILD */
+/* + * exception handlers + */ #ifdef CONFIG_SPL_BUILD .align 5 do_hang: - ldr sp, _TEXT_BASE /* use 32 words abort stack */ + ldr sp, _TEXT_BASE /* use 32 words about stack */ bl hang /* hang and never return */ -#else +#else /* !CONFIG_SPL_BUILD */ .align 5 undefined_instruction: get_bad_stack @@ -494,7 +439,7 @@ undefined_instruction:
.align 5 software_interrupt: - get_bad_stack + get_bad_stack_swi bad_save_user_regs bl do_software_interrupt
@@ -528,11 +473,12 @@ irq: .align 5 fiq: get_fiq_stack - irq_save_user_regs /* someone ought to write a more */ - bl do_fiq /* effiction fiq_save_user_regs */ + /* someone ought to write a more effiction fiq_save_user_regs */ + irq_save_user_regs + bl do_fiq irq_restore_user_regs
-#else /* !CONFIG_USE_IRQ */ +#else
.align 5 irq: @@ -545,63 +491,7 @@ fiq: get_bad_stack bad_save_user_regs bl do_fiq -#endif /* CONFIG_SPL_BUILD */ -#endif /* CONFIG_USE_IRQ */ - -/****************************************************************************/ -/* */ -/* Reset function: the PXA250 doesn't have a reset function, so we have to */ -/* perform a watchdog timeout for a soft reset. */ -/* */ -/****************************************************************************/ -/* Operating System Timer */ -.align 5 -.globl reset_cpu - - /* FIXME: this code is PXA250 specific. How is this handled on */ - /* other XScale processors? */ - -reset_cpu: - - /* We set OWE:WME (watchdog enable) and wait until timeout happens */
- ldr r0, =OWER - ldr r1, [r0] - orr r1, r1, #0x0001 /* bit0: WME */ - str r1, [r0] - - /* OS timer does only wrap every 1165 seconds, so we have to set */ - /* the match register as well. */ - - ldr r0, =OSCR - ldr r1, [r0] /* read OS timer */ - add r1, r1, #0x800 /* let OSMR3 match after */ - add r1, r1, #0x800 /* 4096*(1/3.6864MHz)=1ms */ - ldr r0, =OSMR3 - str r1, [r0] - -reset_endless: - - b reset_endless - -#ifndef CONFIG_SPL_BUILD -.section .mmudata, "a" - .align 14 - .globl mmu_table -mmu_table: - /* 0x00000000 - 0xa0000000 : 1:1, uncached mapping */ - .set __base, 0 - .rept 0xa00 - .word (__base << 20) | 0xc12 - .set __base, __base + 1 - .endr - - /* 0xa0000000 - 0xa0100000 : 1:1, cached mapping */ - .word (0xa00 << 20) | 0x1c1e - - .set __base, 0xa01 - .rept 0x1000 - 0xa01 - .word (__base << 20) | 0xc12 - .set __base, __base + 1 - .endr +#endif + .align 5 #endif /* CONFIG_SPL_BUILD */

The start.S on PXA was very obscure. This reworks it back to be close to arm1136 start.S and others.
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net --- arch/arm/cpu/pxa/cpu.c | 16 ++ arch/arm/cpu/pxa/start.S | 384 ++++++++++++++++----------------------------- 2 files changed, 153 insertions(+), 247 deletions(-)
V2: Don't compile in relocation support if building SPL
diff --git a/arch/arm/cpu/pxa/cpu.c b/arch/arm/cpu/pxa/cpu.c index df351c7..c48b2ef 100644 --- a/arch/arm/cpu/pxa/cpu.c +++ b/arch/arm/cpu/pxa/cpu.c @@ -328,3 +328,19 @@ void i2c_clk_enable(void) writel(readl(CKEN) | CKEN14_I2C, CKEN); #endif } + +void reset_cpu(ulong ignored) __attribute__((noreturn)); + +void reset_cpu(ulong ignored) +{ + uint32_t tmp; + + setbits_le32(OWER, OWER_WME); + + tmp = readl(OSCR); + tmp += 0x1000; + writel(tmp, OSMR3); + + for (;;) + ; +} diff --git a/arch/arm/cpu/pxa/start.S b/arch/arm/cpu/pxa/start.S index 6191a73..88a4cc2 100644 --- a/arch/arm/cpu/pxa/start.S +++ b/arch/arm/cpu/pxa/start.S @@ -1,14 +1,20 @@ /* - * armboot - Startup Code for XScale + * armboot - Startup Code for XScale CPU-core * * Copyright (C) 1998 Dan Malek dmalek@jlc.net * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se> * Copyright (C) 2000 Wolfgang Denk wd@denx.de * Copyright (C) 2001 Alex Zuepke azu@sysgo.de + * Copyright (C) 2001 Marius Groger mag@sysgo.de + * Copyright (C) 2002 Alex Zupke azu@sysgo.de + * Copyright (C) 2002 Gary Jennejohn garyj@denx.de * Copyright (C) 2002 Kyle Harris kharris@nexus-tech.net - * Copyright (C) 2003 Robert Schwebel r.schwebel@pengutronix.de * Copyright (C) 2003 Kai-Uwe Bloem kai-uwe.bloem@auerswald.de - * Copyright (c) 2010 Marek Vasut marek.vasut@gmail.com + * Copyright (C) 2003 Kshitij kshitij@ti.com + * Copyright (C) 2003 Richard Woodruff r-woodruff2@ti.com + * Copyright (C) 2003 Robert Schwebel r.schwebel@pengutronix.de + * Copyright (C) 2004 Texas Instruments r-woodruff2@ti.com + * Copyright (C) 2010 Marek Vasut marek.vasut@gmail.com * * See file CREDITS for list of people who contributed to this * project. @@ -32,15 +38,6 @@ #include <asm-offsets.h> #include <config.h> #include <version.h> -#include <asm/arch/pxa-regs.h> - -/* takes care the CP15 update has taken place */ -.macro CPWAIT reg -mrc p15,0,\reg,c2,c0,0 -mov \reg,\reg -sub pc,pc,#4 -.endm - .globl _start _start: b reset #ifdef CONFIG_SPL_BUILD @@ -77,26 +74,38 @@ _data_abort: .word data_abort _not_used: .word not_used _irq: .word irq _fiq: .word fiq +_pad: .word 0x12345678 /* now 16*4=64 */ #endif /* CONFIG_SPL_BUILD */ +.global _end_vect +_end_vect:
.balignl 16,0xdeadbeef - - /* + ************************************************************************* + * * Startup Code (reset vector) * - * do important init only if we don't start from RAM! - * - relocate armboot to RAM - * - setup stack - * - jump to second stage + * do important init only if we don't start from memory! + * setup Memory and board specific bits prior to relocation. + * relocate armboot to ram + * setup stack + * + ************************************************************************* */
.globl _TEXT_BASE _TEXT_BASE: +#ifdef CONFIG_SPL_BUILD + .word CONFIG_SPL_TEXT_BASE +#else .word CONFIG_SYS_TEXT_BASE +#endif
/* * These are defined in the board-specific linker script. + * Subtracting _start from them lets the linker put their + * relative position in the executable instead of leaving + * them null. */ .globl _bss_start_ofs _bss_start_ofs: @@ -120,9 +129,8 @@ IRQ_STACK_START: .globl FIQ_STACK_START FIQ_STACK_START: .word 0x0badc0de -#endif /* CONFIG_USE_IRQ */ +#endif
-#ifndef CONFIG_SPL_BUILD /* IRQ stack memory (calculated at run-time) + 8 bytes */ .globl IRQ_STACK_START_IN IRQ_STACK_START_IN: @@ -141,95 +149,19 @@ reset: orr r0,r0,#0xd3 msr cpsr,r0
- /* - * Enable MMU to use DCache as DRAM - */ - /* Domain access -- enable for all CPs */ - ldr r0, =0x0000ffff - mcr p15, 0, r0, c3, c0, 0 - - /* Point TTBR to MMU table */ - ldr r0, =mmu_table - adr r2, _start - orr r0, r2 - mcr p15, 0, r0, c2, c0, 0 - -/* !!! Hereby, check if the code is running from SRAM !!! */ -/* If the code is running from SRAM, alias SRAM to 0x0 to simulate NOR. The code - * is linked to 0x0 too, so this makes things easier. */ - cmp r2, #0x5c000000 - - ldreq r1, [r0] - orreq r1, r2 - streq r1, [r0] - - /* Kick in MMU, ICache, DCache, BTB */ - mrc p15, 0, r0, c1, c0, 0 - bic r0, #0x1b00 - bic r0, #0x0087 - orr r0, #0x1800 - orr r0, #0x0005 - mcr p15, 0, r0, c1, c0, 0 - CPWAIT r0 - - /* Unlock Icache, Dcache */ - mcr p15, 0, r0, c9, c1, 1 - mcr p15, 0, r0, c9, c2, 1 - - /* Flush Icache, Dcache, BTB */ - mcr p15, 0, r0, c7, c7, 0 - - /* Unlock I-TLB, D-TLB */ - mcr p15, 0, r0, c10, c4, 1 - mcr p15, 0, r0, c10, c8, 1 - - /* Flush TLB */ - mcr p15, 0, r0, c8, c7, 0 - /* Allocate 4096 bytes of Dcache as RAM */ - - /* Drain pending loads and stores */ - mcr p15, 0, r0, c7, c10, 4 - - mov r4, #0x00 - mov r5, #0x00 - mov r2, #0x01 - mcr p15, 0, r0, c9, c2, 0 - CPWAIT r0 - - /* 128 lines reserved (128 x 32bytes = 4096 bytes total) */ - mov r0, #128 - mov r1, #0xa0000000 -alloc: - mcr p15, 0, r1, c7, c2, 5 - /* Drain pending loads and stores */ - mcr p15, 0, r0, c7, c10, 4 - strd r4, [r1], #8 - strd r4, [r1], #8 - strd r4, [r1], #8 - strd r4, [r1], #8 - subs r0, #0x01 - bne alloc - /* Drain pending loads and stores */ - mcr p15, 0, r0, c7, c10, 4 - mov r2, #0x00 - mcr p15, 0, r2, c9, c2, 0 - CPWAIT r0 - - /* Jump to 0x0 ( + offset) if running from SRAM */ - adr r0, zerojmp - bic r0, #0x5c000000 - mov pc, r0 -zerojmp: +#ifndef CONFIG_SKIP_LOWLEVEL_INIT + bl cpu_init_crit +#endif
/* Set stackpointer in internal RAM to call board_init_f */ call_board_init_f: ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ - ldr r0,=0x00000000 + ldr r0, =0x00000000 bl board_init_f
/*------------------------------------------------------------------------------*/ - +#ifndef CONFIG_SPL_BUILD /* * void relocate_code (addr_sp, gd, addr_moni) * @@ -254,13 +186,11 @@ stack_setup: ldr r3, _bss_start_ofs add r2, r0, r3 /* r2 <- source end address */
- stmfd sp!, {r0-r12} copy_loop: - ldmia r0!, {r3-r5, r7-r11} /* copy from source address [r0] */ - stmia r1!, {r3-r5, r7-r11} /* copy to target address [r1] */ + ldmia r0!, {r9-r10} /* copy from source address [r0] */ + stmia r1!, {r9-r10} /* copy to target address [r1] */ cmp r0, r2 /* until source end address [r2] */ blo copy_loop - ldmfd sp!, {r0-r12}
#ifndef CONFIG_SPL_BUILD /* @@ -275,13 +205,13 @@ copy_loop: ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */ add r3, r3, r0 /* r3 <- rel dyn end in FLASH */ fixloop: - ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */ - add r0, r9 /* r0 <- location to fix up in RAM */ + ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */ + add r0, r0, r9 /* r0 <- location to fix up in RAM */ ldr r1, [r2, #4] and r7, r1, #0xff - cmp r7, #23 /* relative fixup? */ + cmp r7, #23 /* relative fixup? */ beq fixrel - cmp r7, #2 /* absolute fixup? */ + cmp r7, #2 /* absolute fixup? */ beq fixabs /* ignore unknown type of fixup */ b fixnext @@ -298,10 +228,10 @@ fixrel: add r1, r1, r9 fixnext: str r1, [r0] - add r2, r2, #8 /* each rel.dyn entry is 8 bytes */ + add r2, r2, #8 /* each rel.dyn entry is 8 bytes */ cmp r2, r3 blo fixloop -#endif /* #ifndef CONFIG_SPL_BUILD */ +#endif
clear_bss: #ifndef CONFIG_SPL_BUILD @@ -322,15 +252,16 @@ clbss_l:str r2, [r0] /* clear loop... */ * We are done. Do not return, instead branch to second part of board * initialization, now running from RAM. */ -#ifdef CONFIG_ONENAND_IPL - ldr r0, _start_oneboot_ofs +#ifdef CONFIG_ONENAND_SPL + ldr r0, _onenand_boot_ofs mov pc, r0
-_start_oneboot_ofs - : .word start_oneboot +_onenand_boot_ofs: + .word onenand_boot #else +jump_2_ram: ldr r0, _board_init_r_ofs - adr r1, _start + ldr r1, _TEXT_BASE add lr, r0, r1 add lr, lr, r9 /* setup parameters for board_init_r */ @@ -341,7 +272,7 @@ _start_oneboot_ofs
_board_init_r_ofs: .word board_init_r - _start -#endif /* CONFIG_ONENAND_IPL */ +#endif
_rel_dyn_start_ofs: .word __rel_dyn_start - _start @@ -349,43 +280,50 @@ _rel_dyn_end_ofs: .word __rel_dyn_end - _start _dynsym_start_ofs: .word __dynsym_start - _start - -#else /* CONFIG_SPL_BUILD */ - -/****************************************************************************/ -/* */ -/* the actual reset code for OneNAND IPL */ -/* */ -/****************************************************************************/ - -#ifndef CONFIG_PXA27X -#error OneNAND IPL is not supported on PXA25x and 26x due to lack of SRAM #endif +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ +#ifndef CONFIG_SKIP_LOWLEVEL_INIT +cpu_init_crit: + /* + * flush v4 I/D caches + */ + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 /* Invalidate I+D+BTB caches */ + mcr p15, 0, r0, c8, c7, 0 /* Invalidate Unified TLB */
-reset: - /* Set CPU to SVC32 mode */ - mrs r0,cpsr - bic r0,r0,#0x1f - orr r0,r0,#0x13 - msr cpsr,r0 - - /* Point stack at the end of SRAM and leave 32 words for abort-stack */ - ldr sp, =0x5c03ff80 - - /* Start OneNAND IPL */ - ldr pc, =start_oneboot + /* + * disable MMU stuff and caches + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) + bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) + orr r0, r0, #0x00000002 @ set bit 2 (A) Align + orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache + mcr p15, 0, r0, c1, c0, 0
-#endif /* CONFIG_SPL_BUILD */ + mov pc, lr /* back to my caller */ +#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
#ifndef CONFIG_SPL_BUILD -/****************************************************************************/ -/* */ -/* Interrupt handling */ -/* */ -/****************************************************************************/ - -/* IRQ stack frame */ - +/* + ************************************************************************* + * + * Interrupt handling + * + ************************************************************************* + */ +@ +@ IRQ stack frame. +@ #define S_FRAME_SIZE 72
#define S_OLD_R0 68 @@ -409,37 +347,36 @@ reset: #define S_R0 0
#define MODE_SVC 0x13 +#define I_BIT 0x80
- /* use bad_save_user_regs for abort/prefetch/undef/swi ... */ +/* + * use bad_save_user_regs for abort/prefetch/undef/swi ... + * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling + */
.macro bad_save_user_regs - sub sp, sp, #S_FRAME_SIZE - stmia sp, {r0 - r12} /* Calling r0-r12 */ - add r8, sp, #S_PC + sub sp, sp, #S_FRAME_SIZE @ carve out a frame on current user stack + stmia sp, {r0 - r12} @ Save user registers (now in svc mode) r0-r12
- ldr r2, IRQ_STACK_START_IN - ldmia r2, {r2 - r4} /* get pc, cpsr, old_r0 */ - add r0, sp, #S_FRAME_SIZE /* restore sp_SVC */ + ldr r2, IRQ_STACK_START_IN @ set base 2 words into abort stack + ldmia r2, {r2 - r3} @ get values for "aborted" pc and cpsr (into parm regs) + add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack
add r5, sp, #S_SP mov r1, lr - stmia r5, {r0 - r4} /* save sp_SVC, lr_SVC, pc, cpsr, old_r */ - mov r0, sp + stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr + mov r0, sp @ save current stack into r0 (param register) .endm
- - /* use irq_save_user_regs / irq_restore_user_regs for */ - /* IRQ/FIQ handling */ - .macro irq_save_user_regs sub sp, sp, #S_FRAME_SIZE - stmia sp, {r0 - r12} /* Calling r0-r12 */ - add r8, sp, #S_PC - stmdb r8, {sp, lr}^ /* Calling SP, LR */ - str lr, [r8, #0] /* Save calling PC */ + stmia sp, {r0 - r12} @ Calling r0-r12 + add r8, sp, #S_PC @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good. + stmdb r8, {sp, lr}^ @ Calling SP, LR + str lr, [r8, #0] @ Save calling PC mrs r6, spsr - str r6, [r8, #4] /* Save CPSR */ - str r0, [r8, #8] /* Save OLD_R0 */ + str r6, [r8, #4] @ Save CPSR + str r0, [r8, #8] @ Save OLD_R0 mov r0, sp .endm
@@ -452,16 +389,28 @@ reset: .endm
.macro get_bad_stack - ldr r13, IRQ_STACK_START_IN @ setup our mode stack + ldr r13, IRQ_STACK_START_IN @ setup our mode stack (enter in banked mode)
- str lr, [r13] @ save caller lr / spsr - mrs lr, spsr - str lr, [r13, #4] + str lr, [r13] @ save caller lr in position 0 of saved stack + mrs lr, spsr @ get the spsr + str lr, [r13, #4] @ save spsr in position 1 of saved stack
mov r13, #MODE_SVC @ prepare SVC-Mode - msr spsr_c, r13 - mov lr, pc - movs pc, lr + @ msr spsr_c, r13 + msr spsr, r13 @ switch modes, make sure moves will execute + mov lr, pc @ capture return pc + movs pc, lr @ jump to next instruction & switch modes. + .endm + + .macro get_bad_stack_swi + sub r13, r13, #4 @ space on current stack for scratch reg. + str r0, [r13] @ save R0's value. + ldr r0, IRQ_STACK_START_IN @ get data regions start + str lr, [r0] @ save caller lr in position 0 of saved stack + mrs r0, spsr @ get the spsr + str lr, [r0, #4] @ save spsr in position 1 of saved stack + ldr r0, [r13] @ restore r0 + add r13, r13, #4 @ pop stack entry .endm
.macro get_irq_stack @ setup IRQ stack @@ -471,21 +420,17 @@ reset: .macro get_fiq_stack @ setup FIQ stack ldr sp, FIQ_STACK_START .endm -#endif /* CONFIG_SPL_BUILD - - -/****************************************************************************/ -/* */ -/* exception handlers */ -/* */ -/****************************************************************************/ +#endif /* CONFIG_SPL_BUILD */
+/* + * exception handlers + */ #ifdef CONFIG_SPL_BUILD .align 5 do_hang: - ldr sp, _TEXT_BASE /* use 32 words abort stack */ + ldr sp, _TEXT_BASE /* use 32 words about stack */ bl hang /* hang and never return */ -#else +#else /* !CONFIG_SPL_BUILD */ .align 5 undefined_instruction: get_bad_stack @@ -494,7 +439,7 @@ undefined_instruction:
.align 5 software_interrupt: - get_bad_stack + get_bad_stack_swi bad_save_user_regs bl do_software_interrupt
@@ -528,11 +473,12 @@ irq: .align 5 fiq: get_fiq_stack - irq_save_user_regs /* someone ought to write a more */ - bl do_fiq /* effiction fiq_save_user_regs */ + /* someone ought to write a more effiction fiq_save_user_regs */ + irq_save_user_regs + bl do_fiq irq_restore_user_regs
-#else /* !CONFIG_USE_IRQ */ +#else
.align 5 irq: @@ -545,63 +491,7 @@ fiq: get_bad_stack bad_save_user_regs bl do_fiq -#endif /* CONFIG_SPL_BUILD */ -#endif /* CONFIG_USE_IRQ */ - -/****************************************************************************/ -/* */ -/* Reset function: the PXA250 doesn't have a reset function, so we have to */ -/* perform a watchdog timeout for a soft reset. */ -/* */ -/****************************************************************************/ -/* Operating System Timer */ -.align 5 -.globl reset_cpu - - /* FIXME: this code is PXA250 specific. How is this handled on */ - /* other XScale processors? */ - -reset_cpu: - - /* We set OWE:WME (watchdog enable) and wait until timeout happens */
- ldr r0, =OWER - ldr r1, [r0] - orr r1, r1, #0x0001 /* bit0: WME */ - str r1, [r0] - - /* OS timer does only wrap every 1165 seconds, so we have to set */ - /* the match register as well. */ - - ldr r0, =OSCR - ldr r1, [r0] /* read OS timer */ - add r1, r1, #0x800 /* let OSMR3 match after */ - add r1, r1, #0x800 /* 4096*(1/3.6864MHz)=1ms */ - ldr r0, =OSMR3 - str r1, [r0] - -reset_endless: - - b reset_endless - -#ifndef CONFIG_SPL_BUILD -.section .mmudata, "a" - .align 14 - .globl mmu_table -mmu_table: - /* 0x00000000 - 0xa0000000 : 1:1, uncached mapping */ - .set __base, 0 - .rept 0xa00 - .word (__base << 20) | 0xc12 - .set __base, __base + 1 - .endr - - /* 0xa0000000 - 0xa0100000 : 1:1, cached mapping */ - .word (0xa00 << 20) | 0x1c1e - - .set __base, 0xa01 - .rept 0x1000 - 0xa01 - .word (__base << 20) | 0xc12 - .set __base, __base + 1 - .endr +#endif + .align 5 #endif /* CONFIG_SPL_BUILD */

Am 31.10.2011 14:23, schrieb Marek Vasut:
The start.S on PXA was very obscure. This reworks it back to be close to arm1136 start.S and others.
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net
arch/arm/cpu/pxa/cpu.c | 16 ++ arch/arm/cpu/pxa/start.S | 382 ++++++++++++++++----------------------------- 2 files changed, 152 insertions(+), 246 deletions(-)
Hi Marek,
if I understand your code right, you change the initial memory from cache to SRAM, but this is not available on the pxa255. Do you plan to drop the pxa255 support?
Do you plan to update the pxa boards config?
I assume that I can drop my patch to fix the relocation on pxa.
Regards, Stefan

Am 31.10.2011 14:23, schrieb Marek Vasut:
The start.S on PXA was very obscure. This reworks it back to be close to arm1136 start.S and others.
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net
arch/arm/cpu/pxa/cpu.c | 16 ++ arch/arm/cpu/pxa/start.S | 382 ++++++++++++++++----------------------------- 2 files changed, 152 insertions(+), 246 deletions(-)
Hi Marek,
if I understand your code right, you change the initial memory from cache to SRAM, but this is not available on the pxa255. Do you plan to drop the pxa255 support?
No, you're right. I'll probably have to add a workaround for this issue for pxa25x and 26x. Damn.
Do you plan to update the pxa boards config?
I assume that I can drop my patch to fix the relocation on pxa.
Do you have any pxa250 board and are you willing to help with this patch?
Regards, Stefan

Am 02.11.2011 11:25, schrieb Marek Vasut:
Am 31.10.2011 14:23, schrieb Marek Vasut:
The start.S on PXA was very obscure. This reworks it back to be close to arm1136 start.S and others.
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net
arch/arm/cpu/pxa/cpu.c | 16 ++ arch/arm/cpu/pxa/start.S | 382 ++++++++++++++++----------------------------- 2 files changed, 152 insertions(+), 246 deletions(-)
Hi Marek,
if I understand your code right, you change the initial memory from cache to SRAM, but this is not available on the pxa255. Do you plan to drop the pxa255 support?
No, you're right. I'll probably have to add a workaround for this issue for pxa25x and 26x. Damn.
Do you plan to update the pxa boards config?
I assume that I can drop my patch to fix the relocation on pxa.
Do you have any pxa250 board and are you willing to help with this patch?
I have only my customised pxa270 board.

This introduces small OneNAND loader, fitting into 1kB of space (smallest possible OneNAND RAM size). Some devices equipped with such crappy chips will use this.
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net Cc: Kyungmin Park kyungmin.park@samsung.com Cc: Scott Wood scottwood@freescale.com --- drivers/mtd/onenand/Makefile | 4 + drivers/mtd/onenand/onenand_spl.c | 130 +++++++++++++++++++++++++++++++++++++ include/onenand_uboot.h | 18 +++++ spl/Makefile | 1 + 4 files changed, 153 insertions(+), 0 deletions(-) create mode 100644 drivers/mtd/onenand/onenand_spl.c
diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile index b984bd4..b090d40 100644 --- a/drivers/mtd/onenand/Makefile +++ b/drivers/mtd/onenand/Makefile @@ -25,8 +25,12 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libonenand.o
+ifndef CONFIG_SPL_BUILD COBJS-$(CONFIG_CMD_ONENAND) := onenand_uboot.o onenand_base.o onenand_bbt.o COBJS-$(CONFIG_SAMSUNG_ONENAND) += samsung.o +else +COBJS-y := onenand_spl.o +endif
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/mtd/onenand/onenand_spl.c b/drivers/mtd/onenand/onenand_spl.c new file mode 100644 index 0000000..5429972 --- /dev/null +++ b/drivers/mtd/onenand/onenand_spl.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2011 Marek Vasut marek.vasut@gmail.com + * + * Based on code: + * Copyright (C) 2005-2009 Samsung Electronics + * Kyungmin Park kyungmin.park@samsung.com + * + * 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 <common.h> +#include <asm/io.h> +#include <linux/mtd/onenand_regs.h> +#include <onenand_uboot.h> + +inline uint16_t onenand_readw(uint32_t addr) +{ + return readw(CONFIG_SYS_ONENAND_BASE + addr); +} + +inline void onenand_writew(uint16_t value, uint32_t addr) +{ + writew(value, CONFIG_SYS_ONENAND_BASE + addr); +} + + +#define onenand_block_address(block) (block) +#define onenand_sector_address(page) (page << 2) +#define onenand_buffer_address() ((1 << 3) << 8) +#define onenand_bufferram_address(block) (0) + +void spl_onenand_get_geometry(struct spl_onenand_data *data) +{ + uint32_t tmp; + uint32_t dev_id, density; + + /* Default geometry -- 2048b page, 128k erase block. */ + data->pagesize = 2048; + data->erasesize = 0x20000; + + tmp = onenand_readw(ONENAND_REG_TECHNOLOGY); + if (tmp) + goto dev_4k; + + dev_id = onenand_readw(ONENAND_REG_DEVICE_ID); + density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; + density &= ONENAND_DEVICE_DENSITY_MASK; + + if (density < ONENAND_DEVICE_DENSITY_4Gb) + return; + + if (dev_id & ONENAND_DEVICE_IS_DDP) + return; + + /* 4k device geometry -- 4096b page, 256k erase block. */ +dev_4k: + data->pagesize = 4096; + data->erasesize = 0x40000; +} + +int spl_onenand_read_page(uint32_t block, uint32_t page, + uint8_t *buf, int pagesize) +{ + const uint32_t addr = CONFIG_SYS_ONENAND_BASE + ONENAND_DATARAM; + uint32_t offset; + + onenand_writew(onenand_block_address(block), + ONENAND_REG_START_ADDRESS1); + + onenand_writew(onenand_bufferram_address(block), + ONENAND_REG_START_ADDRESS2); + + onenand_writew(onenand_sector_address(page), + ONENAND_REG_START_ADDRESS8); + + onenand_writew(onenand_buffer_address(), + ONENAND_REG_START_BUFFER); + + onenand_writew(ONENAND_INT_CLEAR, ONENAND_REG_INTERRUPT); + + onenand_writew(ONENAND_CMD_READ, ONENAND_REG_COMMAND); + + while (!(onenand_readw(ONENAND_REG_INTERRUPT) & ONENAND_INT_READ)) + continue; + + /* Check for invalid block mark */ + if (page < 2 && (onenand_readw(ONENAND_SPARERAM) != 0xffff)) + return 1; + + for (offset = 0; offset < pagesize; offset++) + buf[offset] = readb(addr + offset); + + return 0; +} + +int spl_onenand_read_block(uint32_t block, uint8_t *buf, uint32_t *read) +{ + struct spl_onenand_data data; + uint32_t page; + int ret; + + spl_onenand_get_geometry(&data); + + for (page = 0; page < ONENAND_PAGES_PER_BLOCK; page++) { + ret = spl_onenand_read_page(block, page, buf, data.pagesize); + if (ret) + return ret; + buf += data.pagesize; + } + + *read = ((block * ONENAND_PAGES_PER_BLOCK) + page) * data.pagesize; + + return 0; +} diff --git a/include/onenand_uboot.h b/include/onenand_uboot.h index 92279d5..66828ce 100644 --- a/include/onenand_uboot.h +++ b/include/onenand_uboot.h @@ -16,6 +16,8 @@
#include <linux/types.h>
+#ifndef CONFIG_SPL_BUILD + /* Forward declarations */ struct mtd_info; struct mtd_oob_ops; @@ -52,4 +54,20 @@ extern int flexonenand_set_boundary(struct mtd_info *mtd, int die, extern void s3c64xx_onenand_init(struct mtd_info *); extern void s3c64xx_set_width_regs(struct onenand_chip *);
+#else + +#define ONENAND_PAGES_PER_BLOCK 64 + +struct spl_onenand_data { + uint32_t pagesize; + uint32_t erasesize; +}; + +void spl_onenand_get_geometry(struct spl_onenand_data *data); +int spl_onenand_read_page(uint32_t block, uint32_t page, + uint8_t *buf, int pagesize); +int spl_onenand_read_block(uint32_t block, uint8_t *buf, uint32_t *read); + +#endif + #endif /* __UBOOT_ONENAND_H */ diff --git a/spl/Makefile b/spl/Makefile index ed1f770..d4184ac 100644 --- a/spl/Makefile +++ b/spl/Makefile @@ -54,6 +54,7 @@ LIBS-$(CONFIG_SPL_FAT_SUPPORT) += fs/fat/libfat.o LIBS-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/libgeneric.o LIBS-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/libpower.o LIBS-$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/libnand.o +LIBS-$(CONFIG_SPL_ONENAND_SUPPORT) += drivers/mtd/onenand/libonenand.o LIBS-$(CONFIG_SPL_DMA_SUPPORT) += drivers/dma/libdma.o
ifeq ($(SOC),omap3)

On 10/31/2011 08:23 AM, Marek Vasut wrote:
+inline uint16_t onenand_readw(uint32_t addr) +{
- return readw(CONFIG_SYS_ONENAND_BASE + addr);
+}
+inline void onenand_writew(uint16_t value, uint32_t addr) +{
- writew(value, CONFIG_SYS_ONENAND_BASE + addr);
+}
static
+#define onenand_block_address(block) (block) +#define onenand_sector_address(page) (page << 2) +#define onenand_buffer_address() ((1 << 3) << 8) +#define onenand_bufferram_address(block) (0)
Space rather than tab after #define
+void spl_onenand_get_geometry(struct spl_onenand_data *data) +{
- uint32_t tmp;
- uint32_t dev_id, density;
- /* Default geometry -- 2048b page, 128k erase block. */
- data->pagesize = 2048;
- data->erasesize = 0x20000;
- tmp = onenand_readw(ONENAND_REG_TECHNOLOGY);
- if (tmp)
goto dev_4k;
- dev_id = onenand_readw(ONENAND_REG_DEVICE_ID);
- density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
- density &= ONENAND_DEVICE_DENSITY_MASK;
- if (density < ONENAND_DEVICE_DENSITY_4Gb)
return;
- if (dev_id & ONENAND_DEVICE_IS_DDP)
return;
- /* 4k device geometry -- 4096b page, 256k erase block. */
+dev_4k:
- data->pagesize = 4096;
- data->erasesize = 0x40000;
+}
This seems like a gratuitous use of goto...
+int spl_onenand_read_block(uint32_t block, uint8_t *buf, uint32_t *read) +{
- struct spl_onenand_data data;
- uint32_t page;
- int ret;
- spl_onenand_get_geometry(&data);
- for (page = 0; page < ONENAND_PAGES_PER_BLOCK; page++) {
ret = spl_onenand_read_page(block, page, buf, data.pagesize);
if (ret)
return ret;
buf += data.pagesize;
- }
Shouldn't this do bad block skipping rather than error on the first bad block it sees? The current onenand IPL does this.
- *read = ((block * ONENAND_PAGES_PER_BLOCK) + page) * data.pagesize;
We only read one block here, but we return the byte address of the next block? A little odd, and if it's really what's intended, needs to be documented.
diff --git a/include/onenand_uboot.h b/include/onenand_uboot.h index 92279d5..66828ce 100644 --- a/include/onenand_uboot.h +++ b/include/onenand_uboot.h @@ -16,6 +16,8 @@
#include <linux/types.h>
+#ifndef CONFIG_SPL_BUILD
/* Forward declarations */ struct mtd_info; struct mtd_oob_ops; @@ -52,4 +54,20 @@ extern int flexonenand_set_boundary(struct mtd_info *mtd, int die, extern void s3c64xx_onenand_init(struct mtd_info *); extern void s3c64xx_set_width_regs(struct onenand_chip *);
+#else
+#define ONENAND_PAGES_PER_BLOCK 64
+struct spl_onenand_data {
- uint32_t pagesize;
- uint32_t erasesize;
+};
+void spl_onenand_get_geometry(struct spl_onenand_data *data); +int spl_onenand_read_page(uint32_t block, uint32_t page,
uint8_t *buf, int pagesize);
+int spl_onenand_read_block(uint32_t block, uint8_t *buf, uint32_t *read);
+#endif
Do these really need to be #ifdeffed?
-Scott

This introduces small OneNAND loader, fitting into 1kB of space (smallest possible OneNAND RAM size). Some devices equipped with such crappy chips will use this.
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net Cc: Kyungmin Park kyungmin.park@samsung.com Cc: Scott Wood scottwood@freescale.com --- drivers/mtd/onenand/Makefile | 4 + drivers/mtd/onenand/onenand_spl.c | 151 +++++++++++++++++++++++++++++++++++++ include/onenand_uboot.h | 8 ++ spl/Makefile | 1 + 4 files changed, 164 insertions(+), 0 deletions(-) create mode 100644 drivers/mtd/onenand/onenand_spl.c
V2: Introduce spl_onenand_load_image() to load data from OneNAND in SPL
diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile index b984bd4..b090d40 100644 --- a/drivers/mtd/onenand/Makefile +++ b/drivers/mtd/onenand/Makefile @@ -25,8 +25,12 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libonenand.o
+ifndef CONFIG_SPL_BUILD COBJS-$(CONFIG_CMD_ONENAND) := onenand_uboot.o onenand_base.o onenand_bbt.o COBJS-$(CONFIG_SAMSUNG_ONENAND) += samsung.o +else +COBJS-y := onenand_spl.o +endif
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/mtd/onenand/onenand_spl.c b/drivers/mtd/onenand/onenand_spl.c new file mode 100644 index 0000000..d887d20 --- /dev/null +++ b/drivers/mtd/onenand/onenand_spl.c @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2011 Marek Vasut marek.vasut@gmail.com + * + * Based on code: + * Copyright (C) 2005-2009 Samsung Electronics + * Kyungmin Park kyungmin.park@samsung.com + * + * 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 <common.h> +#include <asm/io.h> +#include <linux/mtd/onenand_regs.h> +#include <onenand_uboot.h> + +struct spl_onenand_data { + uint32_t pagesize; + uint32_t erasesize; +}; + +#define ONENAND_PAGES_PER_BLOCK 64 +#define onenand_block_address(block) (block) +#define onenand_sector_address(page) (page << 2) +#define onenand_buffer_address() ((1 << 3) << 8) +#define onenand_bufferram_address(block) (0) + +static inline uint16_t onenand_readw(uint32_t addr) +{ + return readw(CONFIG_SYS_ONENAND_BASE + addr); +} + +static inline void onenand_writew(uint16_t value, uint32_t addr) +{ + writew(value, CONFIG_SYS_ONENAND_BASE + addr); +} + +static void spl_onenand_get_geometry(struct spl_onenand_data *data) +{ + uint32_t tmp; + uint32_t dev_id, density; + + /* Default geometry -- 2048b page, 128k erase block. */ + data->pagesize = 2048; + data->erasesize = 0x20000; + + tmp = onenand_readw(ONENAND_REG_TECHNOLOGY); + if (tmp) + goto dev_4k; + + dev_id = onenand_readw(ONENAND_REG_DEVICE_ID); + density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; + density &= ONENAND_DEVICE_DENSITY_MASK; + + if (density < ONENAND_DEVICE_DENSITY_4Gb) + return; + + if (dev_id & ONENAND_DEVICE_IS_DDP) + return; + + /* 4k device geometry -- 4096b page, 256k erase block. */ +dev_4k: + data->pagesize = 4096; + data->erasesize = 0x40000; +} + +static int spl_onenand_read_page(uint32_t block, uint32_t page, + uint32_t *buf, int pagesize) +{ + const uint32_t addr = CONFIG_SYS_ONENAND_BASE + ONENAND_DATARAM; + uint32_t offset; + + onenand_writew(onenand_block_address(block), + ONENAND_REG_START_ADDRESS1); + + onenand_writew(onenand_bufferram_address(block), + ONENAND_REG_START_ADDRESS2); + + onenand_writew(onenand_sector_address(page), + ONENAND_REG_START_ADDRESS8); + + onenand_writew(onenand_buffer_address(), + ONENAND_REG_START_BUFFER); + + onenand_writew(ONENAND_INT_CLEAR, ONENAND_REG_INTERRUPT); + + onenand_writew(ONENAND_CMD_READ, ONENAND_REG_COMMAND); + + while (!(onenand_readw(ONENAND_REG_INTERRUPT) & ONENAND_INT_READ)) + continue; + + /* Check for invalid block mark */ + if (page < 2 && (onenand_readw(ONENAND_SPARERAM) != 0xffff)) + return 1; + + for (offset = 0; offset < pagesize; offset += 4) + buf[offset / 4] = readl(addr + offset); + + return 0; +} + +int spl_onenand_load_image(uint32_t dst, uint32_t offset, uint32_t len) +{ + uint32_t *addr = (uint32_t *)dst; + struct spl_onenand_data data; + uint32_t total_pages; + uint32_t block; + uint32_t page, rpage; + int ret, err = 0; + + spl_onenand_get_geometry(&data); + + /* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */ + if (data.pagesize == 2048) { + total_pages = len / 2048; + page = offset / 2048; + total_pages += !!(len & 2047); + } else if (data.pagesize == 4096) { + total_pages = len / 4096; + page = offset / 4096; + total_pages += !!(len & 4095); + } + + for (; page <= total_pages; page++) { + block = page / ONENAND_PAGES_PER_BLOCK; + rpage = page & (ONENAND_PAGES_PER_BLOCK - 1); + ret = spl_onenand_read_page(block, rpage, addr, data.pagesize); + if (ret) { + total_pages++; + err |= 1; + } else + addr += data.pagesize / 4; + } + + return err; +} diff --git a/include/onenand_uboot.h b/include/onenand_uboot.h index 92279d5..fcb50ff 100644 --- a/include/onenand_uboot.h +++ b/include/onenand_uboot.h @@ -16,6 +16,8 @@
#include <linux/types.h>
+#ifndef CONFIG_SPL_BUILD + /* Forward declarations */ struct mtd_info; struct mtd_oob_ops; @@ -52,4 +54,10 @@ extern int flexonenand_set_boundary(struct mtd_info *mtd, int die, extern void s3c64xx_onenand_init(struct mtd_info *); extern void s3c64xx_set_width_regs(struct onenand_chip *);
+#else + +int spl_onenand_load_image(uint32_t dst, uint32_t offset, uint32_t len); + +#endif + #endif /* __UBOOT_ONENAND_H */ diff --git a/spl/Makefile b/spl/Makefile index d4d754d..b4001bf 100644 --- a/spl/Makefile +++ b/spl/Makefile @@ -54,6 +54,7 @@ LIBS-$(CONFIG_SPL_FAT_SUPPORT) += fs/fat/libfat.o LIBS-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/libgeneric.o LIBS-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/libpower.o LIBS-$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/libnand.o +LIBS-$(CONFIG_SPL_ONENAND_SUPPORT) += drivers/mtd/onenand/libonenand.o LIBS-$(CONFIG_SPL_DMA_SUPPORT) += drivers/dma/libdma.o
ifeq ($(SOC),omap3)

On 11/01/2011 05:54 PM, Marek Vasut wrote:
+static void spl_onenand_get_geometry(struct spl_onenand_data *data) +{
- uint32_t tmp;
- uint32_t dev_id, density;
- /* Default geometry -- 2048b page, 128k erase block. */
- data->pagesize = 2048;
- data->erasesize = 0x20000;
- tmp = onenand_readw(ONENAND_REG_TECHNOLOGY);
- if (tmp)
goto dev_4k;
- dev_id = onenand_readw(ONENAND_REG_DEVICE_ID);
- density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
- density &= ONENAND_DEVICE_DENSITY_MASK;
- if (density < ONENAND_DEVICE_DENSITY_4Gb)
return;
- if (dev_id & ONENAND_DEVICE_IS_DDP)
return;
- /* 4k device geometry -- 4096b page, 256k erase block. */
+dev_4k:
- data->pagesize = 4096;
- data->erasesize = 0x40000;
+}
Drop the goto and "tmp" variable, just do:
if (!onenand_readw(ONENAND_REG_TECHNOLOGY)) { dev_id = onenand_readw(ONENAND_REG_DEVICE_ID); density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; density &= ONENAND_DEVICE_DENSITY_MASK;
if (density < ONENAND_DEVICE_DENSITY_4Gb) return;
if (dev_id & ONENAND_DEVICE_IS_DDP) return; }
+int spl_onenand_load_image(uint32_t dst, uint32_t offset, uint32_t len)
Please use the same name and arguments as nand_spl_load_image() in nand_spl_simple.c.
+{
- uint32_t *addr = (uint32_t *)dst;
Why not pass it in as a pointer in the first place? I know U-Boot is unlkely to support being built as 64-bit any time soon, but why introduce gratuitous 64-bit-uncleanliness?
- struct spl_onenand_data data;
- uint32_t total_pages;
- uint32_t block;
- uint32_t page, rpage;
- int ret, err = 0;
- spl_onenand_get_geometry(&data);
- /* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
- if (data.pagesize == 2048) {
total_pages = len / 2048;
page = offset / 2048;
total_pages += !!(len & 2047);
- } else if (data.pagesize == 4096) {
total_pages = len / 4096;
page = offset / 4096;
total_pages += !!(len & 4095);
- }
What's wrong with DIV_ROUND_UP? It should produce smaller code than what you've done here...
- for (; page <= total_pages; page++) {
block = page / ONENAND_PAGES_PER_BLOCK;
rpage = page & (ONENAND_PAGES_PER_BLOCK - 1);
ret = spl_onenand_read_page(block, rpage, addr, data.pagesize);
if (ret) {
total_pages++;
err |= 1;
} else
addr += data.pagesize / 4;
- }
As discussed, please retain the existing block-skipping semantics. And if you do skip a block, that's not an error to be propagated upward (as opposed to something like an uncorrectable ECC error).
If one side of an if statement requires braces, both sides should have them.
diff --git a/include/onenand_uboot.h b/include/onenand_uboot.h index 92279d5..fcb50ff 100644 --- a/include/onenand_uboot.h +++ b/include/onenand_uboot.h @@ -16,6 +16,8 @@
#include <linux/types.h>
+#ifndef CONFIG_SPL_BUILD
Please use a space rather than a tab after #define, #ifndef, etc.
/* Forward declarations */ struct mtd_info; struct mtd_oob_ops; @@ -52,4 +54,10 @@ extern int flexonenand_set_boundary(struct mtd_info *mtd, int die, extern void s3c64xx_onenand_init(struct mtd_info *); extern void s3c64xx_set_width_regs(struct onenand_chip *);
+#else
+int spl_onenand_load_image(uint32_t dst, uint32_t offset, uint32_t len);
+#endif
Why does this need to be ifdeffed at all? We normally don't ifdef header declarations.
-Scott

On 11/01/2011 05:54 PM, Marek Vasut wrote:
+static void spl_onenand_get_geometry(struct spl_onenand_data *data) +{
[...]
- /* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
- if (data.pagesize == 2048) {
total_pages = len / 2048;
page = offset / 2048;
total_pages += !!(len & 2047);
- } else if (data.pagesize == 4096) {
total_pages = len / 4096;
page = offset / 4096;
total_pages += !!(len & 4095);
- }
What's wrong with DIV_ROUND_UP? It should produce smaller code than what you've done here...
It pulls in aeabi_*div* functions, which won't fit into block 0 of Onenand.
- for (; page <= total_pages; page++) {
block = page / ONENAND_PAGES_PER_BLOCK;
rpage = page & (ONENAND_PAGES_PER_BLOCK - 1);
ret = spl_onenand_read_page(block, rpage, addr, data.pagesize);
if (ret) {
total_pages++;
err |= 1;
} else
addr += data.pagesize / 4;
- }
As discussed, please retain the existing block-skipping semantics. And if you do skip a block, that's not an error to be propagated upward (as opposed to something like an uncorrectable ECC error).
If one side of an if statement requires braces, both sides should have them.
diff --git a/include/onenand_uboot.h b/include/onenand_uboot.h index 92279d5..fcb50ff 100644 --- a/include/onenand_uboot.h +++ b/include/onenand_uboot.h @@ -16,6 +16,8 @@
#include <linux/types.h>
+#ifndef CONFIG_SPL_BUILD
Please use a space rather than a tab after #define, #ifndef, etc.
/* Forward declarations */ struct mtd_info; struct mtd_oob_ops;
@@ -52,4 +54,10 @@ extern int flexonenand_set_boundary(struct mtd_info *mtd, int die,
extern void s3c64xx_onenand_init(struct mtd_info *); extern void s3c64xx_set_width_regs(struct onenand_chip *);
+#else
+int spl_onenand_load_image(uint32_t dst, uint32_t offset, uint32_t len);
+#endif
Why does this need to be ifdeffed at all? We normally don't ifdef header declarations.
-Scott

Hi all,
Marek, did you see the onenand_ipl/onenand_read.c at u-boot? It's already implemented and used for OneNAND boot.
How do you think migrate this file into generic SPL framework?
Thank you, Kyungmin Park
-----Original Message----- From: Marek Vasut [mailto:marek.vasut@gmail.com] Sent: Thursday, November 03, 2011 9:16 AM To: Scott Wood Cc: u-boot@lists.denx.de; Albert ARIBAUD; Kyungmin Park Subject: Re: [PATCH 3/4 V2] OneNAND: Add simple OneNAND SPL
On 11/01/2011 05:54 PM, Marek Vasut wrote:
+static void spl_onenand_get_geometry(struct spl_onenand_data *data) +{
[...]
- /* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
- if (data.pagesize == 2048) {
total_pages = len / 2048;
page = offset / 2048;
total_pages += !!(len & 2047);
- } else if (data.pagesize == 4096) {
total_pages = len / 4096;
page = offset / 4096;
total_pages += !!(len & 4095);
- }
What's wrong with DIV_ROUND_UP? It should produce smaller code than what you've done here...
It pulls in aeabi_*div* functions, which won't fit into block 0 of Onenand.
- for (; page <= total_pages; page++) {
block = page / ONENAND_PAGES_PER_BLOCK;
rpage = page & (ONENAND_PAGES_PER_BLOCK - 1);
ret = spl_onenand_read_page(block, rpage, addr,
data.pagesize);
if (ret) {
total_pages++;
err |= 1;
} else
addr += data.pagesize / 4;
- }
As discussed, please retain the existing block-skipping semantics. And if you do skip a block, that's not an error to be propagated upward (as opposed to something like an uncorrectable ECC error).
If one side of an if statement requires braces, both sides should have them.
diff --git a/include/onenand_uboot.h b/include/onenand_uboot.h index 92279d5..fcb50ff 100644 --- a/include/onenand_uboot.h +++ b/include/onenand_uboot.h @@ -16,6 +16,8 @@
#include <linux/types.h>
+#ifndef CONFIG_SPL_BUILD
Please use a space rather than a tab after #define, #ifndef, etc.
/* Forward declarations */ struct mtd_info; struct mtd_oob_ops;
@@ -52,4 +54,10 @@ extern int flexonenand_set_boundary(struct mtd_info *mtd, int die,
extern void s3c64xx_onenand_init(struct mtd_info *); extern void s3c64xx_set_width_regs(struct onenand_chip *);
+#else
+int spl_onenand_load_image(uint32_t dst, uint32_t offset, uint32_t
len);
+#endif
Why does this need to be ifdeffed at all? We normally don't ifdef header declarations.
-Scott

Hi all,
Marek, did you see the onenand_ipl/onenand_read.c at u-boot? It's already implemented and used for OneNAND boot.
How do you think migrate this file into generic SPL framework?
That's basically what I did, with a little polishing.
Thank you, Kyungmin Park

On 11/02/2011 07:15 PM, Marek Vasut wrote:
On 11/01/2011 05:54 PM, Marek Vasut wrote:
+static void spl_onenand_get_geometry(struct spl_onenand_data *data) +{
[...]
- /* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
- if (data.pagesize == 2048) {
total_pages = len / 2048;
page = offset / 2048;
total_pages += !!(len & 2047);
- } else if (data.pagesize == 4096) {
total_pages = len / 4096;
page = offset / 4096;
total_pages += !!(len & 4095);
- }
What's wrong with DIV_ROUND_UP? It should produce smaller code than what you've done here...
It pulls in aeabi_*div* functions, which won't fit into block 0 of Onenand.
It shouldn't do that if the divisor is a constant power of 2. The compiler will turn it into a shift, just like with the other divides in the above code fragment.
You can't use DIV_ROUND_UP directly on data.pagesize, but you can use it in each branch of the if statement instead of that awkward and slightly more expensive !!(len & 4095) construct.
-Scott

On 11/02/2011 07:15 PM, Marek Vasut wrote:
On 11/01/2011 05:54 PM, Marek Vasut wrote:
+static void spl_onenand_get_geometry(struct spl_onenand_data *data) +{
[...]
- /* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
- if (data.pagesize == 2048) {
total_pages = len / 2048;
page = offset / 2048;
total_pages += !!(len & 2047);
- } else if (data.pagesize == 4096) {
total_pages = len / 4096;
page = offset / 4096;
total_pages += !!(len & 4095);
- }
What's wrong with DIV_ROUND_UP? It should produce smaller code than what you've done here...
It pulls in aeabi_*div* functions, which won't fit into block 0 of Onenand.
It shouldn't do that if the divisor is a constant power of 2. The compiler will turn it into a shift, just like with the other divides in the above code fragment.
You can't use DIV_ROUND_UP directly on data.pagesize, but you can use it in each branch of the if statement instead of that awkward and slightly more expensive !!(len & 4095) construct.
Expensive in what way? Either way, I don't think this matters that much.

On 11/03/2011 11:56 AM, Marek Vasut wrote:
On 11/02/2011 07:15 PM, Marek Vasut wrote:
On 11/01/2011 05:54 PM, Marek Vasut wrote:
+static void spl_onenand_get_geometry(struct spl_onenand_data *data) +{
[...]
- /* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
- if (data.pagesize == 2048) {
total_pages = len / 2048;
page = offset / 2048;
total_pages += !!(len & 2047);
- } else if (data.pagesize == 4096) {
total_pages = len / 4096;
page = offset / 4096;
total_pages += !!(len & 4095);
- }
What's wrong with DIV_ROUND_UP? It should produce smaller code than what you've done here...
It pulls in aeabi_*div* functions, which won't fit into block 0 of Onenand.
It shouldn't do that if the divisor is a constant power of 2. The compiler will turn it into a shift, just like with the other divides in the above code fragment.
You can't use DIV_ROUND_UP directly on data.pagesize, but you can use it in each branch of the if statement instead of that awkward and slightly more expensive !!(len & 4095) construct.
Expensive in what way?
Compare the resulting asm code. You're replacing this:
a = (b + 4095) >> 12;
with this:
a = b >> 12; if (b & 4095) a++;
Either way, I don't think this matters that much.
This is code that has to fit in 1K -- why waste instructions by writing code in a way that is *less* readable?
-Scott

On 11/03/2011 11:56 AM, Marek Vasut wrote:
On 11/02/2011 07:15 PM, Marek Vasut wrote:
On 11/01/2011 05:54 PM, Marek Vasut wrote:
+static void spl_onenand_get_geometry(struct spl_onenand_data *data) +{
[...]
- /* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
- if (data.pagesize == 2048) {
total_pages = len / 2048;
page = offset / 2048;
total_pages += !!(len & 2047);
- } else if (data.pagesize == 4096) {
total_pages = len / 4096;
page = offset / 4096;
total_pages += !!(len & 4095);
- }
What's wrong with DIV_ROUND_UP? It should produce smaller code than what you've done here...
It pulls in aeabi_*div* functions, which won't fit into block 0 of Onenand.
It shouldn't do that if the divisor is a constant power of 2. The compiler will turn it into a shift, just like with the other divides in the above code fragment.
You can't use DIV_ROUND_UP directly on data.pagesize, but you can use it in each branch of the if statement instead of that awkward and slightly more expensive !!(len & 4095) construct.
Expensive in what way?
Compare the resulting asm code. You're replacing this:
a = (b + 4095) >> 12;
with this:
a = b >> 12; if (b & 4095) a++;
Either way, I don't think this matters that much.
This is code that has to fit in 1K -- why waste instructions by writing code in a way that is *less* readable?
The size is the same (tested). I'll submit a patch with DIV_ROUND_UP, whatever.
-Scott

This introduces small OneNAND loader, fitting into 1kB of space (smallest possible OneNAND RAM size). Some devices equipped with such crappy chips will use this.
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net Cc: Kyungmin Park kyungmin.park@samsung.com Cc: Scott Wood scottwood@freescale.com --- drivers/mtd/onenand/Makefile | 4 + drivers/mtd/onenand/onenand_spl.c | 148 +++++++++++++++++++++++++++++++++++++ include/onenand_uboot.h | 3 + spl/Makefile | 1 + 4 files changed, 156 insertions(+), 0 deletions(-) create mode 100644 drivers/mtd/onenand/onenand_spl.c
V2: Introduce spl_onenand_load_image() to load data from OneNAND in SPL V3: Cleanup, align with nand_spl. Skip whole blocks.
diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile index b984bd4..b090d40 100644 --- a/drivers/mtd/onenand/Makefile +++ b/drivers/mtd/onenand/Makefile @@ -25,8 +25,12 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libonenand.o
+ifndef CONFIG_SPL_BUILD COBJS-$(CONFIG_CMD_ONENAND) := onenand_uboot.o onenand_base.o onenand_bbt.o COBJS-$(CONFIG_SAMSUNG_ONENAND) += samsung.o +else +COBJS-y := onenand_spl.o +endif
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/mtd/onenand/onenand_spl.c b/drivers/mtd/onenand/onenand_spl.c new file mode 100644 index 0000000..4bf862e --- /dev/null +++ b/drivers/mtd/onenand/onenand_spl.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2011 Marek Vasut marek.vasut@gmail.com + * + * Based on code: + * Copyright (C) 2005-2009 Samsung Electronics + * Kyungmin Park kyungmin.park@samsung.com + * + * 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 <common.h> +#include <asm/io.h> +#include <linux/mtd/onenand_regs.h> +#include <onenand_uboot.h> + +/* + * Device geometry: + * - 2048b page, 128k erase block. + * - 4096b page, 256k erase block. + */ +enum onenand_spl_pagesize { + PAGE_2K = 2048, + PAGE_4K = 4096, +}; + +#define ONENAND_PAGES_PER_BLOCK 64 +#define onenand_block_address(block) (block) +#define onenand_sector_address(page) (page << 2) +#define onenand_buffer_address() ((1 << 3) << 8) +#define onenand_bufferram_address(block) (0) + +static inline uint16_t onenand_readw(uint32_t addr) +{ + return readw(CONFIG_SYS_ONENAND_BASE + addr); +} + +static inline void onenand_writew(uint16_t value, uint32_t addr) +{ + writew(value, CONFIG_SYS_ONENAND_BASE + addr); +} + +static enum onenand_spl_pagesize onenand_spl_get_geometry(void) +{ + uint32_t dev_id, density; + + if (!onenand_readw(ONENAND_REG_TECHNOLOGY)) { + dev_id = onenand_readw(ONENAND_REG_DEVICE_ID); + density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; + density &= ONENAND_DEVICE_DENSITY_MASK; + + if (density < ONENAND_DEVICE_DENSITY_4Gb) + return PAGE_2K; + + if (dev_id & ONENAND_DEVICE_IS_DDP) + return PAGE_2K; + } + + return PAGE_4K; +} + +static int onenand_spl_read_page(uint32_t block, uint32_t page, uint32_t *buf, + enum onenand_spl_pagesize pagesize) +{ + const uint32_t addr = CONFIG_SYS_ONENAND_BASE + ONENAND_DATARAM; + uint32_t offset; + + onenand_writew(onenand_block_address(block), + ONENAND_REG_START_ADDRESS1); + + onenand_writew(onenand_bufferram_address(block), + ONENAND_REG_START_ADDRESS2); + + onenand_writew(onenand_sector_address(page), + ONENAND_REG_START_ADDRESS8); + + onenand_writew(onenand_buffer_address(), + ONENAND_REG_START_BUFFER); + + onenand_writew(ONENAND_INT_CLEAR, ONENAND_REG_INTERRUPT); + + onenand_writew(ONENAND_CMD_READ, ONENAND_REG_COMMAND); + + while (!(onenand_readw(ONENAND_REG_INTERRUPT) & ONENAND_INT_READ)) + continue; + + /* Check for invalid block mark */ + if (page < 2 && (onenand_readw(ONENAND_SPARERAM) != 0xffff)) + return 1; + + for (offset = 0; offset < pagesize; offset += 4) + buf[offset / 4] = readl(addr + offset); + + return 0; +} + +void onenand_spl_load_image(uint32_t offs, uint32_t size, void *dst) +{ + uint32_t *addr = (uint32_t *)dst; + uint32_t total_pages; + uint32_t block; + uint32_t page, rpage; + enum onenand_spl_pagesize pagesize; + int ret; + + pagesize = onenand_spl_get_geometry(); + + /* + * The page can be either 2k or 4k, avoid using DIV_ROUND_UP to avoid + * pulling further unwanted functions into the SPL. + */ + if (pagesize == 2048) { + total_pages = size / 2048; + page = offs / 2048; + total_pages += !!(size & 2047); + } else { + total_pages = size / 4096; + page = offs / 4096; + total_pages += !!(size & 4095); + } + + for (; page <= total_pages; page++) { + block = page / ONENAND_PAGES_PER_BLOCK; + rpage = page & (ONENAND_PAGES_PER_BLOCK - 1); + ret = onenand_spl_read_page(block, rpage, addr, pagesize); + if (ret) { + total_pages += ONENAND_PAGES_PER_BLOCK; + page += ONENAND_PAGES_PER_BLOCK - 1; + } else { + addr += pagesize / 4; + } + } +} diff --git a/include/onenand_uboot.h b/include/onenand_uboot.h index 92279d5..f321d8a 100644 --- a/include/onenand_uboot.h +++ b/include/onenand_uboot.h @@ -52,4 +52,7 @@ extern int flexonenand_set_boundary(struct mtd_info *mtd, int die, extern void s3c64xx_onenand_init(struct mtd_info *); extern void s3c64xx_set_width_regs(struct onenand_chip *);
+/* SPL */ +void onenand_spl_load_image(uint32_t offs, uint32_t size, void *dst); + #endif /* __UBOOT_ONENAND_H */ diff --git a/spl/Makefile b/spl/Makefile index d4d754d..b4001bf 100644 --- a/spl/Makefile +++ b/spl/Makefile @@ -54,6 +54,7 @@ LIBS-$(CONFIG_SPL_FAT_SUPPORT) += fs/fat/libfat.o LIBS-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/libgeneric.o LIBS-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/libpower.o LIBS-$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/libnand.o +LIBS-$(CONFIG_SPL_ONENAND_SUPPORT) += drivers/mtd/onenand/libonenand.o LIBS-$(CONFIG_SPL_DMA_SUPPORT) += drivers/dma/libdma.o
ifeq ($(SOC),omap3)

This introduces small OneNAND loader, fitting into 1kB of space (smallest possible OneNAND RAM size). Some devices equipped with such crappy chips will use this.
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net Cc: Kyungmin Park kyungmin.park@samsung.com Cc: Scott Wood scottwood@freescale.com --- drivers/mtd/onenand/Makefile | 4 + drivers/mtd/onenand/onenand_spl.c | 146 +++++++++++++++++++++++++++++++++++++ include/onenand_uboot.h | 3 + spl/Makefile | 1 + 4 files changed, 154 insertions(+), 0 deletions(-) create mode 100644 drivers/mtd/onenand/onenand_spl.c
V2: Introduce spl_onenand_load_image() to load data from OneNAND in SPL V3: Cleanup, align with nand_spl. Skip whole blocks. V4: Use DIV_ROUND_UP.
diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile index b984bd4..b090d40 100644 --- a/drivers/mtd/onenand/Makefile +++ b/drivers/mtd/onenand/Makefile @@ -25,8 +25,12 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libonenand.o
+ifndef CONFIG_SPL_BUILD COBJS-$(CONFIG_CMD_ONENAND) := onenand_uboot.o onenand_base.o onenand_bbt.o COBJS-$(CONFIG_SAMSUNG_ONENAND) += samsung.o +else +COBJS-y := onenand_spl.o +endif
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/mtd/onenand/onenand_spl.c b/drivers/mtd/onenand/onenand_spl.c new file mode 100644 index 0000000..50eaa71 --- /dev/null +++ b/drivers/mtd/onenand/onenand_spl.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2011 Marek Vasut marek.vasut@gmail.com + * + * Based on code: + * Copyright (C) 2005-2009 Samsung Electronics + * Kyungmin Park kyungmin.park@samsung.com + * + * 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 <common.h> +#include <asm/io.h> +#include <linux/mtd/onenand_regs.h> +#include <onenand_uboot.h> + +/* + * Device geometry: + * - 2048b page, 128k erase block. + * - 4096b page, 256k erase block. + */ +enum onenand_spl_pagesize { + PAGE_2K = 2048, + PAGE_4K = 4096, +}; + +#define ONENAND_PAGES_PER_BLOCK 64 +#define onenand_block_address(block) (block) +#define onenand_sector_address(page) (page << 2) +#define onenand_buffer_address() ((1 << 3) << 8) +#define onenand_bufferram_address(block) (0) + +static inline uint16_t onenand_readw(uint32_t addr) +{ + return readw(CONFIG_SYS_ONENAND_BASE + addr); +} + +static inline void onenand_writew(uint16_t value, uint32_t addr) +{ + writew(value, CONFIG_SYS_ONENAND_BASE + addr); +} + +static enum onenand_spl_pagesize onenand_spl_get_geometry(void) +{ + uint32_t dev_id, density; + + if (!onenand_readw(ONENAND_REG_TECHNOLOGY)) { + dev_id = onenand_readw(ONENAND_REG_DEVICE_ID); + density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; + density &= ONENAND_DEVICE_DENSITY_MASK; + + if (density < ONENAND_DEVICE_DENSITY_4Gb) + return PAGE_2K; + + if (dev_id & ONENAND_DEVICE_IS_DDP) + return PAGE_2K; + } + + return PAGE_4K; +} + +static int onenand_spl_read_page(uint32_t block, uint32_t page, uint32_t *buf, + enum onenand_spl_pagesize pagesize) +{ + const uint32_t addr = CONFIG_SYS_ONENAND_BASE + ONENAND_DATARAM; + uint32_t offset; + + onenand_writew(onenand_block_address(block), + ONENAND_REG_START_ADDRESS1); + + onenand_writew(onenand_bufferram_address(block), + ONENAND_REG_START_ADDRESS2); + + onenand_writew(onenand_sector_address(page), + ONENAND_REG_START_ADDRESS8); + + onenand_writew(onenand_buffer_address(), + ONENAND_REG_START_BUFFER); + + onenand_writew(ONENAND_INT_CLEAR, ONENAND_REG_INTERRUPT); + + onenand_writew(ONENAND_CMD_READ, ONENAND_REG_COMMAND); + + while (!(onenand_readw(ONENAND_REG_INTERRUPT) & ONENAND_INT_READ)) + continue; + + /* Check for invalid block mark */ + if (page < 2 && (onenand_readw(ONENAND_SPARERAM) != 0xffff)) + return 1; + + for (offset = 0; offset < pagesize; offset += 4) + buf[offset / 4] = readl(addr + offset); + + return 0; +} + +void onenand_spl_load_image(uint32_t offs, uint32_t size, void *dst) +{ + uint32_t *addr = (uint32_t *)dst; + uint32_t total_pages; + uint32_t block; + uint32_t page, rpage; + enum onenand_spl_pagesize pagesize; + int ret; + + pagesize = onenand_spl_get_geometry(); + + /* + * The page can be either 2k or 4k, avoid using DIV_ROUND_UP to avoid + * pulling further unwanted functions into the SPL. + */ + if (pagesize == 2048) { + total_pages = DIV_ROUND_UP(size, 2048); + page = offs / 2048; + } else { + total_pages = DIV_ROUND_UP(size, 4096); + page = offs / 4096; + } + + for (; page <= total_pages; page++) { + block = page / ONENAND_PAGES_PER_BLOCK; + rpage = page & (ONENAND_PAGES_PER_BLOCK - 1); + ret = onenand_spl_read_page(block, rpage, addr, pagesize); + if (ret) { + total_pages += ONENAND_PAGES_PER_BLOCK; + page += ONENAND_PAGES_PER_BLOCK - 1; + } else { + addr += pagesize / 4; + } + } +} diff --git a/include/onenand_uboot.h b/include/onenand_uboot.h index 92279d5..f321d8a 100644 --- a/include/onenand_uboot.h +++ b/include/onenand_uboot.h @@ -52,4 +52,7 @@ extern int flexonenand_set_boundary(struct mtd_info *mtd, int die, extern void s3c64xx_onenand_init(struct mtd_info *); extern void s3c64xx_set_width_regs(struct onenand_chip *);
+/* SPL */ +void onenand_spl_load_image(uint32_t offs, uint32_t size, void *dst); + #endif /* __UBOOT_ONENAND_H */ diff --git a/spl/Makefile b/spl/Makefile index d4d754d..b4001bf 100644 --- a/spl/Makefile +++ b/spl/Makefile @@ -54,6 +54,7 @@ LIBS-$(CONFIG_SPL_FAT_SUPPORT) += fs/fat/libfat.o LIBS-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/libgeneric.o LIBS-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/libpower.o LIBS-$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/libnand.o +LIBS-$(CONFIG_SPL_ONENAND_SUPPORT) += drivers/mtd/onenand/libonenand.o LIBS-$(CONFIG_SPL_DMA_SUPPORT) += drivers/dma/libdma.o
ifeq ($(SOC),omap3)

Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net --- board/vpac270/Makefile | 6 ++ board/vpac270/onenand.c | 136 +++++++++++++++++++++++++++++++++++++++++++++ board/vpac270/vpac270.c | 2 + include/configs/vpac270.h | 25 +++++++-- 4 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 board/vpac270/onenand.c
diff --git a/board/vpac270/Makefile b/board/vpac270/Makefile index b5c60fd..f25822f 100644 --- a/board/vpac270/Makefile +++ b/board/vpac270/Makefile @@ -23,7 +23,13 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).o
+ifndef CONFIG_SPL_BUILD COBJS := vpac270.o +endif + +ifdef CONFIG_SPL_BUILD +COBJS := onenand.o +endif
SRCS := $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS)) diff --git a/board/vpac270/onenand.c b/board/vpac270/onenand.c new file mode 100644 index 0000000..50de2ab --- /dev/null +++ b/board/vpac270/onenand.c @@ -0,0 +1,136 @@ +/* + * Voipac PXA270 OneNAND SPL + * + * Copyright (C) 2011 Marek Vasut marek.vasut@gmail.com + * + * 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 <common.h> +#include <config.h> +#include <asm/io.h> +#include <onenand_uboot.h> + +extern void pxa_dram_init(void); + +inline void spl_copy_self(void) +{ + extern uint32_t _end; + struct spl_onenand_data data; + uint32_t page; + uint32_t total_bytes = (uint32_t)&_end - CONFIG_SPL_TEXT_BASE; + uint32_t total_pages; + uint8_t *addr = (uint8_t *)CONFIG_SPL_TEXT_BASE; + int ret; + + spl_onenand_get_geometry(&data); + + /* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */ + total_pages = total_bytes >> 11; + if (data.pagesize == 4096) + total_pages >>= 1; + + for (page = 0; page <= total_pages; page++) { + ret = spl_onenand_read_page(0, page, addr, data.pagesize); + if (ret) + total_pages++; + else + addr += data.pagesize; + } +} + +inline void spl_copy_uboot(void) +{ + uint8_t *addr = (uint8_t *)CONFIG_SYS_TEXT_BASE; + struct spl_onenand_data data; + uint32_t total_pages; + uint32_t block; + uint32_t page, rpage; + int ret; + + spl_onenand_get_geometry(&data); + + /* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */ + total_pages = CONFIG_SPL_ONENAND_LOAD_SIZE >> 11; + page = CONFIG_SPL_ONENAND_LOAD_ADDR >> 11; + if (data.pagesize == 4096) { + total_pages >>= 1; + page >>= 1; + } + + for (; page <= total_pages; page++) { + block = page >> 6; + rpage = page & 0xff; + ret = spl_onenand_read_page(block, rpage, addr, data.pagesize); + if (ret) + total_pages++; + else + addr += data.pagesize; + } +} + +inline void board_init_f(unsigned long unused) +{ + uint32_t tmp; + + asm volatile("mov %0, pc" : "=r"(tmp)); + tmp >>= 24; + + /* The code runs from OneNAND RAM, copy SPL to SRAM and execute it. */ + if (tmp == 0) { + spl_copy_self(); + asm volatile("mov pc, %0" : : "r"(CONFIG_SPL_TEXT_BASE)); + } + + /* Hereby, the code runs from (S)RAM, copy U-Boot and execute it. */ + arch_cpu_init(); + pxa_dram_init(); + spl_copy_uboot(); + asm volatile("mov pc, %0" : : "r"(CONFIG_SYS_TEXT_BASE)); + + for (;;) + ; +} + +inline void board_init_r(gd_t *id, ulong dest_addr) +{ + for (;;) + ; +} + +inline int printf(const char *fmt, ...) +{ + return 0; +} + +inline void __coloured_LED_init(void) {} +inline void __red_LED_on(void) {} +void coloured_LED_init(void) + __attribute__((weak, alias("__coloured_LED_init"))); +void red_LED_on(void) + __attribute__((weak, alias("__red_LED_on"))); +void hang(void) __attribute__ ((noreturn)); +void hang(void) +{ + for (;;) + ; +} + +inline void icache_disable(void) {} +inline void dcache_disable(void) {} diff --git a/board/vpac270/vpac270.c b/board/vpac270/vpac270.c index 43bbdff..f146009 100644 --- a/board/vpac270/vpac270.c +++ b/board/vpac270/vpac270.c @@ -56,7 +56,9 @@ struct serial_device *default_serial_console(void) extern void pxa_dram_init(void); int dram_init(void) { +#ifndef CONFIG_ONENAND pxa_dram_init(); +#endif gd->ram_size = PHYS_SDRAM_1_SIZE; return 0; } diff --git a/include/configs/vpac270.h b/include/configs/vpac270.h index 9db4d99..d43ff47 100644 --- a/include/configs/vpac270.h +++ b/include/configs/vpac270.h @@ -27,7 +27,17 @@ */ #define CONFIG_PXA27X 1 /* Marvell PXA270 CPU */ #define CONFIG_VPAC270 1 /* Voipac PXA270 board */ -#define CONFIG_SYS_TEXT_BASE 0x0 +#define CONFIG_SYS_TEXT_BASE 0xa0000000 + +#ifdef CONFIG_ONENAND +#define CONFIG_SPL +#define CONFIG_SPL_ONENAND_SUPPORT +#define CONFIG_SPL_ONENAND_LOAD_ADDR 0x2000 +#define CONFIG_SPL_ONENAND_LOAD_SIZE \ + (512 * 1024 - CONFIG_SPL_ONENAND_LOAD_ADDR) +#define CONFIG_SPL_TEXT_BASE 0x5c000000 +#define CONFIG_SPL_LDSCRIPT "board/vpac270/u-boot-spl.lds" +#endif
/* * Environment settings @@ -46,12 +56,19 @@ "bootm 0xa4000000; " \ "fi; " \ "bootm 0x60000;" + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "update_onenand=" \ + "onenand erase 0x0 0x80000 ; " \ + "onenand write 0xa0000000 0x0 0x80000" + #define CONFIG_BOOTARGS "console=tty0 console=ttyS0,115200" #define CONFIG_TIMESTAMP #define CONFIG_BOOTDELAY 2 /* Autoboot delay */ #define CONFIG_CMDLINE_TAG #define CONFIG_SETUP_MEMORY_TAGS #define CONFIG_LZMA /* LZMA compression support */ +#define CONFIG_OF_LIBFDT
/* * Serial Console Configuration @@ -179,16 +196,14 @@ #define CONFIG_SYS_MEMTEST_END 0xa0800000 /* 4 ... 8 MB in DRAM */
#define CONFIG_SYS_LOAD_ADDR PHYS_SDRAM_1 -#define CONFIG_SYS_IPL_LOAD_ADDR (0x5c000000) #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1 -#define CONFIG_SYS_INIT_SP_ADDR \ - (PHYS_SDRAM_1 + GENERATED_GBL_DATA_SIZE + 2048) +#define CONFIG_SYS_INIT_SP_ADDR 0x5c010000
/* * NOR FLASH */ #define CONFIG_SYS_MONITOR_BASE 0x0 -#define CONFIG_SYS_MONITOR_LEN 0x40000 +#define CONFIG_SYS_MONITOR_LEN 0x80000 #define CONFIG_ENV_ADDR \ (CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN) #define CONFIG_ENV_SIZE 0x4000

On 10/31/2011 08:23 AM, Marek Vasut wrote:
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net
board/vpac270/Makefile | 6 ++ board/vpac270/onenand.c | 136 +++++++++++++++++++++++++++++++++++++++++++++ board/vpac270/vpac270.c | 2 + include/configs/vpac270.h | 25 +++++++-- 4 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 board/vpac270/onenand.c
diff --git a/board/vpac270/Makefile b/board/vpac270/Makefile index b5c60fd..f25822f 100644 --- a/board/vpac270/Makefile +++ b/board/vpac270/Makefile @@ -23,7 +23,13 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).o
+ifndef CONFIG_SPL_BUILD COBJS := vpac270.o +endif
+ifdef CONFIG_SPL_BUILD +COBJS := onenand.o +endif
else?
SRCS := $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS)) diff --git a/board/vpac270/onenand.c b/board/vpac270/onenand.c new file mode 100644 index 0000000..50de2ab --- /dev/null +++ b/board/vpac270/onenand.c @@ -0,0 +1,136 @@ +/*
- Voipac PXA270 OneNAND SPL
- Copyright (C) 2011 Marek Vasut marek.vasut@gmail.com
- 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 <common.h> +#include <config.h> +#include <asm/io.h> +#include <onenand_uboot.h>
+extern void pxa_dram_init(void);
+inline void spl_copy_self(void) +{
- extern uint32_t _end;
- struct spl_onenand_data data;
- uint32_t page;
- uint32_t total_bytes = (uint32_t)&_end - CONFIG_SPL_TEXT_BASE;
- uint32_t total_pages;
- uint8_t *addr = (uint8_t *)CONFIG_SPL_TEXT_BASE;
- int ret;
- spl_onenand_get_geometry(&data);
- /* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
- total_pages = total_bytes >> 11;
- if (data.pagesize == 4096)
total_pages >>= 1;
total_bytes / 2048 and total_pages / 2 are more readable and should generate exactly the same code.
- for (page = 0; page <= total_pages; page++) {
ret = spl_onenand_read_page(0, page, addr, data.pagesize);
if (ret)
total_pages++;
else
addr += data.pagesize;
- }
+}
You want to skip to the next block if spl_onenand_read_page() fails (which can occur after you've already read some of the block).
How much of this is board-specific?
+inline void spl_copy_uboot(void) +{
- uint8_t *addr = (uint8_t *)CONFIG_SYS_TEXT_BASE;
- struct spl_onenand_data data;
- uint32_t total_pages;
- uint32_t block;
- uint32_t page, rpage;
- int ret;
- spl_onenand_get_geometry(&data);
- /* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
- total_pages = CONFIG_SPL_ONENAND_LOAD_SIZE >> 11;
- page = CONFIG_SPL_ONENAND_LOAD_ADDR >> 11;
- if (data.pagesize == 4096) {
total_pages >>= 1;
page >>= 1;
- }
- for (; page <= total_pages; page++) {
block = page >> 6;
rpage = page & 0xff;
ret = spl_onenand_read_page(block, rpage, addr, data.pagesize);
if (ret)
total_pages++;
else
addr += data.pagesize;
- }
+}
What is so different about this compared to spl_copy_self, that warrants such duplication? Can't you just pass in offset, length, and destination as parameters? Or just have the OneNAND SPL driver export nand_spl_load_image(), as any other NAND SPL driver would?
+inline void board_init_f(unsigned long unused) +{
- uint32_t tmp;
- asm volatile("mov %0, pc" : "=r"(tmp));
- tmp >>= 24;
- /* The code runs from OneNAND RAM, copy SPL to SRAM and execute it. */
- if (tmp == 0) {
spl_copy_self();
asm volatile("mov pc, %0" : : "r"(CONFIG_SPL_TEXT_BASE));
- }
Is it not possible to use a simple memcpy for spl_copy_self()? If the CPU can run the code, you'd think it could read it.
+inline void board_init_r(gd_t *id, ulong dest_addr) +{
- for (;;)
;
+}
This doesn't seem like a useful board_init_r(). If you don't need it, maybe make sure it's not called, and save yourself some bytes in the SPL. Likewise for the other stub functions, where practical.
+inline int printf(const char *fmt, ...) +{
- return 0;
+}
+inline void __coloured_LED_init(void) {} +inline void __red_LED_on(void) {} +void coloured_LED_init(void)
- __attribute__((weak, alias("__coloured_LED_init")));
+void red_LED_on(void)
- __attribute__((weak, alias("__red_LED_on")));
+void hang(void) __attribute__ ((noreturn)); +void hang(void) +{
- for (;;)
;
+}
+inline void icache_disable(void) {} +inline void dcache_disable(void) {}
Why are you specifying inline on just about everything, even functions that are not used in this file?
Why are you not specifying static on things that are not needed outside this file?
diff --git a/board/vpac270/vpac270.c b/board/vpac270/vpac270.c index 43bbdff..f146009 100644 --- a/board/vpac270/vpac270.c +++ b/board/vpac270/vpac270.c @@ -56,7 +56,9 @@ struct serial_device *default_serial_console(void) extern void pxa_dram_init(void); int dram_init(void) { +#ifndef CONFIG_ONENAND pxa_dram_init(); +#endif gd->ram_size = PHYS_SDRAM_1_SIZE; return 0; }
Should this really be about whether OneNAND support is present, or should it be based on whether you're using the OneNAND SPL?
-Scott

On 10/31/2011 08:23 AM, Marek Vasut wrote:
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net
[...]
- for (page = 0; page <= total_pages; page++) {
ret = spl_onenand_read_page(0, page, addr, data.pagesize);
if (ret)
total_pages++;
else
addr += data.pagesize;
- }
+}
You want to skip to the next block if spl_onenand_read_page() fails (which can occur after you've already read some of the block).
I want to skip to next page, not next block.
How much of this is board-specific?
+inline void spl_copy_uboot(void) +{
- uint8_t *addr = (uint8_t *)CONFIG_SYS_TEXT_BASE;
- struct spl_onenand_data data;
- uint32_t total_pages;
- uint32_t block;
- uint32_t page, rpage;
- int ret;
- spl_onenand_get_geometry(&data);
- /* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
- total_pages = CONFIG_SPL_ONENAND_LOAD_SIZE >> 11;
- page = CONFIG_SPL_ONENAND_LOAD_ADDR >> 11;
- if (data.pagesize == 4096) {
total_pages >>= 1;
page >>= 1;
- }
- for (; page <= total_pages; page++) {
block = page >> 6;
rpage = page & 0xff;
ret = spl_onenand_read_page(block, rpage, addr, data.pagesize);
if (ret)
total_pages++;
else
addr += data.pagesize;
- }
+}
What is so different about this compared to spl_copy_self, that warrants such duplication? Can't you just pass in offset, length, and destination as parameters? Or just have the OneNAND SPL driver export nand_spl_load_image(), as any other NAND SPL driver would?
Good idea.
+inline void board_init_f(unsigned long unused) +{
- uint32_t tmp;
- asm volatile("mov %0, pc" : "=r"(tmp));
- tmp >>= 24;
- /* The code runs from OneNAND RAM, copy SPL to SRAM and execute it. */
- if (tmp == 0) {
spl_copy_self();
asm volatile("mov pc, %0" : : "r"(CONFIG_SPL_TEXT_BASE));
- }
Is it not possible to use a simple memcpy for spl_copy_self()? If the CPU can run the code, you'd think it could read it.
Not exactly. The OneNAND only exposes first 1kb of the contents (aka 1 half of the page 0 in my case). That's why I link all of the relevant code there and the rest of the SPL is aligned beyond that. Then I copy the whole SPL to SRAM and execute it again. Then I init DRAM, copy U-Boot there and run it. Simple, isn't it.
+inline void board_init_r(gd_t *id, ulong dest_addr) +{
- for (;;)
;
+}
This doesn't seem like a useful board_init_r(). If you don't need it, maybe make sure it's not called, and save yourself some bytes in the SPL. Likewise for the other stub functions, where practical.
+inline int printf(const char *fmt, ...) +{
- return 0;
+}
+inline void __coloured_LED_init(void) {} +inline void __red_LED_on(void) {} +void coloured_LED_init(void)
- __attribute__((weak, alias("__coloured_LED_init")));
+void red_LED_on(void)
- __attribute__((weak, alias("__red_LED_on")));
+void hang(void) __attribute__ ((noreturn)); +void hang(void) +{
- for (;;)
;
+}
+inline void icache_disable(void) {} +inline void dcache_disable(void) {}
Why are you specifying inline on just about everything, even functions that are not used in this file?
They are, by dram_init();
Why are you not specifying static on things that are not needed outside this file?
They are actually needed outside.
diff --git a/board/vpac270/vpac270.c b/board/vpac270/vpac270.c index 43bbdff..f146009 100644 --- a/board/vpac270/vpac270.c +++ b/board/vpac270/vpac270.c @@ -56,7 +56,9 @@ struct serial_device *default_serial_console(void)
extern void pxa_dram_init(void); int dram_init(void) {
+#ifndef CONFIG_ONENAND
pxa_dram_init();
+#endif
gd->ram_size = PHYS_SDRAM_1_SIZE; return 0;
}
Should this really be about whether OneNAND support is present, or should it be based on whether you're using the OneNAND SPL?
Basically, on this board this is the same thing.
-Scott

On 11/01/2011 05:12 PM, Marek Vasut wrote:
On 10/31/2011 08:23 AM, Marek Vasut wrote:
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net
[...]
- for (page = 0; page <= total_pages; page++) {
ret = spl_onenand_read_page(0, page, addr, data.pagesize);
if (ret)
total_pages++;
else
addr += data.pagesize;
- }
+}
You want to skip to the next block if spl_onenand_read_page() fails (which can occur after you've already read some of the block).
I want to skip to next page, not next block.
That's not how we normally do things, and is not what the current OneNAND IPL does.
Bad block markers apply to the entire block -- unless this is a difference I'm not aware of between NAND and OneNAND.
Is it not possible to use a simple memcpy for spl_copy_self()? If the CPU can run the code, you'd think it could read it.
Not exactly. The OneNAND only exposes first 1kb of the contents (aka 1 half of the page 0 in my case). That's why I link all of the relevant code there and the rest of the SPL is aligned beyond that. Then I copy the whole SPL to SRAM and execute it again. Then I init DRAM, copy U-Boot there and run it. Simple, isn't it.
Where do you ensure that the stuff used so far is within the 1K? What parts are not within the 1K?
I don't see a linker script.
+inline void icache_disable(void) {} +inline void dcache_disable(void) {}
Why are you specifying inline on just about everything, even functions that are not used in this file?
They are, by dram_init();
There's no point marking something inline if it's not used later on in the same file -- functions aren't inlined across file boundaries. You've got inline functions at the very end of the file.
For that matter, there's not much point marking anything inline that isn't a static inline in a header file (where the compiler must not generate a non-inline version) -- the compiler has heuristics for inlining things, and excessive inlining tends to make things bigger rather than smaller.
Why are you not specifying static on things that are not needed outside this file?
They are actually needed outside.
All of them, including spl_copy_uboot and spl_copy_self?
diff --git a/board/vpac270/vpac270.c b/board/vpac270/vpac270.c index 43bbdff..f146009 100644 --- a/board/vpac270/vpac270.c +++ b/board/vpac270/vpac270.c @@ -56,7 +56,9 @@ struct serial_device *default_serial_console(void)
extern void pxa_dram_init(void); int dram_init(void) {
+#ifndef CONFIG_ONENAND
pxa_dram_init();
+#endif
gd->ram_size = PHYS_SDRAM_1_SIZE; return 0;
}
Should this really be about whether OneNAND support is present, or should it be based on whether you're using the OneNAND SPL?
Basically, on this board this is the same thing.
If you can turn off onenand at all, that suggests there's another boot source. Is it not possible to access onenand when using that other boot source?
In any case, best to use the symbol that most closely matches the reason you're skipping it, which is something SPL-related.
-Scott

On 11/01/2011 05:12 PM, Marek Vasut wrote:
On 10/31/2011 08:23 AM, Marek Vasut wrote:
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net
[...]
- for (page = 0; page <= total_pages; page++) {
ret = spl_onenand_read_page(0, page, addr, data.pagesize);
if (ret)
total_pages++;
else
addr += data.pagesize;
- }
+}
You want to skip to the next block if spl_onenand_read_page() fails (which can occur after you've already read some of the block).
I want to skip to next page, not next block.
That's not how we normally do things, and is not what the current OneNAND IPL does.
Bad block markers apply to the entire block -- unless this is a difference I'm not aware of between NAND and OneNAND.
Well then it will fail reading the whole block and continue onwards ... it's a bit slower like this.
Is it not possible to use a simple memcpy for spl_copy_self()? If the CPU can run the code, you'd think it could read it.
Not exactly. The OneNAND only exposes first 1kb of the contents (aka 1 half of the page 0 in my case). That's why I link all of the relevant code there and the rest of the SPL is aligned beyond that. Then I copy the whole SPL to SRAM and execute it again. Then I init DRAM, copy U-Boot there and run it. Simple, isn't it.
Where do you ensure that the stuff used so far is within the 1K? What parts are not within the 1K?
I don't see a linker script.
Is in V2, missing.
+inline void icache_disable(void) {} +inline void dcache_disable(void) {}
Why are you specifying inline on just about everything, even functions that are not used in this file?
They are, by dram_init();
There's no point marking something inline if it's not used later on in the same file -- functions aren't inlined across file boundaries. You've got inline functions at the very end of the file.
For that matter, there's not much point marking anything inline that isn't a static inline in a header file (where the compiler must not generate a non-inline version) -- the compiler has heuristics for inlining things, and excessive inlining tends to make things bigger rather than smaller.
Why are you not specifying static on things that are not needed outside this file?
They are actually needed outside.
All of them, including spl_copy_uboot and spl_copy_self?
diff --git a/board/vpac270/vpac270.c b/board/vpac270/vpac270.c index 43bbdff..f146009 100644 --- a/board/vpac270/vpac270.c +++ b/board/vpac270/vpac270.c @@ -56,7 +56,9 @@ struct serial_device *default_serial_console(void)
extern void pxa_dram_init(void); int dram_init(void) {
+#ifndef CONFIG_ONENAND
pxa_dram_init();
+#endif
gd->ram_size = PHYS_SDRAM_1_SIZE; return 0;
}
Should this really be about whether OneNAND support is present, or should it be based on whether you're using the OneNAND SPL?
Basically, on this board this is the same thing.
If you can turn off onenand at all, that suggests there's another boot source. Is it not possible to access onenand when using that other boot source?
No, they are mutually exclusive.
In any case, best to use the symbol that most closely matches the reason you're skipping it, which is something SPL-related.
-Scott

On 11/01/2011 05:44 PM, Marek Vasut wrote:
On 11/01/2011 05:12 PM, Marek Vasut wrote:
On 10/31/2011 08:23 AM, Marek Vasut wrote:
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net
[...]
- for (page = 0; page <= total_pages; page++) {
ret = spl_onenand_read_page(0, page, addr, data.pagesize);
if (ret)
total_pages++;
else
addr += data.pagesize;
- }
+}
You want to skip to the next block if spl_onenand_read_page() fails (which can occur after you've already read some of the block).
I want to skip to next page, not next block.
That's not how we normally do things, and is not what the current OneNAND IPL does.
Bad block markers apply to the entire block -- unless this is a difference I'm not aware of between NAND and OneNAND.
Well then it will fail reading the whole block and continue onwards ... it's a bit slower like this.
It doesn't work like that. The bad block marker is in the first page of the block only (sometimes the second page can be used). The bad block marker is not placed on every page in the block, so if you continue to subsequent pages it will not fail, but you won't be getting the data you're expecting.
-Scott

Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net --- board/vpac270/Makefile | 4 ++ board/vpac270/onenand.c | 66 ++++++++++++++++++++++++++++ board/vpac270/u-boot-spl.lds | 97 ++++++++++++++++++++++++++++++++++++++++++ board/vpac270/vpac270.c | 2 + include/configs/vpac270.h | 25 +++++++++-- 5 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 board/vpac270/onenand.c create mode 100644 board/vpac270/u-boot-spl.lds
V2: Add missing u-boot-spl.lds, convert bitshifts to division, convert to spl_onenand_load_image()
diff --git a/board/vpac270/Makefile b/board/vpac270/Makefile index b5c60fd..5967055 100644 --- a/board/vpac270/Makefile +++ b/board/vpac270/Makefile @@ -23,7 +23,11 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).o
+ifndef CONFIG_SPL_BUILD COBJS := vpac270.o +else +COBJS := onenand.o +endif
SRCS := $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS)) diff --git a/board/vpac270/onenand.c b/board/vpac270/onenand.c new file mode 100644 index 0000000..5aea774 --- /dev/null +++ b/board/vpac270/onenand.c @@ -0,0 +1,66 @@ +/* + * Voipac PXA270 OneNAND SPL + * + * Copyright (C) 2011 Marek Vasut marek.vasut@gmail.com + * + * 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 <common.h> +#include <config.h> +#include <asm/io.h> +#include <onenand_uboot.h> + +extern void pxa_dram_init(void); + +inline void board_init_f(unsigned long unused) +{ + extern uint32_t _end; + uint32_t tmp; + + asm volatile("mov %0, pc" : "=r"(tmp)); + tmp >>= 24; + + /* The code runs from OneNAND RAM, copy SPL to SRAM and execute it. */ + if (tmp == 0) { + tmp = (uint32_t)&_end - CONFIG_SPL_TEXT_BASE; + spl_onenand_load_image(CONFIG_SPL_TEXT_BASE, 0, tmp); + asm volatile("mov pc, %0" : : "r"(CONFIG_SPL_TEXT_BASE)); + } + + /* Hereby, the code runs from (S)RAM, copy U-Boot and execute it. */ + arch_cpu_init(); + pxa_dram_init(); + spl_onenand_load_image(CONFIG_SYS_TEXT_BASE, + CONFIG_SPL_ONENAND_LOAD_ADDR, + CONFIG_SPL_ONENAND_LOAD_SIZE); + asm volatile("mov pc, %0" : : "r"(CONFIG_SYS_TEXT_BASE)); + + for (;;) + ; +} + +void __attribute__((noreturn)) hang(void) +{ + for (;;) + ; +} + +void icache_disable(void) {} +void dcache_disable(void) {} diff --git a/board/vpac270/u-boot-spl.lds b/board/vpac270/u-boot-spl.lds new file mode 100644 index 0000000..75acdcd --- /dev/null +++ b/board/vpac270/u-boot-spl.lds @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2011 Marek Vasut marek.vasut@gmail.com + * on behalf of DENX Software Engineering GmbH + * + * January 2004 - Changed to support H4 device + * Copyright (c) 2004-2008 Texas Instruments + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, garyj@denx.de + * + * 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 + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = CONFIG_SPL_TEXT_BASE; + .text.0 : + { + arch/arm/cpu/pxa/start.o (.text*) + board/vpac270/libvpac270.o (.text*) + drivers/mtd/onenand/libonenand.o (.text*) + } + + + /* Start of the rest of the SPL */ + . = CONFIG_SPL_TEXT_BASE + 0x800; + + .text.1 : + { + *(.text*) + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { + *(.data) + } + + . = ALIGN(4); + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + . = ALIGN(4); + + .rel.dyn : { + __rel_dyn_start = .; + *(.rel*) + __rel_dyn_end = .; + } + + .dynsym : { + __dynsym_start = .; + *(.dynsym) + } + + . = ALIGN(0x800); + + _end = .; + + .bss __rel_dyn_start (OVERLAY) : { + __bss_start = .; + *(.bss) + . = ALIGN(4); + __bss_end__ = .; + } + + /DISCARD/ : { *(.bss*) } + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynsym*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.hash*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } +} diff --git a/board/vpac270/vpac270.c b/board/vpac270/vpac270.c index cf8e7b6..d90a859 100644 --- a/board/vpac270/vpac270.c +++ b/board/vpac270/vpac270.c @@ -57,7 +57,9 @@ struct serial_device *default_serial_console(void) extern void pxa_dram_init(void); int dram_init(void) { +#ifndef CONFIG_ONENAND pxa_dram_init(); +#endif gd->ram_size = PHYS_SDRAM_1_SIZE; return 0; } diff --git a/include/configs/vpac270.h b/include/configs/vpac270.h index dd68c66..8accebf 100644 --- a/include/configs/vpac270.h +++ b/include/configs/vpac270.h @@ -27,7 +27,17 @@ */ #define CONFIG_PXA27X 1 /* Marvell PXA270 CPU */ #define CONFIG_VPAC270 1 /* Voipac PXA270 board */ -#define CONFIG_SYS_TEXT_BASE 0x0 +#define CONFIG_SYS_TEXT_BASE 0xa0000000 + +#ifdef CONFIG_ONENAND +#define CONFIG_SPL +#define CONFIG_SPL_ONENAND_SUPPORT +#define CONFIG_SPL_ONENAND_LOAD_ADDR 0x2000 +#define CONFIG_SPL_ONENAND_LOAD_SIZE \ + (512 * 1024 - CONFIG_SPL_ONENAND_LOAD_ADDR) +#define CONFIG_SPL_TEXT_BASE 0x5c000000 +#define CONFIG_SPL_LDSCRIPT "board/vpac270/u-boot-spl.lds" +#endif
/* * Environment settings @@ -46,12 +56,19 @@ "bootm 0xa4000000; " \ "fi; " \ "bootm 0x60000;" + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "update_onenand=" \ + "onenand erase 0x0 0x80000 ; " \ + "onenand write 0xa0000000 0x0 0x80000" + #define CONFIG_BOOTARGS "console=tty0 console=ttyS0,115200" #define CONFIG_TIMESTAMP #define CONFIG_BOOTDELAY 2 /* Autoboot delay */ #define CONFIG_CMDLINE_TAG #define CONFIG_SETUP_MEMORY_TAGS #define CONFIG_LZMA /* LZMA compression support */ +#define CONFIG_OF_LIBFDT
/* * Serial Console Configuration @@ -180,16 +197,14 @@ #define CONFIG_SYS_MEMTEST_END 0xa0800000 /* 4 ... 8 MB in DRAM */
#define CONFIG_SYS_LOAD_ADDR PHYS_SDRAM_1 -#define CONFIG_SYS_IPL_LOAD_ADDR (0x5c000000) #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1 -#define CONFIG_SYS_INIT_SP_ADDR \ - (PHYS_SDRAM_1 + GENERATED_GBL_DATA_SIZE + 2048) +#define CONFIG_SYS_INIT_SP_ADDR 0x5c010000
/* * NOR FLASH */ #define CONFIG_SYS_MONITOR_BASE 0x0 -#define CONFIG_SYS_MONITOR_LEN 0x40000 +#define CONFIG_SYS_MONITOR_LEN 0x80000 #define CONFIG_ENV_ADDR \ (CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN) #define CONFIG_ENV_SIZE 0x4000

On 11/01/2011 05:54 PM, Marek Vasut wrote:
+inline void board_init_f(unsigned long unused)
Drop the inline.
- /* Start of the rest of the SPL */
- . = CONFIG_SPL_TEXT_BASE + 0x800;
- .text.1 :
- {
*(.text*)
- }
- . = ALIGN(4);
- .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
- . = ALIGN(4);
- .data : {
*(.data)
- }
- . = ALIGN(4);
- __u_boot_cmd_start = .;
- .u_boot_cmd : { *(.u_boot_cmd) }
- __u_boot_cmd_end = .;
Commands in an SPL?
-Scott

Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Albert ARIBAUD albert.u.boot@aribaud.net --- board/vpac270/Makefile | 4 ++ board/vpac270/onenand.c | 66 ++++++++++++++++++++++++++++++ board/vpac270/u-boot-spl.lds | 92 ++++++++++++++++++++++++++++++++++++++++++ board/vpac270/vpac270.c | 2 + include/configs/vpac270.h | 25 +++++++++-- 5 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 board/vpac270/onenand.c create mode 100644 board/vpac270/u-boot-spl.lds
V2: Add missing u-boot-spl.lds, convert bitshifts to division, convert to spl_onenand_load_image() V3: Drop inlines, update linker script, update to conform new onenand_spl.
diff --git a/board/vpac270/Makefile b/board/vpac270/Makefile index b5c60fd..5967055 100644 --- a/board/vpac270/Makefile +++ b/board/vpac270/Makefile @@ -23,7 +23,11 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).o
+ifndef CONFIG_SPL_BUILD COBJS := vpac270.o +else +COBJS := onenand.o +endif
SRCS := $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS)) diff --git a/board/vpac270/onenand.c b/board/vpac270/onenand.c new file mode 100644 index 0000000..6a0a37b --- /dev/null +++ b/board/vpac270/onenand.c @@ -0,0 +1,66 @@ +/* + * Voipac PXA270 OneNAND SPL + * + * Copyright (C) 2011 Marek Vasut marek.vasut@gmail.com + * + * 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 <common.h> +#include <config.h> +#include <asm/io.h> +#include <onenand_uboot.h> + +extern void pxa_dram_init(void); + +void board_init_f(unsigned long unused) +{ + extern uint32_t _end; + uint32_t tmp; + + asm volatile("mov %0, pc" : "=r"(tmp)); + tmp >>= 24; + + /* The code runs from OneNAND RAM, copy SPL to SRAM and execute it. */ + if (tmp == 0) { + tmp = (uint32_t)&_end - CONFIG_SPL_TEXT_BASE; + onenand_spl_load_image(0, tmp, (void *)CONFIG_SPL_TEXT_BASE); + asm volatile("mov pc, %0" : : "r"(CONFIG_SPL_TEXT_BASE)); + } + + /* Hereby, the code runs from (S)RAM, copy U-Boot and execute it. */ + arch_cpu_init(); + pxa_dram_init(); + onenand_spl_load_image(CONFIG_SPL_ONENAND_LOAD_ADDR, + CONFIG_SPL_ONENAND_LOAD_SIZE, + (void *)CONFIG_SYS_TEXT_BASE); + asm volatile("mov pc, %0" : : "r"(CONFIG_SYS_TEXT_BASE)); + + for (;;) + ; +} + +void __attribute__((noreturn)) hang(void) +{ + for (;;) + ; +} + +void icache_disable(void) {} +void dcache_disable(void) {} diff --git a/board/vpac270/u-boot-spl.lds b/board/vpac270/u-boot-spl.lds new file mode 100644 index 0000000..1958c2f --- /dev/null +++ b/board/vpac270/u-boot-spl.lds @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011 Marek Vasut marek.vasut@gmail.com + * on behalf of DENX Software Engineering GmbH + * + * January 2004 - Changed to support H4 device + * Copyright (c) 2004-2008 Texas Instruments + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, garyj@denx.de + * + * 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 + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = CONFIG_SPL_TEXT_BASE; + .text.0 : + { + arch/arm/cpu/pxa/start.o (.text*) + board/vpac270/libvpac270.o (.text*) + drivers/mtd/onenand/libonenand.o (.text*) + } + + + /* Start of the rest of the SPL */ + . = CONFIG_SPL_TEXT_BASE + 0x800; + + .text.1 : + { + *(.text*) + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { + *(.data) + } + + . = ALIGN(4); + + .rel.dyn : { + __rel_dyn_start = .; + *(.rel*) + __rel_dyn_end = .; + } + + .dynsym : { + __dynsym_start = .; + *(.dynsym) + } + + . = ALIGN(0x800); + + _end = .; + + .bss __rel_dyn_start (OVERLAY) : { + __bss_start = .; + *(.bss) + . = ALIGN(4); + __bss_end__ = .; + } + + /DISCARD/ : { *(.bss*) } + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynsym*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.hash*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } +} diff --git a/board/vpac270/vpac270.c b/board/vpac270/vpac270.c index cf8e7b6..d90a859 100644 --- a/board/vpac270/vpac270.c +++ b/board/vpac270/vpac270.c @@ -57,7 +57,9 @@ struct serial_device *default_serial_console(void) extern void pxa_dram_init(void); int dram_init(void) { +#ifndef CONFIG_ONENAND pxa_dram_init(); +#endif gd->ram_size = PHYS_SDRAM_1_SIZE; return 0; } diff --git a/include/configs/vpac270.h b/include/configs/vpac270.h index dd68c66..8accebf 100644 --- a/include/configs/vpac270.h +++ b/include/configs/vpac270.h @@ -27,7 +27,17 @@ */ #define CONFIG_PXA27X 1 /* Marvell PXA270 CPU */ #define CONFIG_VPAC270 1 /* Voipac PXA270 board */ -#define CONFIG_SYS_TEXT_BASE 0x0 +#define CONFIG_SYS_TEXT_BASE 0xa0000000 + +#ifdef CONFIG_ONENAND +#define CONFIG_SPL +#define CONFIG_SPL_ONENAND_SUPPORT +#define CONFIG_SPL_ONENAND_LOAD_ADDR 0x2000 +#define CONFIG_SPL_ONENAND_LOAD_SIZE \ + (512 * 1024 - CONFIG_SPL_ONENAND_LOAD_ADDR) +#define CONFIG_SPL_TEXT_BASE 0x5c000000 +#define CONFIG_SPL_LDSCRIPT "board/vpac270/u-boot-spl.lds" +#endif
/* * Environment settings @@ -46,12 +56,19 @@ "bootm 0xa4000000; " \ "fi; " \ "bootm 0x60000;" + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "update_onenand=" \ + "onenand erase 0x0 0x80000 ; " \ + "onenand write 0xa0000000 0x0 0x80000" + #define CONFIG_BOOTARGS "console=tty0 console=ttyS0,115200" #define CONFIG_TIMESTAMP #define CONFIG_BOOTDELAY 2 /* Autoboot delay */ #define CONFIG_CMDLINE_TAG #define CONFIG_SETUP_MEMORY_TAGS #define CONFIG_LZMA /* LZMA compression support */ +#define CONFIG_OF_LIBFDT
/* * Serial Console Configuration @@ -180,16 +197,14 @@ #define CONFIG_SYS_MEMTEST_END 0xa0800000 /* 4 ... 8 MB in DRAM */
#define CONFIG_SYS_LOAD_ADDR PHYS_SDRAM_1 -#define CONFIG_SYS_IPL_LOAD_ADDR (0x5c000000) #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1 -#define CONFIG_SYS_INIT_SP_ADDR \ - (PHYS_SDRAM_1 + GENERATED_GBL_DATA_SIZE + 2048) +#define CONFIG_SYS_INIT_SP_ADDR 0x5c010000
/* * NOR FLASH */ #define CONFIG_SYS_MONITOR_BASE 0x0 -#define CONFIG_SYS_MONITOR_LEN 0x40000 +#define CONFIG_SYS_MONITOR_LEN 0x80000 #define CONFIG_ENV_ADDR \ (CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN) #define CONFIG_ENV_SIZE 0x4000

On 11/02/2011 08:56 PM, Marek Vasut wrote:
- onenand_spl_load_image(CONFIG_SPL_ONENAND_LOAD_ADDR,
CONFIG_SPL_ONENAND_LOAD_SIZE,
(void *)CONFIG_SYS_TEXT_BASE);
If we make it "nand_spl_load_image", and make the #defines conform, we can have the same code call the function for nand and onenand. I don't see any reason why onenand is a completely different subsystem in general, rather than just another NAND driver. The NAND subsystem's driver interface is lower level than it should be, but that affects other NAND controllers as well (such as fsl_elbc).
Switching to the generic nand_boot() in http://patchwork.ozlabs.org/patch/123219/ would get you the ability to load the environment during the SPL.
-Scott

On 11/02/2011 08:56 PM, Marek Vasut wrote:
- onenand_spl_load_image(CONFIG_SPL_ONENAND_LOAD_ADDR,
CONFIG_SPL_ONENAND_LOAD_SIZE,
(void *)CONFIG_SYS_TEXT_BASE);
If we make it "nand_spl_load_image", and make the #defines conform, we can have the same code call the function for nand and onenand. I don't see any reason why onenand is a completely different subsystem in general, rather than just another NAND driver. The NAND subsystem's driver interface is lower level than it should be, but that affects other NAND controllers as well (such as fsl_elbc).
Switching to the generic nand_boot() in http://patchwork.ozlabs.org/patch/123219/ would get you the ability to load the environment during the SPL.
-Scott
I don't think I understand. Why do you want to mix onenand and nand ? Also, will your approach still allow me to squeeze the important code into the first 1kb for the initial copying of SPL?

On 11/03/2011 04:52 PM, Marek Vasut wrote:
On 11/02/2011 08:56 PM, Marek Vasut wrote:
- onenand_spl_load_image(CONFIG_SPL_ONENAND_LOAD_ADDR,
CONFIG_SPL_ONENAND_LOAD_SIZE,
(void *)CONFIG_SYS_TEXT_BASE);
If we make it "nand_spl_load_image", and make the #defines conform, we can have the same code call the function for nand and onenand. I don't see any reason why onenand is a completely different subsystem in general, rather than just another NAND driver. The NAND subsystem's driver interface is lower level than it should be, but that affects other NAND controllers as well (such as fsl_elbc).
Switching to the generic nand_boot() in http://patchwork.ozlabs.org/patch/123219/ would get you the ability to load the environment during the SPL.
-Scott
I don't think I understand. Why do you want to mix onenand and nand ?
Why do we want to separate them? What is the fundamental difference between OneNAND, and a high-level NAND controller such as fsl_elbc? Maybe there would be some differences on init if we can't produce "normal" ID data, but that doesn't justify duplicating the whole subsystem.
Why should the code that just wants to use an API to move data around need to care which it is? Why should there be behavioral differences that aren't rooted in the actual hardware? Another approach might be to use MTD as the common interface, but factor out common code into libraries that drivers can use, and avoid the main nand_base.c code even for things like fsl_elbc.
This is not a new complaint -- I've asked for this before but nobody's put the time into sorting out the mess (and I have neither time nor hardware nor documentation). The SPL load_image function is a simple enough interface to start with, though. :-)
In fact, it should probably just be spl_load_image() with whatever boot source has been configured into this SPL build.
Also, will your approach still allow me to squeeze the important code into the first 1kb for the initial copying of SPL?
If you can't fit the common load sequence in, then of course don't use it, but there's no need for the function name to be different.
-Scott

On 11/03/2011 04:52 PM, Marek Vasut wrote:
On 11/02/2011 08:56 PM, Marek Vasut wrote:
- onenand_spl_load_image(CONFIG_SPL_ONENAND_LOAD_ADDR,
CONFIG_SPL_ONENAND_LOAD_SIZE,
(void *)CONFIG_SYS_TEXT_BASE);
If we make it "nand_spl_load_image", and make the #defines conform, we can have the same code call the function for nand and onenand. I don't see any reason why onenand is a completely different subsystem in general, rather than just another NAND driver. The NAND subsystem's driver interface is lower level than it should be, but that affects other NAND controllers as well (such as fsl_elbc).
Switching to the generic nand_boot() in http://patchwork.ozlabs.org/patch/123219/ would get you the ability to load the environment during the SPL.
-Scott
I don't think I understand. Why do you want to mix onenand and nand ?
Why do we want to separate them? What is the fundamental difference between OneNAND, and a high-level NAND controller such as fsl_elbc?
Honestly, I'm not the author of the subsystem, but please check the documentation. The way we retrieve data from onenand is different to NAND.
Maybe there would be some differences on init if we can't produce "normal" ID data, but that doesn't justify duplicating the whole subsystem.
Where do you see such duplication? cmd_onenand ?
Why should the code that just wants to use an API to move data around need to care which it is? Why should there be behavioral differences that aren't rooted in the actual hardware? Another approach might be to use MTD as the common interface, but factor out common code into libraries that drivers can use, and avoid the main nand_base.c code even for things like fsl_elbc.
I think you're mistaken here. OneNAND != NAND.
This is not a new complaint -- I've asked for this before but nobody's put the time into sorting out the mess (and I have neither time nor hardware nor documentation). The SPL load_image function is a simple enough interface to start with, though. :-)
Well, it seems what you are proposing is way beyond the scope of this patchset.
In fact, it should probably just be spl_load_image() with whatever boot source has been configured into this SPL build.
What if you have two boot sources?
Also, will your approach still allow me to squeeze the important code into the first 1kb for the initial copying of SPL?
If you can't fit the common load sequence in, then of course don't use it, but there's no need for the function name to be different.
-Scott

On 11/03/2011 07:55 PM, Marek Vasut wrote:
On 11/03/2011 04:52 PM, Marek Vasut wrote: Why do we want to separate them? What is the fundamental difference between OneNAND, and a high-level NAND controller such as fsl_elbc?
Honestly, I'm not the author of the subsystem, but please check the documentation. The way we retrieve data from onenand is different to NAND.
What documentation? How is it different? There are substantial differences in how we "retrieve data" between drivers that use the NAND subsystem. Surely you've seen that in the mxs_nand driver. :-)
Maybe there would be some differences on init if we can't produce "normal" ID data, but that doesn't justify duplicating the whole subsystem.
Where do you see such duplication? cmd_onenand ?
cmd_onenand and env_onenand are the most irritating, since they're at a layer that really shouldn't care about the differences -- we should probably have a plain "mtd" command instead, for most of the functionality.
There's also onenand_bbt.c -- what are the hardware-based differences in how the bad block table is managed?
nand_base.c/onenand_base.c are less clear. Obviously much of what is in onenand_base.c would be in the controller driver if it used the NAND subsystem. But it looks like some of it is duplication.
Why should the code that just wants to use an API to move data around need to care which it is? Why should there be behavioral differences that aren't rooted in the actual hardware? Another approach might be to use MTD as the common interface, but factor out common code into libraries that drivers can use, and avoid the main nand_base.c code even for things like fsl_elbc.
I think you're mistaken here. OneNAND != NAND.
Well, last I tried I couldn't find any public documentation, so all I have to go on is the code, some marketing-type info, and asking questions of people that appear to know more about OneNAND than I do. :-)
From what I can see, it looks like NAND with an integrated controller
that exposes an unusual command set, but still for the most part provides the same operations. Several of our existing NAND-subsystem drivers have to fake the command set for the generic layer as well. Initialization/identification might be a problem area that current drivers don't have to deal with, though. Actually integrating OneNAND with NAND would likely involve an already-needed restructuring of the subsystem.
If the answer really is that it makes sense to consider OneNAND to be a totally different thing from NAND, then it's outside my jurisdiction as NAND custodian -- which is fine with me. Frankly, even if it does make sense to merge them, I'd rather not be custodian of the OneNAND stuff unless someone is actually willing to do the merge. I don't have access to hardware or documentation, and it's an entirely separate codebase. People just started sending me the patches a few years back.
This is not a new complaint -- I've asked for this before but nobody's put the time into sorting out the mess (and I have neither time nor hardware nor documentation). The SPL load_image function is a simple enough interface to start with, though. :-)
Well, it seems what you are proposing is way beyond the scope of this patchset.
In fact, it should probably just be spl_load_image() with whatever boot source has been configured into this SPL build.
What if you have two boot sources?
Traditionally SPL has been small and purpose-built to do exactly one thing -- so we decide at compile-time things that we might otherwise decide at runtime.
If there's a requirement for multiple boot sources decided at runtime, then we'll obviously need a runtime mechanism. -- but it seems a bit hackish to why does it matter whether it's two different types of device, or two of the same type of device (possibly with different controller types)? If the answer is that, for example, NAND versus USB versus MMC is a likely use case, but two different NANDs is not likely, is NAND versus OneNAND any more likely?
Maybe spl_load_image should be a function pointer that board code sets, with each implementation being distinctly named (in which case nand_spl_load_image would become nand_spl_simple_load_image, unless we move it to nand_spl_load.c and make nand_read_page a function pointer). If needed to save a few bytes, we could use #defines to eliminate the function pointers in a single-target SPL build.
For now, until we decide to do something SPL-wide, call it what you want.
-Scott

On 11/03/2011 07:55 PM, Marek Vasut wrote:
On 11/03/2011 04:52 PM, Marek Vasut wrote: Why do we want to separate them? What is the fundamental difference between OneNAND, and a high-level NAND controller such as fsl_elbc?
Honestly, I'm not the author of the subsystem, but please check the documentation. The way we retrieve data from onenand is different to NAND.
What documentation? How is it different? There are substantial differences in how we "retrieve data" between drivers that use the NAND subsystem. Surely you've seen that in the mxs_nand driver. :-)
Maybe there would be some differences on init if we can't produce "normal" ID data, but that doesn't justify duplicating the whole subsystem.
Where do you see such duplication? cmd_onenand ?
cmd_onenand and env_onenand are the most irritating, since they're at a layer that really shouldn't care about the differences -- we should probably have a plain "mtd" command instead, for most of the functionality.
There's also onenand_bbt.c -- what are the hardware-based differences in how the bad block table is managed?
nand_base.c/onenand_base.c are less clear. Obviously much of what is in onenand_base.c would be in the controller driver if it used the NAND subsystem. But it looks like some of it is duplication.
Why should the code that just wants to use an API to move data around need to care which it is? Why should there be behavioral differences that aren't rooted in the actual hardware? Another approach might be to use MTD as the common interface, but factor out common code into libraries that drivers can use, and avoid the main nand_base.c code even for things like fsl_elbc.
I think you're mistaken here. OneNAND != NAND.
Well, last I tried I couldn't find any public documentation, so all I have to go on is the code, some marketing-type info, and asking questions of people that appear to know more about OneNAND than I do. :-)
From what I can see, it looks like NAND with an integrated controller that exposes an unusual command set, but still for the most part provides the same operations. Several of our existing NAND-subsystem drivers have to fake the command set for the generic layer as well. Initialization/identification might be a problem area that current drivers don't have to deal with, though. Actually integrating OneNAND with NAND would likely involve an already-needed restructuring of the subsystem.
If the answer really is that it makes sense to consider OneNAND to be a totally different thing from NAND, then it's outside my jurisdiction as NAND custodian -- which is fine with me. Frankly, even if it does make sense to merge them, I'd rather not be custodian of the OneNAND stuff unless someone is actually willing to do the merge. I don't have access to hardware or documentation, and it's an entirely separate codebase. People just started sending me the patches a few years back.
This is not a new complaint -- I've asked for this before but nobody's put the time into sorting out the mess (and I have neither time nor hardware nor documentation). The SPL load_image function is a simple enough interface to start with, though. :-)
Well, it seems what you are proposing is way beyond the scope of this patchset.
In fact, it should probably just be spl_load_image() with whatever boot source has been configured into this SPL build.
What if you have two boot sources?
Traditionally SPL has been small and purpose-built to do exactly one thing -- so we decide at compile-time things that we might otherwise decide at runtime.
If there's a requirement for multiple boot sources decided at runtime, then we'll obviously need a runtime mechanism. -- but it seems a bit hackish to why does it matter whether it's two different types of device, or two of the same type of device (possibly with different controller types)? If the answer is that, for example, NAND versus USB versus MMC is a likely use case, but two different NANDs is not likely, is NAND versus OneNAND any more likely?
Maybe spl_load_image should be a function pointer that board code sets, with each implementation being distinctly named (in which case nand_spl_load_image would become nand_spl_simple_load_image, unless we move it to nand_spl_load.c and make nand_read_page a function pointer). If needed to save a few bytes, we could use #defines to eliminate the function pointers in a single-target SPL build.
For now, until we decide to do something SPL-wide, call it what you want.
Well basically from what I see, you'd like me to do the NAND/OneNAND merge. As I already said, that's way out of the scope of this patchset so I'm not doing that. Either way, are you OK with current state of the patch?
M

On 11/04/2011 03:07 PM, Marek Vasut wrote:
For now, until we decide to do something SPL-wide, call it what you want.
Well basically from what I see, you'd like me to do the NAND/OneNAND merge. As I already said, that's way out of the scope of this patchset so I'm not doing that.
Oh, I didn't mean to imply that was within the scope of this patch. I was just describing the background behind why I'm frustrated with the OneNAND situation, and this looked like an extension of the "onenand is a totally different thing" model, in an independent context.
Either way, are you OK with current state of the patch?
I won't block it.
-Scott

On 11/04/2011 03:07 PM, Marek Vasut wrote:
For now, until we decide to do something SPL-wide, call it what you want.
Well basically from what I see, you'd like me to do the NAND/OneNAND merge. As I already said, that's way out of the scope of this patchset so I'm not doing that.
Oh, I didn't mean to imply that was within the scope of this patch. I was just describing the background behind why I'm frustrated with the OneNAND situation, and this looked like an extension of the "onenand is a totally different thing" model, in an independent context.
Well I suppose this is rooted in Linux. It's different subsys there too.
Either way, are you OK with current state of the patch?
I won't block it.
That's what I meant.
-Scott

On 11/04/2011 03:07 PM, Marek Vasut wrote:
For now, until we decide to do something SPL-wide, call it what you want.
Well basically from what I see, you'd like me to do the NAND/OneNAND merge. As I already said, that's way out of the scope of this patchset so I'm not doing that.
Oh, I didn't mean to imply that was within the scope of this patch. I was just describing the background behind why I'm frustrated with the OneNAND situation, and this looked like an extension of the "onenand is a totally different thing" model, in an independent context.
Either way, are you OK with current state of the patch?
I won't block it.
-Scott
Ok, I'll queue this patchset and submit to Albert when I re-add the PXA250 support to start.S (done already, but I need to test it).
participants (4)
-
Kyungmin Park
-
Marek Vasut
-
Scott Wood
-
Stefan Herbrechtsmeier