*(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,
* 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
#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; //#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
#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 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 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 */