start_armboot分析

 *(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 */

你可能感兴趣的:(uboot学习)