*同上篇,还是针对遇到的问题简要先记录下,以后有空再补全。
一、工程建立
工程目标板 友善 sbc2410x
由于工程中已有sbc2410x的内容。所以先要删除一部分。
删除include/configs/sbc2410x.h
删除board/sbc2410x整个目录
修改顶层boards.cfg
CPU项由arm920t改为s3c2410x。u-boot的初忠是希望尽可能的通用。但带来的坏处是无用代码很多,需要定义很多条件,实际结果是可读性很差,特别是CPU相关的汇编代码部分。所以这里使用arm920t的部分文件+arm920t中s3c24x0的SoC中的文件,在arch/arm/cpu/重新建立一个s3c2410x的CPU,以专一针对s3c2410x组织CPU相关的代码,以方便阅读和分析。
建立 arch/arm/cpu/s3c2410x
拷贝 arch/arm/cpu/arm920t/
start.S
cpu.c
config.mk
Makefile
u-boot.lds
拷贝 arch/arm/cpu/arm920t/s3c24x0/
interrupts.c
speed.c
timer.c
usb.c
usb_ohci.c
usb_ohci.h
修改 arch/arm/cpu/s3c2410x/Makefile
在COBJS-y += cpu.o下面增加
COBJS-y += cpu.o
COBJS-y += speed.o
COBJS-y += timer.o
COBJS-y += usb.o
COBJS-y += usb_ohci.o
在board目录中建立sbc2410x目录
并将board/samsung/smdk2410/的所有文件拷贝到该目录
重命名smdk2410.c 为 sbc2410x.c 并修改Makefile中的smdk2410.o 为 sbc2410x.o
拷贝一份 arch/arm/cpu/arm920t/u-boot.lds到该目录,以修改链接脚本使支持nand启动使用
修改board/sbc2410x/中的config.mk 在末尾增加一句
LDSCRIPT=$(SRCTREE)/board/sbc2410x/u-boot.lds
这样,根目录的链接脚本文件会从board/sbc2410x/u-boot.lds复制。
在include/configs/将smdk2410.h拷贝一份为sbc2410x.h
至此,在主目录中执行
make sbc2410x_config
make
应该可以生成一个u-boot.bin
该u-boot.bin和smdk2410的完全一样。
二、基于smdk2410对sbc2410x的汇编级修改
目标:简化代码,并且从NAND引导,将u-boot复制到RAM中运行。
原理:当从NAND启动时,S3C2410X会将NAND FLASH中的前4K内容复制到片内的4K SRAM中。该4K SRAM在NAND启动时会被映射到0x0。CPU自动复制后会将PC转至0x0处开始执行。则对于CPU的设置,DRAM的设置,NAND控制器的初始化,代码搬运就必须都在这前4K代码中完成。ARM指令为32位字指令,即,4字节一个指令。编译后必须将arch/arm/cpu/s3c2410x/start.s和board/sbc2410x/lowlevel_init.s的编译后指令控制在1024条以内(4K/4) 。
首先修改board/sbc2410x/u-boot.lds,以使链接两个汇编文件在前面部分。压缩代码,以使之在4K之内。
u-boot.lds修改为:
SECTIONS
{
. = 0x00000000; . = ALIGN(4);
.text :
{
arch/arm/cpu/s3c2410x/start.o (.text)
board/sbc2410x/lowlevel_init.o (.text) //这行是加入的
*(.text)
} ......
*这里有一说明,由汇编代码生成的目标文件,不会含有bss rodata等段,完全是text段。
精简和修改arch/arm/cpu/s3c2410x/start.S
/*
* armboot - Startup Code for SAMSUNG S3C2410X ARM920T SoC Chipest
* 2010.11.19 Lianxp Modified from smdk2410's arm920t start.S
*/
#include <common.h>
#include <config.h>
/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/
.globl _start
_start: b start_code
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: b .
_software_interrupt: b .
_prefetch_abort: b .
_data_abort: b .
_not_used: b .
_irq: b .
_fiq: b .
.balignl 16,0xdeadbeef
/*
*************************************************************************
*
* Startup Code (called from the ARM reset exception vector)
*
* do important init only if we don't start from memory!
* relocate armboot to ram
* setup stack
* jump to second stage
*
*************************************************************************
*/
_TEXT_BASE:
.word TEXT_BASE
.globl _armboot_start
_armboot_start:
.word _start
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
/*
* the actual start code
*/
start_code:
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
/* turn off the watchdog */
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
bl cpu_init_crit
bl relocate
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */
sub sp, r0, #12 /* leave 3 words for abort-stack */
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
ldr pc, _start_armboot
_start_armboot: .word start_armboot
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
cpu_init_crit:
/*
* flush v4 I/D caches
*/
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
/*
* 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
/*
* before relocating, we have to setup RAM timing
* because memory timing is board-dependend, you will
* find a lowlevel_init.S in your board directory.
*/
mov ip, lr
bl lowlevel_init
mov lr, ip
mov pc, lr
主要是去掉和本处理器无关的代码,去掉中断响应代码(u-boot在s3c2410中不用中断),去掉从nor flash搬运代码的部分。
增加一个子程序调用,从lowlevel_init.s中调用relocate,以使从nand flash中将指令码搬运到内存执行。
修改 board/sbc2410x/lowlevel_init.s
/*
* Modified from u-boot-2010.09 smdk2410's lowlevel_init.S
* By Lianxp
*/
#include <config.h>
#include <version.h>
/* CPU Clock Set To 200Mhz*/
_TEXT_BASE:
.word TEXT_BASE
.globl lowlevel_init
lowlevel_init:
/* @FCLK:HCLK:PCLK 1:2:4*/
#define MPLLCON 0x4C000004
#define MPLLCON_MDIV 0x5c
#define MPLLCON_PDIV 0x04
#define MPLLCON_SDIV 0x0
CLKSET: ldr r0, =MPLLCON
ldr r1, =((MPLLCON_MDIV<<12)+(MPLLCON_PDIV<<4)+MPLLCON_SDIV)
str r1, [r0]
/* some parameters for the board */
/* Memory Block Set */
#define BWSCON 0x48000000
/* BWSCON */
#define DW8 (0x0) /* 00 */
#define DW16 (0x1) /* 01 */
#define DW32 (0x2) /* 10 */
#define WAIT (0x1<<2)
#define UBLB (0x1<<3)
#define B1_BWSCON (DW32)
#define B2_BWSCON (DW16)
#define B3_BWSCON (DW16 + WAIT + UBLB)
#define B4_BWSCON (DW16)
#define B5_BWSCON (DW16)
#define B6_BWSCON (DW32)
#define B7_BWSCON (DW32)
/* BANK0CON */
#define B0_Tacs 0x0 /* 0clk */
#define B0_Tcos 0x0 /* 0clk */
#define B0_Tacc 0x7 /* 14clk */
#define B0_Tcoh 0x0 /* 0clk */
#define B0_Tah 0x0 /* 0clk */
#define B0_Tacp 0x0
#define B0_PMC 0x0 /* normal */
/* BANK1CON */
#define B1_Tacs 0x0 /* 0clk */
#define B1_Tcos 0x0 /* 0clk */
#define B1_Tacc 0x7 /* 14clk */
#define B1_Tcoh 0x0 /* 0clk */
#define B1_Tah 0x0 /* 0clk */
#define B1_Tacp 0x0
#define B1_PMC 0x0
#define B2_Tacs 0x0
#define B2_Tcos 0x0
#define B2_Tacc 0x7
#define B2_Tcoh 0x0
#define B2_Tah 0x0
#define B2_Tacp 0x0
#define B2_PMC 0x0
#define B3_Tacs 0x0 /* 0clk */
#define B3_Tcos 0x3 /* 4clk */
#define B3_Tacc 0x7 /* 14clk */
#define B3_Tcoh 0x1 /* 1clk */
#define B3_Tah 0x0 /* 0clk */
#define B3_Tacp 0x3 /* 6clk */
#define B3_PMC 0x0 /* normal */
#define B4_Tacs 0x0 /* 0clk */
#define B4_Tcos 0x0 /* 0clk */
#define B4_Tacc 0x7 /* 14clk */
#define B4_Tcoh 0x0 /* 0clk */
#define B4_Tah 0x0 /* 0clk */
#define B4_Tacp 0x0
#define B4_PMC 0x0 /* normal */
#define B5_Tacs 0x0 /* 0clk */
#define B5_Tcos 0x0 /* 0clk */
#define B5_Tacc 0x7 /* 14clk */
#define B5_Tcoh 0x0 /* 0clk */
#define B5_Tah 0x0 /* 0clk */
#define B5_Tacp 0x0
#define B5_PMC 0x0 /* normal */
#define B6_MT 0x3 /* SDRAM */
#define B6_Trcd 0x1
#define B6_SCAN 0x1 /* 9bit */
#define B7_MT 0x3 /* SDRAM */
#define B7_Trcd 0x1 /* 3clk */
#define B7_SCAN 0x1 /* 9bit */
/* REFRESH parameter */
#define REFEN 0x1 /* Refresh enable */
#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */
#define Trp 0x0 /* 2clk */
#define Trc 0x3 /* 7clk */
#define Tchr 0x2 /* 3clk */
#define REFCNT 1113 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */
/**************************************/
/* memory control configuration */
/* make r0 relative the current location so that it */
/* reads SMRDATA out of FLASH rather than memory ! */
MEMSET: ldr r0, =SMRDATA
ldr r1, _TEXT_BASE
sub r0, r0, r1
ldr r1, =BWSCON /* Bus Width Status Controller */
add r2, r0, #13*4
0:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne 0b
/* everything is fine now */
mov pc, lr
.ltorg
/* the literal pools origin */
SMRDATA:
.word ((1<<1)+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
.word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
.word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
.word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
.word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
.word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
.word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
.word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word 0xB1
.word 0x30
.word 0x30
.globl relocate
relocate:
#define NFCONF 0x4E000000
mov ip, lr
mov r5, #NFCONF
ldr r0, =(1<<15)|(1<<12)|(1<<11)|(7<<8)|(7<<4)|(7)
str r0, [r5]
mov r8, #0
ldr r9, _TEXT_BASE
x3: mov r0, r8
mov r1, r9
bl ReadNandPage
add r9, r9, #512 //add a page size to ram addr per time
add r8, r8, #1
x4: cmp r8, #256
bcc x3
mov r5, #NFCONF
ldr r0, [r5]
and r0, r0, #~0x8000
str r0, [r5]
mov pc, ip
.ltorg
WaitNandBusy:
mov r1,#NFCONF
ldrb r0,[r1,#0x10]
//and r0,r0,#1
tst r0,#0x1
beq WaitNandBusy
mov pc,lr
.ltorg
ReadNandPage:
mov r7,lr
mov r4,r1
mov r5,#NFCONF
ldr r1,[r5,#0] //NFChipEn()
bic r1,r1,#0x800
str r1,[r5,#0]
mov r1,#0xff
strb r1,[r5,#4]
mov r6,r0
bl WaitNandBusy
mov r0,r6
mov r1,#0 //WrNFCmd(READCMD0)
strb r1,[r5,#4]
strb r1,[r5,#8] //WrNFAddr(0) a0-a7
strb r0,[r5,#8] //WrNFAddr(addr) a9-a16
mov r1,r0,lsr #8 //r1 <- (addr>>8)
strb r1,[r5,#8] //WrNFAddr(addr) a17-a24
mov r1,r0,lsr #16 //r1 <- (addr>>16)
and r1,r1,#1 //mask a26+
strb r1,[r5,#8] //WrNFAddr(addr) a25
bl WaitNandBusy //WaitNFBusy()
mov r0,#0 //for(i=0; i<512; i++)
r1:
ldrb r1,[r5,#0xc] //buf[i] = RdNFDat()
strb r1,[r4,r0] //write buf[i] to ram
add r0,r0,#1
bic r0,r0,#0x10000
cmp r0,#0x200
bcc r1
ldr r0,[r5,#0] //NFChipDs()
orr r0,r0,#0x800
str r0,[r5,#0]
mov pc,r7
.ltorg
.balignl 16,0xdeadbeef
修改对MPLL的初始化代码,以使主频运行在200M上。修改SDRAM的参数以使可以支持本板的SDRAM运行。这里面有一个设计比较巧妙的地方:该代码的链接地址为0x33f80000,所以SMRDATA的地址在链接后就为0x33f80000+偏移量。而初始化时,代码是在0x0为基地址的4K SRAM中执行的。这样,在代码搬运前SMRDATA实际并不在0x33f80000+偏移量的位置上。所以,这里引入TEXT_BASE,并用编译得到的SMRDATA地址去减基地址TEXT_BASE,得到的恰恰是开始运行的0x33f80000的偏移量,也正是从0x0处计算的实际地址。
这段代码搬运的代码写的还比较粗,只适用于K9F1208U0M以及指令兼容的片子。代码中没有进行坏块处理和识别,最大只读取256页,即128K字节的内容。
对于其中的一些内容进行一点说明
1)在进入relocate:之后,执行mov ip,lr是为了保护返回地址。因为在后面还有大量的子程序调用。
2)在整体搬运过程中,r8属于一个局部的全局变量,用于记录当前在搬运的页地址 0~256
r9也是一个局部的全局变量,用于记录内存中的偏移位置 0x33f80000~0x33f80000+128K
3)对于NAND FLASH控制器,每当将需要执行的指令以及地址输入到相应寄存器后,都要轮询NFSTAT寄存器,直到寄存器状态为READY后才能进行数据读取/写入或其他指令操作。一开始,由于没有注意到这一点,从NAND中读出的不是00就是FF,要不就是乱数据。
4)NAND FLASH在使用00/01指令进行读取数据的时候,其实可以连续的读取后面的数据,后面的数据不光是本页的,还有下一页的数据。包据A段,B段,以及用于校验的C段。由于计算不便,所以本程序每次都重新输入读指令和页地址。
5)readpage子程序中的 r0->r6 ... r6->r0 属于设计失误,临时保存一下r0的状态。
至此,编译生成的u-boot.bin可以烧入2410的nand flash,启动u-boot了。
三、u-boot提供了另一种nand启动的方法。
即在nand_spl中的方式。
大体思路是这样的:写一段较小的可以放入stepping stone中的程序,这段程序用于初始化CPU,初始化RAM,并将NAND FLASH指定位置的指定大小的内容搬到内存中的指定位置,然后跳转到这个内存的指定位置执行后面的代码。
编译后,指定这个小程序的代码尺寸。编译U-boot,生成u-boot.bin 再通过
cat loader.bin u-boot.bin > u-boot-nand.bin
将文件合并成一个文件。烧入NAND中。
这样,当从0x0执行时,首先载入loader那段小程序,将后面的u-boot.bin搬入RAM,然后跳到RAM执行。
这样做的好处是将u-boot系统又进行了一次拆分,以使可读性和可修改性得到更大的提高。
这种方法实现起来并不复杂,只是看懂了模式,等后面有时间的时候实践一下。