U-boot source code analysis-start phase 2, based on 2410 startup code analysis

Source: Internet
Author: User

Let's first look at the initialization function table: init_sequence

Lib_arm/board. C:

Typedef int (init_fnc_t) (void );

Init_fnc_t * init_sequence [] = {

Cpu_init,/* Basic CPU dependent setup */

Board_init,/* Basic board dependent setup */

Interrupt_init,/* set up exceptions */

Env_init,/* initialize environment */

Init_baudrate,/* initialze baudrate settings */

Serial_init,/* serial communications setup */

Lele_init_f,/* Stage 1 init of console */

Display_banner,/* say that we are here */

Dram_init,/* configure available Ram banks */

Display_dram_config,

# If defined (config_vcma9) | defined (config_cmc_pu2)

Checkboard,

# Endif

Null,

};

These initialization functions will be executed one by one.

ARM920T/CPU. C:

Int cpu_init (void)

{

/*

* Setup up stacks if necessary

*/

# Ifdef config_use_irq

Declare_global_data_ptr;

 

Irq_stack_start = _ armboot_start-example _malloc_len-example _gbl_data_size-4;

Fiq_stack_start = irq_stack_start-config_stacksize_irq;

# Endif

Return 0;

}

For smdk2410, this macro config_use_irq is not defined. In fact, irq_stack_start and fiq_stack_start are directed to the IRQ stuff area in Ram.

See board_init:

Board/smdk2410.c:

/*

* Miscellaneous platform dependent initialisations

*/

Int board_init (void)

{

Declare_global_data_ptr;

// Obtain the registers for power, clock, and gpio. These registers will be operated later,

// You Can See That field objects in the s3c24x0_clock_power are arranged according to the actual Register address.

S3c24x0_clock_power * const clk_power = s3c24x0_getbase_clock_power ();

S3c24x0_gpio * const gpio = s3c24x0_getbase_gpio ();

 

/* To reduce PLL lock time, adjust the locktime register */

// Reduce the lock time value of the PLL. For more information, see data sheet.

Clk_power-> locktime = 0 xffffff;

 

/* Configure mpll */

// Configure mpll. For more information, see data sheet.

Clk_power-> mpllcon = (m_mdiv <12) + (m_pdiv <4) + m_sdiv );

 

/* Some delay between mpll and upll */

Delay (4000 );

 

/* Configure upll */

// Configure upll

Clk_power-> upllcon = (u_m_mdiv <12) + (u_m_pdiv <4) + u_m_sdiv );

 

/* Some delay between mpll and upll */

Delay (8000 );

 

/* Set up the I/O Ports */

// Configure the functions, input and output parameters of each gpio

Gpio-> gpacon = 0x007fffff;

Gpio-> gpbcon = 0x00044555;

Gpio-> gpbup = 0x000007ff;

Gpio-> gpccon = 0 xaaaaaaaa;

Gpio-> gpcup = 0x0000ffff;

Gpio-> gpdcon = 0 xaaaaaaaa;

Gpio-> gpdup = 0x0000ffff;

Gpio-> gpecon = 0 xaaaaaaaa;

Gpio-> gpeup = 0x0000ffff;

Gpio-> gpfcon = 0x000055aa;

Gpio-> gpfup = 0x000000ff;

Gpio-> gpgcon = 0xff95ffba;

Gpio-> gpgup = 0x0000ffff;

Gpio-> gphcon = 0x002afaaa;

Gpio-> gphup = 0x000007ff;

 

/* Arch Number of SMDK2410-Board */

// Save the arch number

GD-> BD-> bi_arch_number = mach_type_smdk2410;

 

/* Adress of boot parameters */

// Save the startup parameter address under the Linux Kernel

GD-> BD-> bi_boot_params = 0x30000100;

 

// Enable command cache and data cache

Icache_enable ();

Dcache_enable ();

Return 0;

}

This function is related to a specific board. Therefore, it is generally added by yourself to make the cache simple. You only need to open the related bit of the coprocessor 15 and the code will not be listed, see datasheet.

Next let's look at the initialization function: interrupt_init. Our CPU is the S3C2410 of ARM920T series.

 

CPU/ARM920T/s3c24x0:

Int interrupt_init (void)

{

S3c24x0_timers * const timers = s3c24x0_getbase_timers ();

 

/* Use PWM timer 4 because it has no output */

/* Prescaler for timer 4 is 16 */

Timers-> t1_0 = 0x0f00;

If (timer_load_val = 0)

{

/*

* For 10 MS clock period @ pclk with 4 bit divider = 1/2

* (Default) and prescaler = 16. shocould be 10390

* @ 33.25 MHz and 15625 @ 50 MHz

*/

Timer_load_val = get_pclk ()/(2*16*100 );

}

/* Load value for 10 MS timeout */

Lastdec = timers-> tcntb4 = timer_load_val;

/* Auto load, manual update of timer 4 */

Timers-> tcon = (timers-> tcon &~ 0x0700000) | 0x600000;

/* Auto load, start timer 4 */

Timers-> tcon = (timers-> tcon &~ 0x0700000) | 0x500000;

Timestamp = 0;

 

Return (0 );

}

Looking at datasheet, this function uses timer 4 as the system clock, that is, the clock is ticking once every 10 ms, and an interruption occurs at the point, however, because the interrupt is not enabled yet, the interrupt will not respond.

 

Next let's take a look at env_init: Because we defined pai_env_is_in_flash under inculde/configs/smdk2410.h, this function is located under common/env_flash.c.

 

Common/env_flash.c:

Int env_init (void)

{

Declare_global_data_ptr;/* Do you still remember this? */

# Ifdef config_omap2420h4

Int flash_probe (void );

 

If (flash_probe () = 0)

Goto bad_flash;

# Endif

If (CRC32 (0, env_ptr-> data, env_size) = env_ptr-> CRC ){

GD-> env_addr = (ulong) & (env_ptr-> data );

GD-> env_valid = 1;

Return (0 );

}

# Ifdef config_omap2420h4

Bad_flash:

# Endif

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

GD-> env_valid = 0;

Return (0 );

}

This function stores the storage address of environment variables in GD. Generally, the default environment variable value is used as the default_environment array,

Uchar default_environment [] = {

# Ifdef config_bootargs

"Bootargs =" config_bootargs "/0"

# Endif

# Ifdef config_bootcommand

"Bootcmd =" config_bootcommand "/0"

# Endif

......

}

Visible environment variables are stored in the array as follows

Name = Value

It ends with "/0", and macros similar to config_bootargs are defined in the configuration file of the Board itself, that is, smdk2410.h.

 

Next, let's take a look at init_baudrate.

 

Lib_arm/board. C:

Static int init_baudrate (void)

{

Declare_global_data_ptr;

// Get the baud rate from the Environment Variable

Uchar TMP [64];/* long enough for 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 );

}

This function finds the baud rate value from the previously initialized Environment Variable list. If not, assign the initial value config_baudrate.

 

Continue to see serial_init:

 

CPU/ARM920T/s3c24x0:

/*

* Initialise the serial port with the given baudrate. The settings

* Are always 8 data bits, no parity, 1 stop bit, no start bits.

*

*/

Int serial_init (void)

{

Serial_setbrg (); // set the baud rate and stop bit.

 

Return (0 );

}

 

CPU/ARM920T/s3c24x0:

Void serial_setbrg (void)

{

Declare_global_data_ptr;

S3c24x0_uart * const UART = s3c24x0_getbase_uart (uart_nr); // UART Register address

Int I;

Unsigned int Reg = 0;

 

/* Value is calculated so: (INT) (pclk/16./baudrate)-1 */

Reg = get_pclk ()/(16 * Gd-> baudrate)-1;

 

/* FIFO enable, TX/rx fifo clear */

UART-> ufcon = 0x07; // RX, tx fifo reset, enabling FIFO.

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

}

The above function is opposite to datasheet. It is nothing more than setting the baud rate, start bit, and check the interrupt type.

 

Next, let's look at the initialization function: lele_init_f.

 

Common/console. C:

/* Called before relocation-use serial functions */

Int console_init_f (void)

{

Declare_global_data_ptr;

 

GD-> have_console = 1;

 

# Ifdef config_silent_console

If (getenv ("silent ")! = NULL)

GD-> flags | = gd_flg_silent; // you can specify the Console mode.

# Endif

 

Return (0 );

}

This function initializes several console-related tags.

 

Next let's look at display_banner:

Lib_arm/board. C:

Static int display_banner (void)

{

Printf ("/n % s/n", version_string); // print the version information for the U-BOOT

Printf ("U-Boot Code: % 08lx-> % 08lx BSS:-> % 08lx/N ",

_ Armboot_start, _ bss_start, _ bss_end); // print the U-BOOT code position

# Ifdef config_modem_support

Puts ("modem support enabled/N ");

# Endif

# Ifdef config_use_irq

Printf ("IRQ Stack: % 08lx/N", irq_stack_start );

Printf ("FIQ Stack: % 08lx/N", fiq_stack_start );

# Endif

Return (0 );

}

This function prints some system information on the console.

 

Next let's take a look at dram_init:

Board/smdk2410/smdk2410.c:

Int dram_init (void)

{

Declare_global_data_ptr;

 

GD-> BD-> bi_dram [0]. Start = phys_sdram_1; // Ram start address

GD-> BD-> bi_dram [0]. size = phys_sdram_memory size; // Ram size

 

Return 0;

}

The starting address and size of RAM are related to the specific board. Therefore, both macros are defined in smdk2410.h according to the actual situation,

 

Check display_dram_config again.

Lib_arm/board. C:

/*

* Warning: This code looks "cleaner" than the PowerPC version,

* Has the disadvantage that you either get nothing, or everything.

* On powerpc, you might see "DRAM:" Before the system hangs-which

* Gives a simple yet clear indication which part of

* Initialization if failing.

*/

Static int display_dram_config (void)

{

Declare_global_data_ptr;

Int I;

 

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

}

 

Return (0 );

}

Haha, just print the system Ram information.

Next we will talk about the initialization function. For smdk2410, The checkboard function does not exist,

 

In this way, all the functions in the initialization function table are finished. The following process is summarized:

<! -- [If! Supportlists] --> 1. <! -- [Endif] --> initialization of CPU, borad, and interrupt, including cache, all of which are related to the configuration of a specific board.

<! -- [If! Supportlists] --> 2. <! -- [Endif] --> environment variable initialization,

<! -- [If! Supportlists] --> 3. <! -- [Endif] --> serial port, console, Ram initialization,

<! -- [If! Supportlists] --> 4. <! -- [Endif] --> display system configuration and other related parameters in real time on the console.

 

It should be noted that most of the configuration parameters are pre-defined under include/configs/board_name.h. Therefore, if we want to port our own board, this file is indispensable, it describes the configuration of our Board, such as the CPU model and ram size.

// Configure //---------------------------------------------------------------------------------------

/* Configure available FLASH */
Size = flash_init ();
......
/* Initialize the heap space */
Mem_malloc_init (_ armboot_start-example _malloc_len );

# If (config_commands & cmd_cmd_nand)
Puts ("NAND :");
Nand_init ();/* Go init the NAND */
# Endif

/* Reposition the environment variable ,*/
Env_relocate ();
/* Obtain the IP address from the environment variable */
GD-> BD-> bi_ip_addr = getenv_ipaddr ("ipaddr ");
/* MAC address of the Ethernet interface */
......
Devices_init ();/* Device initialization */
Jumptable_init (); // jump table Initialization
Lele_init_r ();/* completely initialize the console device */
Enable_interrupts ();/* enable Interrupt Processing */
/* Initialize through environment variables */
If (S = getenv ("loadaddr "))! = NULL ){
Oad_addr = simple_strtoul (S, null, 16 );
}
/* The main_loop () loop is continuously executed */
For (;;){
Main_loop ();/* Main Loop function processing execution USER command -- Common/Main. C */
}

//----------------------

Then it enters the main_loop () Delay of 3 seconds to detect the user input. If there is no user input, then directly
Run_command () runs the bootm command in bootcmd, and then enters do_bootm () in common/cmd_bootm.c. In do_bootm, determine which kernel is used, if it is a Linux kernel, call the do_bootm_linux () function in lib_mips/mis_linux.c to pass the parameter to the kernel. Of course, there is still a lot of work to be done during this period, for example: Verify magic number, verify header checksum, determine whether it is initrd image, decompress, and so on. After that, it is Thekernel (linux_argc, linux_argv, linux_env, 0); pass the parameter to the kernel, so that the U-boot task is completed. The next step is the kernel startup process.

 

This article from the csdn blog, reproduced please indicate the source: http://blog.csdn.net/lanmanck/archive/2009/05/19/4201481.aspx

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.