u-boot2020.04移植(3、lowlevel_init.S)
现在开始就进入板级相关的初始化了,跳转到board/samsung/goni/lowlevel_init.S文件,注意这里lowlevel_init搜索出来在arch/arm/cpu/armv7/lowlevel_init.S文件里面也有,而且这个文件还被编译了,但仔细看一下就会发现,这个文件里面的lowlevel_init被声明成了弱属性,所以真正调用的是board/samsung/goni/lowlevel_init.S文件。
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
ENDPROC(cpu_init_crit)
其实在lowlevel_init里面也不需要干多少事,但DDR是必须要初始化好的,我们都知道s5pv210的整个IRAM也就96K,而u-boot的大小远远超过了96K,所以比较好的办法就是在BL1阶段就初始化好DDR,并且将u-boot搬运到DDR运行。
下面看下lowlevel_init得源码(里面有几个宏,如:S5PC100_GPIO_BASE,在两个文件内都有定义,分别是arch\arm\mach-s5pc1xx\include\mach\cpu.h和arch\arm\include\asm\arch\cpu.h,但根据头文件包含#include <asm/arch/cpu.h>可以知道应该是前面那个文件有效,也可以通过ls -l命令查看目录arch/arm/include/asm/可以看到这个符号链接arch -> ../../mach-s5pc1xx/include/mach):
board/samsung/goni/lowlevel_init.S
.globl lowlevel_init
lowlevel_init:/*这里将lr得值保存到r11中,以便之后返回,因为后面也有跳转得过程,防止lr跳转后丢失*/mov r11, lr/* r5 has always zero */mov r5, #0ldr r7, =S5PC100_GPIO_BASEldr r8, =S5PC100_GPIO_BASE/* Read CPU ID */ldr r2, =S5PC110_PRO_IDldr r0, [r2]mov r1, #0x00010000and r0, r0, r1/*根据手册可以得出,这里是不等的*/cmp r0, r5beq 100f/*这里将r8重新赋值成了C110的GPIO基地址*/ldr r8, =S5PC110_GPIO_BASE
100:/* Turn on KEY_LED_ON [GPJ4(1)] XMSMWEN *//*比较结果不相等,这里比较后,Z位的值是一直保持的*/cmp r7, r8/*不相等,不执行*/beq skip_check_didle @ Support C110 only/*读取复位状态*/ldr r0, =S5PC110_RST_STATldr r1, [r0]and r1, r1, #0x000D0000cmp r1, #(0x1 << 19) @ DEEPIDLE_WAKEUP/*如果是从DEEPIDLE模式唤醒的就直接跳到didle_wakeup过程*/beq didle_wakeupcmp r7, r8skip_check_didle:/*下面这一堆代码就是点亮了一颗led灯,我们改成自己板子上对应的灯GPJ0_3*/addeq r0, r8, #0x280 @ S5PC100_GPIO_J4addne r0, r8, #0x240 @ S5PC110_GPIO_J0ldr r1, [r0, #0x0] @ GPIO_CON_OFFSETbic r1, r1, #(0xf << 12) @ 3 * 4-bitorr r1, r1, #(0x1 << 12)str r1, [r0, #0x0] @ GPIO_CON_OFFSETldr r1, [r0, #0x4] @ GPIO_DAT_OFFSETbic r1, r1, #(1 << 3)str r1, [r0, #0x4] @ GPIO_DAT_OFFSET/*执行到这里,上面点的那颗led灯,如果亮了的话那就说明前面暂时没什么问题了*//* Don't setup at s5pc100 */beq 100f/*下面这堆都是写的默认值,不知道具体的作用*//*省略*//** Diable ABB block to reduce sleep current at low temperature* Note that it's hidden register setup don't modify it*//*这里操作的是隐藏寄存器,不要动*/ldr r0, =0xE010C300ldr r1, =0x00800000str r1, [r0]100:/* IO retension release *//*这一堆好像与低功耗有关*/ldreq r0, =S5PC100_OTHERS @ 0xE0108200ldrne r0, =S5PC110_OTHERS @ 0xE010E000ldr r1, [r0]ldreq r2, =(1 << 31) @ IO_RET_RELldrne 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 @ 0xEA200000ldrne r0, =S5PC110_WATCHDOG_BASE @ 0xE2700000str r5, [r0]/* setting SRAM */ldreq r0, =S5PC100_SROMC_BASEldrne r0, =S5PC110_SROMC_BASEldr r1, =0x9str r1, [r0]/* S5PC100 has 3 groups of interrupt sources *//*s5pv210有四组中断源,这里只失能了三组,再添加一组*/ldreq r0, =S5PC100_VIC0_BASE @ 0xE4000000ldrne r0, =S5PC110_VIC0_BASE @ 0xF2000000add r1, r0, #0x00100000add r2, r0, #0x00200000/*r4还没被用过,使用r4*/add r4, r0, #0x00300000/* Disable all interrupts (VIC0, VIC1 and VIC2, VIC3) */mvn r3, #0x0str r3, [r0, #0x14] @ INTENCLEARstr r3, [r1, #0x14] @ INTENCLEARstr r3, [r2, #0x14] @ INTENCLEAR/*增加VIC3*/str r3, [r4, #0x14] @ INTENCLEAR/* Set all interrupts as IRQ */str r5, [r0, #0xc] @ INTSELECTstr r5, [r1, #0xc] @ INTSELECTstr r5, [r2, #0xc] @ INTSELECT/*增加VIC3*/str r5, [r4, #0xc] @ INTSELECT/* Pending Interrupt Clear */str r5, [r0, #0xf00] @ INTADDRESSstr r5, [r1, #0xf00] @ INTADDRESSstr r5, [r2, #0xf00] @ INTADDRESS/*增加VIC3*/str r5, [r4, #0xf00] @ INTADDRESS/* for UART *//*由于IROM代码已经初始化了串口2,而在u-boot里面我也使用的串口2作为调试串口,所以可以选择不初始化,但是后面重新配置了时钟,IROM中的配置在新的时钟下工作不正常,没有输出,主要应该就是波特率相关寄存器的设置没法用了,所以再重新配置一下(参考后面的修改)*/bl uart_asm_init/* 看手册是与安全相关的,不考虑 */bl internal_ram_initcmp r7, r8/* Clear wakeup status register */ldreq r0, =S5PC100_WAKEUP_STATldrne r0, =S5PC110_WAKEUP_STAT/*这里是不是感觉什么都没做,但实际上手册说的是写1清除该位,默认状态为0,那猜测有效状态应该是1,将读出来的值1又写回去就清除了该位*/ldr r1, [r0]str r1, [r0]/* IO retension release *//*是不是很熟悉,前面也有一段一模一样的代码,不知道意欲何为*//*省略*//*向下找标号1*/b 1f/*如果前面检测出是DEEPIDLE模式唤醒的,那么直接就到这儿了*/
didle_wakeup:/* Wait when APLL is locked */ldr r0, =0xE0100100 @ S5PC110_APLL_CON
lockloop:/*等待APLL时钟稳定*/ldr r1, [r0]and r1, r1, #(1 << 29)cmp r1, #(1 << 29)bne lockloop/*S5PC110_INFORM0是一个用户自定义寄存器*/ldr r0, =S5PC110_INFORM0ldr r1, [r0]/*这里将r1的值放到pc指针里面了,猜测是某个地方进入DEEPIDLE的时候,将lr的值保存到了S5PC110_INFORM0里面,这里直接读出来后返回之前执行的地方*/mov pc, r1nopnopnopnopnop1:/*到了这里就直接返回了*/mov lr, r11mov pc, lr
从源码可以看出,目前lowlevel_init主要做的事:
- 检测唤醒条件
- 点了一颗灯显示当前运行到哪儿了
Initialize Async Register
IO retension release相关的
- 关看门狗
- 设置SRAM
- 关中断(这里中断和之前arm内核部分的中断不一样,这些中断是三星公司设计的)
- 初始化了四个串口的引脚
- 初始化内部RAM
- 清除唤醒状态
IO retension release相关的
目前CPU好像是运行在400MHz下的,在本文件lowlevel_init.S的末尾有一个时钟初始化的过程,但是没有被调用,将其添加上:
/*添加到这句后面*/
bl internal_ram_init/*初始化时钟*/bl system_clock_init
由于重新配置了时钟,而串口2的初始化使用的PCLK时钟没有使用串口专有的时钟,所以也跟着发生了变化,串口2在IROM中的配置已经不能用了,不能输出信息,重新配置一下:
/** uart_asm_init: Initialize UART's pins*/
uart_asm_init:/* set GPIO to enable UART0-UART4 */mov r0, r8ldr r1, =0x22222222str r1, [r0, #0x0] @ S5PC100_GPIO_A0_OFFSETldr r1, =0x00002222str r1, [r0, #0x20] @ S5PC100_GPIO_A1_OFFSET/* Check S5PC100 */cmp r7, r8bne 110f/* UART_SEL GPK0[5] at S5PC100 *//*省略*/b 200f
110:/** Note that the following address* 0xE020'0360 is reserved address at S5PC100*//* UART_SEL MP0_5[7] at S5PC110 *//*下面这堆代码是在设置MP05_7这个脚,但在我的开发板上悬空的,可以删除,也可以不管*//*省略*//*配置串口2*/ldr r0, =S5PC110_UART_BASE/*ULCON 8n1*/ldr r1, =0x3str r1, [r0, #0x800]/*UCON*/ldr r1, =0x5str r1, [r0, #0x804]/*UFCON*/ldr r1, =0x217str r1, [r0, #0x808]/*UMCON*/ldr r1, =0x0str r1, [r0, #0x80C]/*UBRDIV*/ldr r1, =34str r1, [r0, #0x828]/*UDIVSLOT*/ldr r1, =0xDFDDstr r1, [r0, #0x82C]
200:mov pc, lr
接着是初始化DDR,我这个开发板的配置是4片128M,每两片并联组成32bit的数据线访问,总容量512M,从手册上面可以得知此芯片有两个DDR控制器,总共能扩展的DDR内存最大1.5G:
硬件上前256M在DRAM0区域,后256M在DRAM1区域,为了让两片地址连续起来,前256M的起始地址设置为0x30000000,后256M的起始地址设为0x40000000,这样刚好地址连续,DDR的初始化程序参考三星提供的,下面只对配置部分参数进行说明,关于时间参数不进行讲解,配置流程参见手册DRAM CONTROLLER篇(完整初始化代码见本文末尾):
/*chip相当于rank,就好像电脑的内存插槽是有正反两面的,我们只有一面,也就是一个rank*/
#define DMC0_MEMCONTROL 0x00202400 // MemControl BL=4, 1Chip, DDR2 Type, dynamic self refresh, force precharge, dynamic power down off/*30代表起始地址是0x30000000,F0有点像大小的意思代表0xfffffff,1有点像扫描方式,3列的位数是10,2行的位数是14,3bank数是8*/
#define DMC0_MEMCONFIG_0 0x30F01323 // MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
/*前面说了我们只用了一面,另一面没用*/
#define DMC0_MEMCONFIG_1 0x30F00312 // MemConfig1 默认值#define DMC0_TIMINGA_REF 0x00000618 // TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
#define DMC0_TIMING_ROW 0x28233287 // TimingRow for @200MHz
#define DMC0_TIMING_DATA 0x23240304 // TimingData CL=3
#define DMC0_TIMING_PWR 0x09C80232 // TimingPower#define DMC1_MEMCONTROL 0x00202400 // MemControl BL=4, 1chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off/*除了起始地址,其它描述和DMC0都一样*/
#define DMC1_MEMCONFIG_0 0x40F01323 // MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
/*这个也是只用了一面*/
#define DMC1_MEMCONFIG_1 0x60E00312 // MemConfig1 默认值#define DMC1_TIMINGA_REF 0x00000618 // TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4
#define DMC1_TIMING_ROW 0x28233289 // TimingRow for @200MHz
#define DMC1_TIMING_DATA 0x23240304 // TimingData CL=3
#define DMC1_TIMING_PWR 0x08280232 // TimingPower
将DDR初始化程序,ddr_init.S文件放到board/samsung/goni/目录,然后修改该目录下的Makefile,添加ddr_init.S的编译:
obj-y := goni.o onenand.o
obj-y += lowlevel_init.o
/*增加ddr_init*/
obj-y += ddr_init.o
然后在时钟初始化的后面添加上DDR的初始化:
/*...*/
bl internal_ram_init/*初始化时钟*/bl system_clock_init/*初始化DDR*/bl sdram_asm_init
DDR怎么验证有没有初始化成功呢,可以添加一段测试程序,先向DDR的某个地址(注意这个地址一定要四字节对齐,因为前面开启了对齐检查,否则访问非对齐地址时会出错,而且这个错误的唯一现象就是你看不到任何输出,这时你可能会怀疑你的DDR初始化没有成功,导致写DDR时出错,但实际上是因为访问了非对齐地址)写入几个值,然后再读出来,我这里写了OK两个字符,通过串口打印查看就可以了:
/*写入字符'O'*/ldr r0, =0x40000000ldr r1, =0x4fstr r1, [r0]/*写入字符'K'*/ldr r0, =0x40000004ldr r1, =0x4bstr r1, [r0]/*读出然后通过串口输出*/ldr r0, =0xE2900820ldr r1, =0x40000000ldr r2, [r1]str r2, [r0]/*读出然后通过串口输出*/ldr r0, =0xE2900820ldr r1, =0x40000004ldr r2, [r1]str r2, [r0]
由于硬件设计的原因,开发板上电后还需要进行电源置锁,不然的话开机按钮如果松手的话就掉电了,这里将电源置锁加上:
/*这个只是简单的拉了一个IO的电平,不作介绍,添加函数体的实现到lowlevel_init.S文件的末尾,然后在时钟初始化的前面调用*/
board_power_hold:ldr r0, =0xE010E81Cldr r1, [r0]ldr r2, =((0x1 << 0) | (0x1 << 8) | (0x1 << 9))orr r1, r1, r2str r1, [r0]mov pc, lr
在时钟初始化前调用:
/*...*/
bl internal_ram_init/*电源置锁*/bl board_power_hold/*初始化时钟*/bl system_clock_init/*初始化DDR*/bl sdram_asm_init
到了这里,DDR已经初始化好了,下一步就是将u-boot拷贝到DDR去执行了,我们u-boot是烧写到sd卡的,三星在IROM代码中已经提供了将SD卡的内容拷贝到内存的函数实现,我们只需要调用就可以了,这里参考手册(S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf):
上面图2表示这个地址存储了当前的启动通道地址,图3就是拷贝函数,三星提供了好几个这样的拷贝函数,用于从不同启动介质中拷贝内容到内存中,这里只截取了SD/MMC和eMMC的拷贝函数,从上面的图可以看出CopySDMMCtoMem这个函数的函数体就放在0xD0037F98这个地址,所以我们只需要通过函数指针的方式,访问这个地址的内容就相当于调用这个函数了,在board/samsung/goni/目录添加一个copy_image_to_mem.c文件,写入以下代码:
#include <configs/s5p_goni.h>/*
参数1:通道号
参数2:从SD卡的哪个扇区开始拷贝
参数3:拷贝多少个扇区
参数4:拷贝到内存的哪里
参数5:不知道具体用途
*/
typedef bool (*CopySDMMCtoMemTypeDef)(int, unsigned int, unsigned short, unsigned int*, bool);void CopySDMMCtoMem(void)
{CopySDMMCtoMemTypeDef pFuncCopySDMMCtoMem;pFuncCopySDMMCtoMem = (CopySDMMCtoMemTypeDef)(*((volatile unsigned int *)0xD0037F98));unsigned int ch = *((volatile unsigned int*)(0xd0037488));if(ch == 0xeb000000){/*通道0,iNand*/}else if(ch == 0xeb200000){/*通道2,SD卡*/pFuncCopySDMMCtoMem(2, 45, 1000,(unsigned int*)CONFIG_SYS_TEXT_BASE, 0); }
}
有个需要注意的地方就是拷贝到内存的地址,这是个C函数,函数的调用需要使用栈,前面start.S里面设置过一次栈,这里的内存地址最好不要和当时设置的栈空间冲突(注意栈的生长方向是向下的);然后就是SD卡的起始扇区,这个是和你烧写u-boot的起始扇区一样的,因为我是烧写到45扇区开始的位置(这个位置不是固定的,只要没有覆盖掉BL1就行了),所以这里设置45,拷贝大小(这里设置的参数值是扇区数,乘以扇区大小512才是真正的大小,我这里拷贝1000*512=500K)只要大于等于u-boot的大小就行了,然后内存地址我设置的是链接地址(经过后面的验证这里必须设置为链接地址,因为重定位的时候代码拷贝的起始地址就是这儿)。
顺便贴下我的烧写脚本:
#! /bin/bashUBOOT=2020.04#mkv210_image是制作BL1的,因为BL1前16个字节需要填写头信息
./mkv210_image ~/Desktop/s5pv210/u-boot-${UBOOT}/u-boot.bin u-boot-sd.bin
sudo dd iflag=dsync oflag=dsync if=u-boot-sd.bin of=/dev/sdb seek=1
sudo dd iflag=dsync oflag=dsync if=~/Desktop/s5pv210/u-boot-${UBOOT}/u-boot.bin of=/dev/sdb seek=45
在board/samsung/goni/Makefile中添加,让其编译进u-boot,就可以调用这个函数进行拷贝了:
obj-y := goni.o onenand.o
obj-y += lowlevel_init.o
obj-y += ddr_init.o
/*添加编译*/
obj-y += copy_image_to_mem.o
/*...*/
bl internal_ram_init/*电源置锁*/bl board_power_hold/*初始化时钟*/bl system_clock_init/*初始化DDR*/bl sdram_asm_init/*拷贝u-boot到DDR*/bl CopySDMMCtoMem
其实还有很重要的一步,我前面没有提到,就是我们调用的这个函数是不是都在BL1里面,也就是是不是在u-boot的前16K,我们可以通过查看System.map文件,这个文件是u-boot编译后生成的,位于u-boot根目录:
起始地址可以看到是0x34800000,前16K的内容就截止与0x34804000这个地址,所以我们只需要看我们调用的内容有没有在这个地址内就行了,或者可以反汇编u-boot文件也可以知道,相对来说反汇编u-boot文件要详细点。
好的,u-boot已经拷贝到DDR里面了,所以紧接着我们进入DDR的u-boot中去执行,修改arch/arm/cpu/armv7/start.S文件:
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
#ifdef CONFIG_CPU_V7Abl cpu_init_cp15
#endif
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLYbl cpu_init_crit
#endif
#endif/*注释掉*/@ bl _main/*修改这里,跳转到DDR中去执行,因为IRAM里面只有u-boot的前16k代码*/ldr pc, =_main
这部分内容结束,就进入board_init_f了(也就是大家说的u-boot的第一阶段),所以编译看一下效果:
可以看到已经出来很多信息了,说明我们成功跳转到DDR去执行了,不过卡在了OneNAND初始化的后面。
完整DDR初始化代码:
#include <config.h>#define ELFIN_GPIO_BASE S5PC110_GPIO_BASE#define MP1_0DRV_SR_OFFSET 0x3CC
#define MP1_1DRV_SR_OFFSET 0x3EC
#define MP1_2DRV_SR_OFFSET 0x40C
#define MP1_3DRV_SR_OFFSET 0x42C
#define MP1_4DRV_SR_OFFSET 0x44C
#define MP1_5DRV_SR_OFFSET 0x46C
#define MP1_6DRV_SR_OFFSET 0x48C
#define MP1_7DRV_SR_OFFSET 0x4AC
#define MP1_8DRV_SR_OFFSET 0x4CC#define MP2_0DRV_SR_OFFSET 0x4EC
#define MP2_1DRV_SR_OFFSET 0x50C
#define MP2_2DRV_SR_OFFSET 0x52C
#define MP2_3DRV_SR_OFFSET 0x54C
#define MP2_4DRV_SR_OFFSET 0x56C
#define MP2_5DRV_SR_OFFSET 0x58C
#define MP2_6DRV_SR_OFFSET 0x5AC
#define MP2_7DRV_SR_OFFSET 0x5CC
#define MP2_8DRV_SR_OFFSET 0x5EC/** SDRAM Controller*/
#define APB_DMC_0_BASE 0xF0000000
#define APB_DMC_1_BASE 0xF1400000
#define ASYNC_MSYS_DMC0_BASE 0xF1E00000#define DMC_CONCONTROL 0x00
#define DMC_MEMCONTROL 0x04
#define DMC_MEMCONFIG0 0x08
#define DMC_MEMCONFIG1 0x0C
#define DMC_DIRECTCMD 0x10
#define DMC_PRECHCONFIG 0x14
#define DMC_PHYCONTROL0 0x18
#define DMC_PHYCONTROL1 0x1C
#define DMC_RESERVED 0x20
#define DMC_PWRDNCONFIG 0x28
#define DMC_TIMINGAREF 0x30
#define DMC_TIMINGROW 0x34
#define DMC_TIMINGDATA 0x38
#define DMC_TIMINGPOWER 0x3C
#define DMC_PHYSTATUS 0x40
#define DMC_CHIP0STATUS 0x48
#define DMC_CHIP1STATUS 0x4C
#define DMC_AREFSTATUS 0x50
#define DMC_MRSTATUS 0x54
#define DMC_PHYTEST0 0x58
#define DMC_PHYTEST1 0x5C
#define DMC_QOSCONTROL0 0x60
#define DMC_QOSCONFIG0 0x64
#define DMC_QOSCONTROL1 0x68
#define DMC_QOSCONFIG1 0x6C
#define DMC_QOSCONTROL2 0x70
#define DMC_QOSCONFIG2 0x74
#define DMC_QOSCONTROL3 0x78
#define DMC_QOSCONFIG3 0x7C
#define DMC_QOSCONTROL4 0x80
#define DMC_QOSCONFIG4 0x84
#define DMC_QOSCONTROL5 0x88
#define DMC_QOSCONFIG5 0x8C
#define DMC_QOSCONTROL6 0x90
#define DMC_QOSCONFIG6 0x94
#define DMC_QOSCONTROL7 0x98
#define DMC_QOSCONFIG7 0x9C
#define DMC_QOSCONTROL8 0xA0
#define DMC_QOSCONFIG8 0xA4
#define DMC_QOSCONTROL9 0xA8
#define DMC_QOSCONFIG9 0xAC
#define DMC_QOSCONTROL10 0xB0
#define DMC_QOSCONFIG10 0xB4
#define DMC_QOSCONTROL11 0xB8
#define DMC_QOSCONFIG11 0xBC
#define DMC_QOSCONTROL12 0xC0
#define DMC_QOSCONFIG12 0xC4
#define DMC_QOSCONTROL13 0xC8
#define DMC_QOSCONFIG13 0xCC
#define DMC_QOSCONTROL14 0xD0
#define DMC_QOSCONFIG14 0xD4
#define DMC_QOSCONTROL15 0xD8
#define DMC_QOSCONFIG15 0xDC#define DMC0_MEMCONTROL 0x00202400 // MemControl BL=4, 1Chip, DDR2 Type, dynamic self refresh, force precharge, dynamic power down off#define DMC0_MEMCONFIG_0 0x30F01323 // MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC0_MEMCONFIG_1 0x30F00312 // MemConfig1 默认值#define DMC0_TIMINGA_REF 0x00000618 // TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
#define DMC0_TIMING_ROW 0x28233287 // TimingRow for @200MHz
#define DMC0_TIMING_DATA 0x23240304 // TimingData CL=3
#define DMC0_TIMING_PWR 0x09C80232 // TimingPower#define DMC1_MEMCONTROL 0x00202400 // MemControl BL=4, 1chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off#define DMC1_MEMCONFIG_0 0x40F01323 // MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC1_MEMCONFIG_1 0x60E00312 // MemConfig1 默认值#define DMC1_TIMINGA_REF 0x00000618 // TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4
#define DMC1_TIMING_ROW 0x28233289 // TimingRow for @200MHz
#define DMC1_TIMING_DATA 0x23240304 // TimingData CL=3
#define DMC1_TIMING_PWR 0x08280232 // TimingPower.globl sdram_asm_init
sdram_asm_init: ldr r0, =0xf1e00000ldr r1, =0x0str r1, [r0, #0x0]/* DMC0 Drive Strength (Setting 2X) */ldr r0, =ELFIN_GPIO_BASEldr r1, =0x0000AAAAstr r1, [r0, #MP1_0DRV_SR_OFFSET] // 寄存器中对应0b10,就是2Xldr r1, =0x0000AAAAstr r1, [r0, #MP1_1DRV_SR_OFFSET]ldr r1, =0x0000AAAAstr r1, [r0, #MP1_2DRV_SR_OFFSET]ldr r1, =0x0000AAAAstr r1, [r0, #MP1_3DRV_SR_OFFSET]ldr r1, =0x0000AAAAstr r1, [r0, #MP1_4DRV_SR_OFFSET]ldr r1, =0x0000AAAAstr r1, [r0, #MP1_5DRV_SR_OFFSET]ldr r1, =0x0000AAAAstr r1, [r0, #MP1_6DRV_SR_OFFSET]ldr r1, =0x0000AAAAstr r1, [r0, #MP1_7DRV_SR_OFFSET]ldr r1, =0x00002AAAstr r1, [r0, #MP1_8DRV_SR_OFFSET]/* DMC1 Drive Strength (Setting 2X) */ldr r0, =ELFIN_GPIO_BASEldr r1, =0x0000AAAAstr r1, [r0, #MP2_0DRV_SR_OFFSET]ldr r1, =0x0000AAAAstr r1, [r0, #MP2_1DRV_SR_OFFSET]ldr r1, =0x0000AAAAstr r1, [r0, #MP2_2DRV_SR_OFFSET]ldr r1, =0x0000AAAAstr r1, [r0, #MP2_3DRV_SR_OFFSET]ldr r1, =0x0000AAAAstr r1, [r0, #MP2_4DRV_SR_OFFSET]ldr r1, =0x0000AAAAstr r1, [r0, #MP2_5DRV_SR_OFFSET]ldr r1, =0x0000AAAAstr r1, [r0, #MP2_6DRV_SR_OFFSET]ldr r1, =0x0000AAAAstr r1, [r0, #MP2_7DRV_SR_OFFSET]ldr r1, =0x00002AAAstr r1, [r0, #MP2_8DRV_SR_OFFSET]/* DMC0 initialization at single Type*/ldr r0, =APB_DMC_0_BASEldr r1, =0x00101000 @PhyControl0 DLL parameter setting, manual 0x00101000str r1, [r0, #DMC_PHYCONTROL0]ldr r1, =0x00000086 @PhyControl1 DLL parameter setting, LPDDR/LPDDR2 Casestr r1, [r0, #DMC_PHYCONTROL1]ldr r1, =0x00101002 @PhyControl0 DLL onstr r1, [r0, #DMC_PHYCONTROL0]ldr r1, =0x00101003 @PhyControl0 DLL startstr r1, [r0, #DMC_PHYCONTROL0]find_lock_val:ldr r1, [r0, #DMC_PHYSTATUS] @Load Phystatus register valueand r2, r1, #0x7cmp r2, #0x7 @Loop until DLL is lockedbne find_lock_valand r1, #0x3fc0 mov r2, r1, LSL #18orr r2, r2, #0x100000orr r2 ,r2, #0x1000 orr r1, r2, #0x3 @Force Value lockingstr r1, [r0, #DMC_PHYCONTROL0]#if 0 /* Memory margin test 10.01.05 */orr r1, r2, #0x1 @DLL offstr r1, [r0, #DMC_PHYCONTROL0]
#endif/* setting DDR2 */ldr r1, =0x0FFF2010 @ConControl auto refresh offstr r1, [r0, #DMC_CONCONTROL]ldr r1, =DMC0_MEMCONTROL @MemControl BL=4, 1 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down offstr r1, [r0, #DMC_MEMCONTROL]ldr r1, =DMC0_MEMCONFIG_0 @MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixedstr r1, [r0, #DMC_MEMCONFIG0]ldr r1, =DMC0_MEMCONFIG_1 @MemConfig1str r1, [r0, #DMC_MEMCONFIG1]ldr r1, =0xFF000000 @PrechConfigstr r1, [r0, #DMC_PRECHCONFIG]ldr r1, =DMC0_TIMINGA_REF @TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)str r1, [r0, #DMC_TIMINGAREF]ldr r1, =DMC0_TIMING_ROW @TimingRow for @200MHzstr r1, [r0, #DMC_TIMINGROW]ldr r1, =DMC0_TIMING_DATA @TimingData CL=3str r1, [r0, #DMC_TIMINGDATA]ldr r1, =DMC0_TIMING_PWR @TimingPowerstr r1, [r0, #DMC_TIMINGPOWER]ldr r1, =0x07000000 @DirectCmd chip0 Deselectstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x01000000 @DirectCmd chip0 PALLstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00020000 @DirectCmd chip0 EMRS2str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00030000 @DirectCmd chip0 EMRS3str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00010400 @DirectCmd chip0 EMRS1 (MEM DLL on, DQS# disable)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00000542 @DirectCmd chip0 MRS (MEM DLL reset) CL=4, BL=4str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x01000000 @DirectCmd chip0 PALLstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x05000000 @DirectCmd chip0 REFAstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x05000000 @DirectCmd chip0 REFAstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00000442 @DirectCmd chip0 MRS (MEM DLL unreset)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00010780 @DirectCmd chip0 EMRS1 (OCD default)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00010400 @DirectCmd chip0 EMRS1 (OCD exit)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x07100000 @DirectCmd chip1 Deselectstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x01100000 @DirectCmd chip1 PALLstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00120000 @DirectCmd chip1 EMRS2str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00130000 @DirectCmd chip1 EMRS3str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00110400 @DirectCmd chip1 EMRS1 (MEM DLL on, DQS# disable)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00100542 @DirectCmd chip1 MRS (MEM DLL reset) CL=4, BL=4str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x01100000 @DirectCmd chip1 PALLstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x05100000 @DirectCmd chip1 REFAstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x05100000 @DirectCmd chip1 REFAstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00100442 @DirectCmd chip1 MRS (MEM DLL unreset)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00110780 @DirectCmd chip1 EMRS1 (OCD default)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00110400 @DirectCmd chip1 EMRS1 (OCD exit)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x0FF02030 @ConControl auto refresh onstr r1, [r0, #DMC_CONCONTROL]ldr r1, =0xFFFF00FF @PwrdnConfigstr r1, [r0, #DMC_PWRDNCONFIG]ldr r1, =0x00202400 @MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down offstr r1, [r0, #DMC_MEMCONTROL]// 上面是DRAM0初始化步骤
/*******************************************************************************************/
// 下面是DRAM1初始化步骤,两者没有联系,是并列的。/* DMC1 initialization */ldr r0, =APB_DMC_1_BASEldr r1, =0x00101000 @Phycontrol0 DLL parameter settingstr r1, [r0, #DMC_PHYCONTROL0]ldr r1, =0x00000086 @Phycontrol1 DLL parameter settingstr r1, [r0, #DMC_PHYCONTROL1]ldr r1, =0x00101002 @PhyControl0 DLL onstr r1, [r0, #DMC_PHYCONTROL0]ldr r1, =0x00101003 @PhyControl0 DLL startstr r1, [r0, #DMC_PHYCONTROL0]find_lock_val1:ldr r1, [r0, #DMC_PHYSTATUS] @Load Phystatus register valueand r2, r1, #0x7cmp r2, #0x7 @Loop until DLL is lockedbne find_lock_val1and r1, #0x3fc0 mov r2, r1, LSL #18orr r2, r2, #0x100000orr r2, r2, #0x1000orr r1, r2, #0x3 @Force Value lockingstr r1, [r0, #DMC_PHYCONTROL0]#if 0 /* Memory margin test 10.01.05 */orr r1, r2, #0x1 @DLL offstr r1, [r0, #DMC_PHYCONTROL0]
#endif/* settinf fot DDR2 */ldr r0, =APB_DMC_1_BASEldr r1, =0x0FFF2010 @auto refresh offstr r1, [r0, #DMC_CONCONTROL]ldr r1, =DMC1_MEMCONTROL @MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down offstr r1, [r0, #DMC_MEMCONTROL]ldr r1, =DMC1_MEMCONFIG_0 @MemConfig0 512MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixedstr r1, [r0, #DMC_MEMCONFIG0]ldr r1, =DMC1_MEMCONFIG_1 @MemConfig1str r1, [r0, #DMC_MEMCONFIG1]ldr r1, =0xFF000000str r1, [r0, #DMC_PRECHCONFIG]ldr r1, =DMC1_TIMINGA_REF @TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4str r1, [r0, #DMC_TIMINGAREF]ldr r1, =DMC1_TIMING_ROW @TimingRow for @200MHzstr r1, [r0, #DMC_TIMINGROW]ldr r1, =DMC1_TIMING_DATA @TimingData CL=3str r1, [r0, #DMC_TIMINGDATA]ldr r1, =DMC1_TIMING_PWR @TimingPowerstr r1, [r0, #DMC_TIMINGPOWER]ldr r1, =0x07000000 @DirectCmd chip0 Deselectstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x01000000 @DirectCmd chip0 PALLstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00020000 @DirectCmd chip0 EMRS2str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00030000 @DirectCmd chip0 EMRS3str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00010400 @DirectCmd chip0 EMRS1 (MEM DLL on, DQS# disable)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00000542 @DirectCmd chip0 MRS (MEM DLL reset) CL=4, BL=4str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x01000000 @DirectCmd chip0 PALLstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x05000000 @DirectCmd chip0 REFAstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x05000000 @DirectCmd chip0 REFAstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00000442 @DirectCmd chip0 MRS (MEM DLL unreset)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00010780 @DirectCmd chip0 EMRS1 (OCD default)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00010400 @DirectCmd chip0 EMRS1 (OCD exit)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x07100000 @DirectCmd chip1 Deselectstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x01100000 @DirectCmd chip1 PALLstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00120000 @DirectCmd chip1 EMRS2str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00130000 @DirectCmd chip1 EMRS3str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00110440 @DirectCmd chip1 EMRS1 (MEM DLL on, DQS# disable)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00100542 @DirectCmd chip1 MRS (MEM DLL reset) CL=4, BL=4str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x01100000 @DirectCmd chip1 PALLstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x05100000 @DirectCmd chip1 REFAstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x05100000 @DirectCmd chip1 REFAstr r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00100442 @DirectCmd chip1 MRS (MEM DLL unreset)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00110780 @DirectCmd chip1 EMRS1 (OCD default)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x00110400 @DirectCmd chip1 EMRS1 (OCD exit)str r1, [r0, #DMC_DIRECTCMD]ldr r1, =0x0FF02030 @ConControl auto refresh onstr r1, [r0, #DMC_CONCONTROL]ldr r1, =0xFFFF00FF @PwrdnConfig str r1, [r0, #DMC_PWRDNCONFIG]ldr r1, =DMC1_MEMCONTROL @MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down offstr r1, [r0, #DMC_MEMCONTROL]// 函数返回mov pc, lr
欢迎扫码关注我的微信公众号
u-boot2020.04移植(3、lowlevel_init.S)相关推荐
- 6004.ubuntu18.04移植qgroundcontrol地面站
ubuntu18.04移植qgroundcontrol地面站 参考博客: 下载qgroundControl源码 第1种方式: git clone --recursive https://github. ...
- uboot研读笔记 | 04 - 移植uboot 2012.04到JZ2440(支持Nor Flash读写)
项目开源地址:https://github.com/Mculover666/uboot-jz2440 0. 教程完整目录 00 - 嵌入式Linux系统中Bootloader的作用和基本运行原理 01 ...
- IMX6ULL-UBoot 20.04移植记录
开发环境简介 开发板 正点原子MINI 操作系统 Linux-Mint 20.2 交叉编译链 gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf U ...
- IMX6ULL u-boot 2020.04 移植LAN8720A(网卡)
1.修改设备树arch/arm/dts/imx6ul-14x14-evk.dtsi 修改后 &fec1 {pinctrl-names = "default";pinctrl ...
- uboot研读笔记 | 05 - 移植uboot 2012.04到JZ2440(支持Nand Flash读写)
项目开源地址:https://github.com/Mculover666/uboot-jz2440 0. 教程完整目录 00 - 嵌入式Linux系统中Bootloader的作用和基本运行原理 01 ...
- RT73 wifi无线网卡驱动移植过程 和wpa支持
转 移植环境: 主机操作系统:Ubantu 8.10 目标系统:linux-2.6.22.6 交叉编译器:arm-softfloat-linux-gnu-gcc-3.4.5 一.RT73驱动编译 1. ...
- 移植u-boot v2018
本篇文章阐述移植 u-boot v2018.01 至 S5PV210 开发板上的主要流程和细节.市场上的S5PV210开发板,均是基于三星smdkv210公版平台山寨出来的.我使用的GEC210开发板 ...
- OK6410A移植mw150us无线网卡驱动
一 ubuntu 12.04移植mw150us驱动 参考: 1)https://blog.csdn.net/wangdapao12138/article/details/82559422 2)http ...
- STM32移植uC/OSIII
坚持就是胜利 一.UCOS简介 01 简介 02 uC/OS-III的任务 03 其他介绍 二.操作过程 01 题目要求 02 配置CubeMX 03 下载代码 04 移植代码 05 效果展示 三.实 ...
- Linux系统的madplay、mplayer音视频播放器的制作
Linux系统音视频播放器的制作 madplay和mplayer的安装环境 一.Linux系统录音播放源码的下载和移植 1.需要下载alsa-lib-1.2.6.tar.bz2(声音驱动的内核组件库) ...
最新文章
- OA的核心模块在那里?
- mysql event使用,用MySQL的Event设置定时任务执行sql语句 | 老疯子
- php redis support,ThinkPHP5报错php not support: redis以及Redis的使用
- 一次由于网卡流量跑满引起的服务器丢包总结(sar命令排查)
- EditPlus配置Python环境
- linux下qt加载boost,信号槽的实现实例—— Qt 和 Boost
- Ogre 1.7 SDKTRAY 初探
- 针对Micro Framework 3.0模拟器进行改造方法(浅谈)
- 如何从完好的数据文件恢复oracle数据库
- Atiitt 经济学体系树与知识点概念大总结attilax
- 6678学习笔记开篇
- 箫演奏技巧符号大全图解
- SpringBoot实现抽奖大转盘
- 【评测】Attana Cell 200蛋白互作分析仪,实现细胞原位生物大分子互作检测
- 如何用Python解析JSON数据
- 计算机编程语言排行榜—TIOBE世界编程语言排行榜(2021年11月份最新版)
- 【mysql报错】Data truncation: Data too long for column ‘XXX‘ at row 1
- Android百度地图之位置定位和附近查找代码简单实现 (上)
- linux之进程观察命令:ps和top
- 判断一个字符串是否为全字母句
热门文章
- linux中文件权限为drwxr,linux drwxr-xr-x 什么意思 ?
- 【GDB】__stack_chk_fail 栈溢出问题定位
- 一图看懂互联网各职位都是干啥的
- 李开复:我要找什么样的人一起创业?
- HDU5956 The Elder(树上斜率DP)
- [Windows系统]visio安装时提示和即点即用版本不能并行怎么办
- 基于python学生档案管理系统的设计与实现.rar(毕业论文+程序源码+答辩PPT)
- 外滩画报:揭秘全球电子垃圾坟墓
- 人工神经网络的算法原理,人工神经网络算法优点
- 转载:王垠 的《完全用Linux工作》