uboot 启动的第一阶段远跳转到 start_armboot。 它在 uboot/lib_arm/board.c 中,是 uboot 第二阶段代码的入口。第一阶段是汇编语言实现的,而第二阶段的代码是用 C 语言实现的。第一阶段在SRAM中、第二阶段在DRAM中。第一阶段注重SoC内部、第二阶段注重SoC外部Board内部。
目录
为 gd 和 bd 的分配内存
init_sequence函数
cpu_init (cpu 内部的初始化,里面是空的可以不用管)
board_init(板级设备的初始化):网卡、机器码、内存传参地址
interrupt_init(定时器的初始化)
env_init(环境变量初始化)
init_baudrate(初始化串口的波特率)
serial_init(初始化串口)
console_init_f(控制台第一阶段初始化)
print_cpuinfo(串口打印cpu信息)
checkboard(打印出开发板的名字)
init_func_i2c(I2C的初始化)
dram_init(DDR的初始化)
display_dram_config(打印显示dram的配置信息)
flash的初始化
显示初始化
mem_malloc_init(初始化uboot的堆管理器)
mmc初始化
env_relocate(是环境变量的重定位)
IP地址、MAC地址的确定
devices_init(设备的初始化)
jumptable_init(初始化跳转表)
console_init_r(控制台第二阶段初始化)
enable_interrupts(CPSR中总中断标志位的使能)
loadaddr、bootfile
board_late_init(开发板晚期初始化)
eth_initialize(网卡本身芯片的初始化)
自动更新
进入死循环,等待命令
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr; //init_fuc_ptr可以用来指向一个函数指针数组。
char *s;
int mmc_exist = 0;
#if !defined(CFG_NO_FLASH) || defined (CONFIG_VFD) || defined(CONFIG_LCD)
ulong size;
#endif
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
#if defined(CONFIG_BOOT_MOVINAND)
uint *magic = (uint *) (PHYS_SDRAM_1);
#endif
/* Pointer is writable since we allocated a register for it */
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
ulong gd_base;
gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);
#ifdef CONFIG_USE_IRQ
gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
#endif
gd = (gd_t*)gd_base;
#else
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
#endif
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset ((void*)gd, 0, sizeof (gd_t)); /* 将全局数据清零 */
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); /* 取得板级信息数据结构的起始地址 */
memset (gd->bd, 0, sizeof (bd_t)); /* 将板级信息清零 */
什么是 gd 和 bd :
gd_t 定义是在 include/asm-arm/global_data.h 中:其中定义了很多全局变量,都是整个uboot使用的。
typedef struct global_data {
bd_t *bd; /* 指向板级信息结构 */
unsigned long flags; /* 标记位 */
unsigned long baudrate; /* 串口波特率 */
unsigned long have_console; /* serial_init() was called */
unsigned long env_addr; /* 环境参数地址 */
unsigned long env_valid; /* 环境参数 CRC 校验有效标志 */
unsigned long fb_base; /* fb 起始地址 */
#ifdef CONFIG_VFD
unsigned char vfd_type; /* 显示器类型(VFD代指真空荧光屏) */
#endif
#if 0
unsigned long cpu_clk; /* cpu 频率*/
unsigned long bus_clk; /* bus 频率 */
phys_size_t ram_size; /* ram 大小 */
unsigned long reset_status; /* reset status register at boot */
#endif
void **jt; /* 跳转函数表 */
} gd_t;
bd_t 定义是在 include/asm-arm/uboot.h 中:这个bd是开发板的板级信息的结构体,里面有不少硬件相关的参数,譬如波特率、IP地址、机器码、DDR内存分布。
typedef struct bd_info {
int bi_baudrate; /* serial console baudrate */
unsigned long bi_ip_addr; /* IP Address */
struct environment_s *bi_env; /* 板子的环境变量 */
ulong bi_arch_number; /* 板子的 id */
ulong bi_boot_params; /* 板子的启动参数 */
struct /* RAM 配置 */
{
ulong start;
ulong size;
} bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;
在 uboot/lib_arm/board.c 的 70 行 用个宏:DECLARE_GLOBAL_DATA_PTR。它的原型是:
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
为什么要分配内存:
怎么分配内存:
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
init_sequence函数里有什么呢:(在 uboot/lib_arm/board.c 中的 416-442 行)
init_fnc_t *init_sequence[] = {
cpu_init, /* cpu 内部的初始化,里面是空的可以不用管 */
#if defined(CONFIG_SKIP_RELOCATE_UBOOT)
reloc_init, /* Set the relocation done flag, must
do this AFTER cpu_init(), but as soon
as possible */
#endif
board_init, /* basic board dependent setup */
interrupt_init, /* set up exceptions */
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 */
display_dram_config,
NULL,
};
int board_init(void)
{
DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_DRIVER_SMC911X
smc9115_pre_init();
#endif
#ifdef CONFIG_DRIVER_DM9000
dm9000_pre_init();
#endif
gd->bd->bi_arch_number = MACH_TYPE;
gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);
return 0;
}
int interrupt_init(void)
{
S5PC11X_TIMERS *const timers = S5PC11X_GetBase_TIMERS();
/* use PWM Timer 4 because it has no output */
/* prescaler for Timer 4 is 16 */
timers->TCFG0 = 0x0f00;
if (timer_load_val == 0) {
/*
* for 10 ms clock period @ PCLK with 4 bit divider = 1/2
* (default) and prescaler = 16. Should be 10390
* @33.25MHz and @ 66 MHz
*/
timer_load_val = get_PCLK() / (16 * 100);
}
/* load value for 10 ms timeout */
lastdec = timers->TCNTB4 = timer_load_val;
/* auto load, manual update of Timer 4 */
timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | TCON_4_UPDATE;
/* auto load, start Timer 4 */
timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | COUNT_4_ON;
timestamp = 0;
return (0);
}
int env_init(void)
{
#if defined(ENV_IS_EMBEDDED)
ulong total;
int crc1_ok = 0, crc2_ok = 0;
env_t *tmp_env1, *tmp_env2;
total = CFG_ENV_SIZE;
tmp_env1 = env_ptr;
tmp_env2 = (env_t *)((ulong)env_ptr + CFG_ENV_SIZE);
crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
if (!crc1_ok && !crc2_ok)
gd->env_valid = 0;
else if(crc1_ok && !crc2_ok)
gd->env_valid = 1;
else if(!crc1_ok && crc2_ok)
gd->env_valid = 2;
else {
/* both ok - check serial */
if(tmp_env1->flags == 255 && tmp_env2->flags == 0)
gd->env_valid = 2;
else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)
gd->env_valid = 1;
else if(tmp_env1->flags > tmp_env2->flags)
gd->env_valid = 1;
else if(tmp_env2->flags > tmp_env1->flags)
gd->env_valid = 2;
else /* flags are equal - almost impossible */
gd->env_valid = 1;
}
if (gd->env_valid == 1)
env_ptr = tmp_env1;
else if (gd->env_valid == 2)
env_ptr = tmp_env2;
#else /* ENV_IS_EMBEDDED */
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 1;
#endif /* ENV_IS_EMBEDDED */
return (0);
}
static int init_baudrate (void)
{
char tmp[64]; /* long enough for environment variables */
int i = getenv_r ("baudrate", tmp, sizeof (tmp));
gd->bd->bi_baudrate = gd->baudrate = (i > 0)
? (int) simple_strtoul (tmp, NULL, 10)
: CONFIG_BAUDRATE;
return (0);
}
int serial_init(void)
{
serial_setbrg();
return (0);
}
/* Called before relocation - use serial functions */
int console_init_f (void)
{
gd->have_console = 1;
#ifdef CONFIG_SILENT_CONSOLE
if (getenv("silent") != NULL)
gd->flags |= GD_FLG_SILENT;
#endif
return (0);
}
static int display_banner (void)
{
printf ("\n\n%s\n\n", version_string);
debug ("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n",
_armboot_start, _bss_start, _bss_end);
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
debug("\t\bMalloc and Stack is above the U-Boot Code.\n");
#else
debug("\t\bMalloc and Stack is below the U-Boot Code.\n");
#endif
#ifdef CONFIG_MODEM_SUPPORT
debug ("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ
debug ("IRQ Stack: %08lx\n", IRQ_STACK_START);
debug ("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif
open_backlight();//lqm.
//open_gprs();
return (0);
}
int print_cpuinfo(void)
{
uint set_speed;
uint tmp;
uchar result_set;
#if defined(CONFIG_CLK_533_133_100_100)
set_speed = 53300;
#elif defined(CONFIG_CLK_667_166_166_133)
set_speed = 66700;
#elif defined(CONFIG_CLK_800_200_166_133)
set_speed = 80000;
#elif defined(CONFIG_CLK_1000_200_166_133)
set_speed = 100000;
#elif defined(CONFIG_CLK_1200_200_166_133)
set_speed = 120000;
#else
set_speed = 100000;
printf("Any CONFIG_CLK_XXX is not enabled\n");
#endif
tmp = (set_speed / (get_ARMCLK()/1000000));
if((tmp < 105) && (tmp > 95)){
result_set = 1;
} else {
result_set = 0;
}
#ifdef CONFIG_MCP_SINGLE
printf("\nCPU: S5PV210@%ldMHz(%s)\n", get_ARMCLK()/1000000, ((result_set == 1) ? "OK" : "FAIL"));
#else
printf("\nCPU: S5PC110@%ldMHz(%s)\n", get_ARMCLK()/1000000, ((result_set == 1) ? "OK" : "FAIL"));
#endif
printf(" APLL = %ldMHz, HclkMsys = %ldMHz, PclkMsys = %ldMHz\n",
get_FCLK()/1000000, get_HCLK()/1000000, get_PCLK()/1000000);
#if 1
printf(" MPLL = %ldMHz, EPLL = %ldMHz\n",
get_MPLL_CLK()/1000000, get_PLLCLK(EPLL)/1000000);
printf(" HclkDsys = %ldMHz, PclkDsys = %ldMHz\n",
get_HCLKD()/1000000, get_PCLKD()/1000000);
printf(" HclkPsys = %ldMHz, PclkPsys = %ldMHz\n",
get_HCLKP()/1000000, get_PCLKP()/1000000);
printf(" SCLKA2M = %ldMHz\n", get_SCLKA2M()/1000000);
#endif
puts("Serial = CLKUART ");
return 0;
}
#ifdef CONFIG_DISPLAY_BOARDINFO
int checkboard(void)
{
#ifdef CONFIG_MCP_SINGLE
#if defined(CONFIG_VOGUES)
printf("\nBoard: VOGUESV210\n");
#else
printf("\nBoard: X210\n");
#endif //CONFIG_VOGUES
#else
printf("\nBoard: X210\n");
#endif
return (0);
}
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
static int init_func_i2c (void)
{
puts ("I2C: ");
i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
puts ("ready\n");
return (0);
}
#endif
int dram_init(void)
{
DECLARE_GLOBAL_DATA_PTR;
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
#if defined(PHYS_SDRAM_2)
gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE;
#endif
#if defined(PHYS_SDRAM_3)
gd->bd->bi_dram[2].start = PHYS_SDRAM_3;
gd->bd->bi_dram[2].size = PHYS_SDRAM_3_SIZE;
#endif
return 0;
}
static int display_dram_config (void)
{
int i;
#ifdef DEBUG
puts ("RAM Configuration:\n");
for(i=0; ibd->bi_dram[i].start);
print_size (gd->bd->bi_dram[i].size, "\n");
}
#else
ulong size = 0;
for (i=0; ibd->bi_dram[i].size;
}
puts("DRAM: ");
print_size(size, "\n");
#endif
return (0);
}
#ifndef CFG_NO_FLASH
/* configure available FLASH banks */
size = flash_init ();
display_flash_config (size);
#endif /* CFG_NO_FLASH */
#ifdef CONFIG_VFD
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for VFD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
size = vfd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_VFD */
#ifdef CONFIG_LCD
/* board init may have inited fb_base */
if (!gd->fb_base) {
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for LCD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
size = lcd_setmem (addr);
gd->fb_base = addr;
}
#endif /* CONFIG_LCD */
/* armboot_start is defined in the board-specific linker script */
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */ /* 初始化堆 */
mem_malloc_init (CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE);
#else
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
#endif
//******************************//
// Board Specific
// #if defined(CONFIG_SMDKXXXX)
//******************************//
#if defined(CONFIG_X210) /* CONFIG_X210 */
#if defined(CONFIG_GENERIC_MMC)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd);
if (mmc_exist != 0)
{
puts ("0 MB\n");
#ifdef CONFIG_CHECK_X210CV3
check_flash_flag=0;//check inand error!
#endif
}
#ifdef CONFIG_CHECK_X210CV3
else
{
check_flash_flag=1;//check inand ok!
}
#endif
#endif
#if defined(CONFIG_MTD_ONENAND)
puts("OneNAND: ");
onenand_init();
/*setenv("bootcmd", "onenand read c0008000 80000 380000;bootm c0008000");*/
#else
//puts("OneNAND: (FSR layer enabled)\n");
#endif
#if defined(CONFIG_CMD_NAND)
puts("NAND: ");
nand_init();
#endif
#endif /* CONFIG_X210 */ /* end of CONFIG_X210 */
/* initialize environment */
env_relocate ();
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
/* MAC Address */
{
int i;
ulong reg;
char *s, *e;
char tmp[64];
i = getenv_r ("ethaddr", tmp, sizeof (tmp));
s = (i > 0) ? tmp : NULL;
for (reg = 0; reg < 6; ++reg) {
gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
if (s)
s = (*e) ? e + 1 : e;
}
#ifdef CONFIG_HAS_ETH1
i = getenv_r ("eth1addr", tmp, sizeof (tmp));
s = (i > 0) ? tmp : NULL;
for (reg = 0; reg < 6; ++reg) {
gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
if (s)
s = (*e) ? e + 1 : e;
}
#endif
}
devices_init (); /* get the devices list going. */
jumptable_init ();
#if !defined(CONFIG_SMDK6442)
console_init_r (); /* fully init console as a device */
#endif
/* enable exceptions */
enable_interrupts ();
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
#if defined(CONFIG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
}
#endif
#ifdef BOARD_LATE_INIT
board_late_init ();
#endif
eth_initialize(gd->bd);
if(check_menu_update_from_sd()==0)//update mode
{
puts ("[LEFT DOWN] update mode\n");
run_command("fdisk -c 0",0);
update_all();
}
else
puts ("[LEFT UP] boot mode\n");
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
void main_loop (void)
{
static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
int len;
int rc = 1;
int flag;
char *s;
int bootdelay;
s = getenv ("bootdelay");
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; /* 获取超时信息 */
s = getenv ("bootcmd"); /* 获取启动命令 */
/* abortboot会判断用户选择的启动模式,如果是命令模式就会返回1,如果是其他模式就不再返回 */
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
s = getenv ("bootcmd");
run_command (s, 0);
}
for (;;) {
len = readline (CONFIG_SYS_PROMPT); /* 读取输入 */
flag = 0;
if (len > 0)
strcpy (lastcommand, console_buffer); /* 将输入保存到历史记录中 */
else if (len == 0)
flag |= CMD_FLAG_REPEAT; /* 如果没有输入则重复上次 */
if (len == -1)
puts ("\n");
else
rc = run_command (lastcommand, flag); /* 执行命令 */
if (rc <= 0) { /* 执行错误的命令从历史记录中删除 */
lastcommand[0] = 0;
}
}
}
这样uboot的启动第二阶段到这里已经结束了。uboot/lib_arm/board.c 代码如下:
/*
* (C) Copyright 2002-2006
* Wolfgang Denk, DENX Software Engineering, [email protected].
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH
* Marius Groeger
*
* 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
*/
/*
* To match the U-Boot user interface on ARM platforms to the U-Boot
* standard (as on PPC platforms), some messages with debug character
* are removed from the default U-Boot build.
*
* Define DEBUG here if you want additional info as shown below
* printed upon startup:
*
* U-Boot code: 00F00000 -> 00F3C774 BSS: -> 00FC3274
* IRQ Stack: 00ebff7c
* FIQ Stack: 00ebef7c
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef CONFIG_GENERIC_MMC
#include
#endif
#undef DEBUG
#ifdef CONFIG_DRIVER_SMC91111
#include "../drivers/net/smc91111.h"
#endif
#ifdef CONFIG_DRIVER_LAN91C96
#include "../drivers/net/lan91c96.h"
#endif
#include
DECLARE_GLOBAL_DATA_PTR;
void nand_init (void);
void onenand_init(void);
ulong monitor_flash_len;
int check_flash_flag=1;
#ifdef CONFIG_HAS_DATAFLASH
extern int AT91F_DataflashInit(void);
extern void dataflash_print_info(void);
#endif
#ifndef CONFIG_IDENT_STRING
#define CONFIG_IDENT_STRING ""
#endif
const char version_string[] =
U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")"CONFIG_IDENT_STRING;
#ifdef CONFIG_DRIVER_CS8900
extern int cs8900_get_enetaddr (uchar * addr);
#endif
#ifdef CONFIG_DRIVER_RTL8019
extern void rtl8019_get_enetaddr (uchar * addr);
#endif
#if defined(CONFIG_HARD_I2C) || \
defined(CONFIG_SOFT_I2C)
#include
#endif
/*
* Begin and End of memory area for malloc(), and current "brk"
*/
static ulong mem_malloc_start = 0;
static ulong mem_malloc_end = 0;
static ulong mem_malloc_brk = 0;
static void mem_malloc_init (ulong dest_addr)
{
mem_malloc_start = dest_addr;
mem_malloc_end = dest_addr + CFG_MALLOC_LEN;
mem_malloc_brk = mem_malloc_start;
memset ((void *) mem_malloc_start, 0,
mem_malloc_end - mem_malloc_start);
}
void *sbrk (ptrdiff_t increment)
{
ulong old = mem_malloc_brk;
ulong new = old + increment;
if ((new < mem_malloc_start) || (new > mem_malloc_end)) {
return (NULL);
}
mem_malloc_brk = new;
return ((void *) old);
}
char *strmhz(char *buf, long hz)
{
long l, n;
long m;
n = hz / 1000000L;
l = sprintf (buf, "%ld", n);
m = (hz % 1000000L) / 1000L;
if (m != 0)
sprintf (buf + l, ".%03ld", m);
return (buf);
}
/************************************************************************
* Coloured LED functionality
************************************************************************
* May be supplied by boards if desired
*/
void __coloured_LED_init (void) {}
void coloured_LED_init (void)
__attribute__((weak, alias("__coloured_LED_init")));
void __red_LED_on (void) {}
void red_LED_on (void)
__attribute__((weak, alias("__red_LED_on")));
void __red_LED_off(void) {}
void red_LED_off(void) __attribute__((weak, alias("__red_LED_off")));
void __green_LED_on(void) {}
void green_LED_on(void) __attribute__((weak, alias("__green_LED_on")));
void __green_LED_off(void) {}
void green_LED_off(void)__attribute__((weak, alias("__green_LED_off")));
void __yellow_LED_on(void) {}
void yellow_LED_on(void)__attribute__((weak, alias("__yellow_LED_on")));
void __yellow_LED_off(void) {}
void yellow_LED_off(void)__attribute__((weak, alias("__yellow_LED_off")));
/************************************************************************
* Init Utilities *
************************************************************************
* Some of this code should be moved into the core functions,
* or dropped completely,
* but let's get it working (again) first...
*/
static int init_baudrate (void)
{
char tmp[64]; /* long enough for environment variables */
int i = getenv_r ("baudrate", tmp, sizeof (tmp));
gd->bd->bi_baudrate = gd->baudrate = (i > 0)
? (int) simple_strtoul (tmp, NULL, 10)
: CONFIG_BAUDRATE;
return (0);
}
static void open_backlight(void)
{
unsigned int reg;
//open backlight. GPF3_5=1
reg = readl(GPF3CON);
reg = reg & ~(0xf<<20) | (0x1<<20);
writel(reg,GPF3CON);
reg = readl(GPF3PUD);
reg = reg & ~(0x3<<10) | (0x2<<10);
writel(reg,GPF3PUD);
reg = readl(GPF3DAT);
reg |= (0x1<<5);
writel(reg,GPF3DAT);
}
/*
* GPH0_2: LEFT
*/
static int check_menu_update_from_sd(void)
{
unsigned int i;
unsigned int reg;
//GPH0_2
reg = readl(GPH0CON);
reg = reg & ~(0xf<<8) | (0x0<<8);
writel(reg,GPH0CON);
for(i=0;i<100;i++)
udelay(500);
reg = readl(GPH0DAT);
reg = reg & (0x1<<2);
if(reg)
return 1;
else //update mode
return 0;
}
/*
* GPC1_1: GPRS_PWR_EN
* GPJ0_4: CDMAPWR
* GPJ0_1: GSM_RST
* GPJ0_6: GSM_ON_OFF
*/
static void open_gprs(void)
{
unsigned int i;
unsigned int reg;
//step0: init gpio
reg = readl(GPC1CON);
reg = reg & ~(0xf<<4) | (0x1<<4); //set GPC1_1 to output and enable pullup
writel(reg,GPC1CON);
reg = readl(GPC1PUD);
reg = reg & ~(0x3<<2) | (0x2<<2);
writel(reg,GPC1PUD);
reg = readl(GPJ0CON);
reg = reg & ~(0xf<<4) | (0x1<<4); //set GPJ0_1 to output and enable pullup
writel(reg,GPJ0CON);
reg = readl(GPJ0PUD);
reg = reg & ~(0x3<<2) | (0x2<<2);
writel(reg,GPJ0PUD);
reg = readl(GPJ0CON);
reg = reg & ~(0xf<<16) | (0x1<<16); //set GPJ0_4 to output and enable pullup
writel(reg,GPJ0CON);
reg = readl(GPJ0PUD);
reg = reg & ~(0x3<<8) | (0x2<<8);
writel(reg,GPJ0PUD);
reg = readl(GPJ0CON);
reg = reg & ~(0xf<<24) | (0x1<<24); //set GPJ0_6 to low level and enable pullup
writel(reg,GPJ0CON);
reg = readl(GPJ0PUD);
reg = reg & ~(0x3<<12) | (0x2<<12);
writel(reg,GPJ0PUD);
reg = readl(GPJ0DAT);
reg &= ~(0x1<<6);
writel(reg,GPJ0DAT);
//step1: disable reset
reg = readl(GPJ0DAT);
reg &= ~(0x1<<1);
writel(reg,GPJ0DAT);
//step2: enable GPRS power(4.2V to GPRS module)
reg = readl(GPC1DAT);
reg |= (0x1<<1);
writel(reg,GPC1DAT);
//step3: enable CDMAPWR(4.2V to GC864)
reg = readl(GPJ0DAT);
reg |= (0x1<<4);
writel(reg,GPJ0DAT);
for(i=0;i<100;i++)
udelay(1000);
//step4: power on GC864
reg = readl(GPJ0DAT);
reg |= (0x1<<6);
writel(reg,GPJ0DAT);
for(i=0;i<1000/*2000*/;i++)
udelay(1000);
reg &= ~(0x1<<6);
writel(reg,GPJ0DAT);
}
static int display_banner (void)
{
printf ("\n\n%s\n\n", version_string);
debug ("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n",
_armboot_start, _bss_start, _bss_end);
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
debug("\t\bMalloc and Stack is above the U-Boot Code.\n");
#else
debug("\t\bMalloc and Stack is below the U-Boot Code.\n");
#endif
#ifdef CONFIG_MODEM_SUPPORT
debug ("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ
debug ("IRQ Stack: %08lx\n", IRQ_STACK_START);
debug ("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif
open_backlight();//lqm.
//open_gprs();
return (0);
}
/*
* WARNING: this code looks "cleaner" than the PowerPC version, but
* has the disadvantage that you either get nothing, or everything.
* On PowerPC, you might see "DRAM: " before the system hangs - which
* gives a simple yet clear indication which part of the
* initialization if failing.
*/
static int display_dram_config (void)
{
int i;
#ifdef DEBUG
puts ("RAM Configuration:\n");
for(i=0; ibd->bi_dram[i].start);
print_size (gd->bd->bi_dram[i].size, "\n");
}
#else
ulong size = 0;
for (i=0; ibd->bi_dram[i].size;
}
puts("DRAM: ");
print_size(size, "\n");
#endif
return (0);
}
#ifndef CFG_NO_FLASH
static void display_flash_config (ulong size)
{
puts ("Flash: ");
print_size (size, "\n");
}
#endif /* CFG_NO_FLASH */
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
static int init_func_i2c (void)
{
puts ("I2C: ");
i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
puts ("ready\n");
return (0);
}
#endif
#ifdef CONFIG_SKIP_RELOCATE_UBOOT
/*
* This routine sets the relocation done flag, because even if
* relocation is skipped, the flag is used by other generic code.
*/
static int reloc_init(void)
{
gd->flags |= GD_FLG_RELOC;
return 0;
}
#endif
/*
* Breathe some life into the board...
*
* Initialize a serial port as console, and carry out some hardware
* tests.
*
* The first part of initialization is running from Flash memory;
* its main purpose is to initialize the RAM so that we
* can relocate the monitor code to RAM.
*/
/*
* All attempts to come up with a "common" initialization sequence
* that works for all boards and architectures failed: some of the
* requirements are just _too_ different. To get rid of the resulting
* mess of board dependent #ifdef'ed code we now make the whole
* initialization sequence configurable to the user.
*
* The requirements for any new initalization function is simple: it
* receives a pointer to the "global data" structure as it's only
* argument, and returns an integer return code, where 0 means
* "continue" and != 0 means "fatal error, hang the system".
*/
typedef int (init_fnc_t) (void);
int print_cpuinfo (void); /* test-only */
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup */
#if defined(CONFIG_SKIP_RELOCATE_UBOOT)
reloc_init, /* Set the relocation done flag, must
do this AFTER cpu_init(), but as soon
as possible */
#endif
board_init, /* basic board dependent setup */
interrupt_init, /* set up exceptions */
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 */
display_dram_config,
NULL,
};
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;
char *s;
int mmc_exist = 0;
#if !defined(CFG_NO_FLASH) || defined (CONFIG_VFD) || defined(CONFIG_LCD)
ulong size;
#endif
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
#if defined(CONFIG_BOOT_MOVINAND)
uint *magic = (uint *) (PHYS_SDRAM_1);
#endif
/* Pointer is writable since we allocated a register for it */
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
ulong gd_base;
gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);
#ifdef CONFIG_USE_IRQ
gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
#endif
gd = (gd_t*)gd_base;
#else
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
#endif
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
monitor_flash_len = _bss_start - _armboot_start;
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
#ifndef CFG_NO_FLASH
/* configure available FLASH banks */
size = flash_init ();
display_flash_config (size);
#endif /* CFG_NO_FLASH */
#ifdef CONFIG_VFD
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for VFD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
size = vfd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_VFD */
#ifdef CONFIG_LCD
/* board init may have inited fb_base */
if (!gd->fb_base) {
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for LCD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
size = lcd_setmem (addr);
gd->fb_base = addr;
}
#endif /* CONFIG_LCD */
/* armboot_start is defined in the board-specific linker script */
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
mem_malloc_init (CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE);
#else
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
#endif
//******************************//
// Board Specific
// #if defined(CONFIG_SMDKXXXX)
//******************************//
#if defined(CONFIG_SMDK6410)
#if defined(CONFIG_GENERIC_MMC)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd);
if (mmc_exist != 0)
{
puts ("0 MB\n");
}
#else
#if defined(CONFIG_MMC)
puts("SD/MMC: ");
if (INF_REG3_REG == 0)
movi_ch = 0;
else
movi_ch = 1;
movi_set_capacity();
movi_init();
movi_set_ofs(MOVI_TOTAL_BLKCNT);
#endif
#endif
if (INF_REG3_REG == BOOT_ONENAND) {
#if defined(CONFIG_CMD_ONENAND)
puts("OneNAND: ");
onenand_init();
#endif
/*setenv("bootcmd", "onenand read c0008000 80000 380000;bootm c0008000");*/
} else {
puts("NAND: ");
nand_init();
if (INF_REG3_REG == 0 || INF_REG3_REG == 7)
setenv("bootcmd", "movi read kernel c0008000;movi read rootfs c0800000;bootm c0008000");
else
setenv("bootcmd", "nand read c0008000 80000 380000;bootm c0008000");
}
#endif /* CONFIG_SMDK6410 */
#if defined(CONFIG_SMDKC100)
#if defined(CONFIG_GENERIC_MMC)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd);
if (mmc_exist != 0)
{
puts ("0 MB\n");
}
#endif
#if defined(CONFIG_CMD_ONENAND)
puts("OneNAND: ");
onenand_init();
#endif
#if defined(CONFIG_CMD_NAND)
puts("NAND: ");
nand_init();
#endif
#endif /* CONFIG_SMDKC100 */
#if defined(CONFIG_X210)
#if defined(CONFIG_GENERIC_MMC)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd);
if (mmc_exist != 0)
{
puts ("0 MB\n");
#ifdef CONFIG_CHECK_X210CV3
check_flash_flag=0;//check inand error!
#endif
}
#ifdef CONFIG_CHECK_X210CV3
else
{
check_flash_flag=1;//check inand ok!
}
#endif
#endif
#if defined(CONFIG_MTD_ONENAND)
puts("OneNAND: ");
onenand_init();
/*setenv("bootcmd", "onenand read c0008000 80000 380000;bootm c0008000");*/
#else
//puts("OneNAND: (FSR layer enabled)\n");
#endif
#if defined(CONFIG_CMD_NAND)
puts("NAND: ");
nand_init();
#endif
#endif /* CONFIG_X210 */
#if defined(CONFIG_SMDK6440)
#if defined(CONFIG_GENERIC_MMC)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd);
if (mmc_exist != 0)
{
puts ("0 MB\n");
}
#else
#if defined(CONFIG_MMC)
if (INF_REG3_REG == 1) { /* eMMC_4.3 */
puts("eMMC: ");
movi_ch = 1;
movi_emmc = 1;
movi_init();
movi_set_ofs(0);
} else if (INF_REG3_REG == 7 || INF_REG3_REG == 0) { /* SD/MMC */
if (INF_REG3_REG & 0x1)
movi_ch = 1;
else
movi_ch = 0;
puts("SD/MMC: ");
movi_set_capacity();
movi_init();
movi_set_ofs(MOVI_TOTAL_BLKCNT);
} else {
}
#endif
#endif
if (INF_REG3_REG == 2) {
/* N/A */
} else {
puts("NAND: ");
nand_init();
//setenv("bootcmd", "nand read c0008000 80000 380000;bootm c0008000");
}
#endif /* CONFIG_SMDK6440 */
#if defined(CONFIG_SMDK6430)
#if defined(CONFIG_GENERIC_MMC)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd);
if (mmc_exist != 0)
{
puts ("0 MB\n");
}
#else
#if defined(CONFIG_MMC)
puts("SD/MMC: ");
if (INF_REG3_REG == 0)
movi_ch = 0;
else
movi_ch = 1;
movi_set_capacity();
movi_init();
movi_set_ofs(MOVI_TOTAL_BLKCNT);
#endif
#endif
if (INF_REG3_REG == BOOT_ONENAND) {
#if defined(CONFIG_CMD_ONENAND)
puts("OneNAND: ");
onenand_init();
#endif
/*setenv("bootcmd", "onenand read c0008000 80000 380000;bootm c0008000");*/
} else if (INF_REG3_REG == BOOT_NAND) {
puts("NAND: ");
nand_init();
} else {
}
if (INF_REG3_REG == 0 || INF_REG3_REG == 7)
setenv("bootcmd", "movi read kernel c0008000;movi read rootfs c0800000;bootm c0008000");
else
setenv("bootcmd", "nand read c0008000 80000 380000;bootm c0008000");
#endif /* CONFIG_SMDK6430 */
#if defined(CONFIG_SMDK6442)
#if defined(CONFIG_GENERIC_MMC)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd);
if (mmc_exist != 0)
{
puts ("0 MB\n");
}
#else
#if defined(CONFIG_MMC)
puts("SD/MMC: ");
movi_set_capacity();
movi_init();
movi_set_ofs(MOVI_TOTAL_BLKCNT);
#endif
#endif
#if defined(CONFIG_CMD_ONENAND)
if (INF_REG3_REG == BOOT_ONENAND) {
puts("OneNAND: ");
onenand_init();
}
#endif
#endif /* CONFIG_SMDK6442 */
#if defined(CONFIG_SMDK2416) || defined(CONFIG_SMDK2450)
#if defined(CONFIG_NAND)
puts("NAND: ");
nand_init();
#endif
#if defined(CONFIG_ONENAND)
puts("OneNAND: ");
onenand_init();
#endif
#if defined(CONFIG_BOOT_MOVINAND)
puts("SD/MMC: ");
if ((0x24564236 == magic[0]) && (0x20764316 == magic[1])) {
printf("Boot up for burning\n");
} else {
movi_init();
movi_set_ofs(MOVI_TOTAL_BLKCNT);
}
#endif
#endif /* CONFIG_SMDK2416 CONFIG_SMDK2450 */
#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
/* initialize environment */
env_relocate ();
#ifdef CONFIG_VFD
/* must do this after the framebuffer is allocated */
drv_vfd_init();
#endif /* CONFIG_VFD */
#ifdef CONFIG_SERIAL_MULTI
serial_initialize();
#endif
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
/* MAC Address */
{
int i;
ulong reg;
char *s, *e;
char tmp[64];
i = getenv_r ("ethaddr", tmp, sizeof (tmp));
s = (i > 0) ? tmp : NULL;
for (reg = 0; reg < 6; ++reg) {
gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
if (s)
s = (*e) ? e + 1 : e;
}
#ifdef CONFIG_HAS_ETH1
i = getenv_r ("eth1addr", tmp, sizeof (tmp));
s = (i > 0) ? tmp : NULL;
for (reg = 0; reg < 6; ++reg) {
gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
if (s)
s = (*e) ? e + 1 : e;
}
#endif
}
devices_init (); /* get the devices list going. */
#ifdef CONFIG_CMC_PU2
load_sernum_ethaddr ();
#endif /* CONFIG_CMC_PU2 */
jumptable_init ();
#if !defined(CONFIG_SMDK6442)
console_init_r (); /* fully init console as a device */
#endif
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r ();
#endif
/* enable exceptions */
enable_interrupts ();
/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_TI_EMAC
extern void dm644x_eth_set_mac_addr (const u_int8_t *addr);
if (getenv ("ethaddr")) {
dm644x_eth_set_mac_addr(gd->bd->bi_enetaddr);
}
#endif
#ifdef CONFIG_DRIVER_CS8900
cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
if (getenv ("ethaddr")) {
smc_set_mac_addr(gd->bd->bi_enetaddr);
}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
#if defined(CONFIG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
}
#endif
#ifdef BOARD_LATE_INIT
board_late_init ();
#endif
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
puts ("Net: ");
#endif
eth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)
debug ("Reset Ethernet PHY\n");
reset_phy();
#endif
#endif
#if defined(CONFIG_CMD_IDE)
puts("IDE: ");
ide_init();
#endif
/****************lxg added**************/
#ifdef CONFIG_MPAD
extern int x210_preboot_init(void);
x210_preboot_init();
#endif
/****************end**********************/
/* check menukey to update from sd */
extern void update_all(void);
if(check_menu_update_from_sd()==0)//update mode
{
puts ("[LEFT DOWN] update mode\n");
run_command("fdisk -c 0",0);
update_all();
}
else
puts ("[LEFT UP] boot mode\n");
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
/* NOTREACHED - no way out of command loop except booting */
}
void hang (void)
{
puts ("### ERROR ### Please RESET the board ###\n");
for (;;);
}
#ifdef CONFIG_MODEM_SUPPORT
static inline void mdm_readline(char *buf, int bufsiz);
/* called from main loop (common/main.c) */
extern void dbg(const char *fmt, ...);
int mdm_init (void)
{
char env_str[16];
char *init_str;
int i;
extern char console_buffer[];
extern void enable_putc(void);
extern int hwflow_onoff(int);
enable_putc(); /* enable serial_putc() */
#ifdef CONFIG_HWFLOW
init_str = getenv("mdm_flow_control");
if (init_str && (strcmp(init_str, "rts/cts") == 0))
hwflow_onoff (1);
else
hwflow_onoff(-1);
#endif
for (i = 1;;i++) {
sprintf(env_str, "mdm_init%d", i);
if ((init_str = getenv(env_str)) != NULL) {
serial_puts(init_str);
serial_puts("\n");
for(;;) {
mdm_readline(console_buffer, CFG_CBSIZE);
dbg("ini%d: [%s]", i, console_buffer);
if ((strcmp(console_buffer, "OK") == 0) ||
(strcmp(console_buffer, "ERROR") == 0)) {
dbg("ini%d: cmd done", i);
break;
} else /* in case we are originating call ... */
if (strncmp(console_buffer, "CONNECT", 7) == 0) {
dbg("ini%d: connect", i);
return 0;
}
}
} else
break; /* no init string - stop modem init */
udelay(100000);
}
udelay(100000);
/* final stage - wait for connect */
for(;i > 1;) { /* if 'i' > 1 - wait for connection
message from modem */
mdm_readline(console_buffer, CFG_CBSIZE);
dbg("ini_f: [%s]", console_buffer);
if (strncmp(console_buffer, "CONNECT", 7) == 0) {
dbg("ini_f: connected");
return 0;
}
}
return 0;
}
/* 'inline' - We have to do it fast */
static inline void mdm_readline(char *buf, int bufsiz)
{
char c;
char *p;
int n;
n = 0;
p = buf;
for(;;) {
c = serial_getc();
/* dbg("(%c)", c); */
switch(c) {
case '\r':
break;
case '\n':
*p = '\0';
return;
default:
if(n++ > bufsiz) {
*p = '\0';
return; /* sanity check */
}
*p = c;
p++;
break;
}
}
}
#endif /* CONFIG_MODEM_SUPPORT */