u-boot 1.1.6分析:start_armboot()分析一

  当跑完start.S和lowlevel_init.S后,就会跳转到start_armboot()这个函数继续运行,这个函数定义在/lib_arm/board.c文件中。

 

一、全局变量gd初始化

  1、为类型为struct gd_t的全局变量gd分配空间,并对其进行初始化;同时为类型为struct bd_t的gd_t->bd变量分配空间,并对其进行初始化。(在当前版本,这两个结构体的大小都为36字节)

  2、gd即global data,表示全局变量,存放在r8寄存器中。gd->bd即board data,用来存放开发板的信息。

gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

/* 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));

 

二、获取u-boot的代码长度

  1、程序的主要分段:.text段(代码段,用来存放程序代码)、.data段(数据段,用来存放已经初始化的全局变量和静态变量)、.bss段(用来存放未初始化的全局变量)

  2、根据/board/100ask24x0/u-boot.lds链接脚本可知,.bss段在最后,所以u-boot的代码长度就等于.bss段起始地址减去入口地址

  3、之所以不考虑.bss段,是因为.bss段里的内容是已知的,初始化后全为0。

  4、注意:此时程序已经运行在SDRAM中的,所以入口地址为0x33f80000。

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 ();
    }
}    

  1、cpu_init()

    (1)该函数定义在/cpu/arm920t/cpu.c中

    (2)由于在配置头文件中定义了宏CONFIG_USE_IRQ,所以这里会配置IRQ和FIQ的栈大小,以及配置可用的SDRAM的大小

    (3)在IRQ栈中,预留了4字节。

#define CFG_ENV_SIZE       0x20000
#define CFG_MALLOC_LEN     (CFG_ENV_SIZE + 128*1024)
#define CFG_GBL_DATA_SIZE  128
#define PHYS_SDRAM_1       0x30000000

#define CONFIG_STACKSIZE_IRQ    (4*1024) 
#define CONFIG_STACKSIZE_FIQ    (4*1024) 

int cpu_init (void)
{
  #ifdef CONFIG_USE_IRQ
     IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;    //IRQ_STACK_START = 0x33f3ff7c
     FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;                  //FRQ_STACK_START = 0x33f3ef7c
     FREE_RAM_END = FIQ_STACK_START - CONFIG_STACKSIZE_FIQ - CONFIG_STACKSIZE;
      FREE_RAM_SIZE = FREE_RAM_END - PHYS_SDRAM_1;
  #else    
     FREE_RAM_END = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4 - CONFIG_STACKSIZE;
     FREE_RAM_SIZE = FREE_RAM_END - PHYS_SDRAM_1;
  #endif
   
  return 0;
}

   2、board_init()

    (1)该函数定义在/board/100ask24x0/100ask24x0.c文件中

    (2)配置GPIO口、开发板的芯片ID、启动参数的存放地址

int board_init (void)
{
    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
    S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();

    gpio->GPACON = 0x007FFFFF;
    gpio->GPBCON = 0x00044555;
    gpio->GPBUP  = 0x000007FF;
    gpio->GPCCON = 0xAAAAAAAA;
    gpio->GPCUP  = 0x0000FFFF;
    gpio->GPDCON = 0xAAAAAAAA;
    gpio->GPDUP  = 0x0000FFFF;
    gpio->GPECON = 0xAAAAAAAA;
    gpio->GPEUP  = 0x0000FFFF;
    gpio->GPFCON = 0x000055AA;
    gpio->GPFUP  = 0x000000FF;
    gpio->GPGCON = 0xFF95FFBA;
    gpio->GPGUP  = 0x0000FFFF;
    gpio->GPHCON = 0x002AFAAA;
    gpio->GPHUP  = 0x000007FF;
 
    gd->bd->bi_arch_number = MACH_TYPE_S3C2440;

    gd->bd->bi_boot_params = 0x30000100;

    return 0;
}

  3、interrupt_init()

    (1)这里的中断初始化实际上是定时器的初始化

    (2)根据芯片手册,定时器4是内部定时器,没有输出,所以这里是初始化定时器4

    (3)由于周期要使用10ms,所以可根据公式算出相关配置参数  f = PCLK / (prescaler value) / (divider value)

int interrupt_init (void)
{
    S3C24X0_TIMERS * const timers = S3C24X0_GetBase_TIMERS();

    timers->TCFG0 = 0x0f00;  //定时器4的预分频系数为16
                  //TCFG1寄存器使用默认值,所以定时器4的分配值为2  

    if (timer_load_val == 0)
    {
        timer_load_val = get_PCLK()/(2 * 16 * 100);   //HZ对应的单位为s,所以要除以100得到10ms单位
    }
    lastdec = timers->TCNTB4 = timer_load_val;
    timers->TCON = (timers->TCON & ~0x0700000) | 0x600000;  //自动装载,手动更新计数值
    timers->TCON = (timers->TCON & ~0x0700000) | 0x500000;  //启动定时器4
    timestamp = 0;

    return (0);
}

  4、env_init()

    (1)环境变量的初始化函数要根据启动方式来确定,由于JZ2440使用的是NAND FLASH启动,并在配置头文件中定义了宏CFG_ENV_IS_IN_NAND,所以该函数定义在/common/env_nand.c文件中。

    (2)但由于未定义CONFIG_NAND_U_BOOT(可在顶层的Makefile中定义:@echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk),所以环境变量需要进行配置。

    (3)环境变量数组default_environment定义在/common/env_common.c中,而具体的宏则是由配置头文件来确定的。

#define CONFIG_BOOTARGS    "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0,115200"
#define CONFIG_BOOTCOMMAND "nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0"
#define CONFIG_BOOTDELAY   2
#define CONFIG_BAUDRATE    115200
#define CONFIG_ETHADDR     08:00:3e:26:0a:5b
#define CONFIG_IPADDR      192.168.1.17
#define CONFIG_SERVERIP    192.168.1.11
#define CONFIG_NETMASK     255.255.255.0

//在这个数组中,只列出JZ2440定义好的环境变量
uchar default_environment[] = 
{
  #ifdef    CONFIG_BOOTARGS
      "bootargs="    CONFIG_BOOTARGS            "\0"
  #endif

  #ifdef    CONFIG_BOOTCOMMAND
      "bootcmd="    CONFIG_BOOTCOMMAND        "\0"
  #endif

  #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
      "bootdelay="    MK_STR(CONFIG_BOOTDELAY)    "\0"
  #endif

  #if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
      "baudrate="    MK_STR(CONFIG_BAUDRATE)        "\0"
  #endif

  #ifdef    CONFIG_ETHADDR
      "ethaddr="    MK_STR(CONFIG_ETHADDR)        "\0"
  #endif

  #ifdef    CONFIG_IPADDR
      "ipaddr="    MK_STR(CONFIG_IPADDR)        "\0"
  #endif

  #ifdef    CONFIG_SERVERIP
      "serverip="    MK_STR(CONFIG_SERVERIP)        "\0"
  #endif

  #ifdef    CONFIG_NETMASK
      "netmask="    MK_STR(CONFIG_NETMASK)        "\0"
  #endif
};

int env_init(void)
{

  gd->env_addr = (ulong)&default_environment[0];

  gd->env_valid = 1;

  return (0);
}

  5、init_baudrate()

static int init_baudrate (void)
{
    char tmp[64];    
    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);
}

  6、serial_init()

    (1)不同的SOC的串口寄存器地址不同,所以有不同的初始化函数,JZ2440的初始化函数定义在/cpu/arm920t/s3c24x0/serial.c中

    (2)串口初始化完成后,串口才有输出。

#define CONFIG_SERIAL1  1

#ifdef CONFIG_SERIAL1
#define UART_NR    S3C24X0_UART0
#endif

void serial_setbrg (void)
{
    S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR);
    int i;
    unsigned int reg = 0;

    reg = get_PCLK() / (16 * gd->baudrate) - 1;

    /* FIFO enable, Tx/Rx FIFO clear */
    uart->UFCON = 0x07;
    uart->UMCON = 0x0;
    /* Normal,No parity,1 stop,8 bit */
    uart->ULCON = 0x3;
    /*
     * tx=level,rx=edge,disable timeout int.,enable rx error int.,
     * normal,interrupt or polling
     */
    uart->UCON = 0x245;
    uart->UBRDIV = reg;

#ifdef CONFIG_HWFLOW
    uart->UMCON = 0x1; /* RTS up */
#endif
    for (i = 0; i < 100; i++);
}

int serial_init (void)
{
    serial_setbrg ();

    return (0);
}

  7、console_init_f()

int console_init_f (void)
{
    gd->have_console = 1;
    return (0);
}

  8、display_banner()

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);

    debug ("IRQ Stack: %08lx\n", IRQ_STACK_START);
    debug ("FIQ Stack: %08lx\n", FIQ_STACK_START);
    return (0);
}

  9、dram_init()

int dram_init (void)
{
    gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
    gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

    return 0;
}

  10、display_dram_config()

static int display_dram_config (void)
{
    int i;
    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");

    return (0);
}

 

  到这里,初始化序列就已经跑完了,那么接下来该继续执行start_armboot()的后续代码了。

posted @ 2019-09-07 13:53  Recca  阅读(303)  评论(0编辑  收藏  举报