*(C) Copyright 2002-2006
*Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
*(C) Copyright 2002
*Sysgo Real-Time Solutions, GmbH <www.elinos.com>
*Marius Groeger <mgroeger@sysgo.de>
*
*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,
* MA02111-1307 USA
*/
/*
* Tomatch 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 <common.h>
#include <command.h>
#include <malloc.h>
#include <devices.h>
#include <version.h>
#include <net.h>
#include <asm/io.h>
#include <movi.h>
#include <regs.h>
#include <serial.h>
#include <nand.h>
#include <onenand_uboot.h>
#ifdef CONFIG_GENERIC_MMC
#include <mmc.h>
#endif
#undef DEBUG
#ifdef CONFIG_DRIVER_SMC91111
#include"../drivers/net/smc91111.h"
#endif
#ifdef CONFIG_DRIVER_LAN91C96
#include"../drivers/net/lan91c96.h"
#endif
#include <s5pc110.h>
DECLARE_GLOBAL_DATA_PTR; //#defineDECLARE_GLOBAL_DATA_PTR registervolatile gd_t *gd asm ("r8")定义了一个指针类型的全局变量叫gd这个全局变量
//是一个gd_t结构体的指针类型,占4字节,用volatile表示可变的,用register修饰表示这个变量要尽量放到寄存器中,后面的asm ("r8")是gcc支持放入一种语法,
//意思就是要把gd放到寄存器r8中,为什么定义为register?因为这个全局变量gd(global data 的简称)是uboot中很重要的一个全局变量
//(准确的说这个全局变量是指向一个结构体gd_t),里面的内容就是构成uboot的常用的所有的全局变量所形成的结构体,所以这个gd在程序中经常被访问
//因放在register中提升运行效率,和功能无关,并不是必须要放在register 中
//2:DECLARE_GLOBAL_DATA_PTR只能定义了一个指针,就是说gd里的这些全局变量并没有被分配内存,我们在使用gd之前要给她分配内存
void nand_init (void); //否则gd也只是一个野指针,裸机情况下是没有malloc来申请内存的,因为没有这个机制管理内存,操作系统下才行
void onenand_init(void);//(2)gd和bd需要内存,内存当前没有被人管理(因为没有操作系统统一管理内存),
//大片的DDR内存散放着可以随意使用(只要使用内存地址直接去访问内存即可)。但是因为uboot中后续很多操作还需要大片的连着内存块,
//因此这里使用内存要本着够用就好,紧凑排布的原则。所以我们在uboot中需要有一个整体规划。
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 <i2c.h>
#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 (ulongdest_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,
* ordropped completely,
*but let's get it working (again) first...
*/
static int init_baudrate (void)
{
char tmp[64]; /* long enoughfor 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 tooutput 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 tooutput 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.
* OnPowerPC, 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; i<CONFIG_NR_DRAM_BANKS; i++) {
printf ("Bank #%d: %08lx ", i,gd->bd->bi_dram[i].start);
print_size (gd->bd->bi_dram[i].size, "\n");
}
#else
ulong size = 0;
for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {
size += gd->bd->bi_dram[i].size;
}
puts("DRAM: ");
print_size(size, "\n");
#endif
return (0);
}
#ifndef CFG_NO_FLASH
static void display_flash_config (ulongsize)
{
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); //init_fnc_t是一个函数类型 init_fnc_t**init_fnc_ptr; //是一个函数类型的二重指针,所以指向函数指针数组
int print_cpuinfo (void); /* test-only */
init_fnc_t *init_sequence[] = { //函数指针数组,函数指针是init_fnc_t类型的(特征是接受的参数的类型是void,返回值是int)
cpu_init, /* basic cpudependent setup */ //定义时就实现了初始化,初始化的函数指针都是一些函数名
#if defined(CONFIG_SKIP_RELOCATE_UBOOT) //init_sequence的这些函数都是board级别的各种硬件初始化,就是开发板级别,相对于SOC来说的,是CPU外边,开发板里边的
reloc_init, /* Set therelocation done flag, must
do this AFTER cpu_init(),but as soon
as possible */
#endif //pu_init,是CPU里面的,在之前已经初始化完了,
board_init, /* basic boarddependent setup */ //board_init是在uboot/board/samsung/x210/x210.c中,是对x210 开发板相关的初始化
//其中在board_init中声明有DECLARE_GLOBAL_DATA_PTR是为了本函数里面的后面使用gd方便,因此可以看出gd声明定义成一个宏
//的原因就是我们要到处去使用gd,因此就要到处声明,定义成宏比较方便。不包含头文件方便路径查找
//本函数里面还有个CONFIG_DRIVER_DM9000宏,是配置网卡(初始化),这个宏是x210_sd.h中定义的,用来配置开发板的网卡,
//dm9000_pre_init函数就是对应的DM9000网卡的初始化函数,开发板移植uboot时,如果要移植网卡主要就是这里。
//这个函数中主要是网卡GPIO和端口配置,不是网卡的驱动,因为网卡的驱动是现成的正确的,移植的时候驱动是不需要改动的,
//关键是这里的初始化,因为这些基本初始化是跟硬件相关的,
//board_init中除了网卡上的初始化,还有DDR的初始化:
//gd->bd->bi_arch_number = MACH_TYPE;
//gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);
//这里的初始化DDr跟之前在汇编阶段lowlevel_init讲的初始化DDr是不同的,当初是硬件的初始化,让DDR可以开始工作,
//现在是DDR的配置的DDR的相关的属性配置和地址设置的初始化,纯软件上的初始化,
//软件层次上的初始化DDR的原因,对于uboot来说,至于uboot 中怎么知道ddr的信息(如有几片DDR内存,每一片的地址,长度这些信息呢?),是由程序员在移植uboot
//到一个开发板时,程序员自己在x210_sd.h中使用宏定义去配置出来板子上的DDR内存的信息,然后uboot只要读取这些信息就行
//实际上还有一条思路:就是uboot通过代码读取硬件信息来知道DDR的配置,但是uboot没有这样。实际上pc的bios采用的是这种
interrupt_init, /* set upexceptions */ //
env_init, /* initializeenvironment */
init_baudrate, /* initialzebaudrate settings */
serial_init, /* serialcommunications setup */
console_init_f, /* stage 1init of console */
display_banner, /* say thatwe are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* displaycpu 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, /* configureavailable RAM banks */
display_dram_config,//打印dram配置信息
NULL, //在这里加了NULL,为了循环的终止
};
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr; //是一个二重函数指针,作用:用来指向一个一重指针,一个是指向指针数组,因此这里的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在DDr中内存分配的起始地址
// uboot的区域地址:CFG_UBOOT_BASE,内存如果不够,UBoot怕被冲掉,就把CFG_UBOOT_SIZE(原本为设为2MB)改大点
gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN -CFG_STACK_SIZE - sizeof(gd_t);//算内存的地址33E00000+2MB-CFG_MALLOC_LEN(堆912KB) - CFG_STACK_SIZE(栈512KB)-sizeof(gd_t)(36字节)gd_t结构体的大小
#ifdef CONFIG_USE_IRQ //gd_t定义在include/asm-arm/global_data.h中,gd_t中定义了很多变量,都是整个uboot使用的,其中有一个
gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ); //bd_t类型的指针,指向一个bd_t类型的变量,这个bd是开发板的板级信息的结构体
#endif //里面有不少跟硬件相关的参数,譬如波特率,IP地址,机器码,DDR内存分布
gd = (gd_t*)gd_base; //实例化,将指针跟内存绑在一起
#else
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
#endif
//465到491之间的代码都是在给gd_t,bd分配内存 gd,bd是普通的全局变量而已,只是全局变量太多把他们集合起来而已了。
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory"); //内嵌汇编:作用:避免高版本的GCC编译器的过度优化造成的错误
memset ((void*)gd, 0, sizeof (gd_t)); //gd跟bd的分配内存,虽然内存没人管,有好多,但是不能随便用。要紧凑摆布
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); //申请完先memset清内存,(普通内存是想上涨的,栈是向下张),这几段语句就是将gd,bd
memset (gd->bd, 0, sizeof (bd_t)); //算出他们的内存的并实例化
monitor_flash_len = _bss_start - _armboot_start;
//把一个函数指针数组赋给init_fnc_ptr(二重函数指针),就是用for循环的方式遍历数组,从而达到调用数组里面的函数应用
//便利的目的:就是为了一次执行函数数组中一次执行数组中的所有函数,
//遍历的方式:1:数组下标,用数组个数来截止,2:就是在数组的有效元素末尾放一个标志,一次遍历到标准此截止(如NULL,有点类似字符串遍历)
//因为是指针,所以用NULL做标志,我们遍历时从头一次开始遍历,直到NULL结束,这种方式就是不用事先统计数组个数
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { //for循环init_sequence,for(init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)==for(init_fnc_ptr = init_sequence; *init_fnc_ptr!=NULL; ++init_fnc_ptr)
if ((*init_fnc_ptr)() != 0) {//函数指针调用方法 //原init_sequence数组中的函数都是正确返回0,不正确返回-1
hang (); //挂起,不执行什么,如果中间出错误就启动这个函数,系统挂起,整个启动终止,除非重启开发板,不然没有办法
}
}
#ifndef CFG_NO_FLASH//如果没有定义就执行以下信息:一般norflash才叫FLASH,nandflash叫Nand
/* configure available FLASH banks */
size = flash_init ();//这两行代码是norFLASH相关的,是norflash 的初始化
display_flash_config (size); //打印norflash配置信息:信息中打印:flash :8MB,但是实际上x210没有NorFlash
//以前需要norflash是因为启动内核只能在nor启动,而现在已经有好多启动方式了,所以不需要norflash,因为norflash 掉电不丢失
//实际可以去掉,这里没去掉,不清楚,可能去掉了,会不正常,实际上不去掉也不影响
#endif /* CFG_NO_FLASH */
#ifdef CONFIG_VFD//lcd显示相关的,是uboot自带的lcd显示相关的,但这里不是现在这板子的lcd显示相关的
# 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);//堆的起始地址
//在这里ddr内存中给堆预留了896KB的内存
//这个函数用来初始化堆管理器,因此这里uboot也可以用malloc,free函数可以分配,释放内存
#else
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
#endif
//******************************//从这里开始到#endif /* CONFIG_SMDK2416CONFIG_SMDK2450 */,为开发板独有的初始化
//三星用一套代码满足多个系列型号的开发板,然后将各开发板独有的初始化写在这里
//因为是210的板子,所以只看210的配置信息
// 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 80000380000;bootm c0008000");*/
}else {
puts("NAND: ");
nand_init();
if (INF_REG3_REG == 0 || INF_REG3_REG ==7)
setenv("bootcmd", "movi read kernel c0008000;movi readrootfs c0800000;bootm c0008000");
else
setenv("bootcmd", "nand read c0008000 80000 380000;bootmc0008000");
}
#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);//mmc初始化:初始化soc中的sd/mmc的控制器
//位置在于uboot/drivers/mmc/mmc.c里面,uboot中的drivers也是从内核中来的(uboot是没有系统的)
//mmc_initialize 中调用board_mmc_init和cpu_mmc_init来完成具体的硬件的mmc控制器初始化工作
//cpu_mmc_init在uboot/cpu/s5pc11x/cpu.c中,这里面调用了drivers/mmc/s3c_mmcxxx.c中的驱动代码来
//初始化硬件mmc控制器。
//所有使用了这套架构的代码都调用了这个函数来完成mmc的初始化
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 80000380000;bootm c0008000");*/
#else
//puts("OneNAND: (FSR layer enabled)\n");
#endif
#if defined(CONFIG_CMD_NAND)
puts("NAND: ");//nandflash
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 80000380000;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 80000380000;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 readrootfs c0800000;bootm c0008000");
else
setenv("bootcmd", "nand read c0008000 80000 380000;bootmc0008000");
#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 ();//就是将sd卡中的环境变量读取到ddr中。属于环境变量的重定位
//环境变量的来源:sd卡中有一些(8个)独立的扇区作为环境变量存储区域,env区,但是我们在不熟系统时
//只是烧录了uboot区,kernel区,rootfs分区,没有env区
//里面有:set_default_env();设置的默认环境变量
//其中真正的执行将环境变量到ddr中的是在env_recolate_spec内部的movi_read_env完成的
//因为这里第一次执行后有记录环境变量到ddr中,所以下次启动时uboot就会从sd卡的env区读取环境变量到ddr中。
//在这次之前的读取crc出错,所以之前的都不成功,具体可看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"); //获取ip,mac地址
//开发板的ip地址是在gd->bd中维护的,来源于环境变量中的ipaddr,getenv函数用来获取字符串格式的
//的ip地址,然后用string_to_ip将字符串格式的ip地址转换为字符串格式的点分十进制格式(例192.168.1.10)
//一个ip地址就是32威,因为ip地址就是4个0-255之间的数据组成的,所以最好的,最简单的存储方式
//就是unsigned int 与点分十进制之间可以转换
/* MAC Address *///mac地址:即网卡的硬件地址
{
int i;
ulong reg;
char *s, *e;
char tmp[64];
//一开始都是默认的环境变量(在include里面的configs里面有)来的(默认的环境变量是第一次搞的时候才有用,
//加载过后就不关默认环境变量的事了),之后认为修改城自己想要的
i = getenv_r ("ethaddr", tmp, sizeof (tmp));
s = (i > 0) ? tmp : NULL;
for (reg = 0; reg < 6; ++reg) {//simple_strtoul:转换函数,mac地址是6个0-255数据组成
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 thedevices list going. *///开发板的硬件设备的初始化
//这里的设备初始化是驱动设备,从驱动框架过来的。uboot中很多驱动是移植linux内核的(如:网卡,sd卡)
//
#ifdef CONFIG_CMC_PU2
load_sernum_ethaddr ();
#endif /* CONFIG_CMC_PU2 */
jumptable_init ();//跳转表。本身就是一个函数指针数组,里面记录了很多函数的函数名,本来是想要实现一个
//函数指针到具体函数的映射关系,将来通过跳转表中的函数指针就可以执行具体的函数,这个其实就是在
//用c语言实现面向对象编程,在linux内核中有很多这样的技巧
//通过分析发现跳转表知识被复值,从未被引用,因此跳转表在uboot中根本就没使用
//引用函数指针数组就可以实现类似于c语言实现的对象访问编程
#if !defined(CONFIG_SMDK6442)
console_init_r (); /* fullyinit console as a device *///挺重要的
//console_init_f:是实现控制台的第一阶段的初始化程序(没有实质性的工作),console_init_r是控制台的
//第二阶段初始化(有实质性的工作)
#endif
#if defined(CONFIG_MISC_INIT_R)//不定义宏就不执行下面的代码。uboot提供两种条件编译的方法:
//这里宏定义是一种(里面可以实现函数的功能),下面利用空函数也是一种
/* miscellaneous platform dependent initialisations */
misc_init_r ();
#endif
/* enable exceptions */
enable_interrupts ();//使能中断,中断初始化。因为宏定义没实现,而且uboot本身就不使用中断
//所以这里的函数是空函数(为了这里编译不报错),因为宏没定义,所以宏下面的代码不执行,在这里又有函数调用,所以需要一个这个函数的空函数
//在宏定义里面的代码中有实现对cpsr中总中断标志位使能
/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_TI_EMAC
extern void dm644x_eth_set_mac_addr (constu_int8_t *addr);
if (getenv ("ethaddr")) {
dm644x_eth_set_mac_addr(gd->bd->bi_enetaddr);
}
#endif
#ifdef CONFIG_DRIVER_CS8900//这个也是没用的网卡,因为x210这个板子用的是dm9000网卡
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));//loadaddr,bootfile两个环境变量都是内核启动有关的,在linux
//内核会使用这两个环境变量
}
#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);//网卡相关的初始化。属于网卡芯片本身的初始化,不是soc这边的初始化
//对于x210(dm9000)来说,这个初始化函数是空的,x210的网卡初始化在board_init函数中,网卡芯片的初始化在驱动中
#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();//(LCD ,logo显示)
//x210开发板在启动起来之前的一些初始化,以及LCD屏幕上的logo显示
#endif
/****************end**********************/
/* check menukey to update from sd */
extern void update_all(void);
if(check_menu_update_from_sd()==0)//update mode//uboot启动的最后阶段设置了一个自动更新过程
//就是:我们可以将要升级的镜像放到sd卡的固定目录中,然后开机时在uboot启动的最后阶段检查
//升级标志(是一个按键,按键中的标志是“LEFT”的那个按键。板子上有,这个按键如果按下则表示update mode
//,否则不按下就表示boot mode )如果进入update mode则uboot会自动从sd卡中读取镜像文件然后烧录到
//inand中,如果进入boot mode就不执行update 直接启动正常运行
//这种机制可以帮助我们快速烧录系统,常用于量产时用sd卡进行系统烧录部署
{
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 ();//解析控制台输入的命令(解析器CFG_HUSH_PARSER),还有个自动倒数,自动执行,命令的补全(uboot好像不支持,因为里面的宏没配置好)
}
/* 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: cmddone", i);
break;
} else /* in case we areoriginating 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 */