从零开始进行官方uboot移植到x210(cpu:s5pv210)
@从零开始进行官方uboot移植到x210(cpu:s5pv210)
以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除
前言
在前面进行了一系列对于uboot中各个文件夹,还有各个文件中参数的设置,在此进行零基础从零开始对uboot进行移植
一、前期准备
1.在官网下载了一个全新的uboot后,解压得到
2.由于一个uboot中适配了很多其他开发板,我们需要对其他无关的内容进行删除,这里得先从中找到我们的cpu,并且把其他无关的给删除了
在删除了除了arm架构以外的文件夹后,我们需要进入arm,发现里面很多对应于arm不同的架构,因此我们得判断我们使用的cpu是具体属于什么架构的,我们在mkconfig脚本中会创建很多符号链接,通过这些符号链接去寻找对应的文件目录,我们之前的makefile中就有对这里直接进行配置,但是我们现在换了,将这个makefile中配置的文件进行分离,组成了boards.cfg文件,所以我们可以去这个文件找到我们的cpu对应的架构,我们的想移植的是s5p_goni,因此这里我们的具体架构是armv7,因此可以把arm文件夹中其他无关的给删了
在进入armv7后发现了很多其他不同的cpu,所以我们进行也把其他无关的给删除了
返回上级目录中,include目录底下也有许多无关的文件,除了我们要的其他也一并删除
3.除了把cpu无关的一并删除外,还需要对其他无关板子进行删除,但是由于uboot官方没有对我们使用的x210进行单独的适配,所以我们以相似度比较高的s5p_goni进行移植,因此删除除了s5_goni外的板子文件夹
4.最后通过sourceinsight,将剩下的所有文件一并读取到这里面的新工程中,可以发现,由于我们删除了其他无关的,所以这里我们找文件方便了许多,少了很多其他板子重复的函数文件
5.在主目录include下的config配置文件中,删除与我们板子无关的配置文件
二、移植前分析
1.Makefile与mkconfig脚本分析
Makefile中给mkconfig脚本传参$1= -A ,$2 = $(@:_config=)
%_config:: unconfig //这里的%是万能匹配符,我们到时候在命令行中输入make xxx_config后,会被下面的$(@:_config=)引用
@$(MKCONFIG) -A $(@:_config=) //这里传参$(@:_config=)实际上传的是xxx,后面的_config被替换了
mkconfig脚本中,先对boards.cfg进行进行解析,通过$2去到boards.cfg中对进行查找到对应的开发板,这里$2便是s5p_goni
if [ \( $# -eq 2 \) -a \( "$1" = "-A" \) ] ; then
# Automatic mode
line=`awk '($0 !~ /^#/ && $7 ~ /^'"$2"'$/) { print $1, $2, $3, $4, $5, $6, $7, $8 }' boards.cfg`
if [ -z "$line" ] ; then
echo "make: *** No rule to make target \`$2_config'. Stop." >&2
exit 1
fi
set ${line}
# add default board name if needed
[ $# = 3 ] && set ${line} ${1}
fi
解析完上面后,会在mkconfig脚本中对我们我们的S$1-$8重新进行赋值
我们在linux底下命令行中,对整个uboot进行配置make s5_goni_config,后会输出什么就是在mkconfig脚本下面代码实现的
if [ "$options" ] ; then
echo "Configuring for ${BOARD_NAME} - Board: ${CONFIG_NAME}, Options: ${options}"
else
echo "Configuring for ${BOARD_NAME} board..."//显然我们实现的是这里
fi
mkconfig脚本中还创建了许多符号链接
if [ "$SRCTREE" != "$OBJTREE" ] ; then //这里判断的是我们实现的是否为静默编译
mkdir -p ${OBJTREE}/include
mkdir -p ${OBJTREE}/include2
cd ${OBJTREE}/include2
rm -f asm
ln -s ${SRCTREE}/arch/${arch}/include/asm asm
LNPREFIX=${SRCTREE}/arch/${arch}/include/asm/
cd ../include
mkdir -p asm
else //我们在主目录(进入uboot后的第一个目录)下的include目录中,创建一个符号链接,这个符号
cd ./include //这个符号链接指向了我们的主目录/arch/arm/include/asm
rm -f asm
ln -s ../arch/${arch}/include/asm asm
fi
这里举例创建的符号的链接,这些符号链接只有在配置时,才会生成
最后创建一个config.h文件
# Create board specific header file
#
if [ "$APPEND" = "yes" ] # Append to existing config file
then
echo >> config.h
else
> config.h # Create new config file
fi
echo "/* Automatically generated - do not edit */" >>config.h
for i in ${TARGETS} ; do
i="`echo ${i} | sed '/=/ {s/=/ /;q; } ; { s/$/ 1/; }'`"
echo "#define CONFIG_${i}" >>config.h ;
done
echo "#define CONFIG_SYS_ARCH \"${arch}\"" >> config.h
echo "#define CONFIG_SYS_CPU \"${cpu}\"" >> config.h
echo "#define CONFIG_SYS_BOARD \"${board}\"" >> config.h
[ "${vendor}" ] && echo "#define CONFIG_SYS_VENDOR \"${vendor}\"" >> config.h
[ "${soc}" ] && echo "#define CONFIG_SYS_SOC \"${soc}\"" >> config.h
生成的config.h在主目录的include中,里面的内容也是由上面代码生成的,分别定义一些宏还有头文件的包含,在以后的很多文件中都可以看到这些
从这里开始我们就可以进行
make distclean
make s5p_goni_config
make
来产生u-boot.bin文件
sd_fusing分析
echo "BL1 fusing"
./mkbl1 ../u-boot.bin SD-bl1-8k.bin 8192 //执行mkbl1,这将我们上面生成的
dd iflag=dsync oflag=dsync if=SD-bl1-8k.bin of=$1 seek=$bl1_position //u-boot.bin,截取8192字节(8k)
rm SD-bl1-8k.bin //生成SD-bl1-8k.bin文件
而我们的这个mkbl1是由sd_fusing中C110-EVT1-mkbl1.c文件生成的,这个文件会计算校验和(16字节)并且填充到我们的uboot中去,所以我们在start.S中需要在最开始定义出16字节占位,然后面的有关uboot内容能够往后挪一下,这样才可以使得我们的校验和成功通过
在start.S中添加16字节进行占位
2.start.S分析
#include <asm-offsets.h>
#include <config.h>
#include <version.h>
#include <asm/system.h>
#include <linux/linkage.h>
.globl _start
.word 0x2000 //前面说的16字节占位
.word 0x0
.word 0x0
.word 0x0
_start: b reset //异常向量表
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
#ifdef CONFIG_SPL_BUILD
_undefined_instruction: .word _undefined_instruction
_software_interrupt: .word _software_interrupt
_prefetch_abort: .word _prefetch_abort
_data_abort: .word _data_abort
_not_used: .word _not_used
_irq: .word _irq
_fiq: .word _fiq
_pad: .word 0x12345678 /* now 16*4=64 */
#else
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_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 //16字节对齐
*************************************************************************
.globl _TEXT_BASE //这个函数里面定义了CONFIG_SPL_TEXT_BASE这个宏定义,这个宏定义定义了我们uboot的
_TEXT_BASE: //链接地址
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
.word CONFIG_SPL_TEXT_BASE
#else
.word CONFIG_SYS_TEXT_BASE
#endif
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start_ofs //这里是一堆符号的声明
_bss_start_ofs:
.word __bss_start - _start
.globl _bss_end_ofs
_bss_end_ofs:
.word __bss_end - _start
.globl _end_ofs
_end_ofs:
.word _end - _start
#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
/* IRQ stack memory (calculated at run-time) + 8 bytes */
.globl IRQ_STACK_START_IN
IRQ_STACK_START_IN:
.word 0x0badc0de
/*
* the actual reset code //真正的复位代码,我们复位后执行的就是这里的代码
*/
reset:
bl save_boot_params //这里调用了stars.S中的一个空函数,没什么用,留给我们自行添加
/*
* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
* except if in HYP mode already
*/
mrs r0, cpsr //这里设置cpu为svc模式,禁止fiq和irq
and r1, r0, #0x1f @ mask mode bits
teq r1, #0x1a @ test for HYP mode
bicne r0, r0, #0x1f @ clear all mode bits
orrne r0, r0, #0x13 @ set SVC mode
orr r0, r0, #0xc0 @ disable FIQ and IRQ
msr cpsr,r0
/*
* Setup vector://与我们开发板无关,不用搭理
* (OMAP4 spl TEXT_BASE is not 32 byte aligned.
* Continue to use ROM code vector only in OMAP4 spl)
*/
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
/* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */
mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTRL Register
bic r0, #CR_V @ V = 0
mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTRL Register
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
#endif
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT //这两个函数的定义也在start.S函数中,函数1设置,mmu和cache
bl cpu_init_cp15 //这个uboot不用mmu,这里直接禁止,后面也不会用到
bl cpu_init_crit //函数2跳转到了lowlevel.init函数,这个函数存在于
#endif //board/samsung/goni中,不在arch/arm/cpu/armv7中
//这个判断可以在两个文件夹中的makefile中看有没有包含
//或者可以查看的编译出的这两个文件夹中,有没有编译出.o文件
//函数2实现的是时钟设置、串口设置、复位状态,是s5pc100和
s5pc110公用的,这个函数在lowlevel_init.S中,实现:关看门狗、
初始化串口,有定义了时钟初始化函数但是没有用,因为irom中已经对
时钟进行了初始化,这里便没有再次使用
bl _main //这个函数在arch/arm/lib/crt0.S中
------------------------------------------------------------------------------
ENTRY(c_runtime_cpu_setup)
/*
* If I-cache is enabled invalidate it
*/
#ifndef CONFIG_SYS_ICACHE_OFF
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
mcr p15, 0, r0, c7, c10, 4 @ DSB
mcr p15, 0, r0, c7, c5, 4 @ ISB
#endif
/*
* Move vector table
*/
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
bx lr
ENDPROC(c_runtime_cpu_setup)
ENTRY(save_boot_params)
bx lr @ back to my caller
ENDPROC(save_boot_params)
.weak save_boot_params
/*************************************************************************
*
* cpu_init_cp15
*
* Setup CP15 registers (cache, MMU, TLBs). The I-cache is turned on unless
* CONFIG_SYS_ICACHE_OFF is defined.
*
*************************************************************************/
ENTRY(cpu_init_cp15)
/*
* Invalidate L1 I/D
*/
mov r0, #0 @ set up for MCR
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array
mcr p15, 0, r0, c7, c10, 4 @ DSB
mcr p15, 0, r0, c7, c5, 4 @ ISB
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
#ifdef CONFIG_SYS_ICACHE_OFF
bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache
#else
orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache
#endif
mcr p15, 0, r0, c1, c0, 0
#ifdef CONFIG_ARM_ERRATA_716044
mrc p15, 0, r0, c1, c0, 0 @ read system control register
orr r0, r0, #1 << 11 @ set bit #11
mcr p15, 0, r0, c1, c0, 0 @ write system control register
#endif
#ifdef CONFIG_ARM_ERRATA_742230
mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register
orr r0, r0, #1 << 4 @ set bit #4
mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register
#endif
#ifdef CONFIG_ARM_ERRATA_743622
mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register
orr r0, r0, #1 << 6 @ set bit #6
mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register
#endif
#ifdef CONFIG_ARM_ERRATA_751472
mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register
orr r0, r0, #1 << 11 @ set bit #11
mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register
#endif
mov pc, lr @ back to my caller
ENDPROC(cpu_init_cp15)
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
/*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************/
ENTRY(cpu_init_crit)
/*
* Jump to board specific initialization...
* The Mask ROM will have already initialized
* basic memory. Go here to bump up clock rate and handle
* wake up conditions.
*/
b lowlevel_init @ go setup pll,mux,memory //这里就跳转到了lowlevel_init.S文件中,在里面进行初
//始化,所以这里相当于uboot第一阶段的入口
ENDPROC(cpu_init_crit)
#endif
#ifndef CONFIG_SPL_BUILD
/*
*************************************************************************
*
* Interrupt handling
*
*************************************************************************
*/
@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72
#define S_OLD_R0 68
#define S_PSR 64
#define S_PC 60
#define S_LR 56
#define S_SP 52
#define S_IP 48
#define S_FP 44
#define S_R10 40
#define S_R9 36
#define S_R8 32
#define S_R7 28
#define S_R6 24
#define S_R5 20
#define S_R4 16
#define S_R3 12
#define S_R2 8
#define S_R1 4
#define S_R0 0
#define MODE_SVC 0x13
#define I_BIT 0x80
/*
* 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 @ 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 @ 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 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
mov r0, sp @ save current stack into r0
@ (param register)
.endm
.macro irq_save_user_regs
sub sp, sp, #S_FRAME_SIZE
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
mov r0, sp
.endm
.macro irq_restore_user_regs
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
mov r0, r0
ldr lr, [sp, #S_PC] @ Get PC
add sp, sp, #S_FRAME_SIZE
subs pc, lr, #4 @ return & move spsr_svc into
@ cpsr
.endm
.macro get_bad_stack
ldr r13, IRQ_STACK_START_IN @ setup our mode stack (enter
@ in banked mode)
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
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
@ spots for abort stack
str lr, [r0] @ save caller lr in position 0
@ of saved stack
mrs lr, spsr @ get the spsr
str lr, [r0, #4] @ save spsr in position 1 of
@ saved stack
ldr lr, [r0] @ restore lr
ldr r0, [r13] @ restore r0
add r13, r13, #4 @ pop stack entry
.endm
.macro get_irq_stack @ setup IRQ stack
ldr sp, IRQ_STACK_START
.endm
.macro get_fiq_stack @ setup FIQ stack
ldr sp, FIQ_STACK_START
.endm
/*
* exception handlers
*/
.align 5
undefined_instruction:
get_bad_stack
bad_save_user_regs
bl do_undefined_instruction
.align 5
software_interrupt:
get_bad_stack_swi
bad_save_user_regs
bl do_software_interrupt
.align 5
prefetch_abort:
get_bad_stack
bad_save_user_regs
bl do_prefetch_abort
.align 5
data_abort:
get_bad_stack
bad_save_user_regs
bl do_data_abort
.align 5
not_used:
get_bad_stack
bad_save_user_regs
bl do_not_used
#ifdef CONFIG_USE_IRQ
.align 5
irq:
get_irq_stack
irq_save_user_regs
bl do_irq
irq_restore_user_regs
.align 5
fiq:
get_fiq_stack
/* someone ought to write a more effective fiq_save_user_regs */
irq_save_user_regs
bl do_fiq
irq_restore_user_regs
#else
.align 5
irq:
get_bad_stack
bad_save_user_regs
bl do_irq
.align 5
fiq:
get_bad_stack
bad_save_user_regs
bl do_fiq
#endif /* CONFIG_USE_IRQ */
#endif /* CONFIG_SPL_BUILD */
3.lowlevel_init.S文件分析
.globl lowlevel_init
lowlevel_init:
mov r11, lr
/* r5 has always zero */
mov r5, #0
ldr r7, =S5PC100_GPIO_BASE
ldr r8, =S5PC100_GPIO_BASE
/* Read CPU ID */
ldr r2, =S5PC110_PRO_ID
ldr r0, [r2]
mov r1, #0x00010000
and r0, r0, r1
cmp r0, r5
beq 100f
ldr r8, =S5PC110_GPIO_BASE
100:
/* Turn on KEY_LED_ON [GPJ4(1)] XMSMWEN */
cmp r7, r8
beq skip_check_didle @ Support C110 only
ldr r0, =S5PC110_RST_STAT
ldr r1, [r0]
and r1, r1, #0x000D0000
cmp r1, #(0x1 << 19) @ DEEPIDLE_WAKEUP
beq didle_wakeup
cmp r7, r8
skip_check_didle:
addeq r0, r8, #0x280 @ S5PC100_GPIO_J4
addne r0, r8, #0x2C0 @ S5PC110_GPIO_J4
ldr r1, [r0, #0x0] @ GPIO_CON_OFFSET
bic r1, r1, #(0xf << 4) @ 1 * 4-bit
orr r1, r1, #(0x1 << 4)
str r1, [r0, #0x0] @ GPIO_CON_OFFSET
ldr r1, [r0, #0x4] @ GPIO_DAT_OFFSET
bic r1, r1, #(1 << 1)
str r1, [r0, #0x4] @ GPIO_DAT_OFFSET
beq 100f
/*
* Initialize Async Register Setting for EVT1
* Because we are setting EVT1 as the default value of EVT0,
* setting EVT0 as well does not make things worse.
* Thus, for the simplicity, we set for EVT0, too
*
* The "Async Registers" are:
* 0xE0F0_0000
* 0xE1F0_0000
* 0xF180_0000
* 0xF190_0000
* 0xF1A0_0000
* 0xF1B0_0000
* 0xF1C0_0000
* 0xF1D0_0000
* 0xF1E0_0000
* 0xF1F0_0000
* 0xFAF0_0000
*/
ldr r0, =0xe0f00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xe1f00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1800000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1900000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1a00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1b00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1c00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1d00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1e00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1f00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xfaf00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
/*
* Diable ABB block to reduce sleep current at low temperature
* Note that it's hidden register setup don't modify it
*/
ldr r0, =0xE010C300
ldr r1, =0x00800000
str r1, [r0]
100:
/* IO retension release */
ldreq r0, =S5PC100_OTHERS @ 0xE0108200
ldrne r0, =S5PC110_OTHERS @ 0xE010E000
ldr r1, [r0]
ldreq r2, =(1 << 31) @ IO_RET_REL
ldrne r2, =((1 << 31) | (1 << 30) | (1 << 29) | (1 << 28))
orr r1, r1, r2
/* Do not release retention here for S5PC110 */
streq r1, [r0]
/* Disable Watchdog */ //关看门狗
ldreq r0, =S5PC100_WATCHDOG_BASE @ 0xEA200000
ldrne r0, =S5PC110_WATCHDOG_BASE @ 0xE2700000
str r5, [r0]
ldr r0, =0xE010E81C //我们自己添加的开发板置锁
ldr r1, =0x301
str r1, [r0]
/* setting SRAM */
ldreq r0, =S5PC100_SROMC_BASE
ldrne r0, =S5PC110_SROMC_BASE
ldr r1, =0x9
str r1, [r0]
/* S5PC100 has 3 groups of interrupt sources */
ldreq r0, =S5PC100_VIC0_BASE @ 0xE4000000
ldrne r0, =S5PC110_VIC0_BASE @ 0xF2000000
add r1, r0, #0x00100000
add r2, r0, #0x00200000
/* Disable all interrupts (VIC0, VIC1 and VIC2) */
mvn r3, #0x0
str r3, [r0, #0x14] @ INTENCLEAR
str r3, [r1, #0x14] @ INTENCLEAR
str r3, [r2, #0x14] @ INTENCLEAR
/* Set all interrupts as IRQ */
str r5, [r0, #0xc] @ INTSELECT
str r5, [r1, #0xc] @ INTSELECT
str r5, [r2, #0xc] @ INTSELECT
/* Pending Interrupt Clear */
str r5, [r0, #0xf00] @ INTADDRESS
str r5, [r1, #0xf00] @ INTADDRESS
str r5, [r2, #0xf00] @ INTADDRESS
/* for UART */
bl uart_asm_init //这里我们只初始化了串口的GPIO,没初始化寄存器,但是我们到这里还能
输出的原因就是我们的irom中已经帮我们进行了初始化,所以我们才可以成
功输出,事实上就算这里我们没有进行初始化依旧可以实现串口的输出
bl internal_ram_init
cmp r7, r8
/* Clear wakeup status register */
ldreq r0, =S5PC100_WAKEUP_STAT
ldrne r0, =S5PC110_WAKEUP_STAT
ldr r1, [r0]
str r1, [r0]
/* IO retension release */
ldreq r0, =S5PC100_OTHERS @ 0xE0108200
ldrne r0, =S5PC110_OTHERS @ 0xE010E000
ldr r1, [r0]
ldreq r2, =(1 << 31) @ IO_RET_REL
ldrne r2, =((1 << 31) | (1 << 30) | (1 << 29) | (1 << 28))
orr r1, r1, r2
str r1, [r0]
b 1f
didle_wakeup:
/* Wait when APLL is locked */
ldr r0, =0xE0100100 @ S5PC110_APLL_CON
lockloop:
ldr r1, [r0]
and r1, r1, #(1 << 29)
cmp r1, #(1 << 29)
bne lockloop
ldr r0, =S5PC110_INFORM0
ldr r1, [r0]
mov pc, r1
nop
nop
nop
nop
nop
1:
mov lr, r11
mov pc, lr
/*
* system_clock_init: Initialize core clock and bus clock.
* void system_clock_init(void)
*/
system_clock_init:
ldr r0, =S5PC110_CLOCK_BASE @ 0xE0100000
/* Check S5PC100 */
cmp r7, r8
bne 110f
100:
/* Set Lock Time */
ldr r1, =0xe10 @ Locktime : 0xe10 = 3600
str r1, [r0, #0x000] @ S5PC100_APLL_LOCK
str r1, [r0, #0x004] @ S5PC100_MPLL_LOCK
str r1, [r0, #0x008] @ S5PC100_EPLL_LOCK
str r1, [r0, #0x00C] @ S5PC100_HPLL_LOCK
/* S5P_APLL_CON */
ldr r1, =0x81bc0400 @ SDIV 0, PDIV 4, MDIV 444 (1333MHz)
str r1, [r0, #0x100]
/* S5P_MPLL_CON */
ldr r1, =0x80590201 @ SDIV 1, PDIV 2, MDIV 89 (267MHz)
str r1, [r0, #0x104]
/* S5P_EPLL_CON */
ldr r1, =0x80870303 @ SDIV 3, PDIV 3, MDIV 135 (67.5MHz)
str r1, [r0, #0x108]
/* S5P_HPLL_CON */
ldr r1, =0x80600603 @ SDIV 3, PDIV 6, MDIV 96
str r1, [r0, #0x10C]
ldr r1, [r0, #0x300]
ldr r2, =0x00003fff
bic r1, r1, r2
ldr r2, =0x00011301
orr r1, r1, r2
str r1, [r0, #0x300]
ldr r1, [r0, #0x304]
ldr r2, =0x00011110
orr r1, r1, r2
str r1, [r0, #0x304]
ldr r1, =0x00000001
str r1, [r0, #0x308]
/* Set Source Clock */
ldr r1, =0x00001111 @ A, M, E, HPLL Muxing
str r1, [r0, #0x200] @ S5PC1XX_CLK_SRC0
b 200f
110:
ldr r0, =0xE010C000 @ S5PC110_PWR_CFG
/* Set OSC_FREQ value */
ldr r1, =0xf
str r1, [r0, #0x100] @ S5PC110_OSC_FREQ
/* Set MTC_STABLE value */
ldr r1, =0xffffffff
str r1, [r0, #0x110] @ S5PC110_MTC_STABLE
/* Set CLAMP_STABLE value */
ldr r1, =0x3ff03ff
str r1, [r0, #0x114] @ S5PC110_CLAMP_STABLE
ldr r0, =S5PC110_CLOCK_BASE @ 0xE0100000
/* Set Clock divider */
ldr r1, =0x14131330 @ 1:1:4:4, 1:4:5
str r1, [r0, #0x300]
ldr r1, =0x11110111 @ UART[3210]: MMC[3210]
str r1, [r0, #0x310]
/* Set Lock Time */
ldr r1, =0x2cf @ Locktime : 30us
str r1, [r0, #0x000] @ S5PC110_APLL_LOCK
ldr r1, =0xe10 @ Locktime : 0xe10 = 3600
str r1, [r0, #0x008] @ S5PC110_MPLL_LOCK
str r1, [r0, #0x010] @ S5PC110_EPLL_LOCK
str r1, [r0, #0x020] @ S5PC110_VPLL_LOCK
/* S5PC110_APLL_CON */
ldr r1, =0x80C80601 @ 800MHz
str r1, [r0, #0x100]
/* S5PC110_MPLL_CON */
ldr r1, =0x829B0C01 @ 667MHz
str r1, [r0, #0x108]
/* S5PC110_EPLL_CON */
ldr r1, =0x80600602 @ 96MHz VSEL 0 P 6 M 96 S 2
str r1, [r0, #0x110]
/* S5PC110_VPLL_CON */
ldr r1, =0x806C0603 @ 54MHz
str r1, [r0, #0x120]
/* Set Source Clock */
ldr r1, =0x10001111 @ A, M, E, VPLL Muxing
str r1, [r0, #0x200] @ S5PC1XX_CLK_SRC0
/* OneDRAM(DMC0) clock setting */
ldr r1, =0x01000000 @ ONEDRAM_SEL[25:24] 1 SCLKMPLL
str r1, [r0, #0x218] @ S5PC110_CLK_SRC6
ldr r1, =0x30000000 @ ONEDRAM_RATIO[31:28] 3 + 1
str r1, [r0, #0x318] @ S5PC110_CLK_DIV6
/* XCLKOUT = XUSBXTI 24MHz */
add r2, r0, #0xE000 @ S5PC110_OTHERS
ldr r1, [r2]
orr r1, r1, #(0x3 << 8) @ CLKOUT[9:8] 3 XUSBXTI
str r1, [r2]
/* CLK_IP0 */
ldr r1, =0x8fefeeb @ DMC[1:0] PDMA0[3] IMEM[5]
str r1, [r0, #0x460] @ S5PC110_CLK_IP0
/* CLK_IP1 */
ldr r1, =0xe9fdf0f9 @ FIMD[0] USBOTG[16]
@ NANDXL[24]
str r1, [r0, #0x464] @ S5PC110_CLK_IP1
/* CLK_IP2 */
ldr r1, =0xf75f7fc @ CORESIGHT[8] MODEM[9]
@ HOSTIF[10] HSMMC0[16]
@ HSMMC2[18] VIC[27:24]
str r1, [r0, #0x468] @ S5PC110_CLK_IP2
/* CLK_IP3 */
ldr r1, =0x8eff038c @ I2C[8:6]
@ SYSTIMER[16] UART0[17]
@ UART1[18] UART2[19]
@ UART3[20] WDT[22]
@ PWM[23] GPIO[26] SYSCON[27]
str r1, [r0, #0x46c] @ S5PC110_CLK_IP3
/* CLK_IP4 */
ldr r1, =0xfffffff1 @ CHIP_ID[0] TZPC[8:5]
str r1, [r0, #0x470] @ S5PC110_CLK_IP3
200:
/* wait at least 200us to stablize all clock */
mov r2, #0x10000
1: subs r2, r2, #1
bne 1b
mov pc, lr
internal_ram_init:
ldreq r0, =0xE3800000
ldrne r0, =0xF1500000
ldr r1, =0x0
str r1, [r0]
mov pc, lr
uart_asm_init:
/* set GPIO to enable UART0-UART4 */
mov r0, r8
ldr r1, =0x22222222
str r1, [r0, #0x0] @ S5PC100_GPIO_A0_OFFSET
ldr r1, =0x00002222
str r1, [r0, #0x20] @ S5PC100_GPIO_A1_OFFSET
/* Check S5PC100 */
cmp r7, r8
bne 110f
/* UART_SEL GPK0[5] at S5PC100 */
add r0, r8, #0x2A0 @ S5PC100_GPIO_K0_OFFSET
ldr r1, [r0, #0x0] @ S5PC1XX_GPIO_CON_OFFSET
bic r1, r1, #(0xf << 20) @ 20 = 5 * 4-bit
orr r1, r1, #(0x1 << 20) @ Output
str r1, [r0, #0x0] @ S5PC1XX_GPIO_CON_OFFSET
ldr r1, [r0, #0x8] @ S5PC1XX_GPIO_PULL_OFFSET
bic r1, r1, #(0x3 << 10) @ 10 = 5 * 2-bit
orr r1, r1, #(0x2 << 10) @ Pull-up enabled
str r1, [r0, #0x8] @ S5PC1XX_GPIO_PULL_OFFSET
ldr r1, [r0, #0x4] @ S5PC1XX_GPIO_DAT_OFFSET
orr r1, r1, #(1 << 5) @ 5 = 5 * 1-bit
str r1, [r0, #0x4] @ S5PC1XX_GPIO_DAT_OFFSET
b 200f
110:
/*
* Note that the following address
* 0xE020'0360 is reserved address at S5PC100
*/
/* UART_SEL MP0_5[7] at S5PC110 */
add r0, r8, #0x360 @ S5PC110_GPIO_MP0_5_OFFSET
ldr r1, [r0, #0x0] @ S5PC1XX_GPIO_CON_OFFSET
bic r1, r1, #(0xf << 28) @ 28 = 7 * 4-bit
orr r1, r1, #(0x1 << 28) @ Output
str r1, [r0, #0x0] @ S5PC1XX_GPIO_CON_OFFSET
ldr r1, [r0, #0x8] @ S5PC1XX_GPIO_PULL_OFFSET
bic r1, r1, #(0x3 << 14) @ 14 = 7 * 2-bit
orr r1, r1, #(0x2 << 14) @ Pull-up enabled
str r1, [r0, #0x8] @ S5PC1XX_GPIO_PULL_OFFSET
ldr r1, [r0, #0x4] @ S5PC1XX_GPIO_DAT_OFFSET
orr r1, r1, #(1 << 7) @ 7 = 7 * 1-bit
str r1, [r0, #0x4] @ S5PC1XX_GPIO_DAT_OFFSET
200:
ldr r1, =0x4f4f4f4f //这是自己加的打印一个字母‘O’,为了测试看前面的串口初始化是否成功
ldr r2, =0xE2900820 //查数据手册,这个是串口二的地址
str r1, [r2]
mov pc, lr
另外,我们得避免重复将这个lowlevel_init.S文件重复编译
第一次这个在board\samsung\goni中的makefile编译时链接了一次,为了生成这个libgoni.o,所以这个libgoni.o中就链接了这个一次
第二次是arch\arm\cpu中的u-boot.lds中为了形成uboot进行连接时又重新连接了一次,因此会导致重复定义出错
解决方法
1.由于我们在makefile中链接了,而且我们要保证u-boot.lds中能够把我们的这个脚本放在前面,所以这个不能动,所以我们把makefile中的链接给删除了,这样生成的libgoni.o文件中就没有链接我们的lowlevel_init.o文件,但是这样导致了一个结果,由于我们把这东西给删了,导致我们makefile中没有生成lowlevel_init.o文件,也就导致了我们图二中我们想把这段放前面根本没有这个文件,同样出错。
2.解决方法:我们要成功在makefile中生成一个libgoni.o文件,同时不包含lowlevel_init.o文件,又同时能够保证我们这个lowlevel_init.o文件能够成功被生成,所以解决方法如下:
我们直接重新定义一个all目标,这个目标会依赖我们的LOW,这样我们的文件就可以成功得到编译生成对应.o文件
4.u-boot.lds文件分析
这个文件在arch\arm\cpu中,通过链接我们的脚本,形成uboot,但是我们的uboot要求把uboot的第一阶段的代码放在我们的前8k中,如果我们的没有声明如下这一句,那么将随机存放,不一定能够成功将我们第一阶段的代码成功放在前面,所以我们这里需要手动添加
5.crt0.S文件分析
ENTRY(_main)
/*
* Set up initial C runtime environment and call board_init_f(0).
*/
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr sp, =(CONFIG_SPL_STACK)
#else
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) //设置栈,并且把sp指向ddr的栈地址
#endif
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
sub sp, #GD_SIZE /* allocate one GD above SP */
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
mov r9, sp /* GD is above SP */
mov r0, #0
bl board_init_f //这里函数进行了板级的初始化,这个函数和board_init_r
//共同构成了uboot的第二阶段,所以这个board_init_r
应该是进入uboot的命令行,所以这里就算uboot第二阶段的
函数入口
#if ! defined(CONFIG_SPL_BUILD)
/*
* Set up intermediate environment (new sp and gd) and call
* relocate_code(addr_moni). Trick here is that we'll return
* 'here' but relocated.
*/
ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r9, [r9, #GD_BD] /* r9 = gd->bd */
sub r9, r9, #GD_SIZE /* new GD is below bd */
adr lr, here
ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */
add lr, lr, r0
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
b relocate_code
here:
/* Set up final (full) environment */
bl c_runtime_cpu_setup /* we still call old routine here */
ldr r0, =__bss_start /* this is auto-relocated! */
ldr r1, =__bss_end /* this is auto-relocated! */
mov r2, #0x00000000 /* prepare zero to clear BSS */
clbss_l:cmp r0, r1 /* while not at end of BSS */
strlo r2, [r0] /* clear 32-bit BSS word */
addlo r0, r0, #4 /* move to next */
blo clbss_l
bl coloured_LED_init
bl red_led_on
/* call board_init_r(gd_t *id, ulong dest_addr) */
mov r0, r9 /* gd_t */
ldr r1, [r9, #GD_RELOCADDR] /* dest_addr */
/* call board_init_r */
ldr pc, =board_init_r /* this is auto-relocated! */
/* we should not return here. */
#endif
ENDPROC(_main)
三、移植
1.ddr初始化相关移植
现状:从start.S出发,遇到了uboot第一阶段初始函数cpu_init_crit,这个函数跳转到board\samsung\goni\lowlevel_init.S中的lowlevel.init函数中,而这个lowlevel.init函数就算具体实现第一阶段各种初始化:关看门狗,设置时钟等,但是还没有进行ddr初始化和重定位,执行完第一阶段后出来继续执行,到了_main函数,这个函数在arch\arm\lib\crt0.S 文件中,而第二阶段的入口就是_main 函数
问题:因为我们这个uboot中没有对ddr进行初始化,所以我们现在的目标:就是在整个start.S执行到_main之前完成ddr初始化和重定位,另外,如果我们原uboot如果带有ddr初始化,那是最好的,但是我们这个uboot中,没有对ddr进行任何的初始化,所以我们的安排:在之前移植的uboot中得到cpu_init.S文件,这个文件之前用于对我们的ddr进行初始化,所以我们利用这个完成ddr初始化,在start.S中完成重定位
1.将之前的uboot中进行了ddr初始化文件uboot/cpu/s5pc11x/s5pc110/cpu_init.S文件copy到\board\samsung\goni中,然后在makefile中修改(联系之前的lowlevel_init.S,避免重复链接)
在对应的makefile文件中添加,实现可以生成cpu_init.o文件但是又不会被这个makefile编译链接进去
在u-boot.lds文件实现最终链接,保证这能够在前8k中作为第一阶段
2.由于我们复制过来的文件cpu_init.S中头文件包含了
#include <config.h> //这个不用怕,我们通过/include/configs编译也有生成,这也解释了我们在后 面/include/configs/s5p_goni.h中添加那些ddr初始相关宏的时候,不用包含s5p_goni.h头文件。
#include <s5pc110.h> //这个没有我们也得去复制过来
从旧uboot主目录中的include文件夹中copy到新的uboot中主目录的include文件夹中即可
3.我们的cpu_init.S中还定义了很多来自旧uboot的宏,处理这些宏要么把条件编译的相关宏,然后再删除其中一个情况的代码,剩下直接执行我们想要的内容,要么把他的宏给copy过来,这里选择删除
4.将我们新加入的两个文件导入到source insight中,然后查看其中相关宏,这里的处理方法:看我们的宏有哪些需要哪些不需要,进行各种删除或者各种添加宏,这个cpu_init.S中要初始化ddr,缺少了在原uboot中的include/configs/smdkv210single.h中定义的宏,这里我们把这些宏copy到我们uboot中/include/configs/s5p_goni.h中
5.剩下就是我们之前移植的cpu_init.S中包含的一个头文件s5pc110.h,这个文件需要进行很多删改
这里是在我们的include/asm-arm/s5pc11x/中把里面的hardwawre.h中这个_reg这个宏定义给copy过来
6.最后编译成功后,进行我们的调试,现在我们在lowlevel_init.S中,调用我们移植的ddr初始化函数,原来我们在串口初始化函数中打印了一个字符O,现在我们在ddr初始化后打印一个K,如果到时候我们看到了一个OK,那就代表我们成功了
最终进行我们开发板验证,出现了OK,代表我们的代码成功!
2.重定位相关初始化移植
现状:我们已经完成了ddr相关的初始化,从lowlevel_init.S跳回我们的start.S,主函数,现在可以进行重定位
问题:1.我们重定位需要在ddr完成后,才可以进行ddr初始化,同时又得保证我们重定位需要第二阶段开始之前,而且完成了ddr初始化和重定位的这第一阶段的代码加起来不能超过8kb,
2.由于我们之前还没有进行重定位,所以我们函数跳转可以用bl位置无关码来进行,但是一旦我们实现了重定位,我们就应该使用位置有关码来进行跳转,所以这里的bl _main得变
1.改变我们的第二阶段跳转指令,将原本的位置无关码变成位置有关码ldr pc,__main
2.从我们之前移植的开发板中的start.S中将重定位代码copy过来
ldr sp, _TEXT_PHY_BASE setup temp stack pointer 这个宏追到底发现就算原uboot的链接起始地址,这里不一样
sub sp, sp, #12
mov fp, #0 所以可以将上面的宏代替这个宏定义
由于移植了movi.c那么就得分析movi.c中的各种文件包含,还有各种宏定义,看看我们是不是没进行移植
3.接下来进行编译,解决编译出现的错误
结果编译正确,烧写进sd卡,然后开发板进行验证
3.cpu时钟信息显示进行移植
现状:我们已经完成了代码的重定位,发现开发板运行成功串口输出了我们之前设置的OKA,而且还多了部分我们的开发板信息,但是这些信息是错误的,回到strat.S中就是到了这就表明我们在uboot第一阶段已经完成,可以开始进入第二阶段即进入_main函数,而这个函数在于crt0.S中,这个函数又调用了board.c中的board_init.c函数所以我们需要将这个东西配置好
问题:由于我们之前最开始进行的时钟配置是在irom中进行的,而我们时钟配置相关是在lowlevel_init.S中,由于我们没有调用这个函数,所以我们现在这里的时钟寄存器配置是在irom中的,但是这个irom中自己配置的不是按照我们相要的进行的,它配置成了800Mhz,所以我们要把在lowlevel_init.S中进行配置,并且重新lowlevel_init.S在中进行调用,才可以正确得到我们要的时钟。
4.board和ddr显示配置移植
现状:我们从start.S中进入了_main,从_main进入了crt0.S,再从crt0.S进入了board_init_f,再从board_init_f进入到board.c中,而这个board.c中这个board_init_f函数里面有一个init_sequence,这个是上面的大部分的初始化代码,
,然后执行完之后,这里并没有返回,所以会继续往下执行
到这里 board_init_f就已经完成了,接下来跳出来board.c返回到crt0.S,然后从这里跳到我们的board_init_r函数,y又进入board.c,然后从这里进行其他的配置初始化
goni.h中定义的宏的含义:就是说我们一旦定义了这个宏,那么我们就会去配置,即我们makefile中是否编译生成.o文件由这里的宏来确定,一旦定义了,那么就代表我们想makefile编译出我们想要的对应文件,由于这个东西是跟我们无关的,所以我们直接注释
4.sd_mmc驱动移植
现状:现在我们已经成功进入了命令行这里,我们处在board.c中的board_init_r函数中
问题:到这里后发现我们的sd卡还是没有办法读取,即我们读取sd卡的函数有问题需要解决
总结
提示:这里对文章进行总结:
1.在共享文件夹里面不能直接进行make 编译等操作,但是可以在windows下改变makefile,从而在linux下可以得到响应的改变,由于不知道是什么原因,排查了许久后将问题确定在了u-boot-2013.10\arch\arm\include\asm底下,应该是删除了一些不该删除的,导致了编译出现错误(问题解决:在我们的arch\arm\include\asm\下有一个目录arch-s5pc1xx不得删除,否则会提示出错)
2.