×
单片机 > 单片机程序设计 > 详情

TQ210 —— s5pv210 lowlevel_init.S分析(uboot第一阶段)

发布时间:2024-05-21 发布时间:
|

/*

* Memory Setup stuff - taken from blob memsetup.S

*

* Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and

* Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)

*

* Modified for the Samsung SMDK2410 by

* (C) Copyright 2002

* David Mueller, ELSOFT AG,

*

* See file CREDITS for list of people who contributed to this

* project.

*

* This program is free software; you can redistribute it and/or

* modify it under the terms of the GNU General Public License as

* published by the Free Software Foundation; either version 2 of

* the License, or (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston,

* MA 02111-1307 USA

*/

#include

#include

#include

#include "tq210_val.h"

@ 讲start.S的时候已经说过这个TEXT_BASE了

_TEXT_BASE:

.word TEXT_BASE

.globl lowlevel_init

lowlevel_init:

push {lr} @ 将上一个函数的返回地址压入栈中

/* check reset status */

@ 检查复位标志,如果是睡眠唤醒,跳过接下来的初始化

ldr r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET) @ 跳转到目的地Reset Control Register的地址传送给r0 Address = 0xE010_A000 =0xE010_0000+0xA000

ldr r1, [r0] @ 将存储器地址为 R0(内存储的值) 的字数据读入寄存器 R1

bic r1, r1, #0xfff6ffff @将r1与0xfff6ffff的反码按位进行与运算(既和0xfff6ffff进行与非运算),并写入r1;结合上一步,可知,这一步的作用是16和19bit置一,其他位清零

cmp r1, #0x10000 @ 判断16bit是不是等于1

beq wakeup_reset_pre @ 如果是从睡眠状态唤醒,就跳转到wakeup_reset_pre,既跳过接下来的初始化

cmp r1, #0x80000 @ 判断是不是从深度空闲(Deep-IDLE)状态唤醒

beq wakeup_reset_from_didle @ 如果是,就跳转到wakeup_reset_from_didle

/* IO Retention release */

ldr r0, =(ELFIN_CLOCK_POWER_BASE + OTHERS_OFFSET) @ 将跳转目的地址MISC Register的地址传送给r0 Address = 0xE010_E000 =0xE010_0000+0xE000

ldr r1, [r0] @ 将存储器地址为 R0(内存储的值) 的字数据读入寄存器 R1

ldr r2, =IO_RET_REL @将IO_RET_REL( ((1 << 31) | (1 << 29) | (1 << 28)) )存入r2

orr r1, r1, r2 @ 将r1和r2的值进行或运算,结果存入r1

str r1, [r0] @ 将r1的值写入以r0内的值为地址的内存空间

/* Disable Watchdog */

@ 关闭看门狗

ldr r0, =ELFIN_WATCHDOG_BASE /* 0xE2700000 */

mov r1, #0

str r1, [r0]

/* SRAM(2MB) init for SMDKC110 */

/* GPJ1 SROM_ADDR_16to21 */

@ 配置sram引脚,16位数据宽度,22位地址宽度

ldr r0, =ELFIN_GPIO_BASE

ldr r1, [r0, #GPJ1CON_OFFSET]

bic r1, r1, #0xFFFFFF

ldr r2, =0x444444

orr r1, r1, r2

str r1, [r0, #GPJ1CON_OFFSET]

ldr r1, [r0, #GPJ1PUD_OFFSET]

ldr r2, =0x3ff

bic r1, r1, r2

str r1, [r0, #GPJ1PUD_OFFSET]

/* GPJ4 SROM_ADDR_16to21 */

ldr r1, [r0, #GPJ4CON_OFFSET]

bic r1, r1, #(0xf<<16)

ldr r2, =(0x4<<16)

orr r1, r1, r2

str r1, [r0, #GPJ4CON_OFFSET]

ldr r1, [r0, #GPJ4PUD_OFFSET]

ldr r2, =(0x3<<8)

bic r1, r1, r2

str r1, [r0, #GPJ4PUD_OFFSET]

/* CS0 - 16bit sram, enable nBE, Byte base address */

ldr r0, =ELFIN_SROM_BASE /* 0xE8000000 */

mov r1, #0x1

str r1, [r0]

/* PS_HOLD pin(GPH0_0) set to high */

@ 设置PMIC(Power Management IC)控制引脚,既电源管理ic引脚(基于I2C)

ldr r0, =(ELFIN_CLOCK_POWER_BASE + PS_HOLD_CONTROL_OFFSET)

ldr r1, [r0]

orr r1, r1, #0x300

orr r1, r1, #0x1

str r1, [r0]

/* when we already run in ram, we don't need to relocate U-Boot.

* and actually, memory controller must be configured before U-Boot

* is running in ram.

*/

/*下面的代码事实上只是判断pc和_TEXT_BASE(0X23e00000)的最高两位是否相同*/

/* 根据s5pv210的数据手册可知,首先,系统会运行固化在irom的BL0,紧接着会从外部nand

* 或sdcard等设备读取前16K的BL1代码到IRAM中的0xD0020000处。然后从0xD0020010处运行(因为前16byte是校验和的值)

* BL1的作用是初始化DRAM,拷贝BL2到DRAM中_TEXT_BASE(0X23e00000)处,然后跳到DRAM中运行

* 因此可以通过最高两位来判断代码是在哪里运行

* 同时可知,当代码已经就在DRAM中运行时,就必须跳过DRAM的初始化

*/

ldr r0, =0xff000fff

bic r1, pc, r0 /* r0

ldr r2, _TEXT_BASE /* r1

bic r2, r2, r0 /* r0

cmp r1, r2 /* compare r0, r1 */

beq 1f /* r0 == r1 then skip sdram init */

/* init PMIC chip */

#ifdef CONFIG_TQ210_IIC_PM_CHIP

bl PMIC_InitIp

#endif

/* init system clock */

@ 时钟初始化 PLL初始化,要想看懂此汇编,请查看datsheet中,clk control章节

bl system_clock_init

/* Memory initialize */

@ 内存初始化

bl mem_ctrl_asm_init

1:

/* for UART */

@ 串口初始化,要看懂此汇编, 请查看datsheet中, 请查看串口章节

bl uart_asm_init

bl tzpc_init

@ 这段不执行

#if defined(CONFIG_ONENAND)

bl onenandcon_init

#endif

@ nand初始化

#if defined(CONFIG_NAND)

/* simple init for NAND */

bl nand_asm_init

#endif

/* check reset status */

ldr r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)

ldr r1, [r0]

bic r1, r1, #0xfffeffff

cmp r1, #0x10000

beq wakeup_reset_pre

/* ABB disable */

ldr r0, =0xE010C300

orr r1, r1, #(0x1<<23)

str r1, [r0]

/* Print 'K' */

ldr r0, =ELFIN_UART_CONSOLE_BASE

ldr r1, =0x4b4b4b4b

str r1, [r0, #UTXH_OFFSET]

pop {pc} @ 返回到start.S

wakeup_reset_from_didle: @ 从深度睡眠中唤醒

/* Wait when APLL is locked */

ldr r0, =ELFIN_CLOCK_POWER_BASE

lockloop:

ldr r1, [r0, #APLL_CON0_OFFSET]

and r1, r1, #(1<<29)

cmp r1, #(1<<29)

bne lockloop @ 这里使用循环

beq exit_wakeup

wakeup_reset_pre:

mrc p15, 0, r1, c1, c0, 1 @Read CP15 Auxiliary control register

and r1, r1, #0x80000000 @Check L2RD is disable or not

cmp r1, #0x80000000

bne wakeup_reset @if L2RD is not disable jump to wakeup_reset

bl disable_l2cache

bl v7_flush_dcache_all

/* L2 cache enable at sleep.S of kernel

* bl enable_l2cache

*/

#ifdef CONFIG_TQ210

bl enable_l2cache

#endif

wakeup_reset:

/* init system clock */

bl system_clock_init

bl mem_ctrl_asm_init

bl tzpc_init

#if defined(CONFIG_ONENAND)

bl onenandcon_init

#endif

#if defined(CONFIG_NAND)

bl nand_asm_init

#endif

exit_wakeup:

/*Load return address and jump to kernel*/

ldr r0, =(INF_REG_BASE+INF_REG0_OFFSET)

ldr r1, [r0] /* r1 = physical address of s5pc110_cpu_resume function*/

mov pc, r1 /*Jump to kernel */

nop

nop

/*

* system_clock_init: Initialize core clock and bus clock.

* void system_clock_init(void)

*/

system_clock_init:

/* 这一段的作用是将Clock Source Control Registers值清空

* 具体的作用是将VPLL_SEL、EPLL_SEL、MPLL_SEL和APLL_SEL的时钟源设置为FINVPLL,将MUX_MSYS_SEL、MUX_DSYS_SEL和MUX_PSYS_SEL时钟源设置为SCLKMPLL

* 将ONENAND_SEL时钟源设置为HCLK_PSYS

* 为什么这样设置,因为未设置 PLL 和各种分频系数之前,我们不能使用 PLL,为了保险起见,暂时直接使用频率较低

* 的外接的 24MHz 晶振,待设置好 PLL 和分频系数后再重新设置各种时钟开关

*/

ldr r0, =ELFIN_CLOCK_POWER_BASE @0xe0100000

/* Set Mux to FIN */

ldr r1, =0x0

str r1, [r0, #CLK_SRC0_OFFSET]

ldr r1, =APLL_LOCKTIME_VAL @将APLL_LOCKTIME_VAL(0x2cf)装入r1

str r1, [r0, #APLL_LOCK_OFFSET] @将r1内的值装入地址为(r0内的值+CLK_SRC0_OFFSET = 0xe0100000)的内存,即设置APLL的锁定周期

/*

* A PLL requires locking period when input frequency is changed or frequency division (multiplication) values are

* changed.PLL_LOCK register specifies this locking period, which is based on PLL’s source clock. During this

* period, output will be low state

*/

/* Disable PLL */

#if defined(CONFIG_CHECK_MPLL_LOCK)

retryloop:

#endif

ldr r1, =0x0

str r1, [r0, #APLL_CON0_OFFSET] @ 将APLL控制寄存器的值清空,这个寄存器的第31位置零关闭APLL 25-16bit配置MDIV的分频

@ 13-8bit配置PDIV的分频 2-0bit配置SDIV的分频

ldr r1, =0x0

str r1, [r0, #MPLL_CON_OFFSET] @ 配置MPLL

ldr r1, =0x0

str r1, [r0, #MPLL_CON_OFFSET] @ 重复配置MPLL,确保MPLL配置成功

ldr r1, [r0, #CLK_DIV0_OFFSET] @ Clock Divider Control Register(0xe0100300)

ldr r2, =CLK_DIV0_MASK @ CLK_DIV0_MASK(0x7fffffff)

bic r1, r1, r2 @ 首先清零

ldr r2, =

[1] [2] [3]
TQ210s5pv210lowlevel_initS分析uboot

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
单片机制作超级流水灯