• Uboot详细解析2


    1。第二阶段的主线函数位于u-boot-2010.06/arch/arm/lib/board.c。

    第二阶段的功能:

    <1> 初始化本阶段要使用到的硬件设备。

    设置时钟、初始化串口。

    board_init函数设置MPLL、改变系统时钟,它是开发板相关的函数,在board/samsung/smdk2440/smdk2440.c中实现。值得注意的是board_init函数还保存了机器类型ID,这将在调用内核的时候传递给内核。代码如下:

    gd->bd->bi_arch_number = MACH_TYPE_S3C2440; //值为362

    串口的初始化函数主要是serial_init,它设置UART控制器,是CPU相关的函数。

    <2>检测系统内存映射(memory map)。

    对于smdk2440的开发板,其内存分布是明确的,一般内存起始地址为0x3000 0000,大小为64M = 0x0400 0000。代码如下:

    int dram_init(void)

    {

    gd->bd->bi_dram[0] . start = PHYS_SDRAM_1; //即0x3000 0000

    gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; //即0x0400 0000

    //这两个值都定义在include/configs/smdk2440.h中

    }

    <3>将内核映像和根文件系统映像从Flash上读到RAM空间中。

    <4>为内核设置启动参数。

    U-Boot 是通过标记列表向内核传递参数。

    setup_memory_tags

    setup_commandline_tag

    这两个标记列表定义在arch/arm/lib/bootm.c中,需要在定义命令的文件include/configs/smdk2440.h中定义两个命令

    #define CONFIG_SETUP_MEMORY_TAGS 1

    #define CONFIG_CMDLINE_TAG 1

    对于ARM构架的CPU来说,都是通过arch/arm/lib/bootm.c中的do_bootm_linux函数来启动内核的。这个函数中,设置标记列表,最后通过 theKernel = (void (星)(int, int, uint))images->ep;调用内核。其中,theKernel 指向内核存放的地址(对于ARM构架的CPU,通常这个地址是0x3000 8000)。传递的3个参数如下:void (星theKernel)(int zero, int arch, uint params);

    R0: 0

    R1: 机器类型ID -- gd->bd->bi_arch_number = MACH_TYPE_S3C2440; //值为362

    R2: 启动参数标记列表在RAM中的起始地址 0x3000 0100

    2。源码解析。

    arch/arm/lib/board.c

    void start_armboot (void)
    {
    init_fnc_t **init_fnc_ptr;
    //定义二级函数指针
    char *s;

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

    unsigned long env_addr;
    unsigned long env_valid;
    unsigned long fb_base;
    #ifdef CONFIG_VFD
    unsigned char vfd_type;
    #endif
    #ifdef CONFIG_FSL_ESDHC
    unsigned long sdhc_clk;
    #endif
    #if 0
    unsigned long cpu_clk;
    unsigned long bus_clk;
    phys_size_t ram_size;
    unsigned long reset_status;
    #endif
    void **jt;
    } gd_t;

    sizeof(gd_t)=4 + 4 * 6 + 4 = 32 = 0x20。

    故gd所指向地址 0x3ff80000 - 0x40000 - 0x20为 0x3FF3 FFE0


    #define GD_FLG_RELOC 0x00001
    #define GD_FLG_DEVINIT 0x00002
    #define GD_FLG_SILENT 0x00004
    #define GD_FLG_POSTFAIL 0x00008
    #define GD_FLG_POSTSTOP 0x00010
    #define GD_FLG_LOGINIT 0x00020
    #define GD_FLG_DISABLE_CONSOLE 0x00040

    #define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")


    __asm__ __volatile__("": : :"memory"); //分配一个存储全局数据的区域,地址给指针 gd

    memset ((void*)gd, 0, sizeof (gd_t)); //分配空间并清0
    gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));


    unsigned long bi_ip_addr;
    struct environment_s *bi_env;
    ulong bi_arch_number;
    ulong bi_boot_params;
    struct
    {
    ulong start;
    ulong size;
    } bi_dram[CONFIG_NR_DRAM_BANKS];
    } bd_t;

    #define bi_env_data bi_env->data
    #define bi_env_crc bi_env->crc

    #endif

    ****************************************************************************************************************/
    memset (gd->bd, 0, sizeof (bd_t));
    //分配空间并清0

    gd->flags |= GD_FLG_RELOC; //设置当前uboot标志位已经重定位

    monitor_flash_len = _bss_start - _armboot_start; //uboot镜像文件大小

    //初始化函数循环

    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
    if ((*init_fnc_ptr)() != 0)

    {
    hang ();
    }
    }


    #endif
    board_init,
    #if defined(CONFIG_USE_IRQ)
    interrupt_init,
    #endif
    timer_init,
    #ifdef CONFIG_FSL_ESDHC
    get_clocks,
    #endif
    env_init,
    init_baudrate,
    serial_init,
    console_init_f,
    display_banner,
    #if defined(CONFIG_DISPLAY_CPUINFO)
    print_cpuinfo,
    #endif
    #if defined(CONFIG_DISPLAY_BOARDINFO)
    checkboard,
    #endif
    #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
    init_func_i2c,
    #endif
    dram_init,
    #if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
    arm_pci_init,
    #endif
    display_dram_config,
    NULL,
    };

    ***************************************************************************************************************/


    mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,
    CONFIG_SYS_MALLOC_LEN);

    #ifndef CONFIG_SYS_NO_FLASH

    display_flash_config (flash_init ());
    #endif

    #if defined(CONFIG_CMD_NAND)
    puts ("NAND: ");
    nand_init();
    #endif

    #if defined(CONFIG_CMD_ONENAND)
    onenand_init();
    #endif


    env_relocate ();

    //多串口配置,跳过。

    #ifdef CONFIG_SERIAL_MULTI
    serial_initialize();
    #endif

    //IP地址获取。


    gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

    //标准的输入输出

    stdio_init ();

    //初始化外设列表

    jumptable_init ();

    //u-boot的应用函数集,跳过

    #if defined(CONFIG_API)

    api_init ();
    #endif

    //初始化控制台(console),平台无关,不一定是串口哦,如果把标准输出设为vga,字符会显示在LCD上。

    console_init_r ();

    //平台相关的其他设备初始化,这些s3c2440都没有。跳过

    #if defined(CONFIG_ARCH_MISC_INIT)

    arch_misc_init ();
    #endif

    #if defined(CONFIG_MISC_INIT_R)

    misc_init_r ();
    #endif

    //允许中断,这里还没移植USB下载,所以直接return。


    enable_interrupts ();

    //TI平台的网卡驱动,直接跳过


    #ifdef CONFIG_DRIVER_TI_EMAC

    extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
    if (getenv ("ethaddr"))

    {
    uchar enetaddr[6];
    eth_getenv_enetaddr("ethaddr", enetaddr);
    davinci_eth_set_mac_addr(enetaddr);
    }
    #endif

    //其他网卡的设置,直接跳过。

    #if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)

    if (getenv ("ethaddr"))

    {
    uchar enetaddr[6];
    eth_getenv_enetaddr("ethaddr", enetaddr);
    smc_set_mac_addr(enetaddr);
    }
    #endif


    if ((s = getenv ("loadaddr")) != NULL)

    {
    load_addr = simple_strtoul (s, NULL, 16);
    }

    //获取bootfile参数

    #if defined(CONFIG_CMD_NET)
    if ((s = getenv ("bootfile")) != NULL)

    {
    copy_filename (BootFile, s, sizeof (BootFile));
    }
    #endif

    #ifdef BOARD_LATE_INIT
    board_late_init ();
    #endif

    //MMC卡的控制器初始化

    #ifdef CONFIG_GENERIC_MMC
    puts ("MMC: ");
    mmc_initialize (gd->bd);
    #endif

    #ifdef CONFIG_BITBANGMII
    bb_miiphy_init();
    #endif

    #if defined(CONFIG_CMD_NET)
    //多网卡配置

    #if defined(CONFIG_NET_MULTI)
    puts ("Net: ");
    #endif

    //网卡初始化
    eth_initialize(gd->bd);

    //允许网卡复位
    #if defined(CONFIG_RESET_PHY_R)
    debug ("Reset Ethernet PHY ");
    reset_phy();
    #endif
    #endif

    //进入主循环。其中会读取bootdelay和bootcmd。在bootdelay时间内按下键进入命令行,否则执行bootcmd的命令。


    for (;;)

    {
    main_loop ();
    }


    }

    //出错提示

    void hang (void)
    {
    puts ("### ERROR ### Please RESET the board ### ");
    for (;;);
    }

    3。初始化列表具体分析。

    void jumptable_init(void)
    {

    //为gd->jt是这个函数指针数组分配空间。
    gd->jt = malloc(XF_MAX * sizeof(void *));
    #include <_exports.h>
    }

    init_fnc_t *init_sequence[] = {
    #if defined(CONFIG_ARCH_CPU_INIT)
    arch_cpu_init,
    #endif

    board_init,


    clk_power->LOCKTIME = 0xFFFFFF;


    clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);


    delay (4000);


    clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);


    delay (8000);


    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;

    icache_enable(); //关闭指令cache
    dcache_enable(); //关闭数据cache

    return 0;
    }
    ***************************************************************************************************************/
    #if defined(CONFIG_USE_IRQ)
    interrupt_init,
    #endif
    timer_init, //定时器初始化



    writel(0x0f00, &timers->TCFG0);
    if (timer_load_val == 0) {

    timer_load_val = get_PCLK() / (2 * 16 * 100);
    timer_clk = get_PCLK() / (2 * 16);
    }

    lastdec = timer_load_val;
    writel(timer_load_val, &timers->TCNTB4);

    tmr = (readl(&timers->TCON) & ~0x0700000) | 0x0600000;
    writel(tmr, &timers->TCON);

    tmr = (tmr & ~0x0700000) | 0x0500000;
    writel(tmr, &timers->TCON);
    timestamp = 0;

    return (0);
    }

    ****************************************************************************************************************/
    #ifdef CONFIG_FSL_ESDHC
    get_clocks,
    #endif
    env_init, //环境变量


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

    return 0;
    }
    ****************************************************************************************************************/
    init_baudrate, //波特率获取


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

    ***************************************************************************************************************/
    serial_init, //串口设置


    int serial_init(void)
    {
    return serial_init_dev(UART_NR); //UART_NR 就是串口号,在文件drivers/serial/serial_s3c24x0.c中有如下定义:

    默认的输出为串口0 即定义在include/configs/smdk2440.h

    #define CONFIG_S3C24X0_SERIAL
    #define CONFIG_SERIAL1 1
    }
    #endif

    |

    |

    |

    static int serial_init_dev(const int dev_index)
    {
    struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);

    #ifdef CONFIG_HWFLOW
    hwflow = 0;
    #endif


    writel(0x07, &uart->UFCON);
    writel(0x0, &uart->UMCON);


    writel(0x3, &uart->ULCON);

    writel(0x245, &uart->UCON);

    #ifdef CONFIG_HWFLOW
    writel(0x1, &uart->UMCON);
    #endif


    #if defined(CONFIG_ARCH_GTA02_v1) || defined(CONFIG_ARCH_GTA02_v2)

    if (dev_index == 0 || dev_index == 1)
    writel(0x10, &uart->UMCON);
    #endif
    _serial_setbrg(dev_index);

    return (0);
    }

    ****************************************************************************************************************/
    console_init_f,


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

    #ifdef CONFIG_SILENT_CONSOLE
    if (getenv("silent") != NULL)
    gd->flags |= GD_FLG_SILENT;
    #endif

    return 0;
    }

    ****************************************************************************************************************/
    display_banner,


    #if defined(CONFIG_DISPLAY_CPUINFO)
    print_cpuinfo,
    #endif
    #if defined(CONFIG_DISPLAY_BOARDINFO)
    checkboard,
    #endif
    #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
    init_func_i2c,
    #endif
    dram_init, //内存初始化


    #if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
    arm_pci_init,
    #endif
    display_dram_config, //显示内存信息


    NULL,
    };

  • 相关阅读:
    HTML滚动时位置固定 PHP
    js判断验证码是否正确 PHP
    PNG渐变图生成工具 PHP
    C# 提醒小工具 PHP
    js 密码强度检测 PHP
    js辅助输入层 PHP
    不常用样式 PHP
    ASP.NET编程中的十大技巧
    WEB打印大全
    如何在ASP.NET中用OWC绘制图表
  • 原文地址:https://www.cnblogs.com/songfeixiang/p/3733818.html
Copyright © 2020-2023  润新知