cpu/arm_cortexa8/cpu.S 就像是以前 ads 的 startup.S
一開始就是 arm 的 interrupt vector。
後面就是 code.
從 reset 開始。
然後call cpu_init_crit (low level init ?)。
之後就是 relocate。
-- 因為 iMX51 的 bootrom 已經把DDR config 好,並且把 uboot load 到 DDR,所以不用作 reloacate 了。
設定 stack:
sp = _TEXT_BASE - #CONFIG_SYS_MALLOC_LEN - #CONFIG_SYS_GBL_DATA_SIZE - 12
clear bbs:
__bss_start -- __bss_end 的區域都填 0
run board_mmu_init.
這段code 要參考 Reference Manual Chapter 2 : Memory Map. 對照 Physical Address 的內容 (其實註解已經寫得很清楚)
/* Actual Virtual Size Attributes Function */
/* Base Base MB cached? buffered? access permissions */
/* xxx00000 xxx00000 */
X_ARM_MMU_SECTION(0x000, 0x200, 0x1,
ARM_UNCACHEABLE, ARM_UNBUFFERABLE,
ARM_ACCESS_PERM_RW_RW); /* ROM */
X_ARM_MMU_SECTION(0x1FF, 0x1FF, 0x001,
ARM_UNCACHEABLE, ARM_UNBUFFERABLE,
ARM_ACCESS_PERM_RW_RW); /* IRAM */
X_ARM_MMU_SECTION(0x300, 0x300, 0x100,
ARM_UNCACHEABLE, ARM_UNBUFFERABLE,
ARM_ACCESS_PERM_RW_RW); /* GPU */
X_ARM_MMU_SECTION(0x400, 0x400, 0x200,
ARM_UNCACHEABLE, ARM_UNBUFFERABLE,
ARM_ACCESS_PERM_RW_RW); /* IPUv3D */
X_ARM_MMU_SECTION(0x600, 0x600, 0x300,
ARM_UNCACHEABLE, ARM_UNBUFFERABLE,
ARM_ACCESS_PERM_RW_RW); /* periperals */
X_ARM_MMU_SECTION(0x900, 0x000, 0x1FF,
ARM_CACHEABLE, ARM_BUFFERABLE,
ARM_ACCESS_PERM_RW_RW); /* SDRAM */
X_ARM_MMU_SECTION(0x900, 0x900, 0x200,
ARM_CACHEABLE, ARM_BUFFERABLE,
ARM_ACCESS_PERM_RW_RW); /* SDRAM */
X_ARM_MMU_SECTION(0x900, 0xE00, 0x200,
ARM_UNCACHEABLE, ARM_UNBUFFERABLE,
ARM_ACCESS_PERM_RW_RW); /* SDRAM 0:128M*/
X_ARM_MMU_SECTION(0xB80, 0xB80, 0x10,
ARM_UNCACHEABLE, ARM_UNBUFFERABLE,
ARM_ACCESS_PERM_RW_RW); /* CS1 EIM control*/
X_ARM_MMU_SECTION(0xCC0, 0xCC0, 0x040,
ARM_UNCACHEABLE, ARM_UNBUFFERABLE,
ARM_ACCESS_PERM_RW_RW); /* CS4/5/NAND Flash buffer */
其中 X_ARM_MMU_SECTION 的內容,跟 MMU 的spec 一樣,一個 entry 是 1M ,所以:
#define X_ARM_MMU_SECTION(abase, vbase, size, cache, buff, access) \
{ \
int i; int j = abase; int k = vbase; \
for (i = size; i > 0 ; i--, j++, k++) \
ARM_MMU_SECTION(ttb_base, j, k, cache, buff, access); \
}
根據 size 以 1M 為單位,把所有的 table entry 都設完。
-- 因為 MMU 的 translation 是把bit20~31 拿去作 translate。所以單位是 1M (0~19 bit).
- 關於 mmu section translation 可以google 一下:https://www.google.com.tw/search?q=arm%20mmu%20section%20translation&um=1&ie=UTF-8&hl=zh-TW&tbm=isch&source=og&sa=N&tab=wi&ei=3NSDT_-eJaz0mAWizJW4Bw&biw=1366&bih=630&sei=-dSDT8-LEMycmQXnquSyBw
這 code 跟 spec 的圖結合在一起:
union ARM_MMU_FIRST_LEVEL_DESCRIPTOR {
unsigned long word;
struct ARM_MMU_FIRST_LEVEL_FAULT fault;
struct ARM_MMU_FIRST_LEVEL_PAGE_TABLE page_table;
struct ARM_MMU_FIRST_LEVEL_SECTION section;
struct ARM_MMU_FIRST_LEVEL_RESERVED reserved;
};
是 UNION.ref : ARM processor MMU -- level one descriptor 的圖。
之後就可以啟動 MMU。
然後執行 start_armboot()。
start_armboot()準備 gd_t (globale_data) 的空間,然後用類似 linux init 的方式 call init function (這裡是手動):
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init, /* basic arch cpu dependent setup */
#endif
board_init, /* basic board dependent setup */
#if defined(CONFIG_USE_IRQ)
interrupt_init, /* set up exceptions */
#endif
timer_init, /* initialize timer */
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init, /* configure available RAM banks */
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
arm_pci_init,
#endif
display_dram_config,
NULL,
};
之後就是一個一個個別 hardware function 的 init... (?為什摩不在 init_sequence[] 裡作?)然後 call check_recovery_mode()
最後是 main_loop().
check_recovery_mode( ) 就是偵測 hardware pin,然後call setup_recovery_env( )。
單純操作 env:
void setup_recovery_env(void)
{
char *env, *boot_args, *boot_cmd;
int bootdev = get_boot_device();
boot_cmd = supported_reco_envs[bootdev].cmd;
boot_args = supported_reco_envs[bootdev].args;
if (boot_cmd == NULL) {
printf("Unsupported bootup device for recovery\n");
return;
}
printf("setup env for recovery..\n");
env = getenv("bootargs_android_recovery");
/* Set env to recovery mode */
/* Only set recovery env when these env not exist, give user a
* chance to change their recovery env */
if (!env)
setenv("bootargs_android_recovery", boot_args);
env = getenv("bootcmd_android_recovery");
if (!env)
setenv("bootcmd_android_recovery", boot_cmd);
setenv("bootcmd", "run bootcmd_android_recovery");
}
就是改 bootcmd 為 "run bootcmd_android_recoery"。
這樣之後的 boot process,去 run bootcmd ,就會 run bootcmd_android_recovery.
沒有留言:
張貼留言