标签:sequence int boot mx28 init dram CONFIG cpu
start_armboot (void)是u-boot开始执行的第一个C函数,该 函数自然要进行各种初始化工作,而init_sequence则是进行各种初始化的 函数数组,该函数定义在/lib_arm/board.c中,如下所示:
typedef int (init_fnc_t) (void); //init_fnc_t就是个返回值为int的函数,参数为空
init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init, /* basic arch cpu dependent setup */
#endif
board_init, /* basic board dependent setup */
#if defined(CONFIG_USE_IRQ)
interrupt_init, /* set up exceptions */
#endif
timer_init, /* initialize timer */
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu 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, /* configure available RAM banks */
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
arm_pci_init,
#endif
display_dram_config,
NULL,
};
这些配置宏定义(CONFIG_xxx)一般在要移值的开发板的头文件里,比如/include/configs/mx28_evk.h中,去掉这些条件编译,该指针数组为:
init_fnc_t *init_sequence[] = {
arch_cpu_init, /* basic arch cpu dependent setup */
board_init, /* basic board dependent setup */
timer_init, /* initialize timer */
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
print_cpuinfo, /* display cpu info (and speed) */
init_func_i2c,
dram_init, /* configure available RAM banks */
display_dram_config,
NULL,
};
下面就逐个分析上述包含的初始化函数:
1、arch_cpu_init, /* basic arch cpu dependent setup */
//mx28/generic.c
//对cache的使能,寄存器层面,freescale官方提供
int arch_cpu_init(void)
{
icache_enable();
dcache_enable();
return 0;
}
2、board_init, /* basic board dependent setup */
//mx28/mx28_evk.c
//给gd->bd赋值,2个要传递给linux的参数:CPU架构,bi_boot_params
//bi_boot_params:表示传递给内核的参数位置
//初始化nand flash接口
//初始化看门狗
int board_init(void)
{
/* Will change it for MX28 EVK later */
gd->bd->bi_arch_number = MACH_TYPE_MX28EVK;
/* Adress of boot parameters */
gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;
setup_gpmi_nand();
//watch dog init
pin_set_type(PINID_GPMI_RDY1, PIN_GPIO);
pin_gpio_direction(PINID_GPMI_RDY1, 1);
pin_gpio_set(PINID_GPMI_RDY1, 0);
return 0;
}
3、timer_init, /* initialize timer */
//mx28/timer.c
//定时器初始化,freescale厂家提供
int timer_init(void)
{
/*
* Reset Timers and Rotary Encoder module
*/
/* Clear SFTRST */
REG_CLR(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL, 1 << 31);
while (REG_RD(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL) & (1 << 31))
;
/* Clear CLKGATE */
REG_CLR(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL, 1 << 30);
/* Set SFTRST and wait until CLKGATE is set */
REG_SET(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL, 1 << 31);
while (!(REG_RD(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL) & (1 << 30)))
;
/* Clear SFTRST and CLKGATE */
REG_CLR(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL, 1 << 31);
REG_CLR(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL, 1 << 30);
/*
* Now initialize timer
*/
/* Set fixed_count to 0 */
REG_WR(REGS_TIMROT_BASE, HW_TIMROT_FIXED_COUNTn(N), 0);
/* set UPDATE bit and 1Khz frequency */
REG_WR(REGS_TIMROT_BASE, HW_TIMROT_TIMCTRLn(N),
BM_TIMROT_TIMCTRLn_RELOAD | BM_TIMROT_TIMCTRLn_UPDATE |
BV_TIMROT_TIMCTRLn_SELECT__1KHZ_XTAL);
/* Set fixed_count to maximal value */
REG_WR(REGS_TIMROT_BASE, HW_TIMROT_FIXED_COUNTn(N), TIMER_LOAD_VAL);
/* init the timestamp and lastdec value */
reset_timer_masked();
return 0;
}
4、env_init, /* initialize environment */
//u-boot环境参数初始化
//将u-boot默认支持的环境参数指针赋值给gd->env_addr
int env_init(void)
{
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 0;
return (0);
}
5、init_baudrate, /* initialze baudrate settings */
///lib_arm/board.c
//波特率初始化,主要是对bd->bi_baudrate的初始化赋值
//判断环境参数baudrate的值,如果不为0,则取env的值
//反之则取移值板子头文件mx28_evk.h中的默认配置宏定义CONFIG_BAUDRATE
//这里很显然取值为 CONFIG_BAUDRATE 115200
static int init_baudrate (void)
{
char 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);
}
6、serial_init, /* serial communications setup */
///cpu/arm926ejs/mx28/serial.c
//串口的初始化,主要是对调试串口的初始化,也是能实现整个运行信息打印
int serial_init(void)
{
/*Config the AUART0_CTS/RTS as the DUART.RX/TX*/
//lolevel_init.s config the duart functin
// pin_set_type(PINID_PWM0, PIN_FUN2);
// pin_set_type(PINID_PWM1, PIN_FUN2);
// pin_set_type(PINID_AUART0_CTS, PIN_FUN3);
// pin_set_type(PINID_AUART0_RTS, PIN_FUN3);
/* Disable UART */
REG_WR(REGS_UARTDBG_BASE, HW_UARTDBGCR, 0);
/* Mask interrupts */
REG_WR(REGS_UARTDBG_BASE, HW_UARTDBGIMSC, 0);
/* Set default baudrate */
serial_setbrg();
/* Enable UART */
REG_WR(REGS_UARTDBG_BASE, HW_UARTDBGCR,
BM_UARTDBGCR_TXE | BM_UARTDBGCR_RXE | BM_UARTDBGCR_UARTEN);
return 0;
}
7、console_init_f, /* stage 1 init of console */
///common/console.c
/* Called before relocation - use serial functions */
// have_console = 1 表明将串口作为控制台的输入输出设备
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;
}
8、display_banner, /* say that we are here */
//lib/board.c
//显示debug信息,比如各种开始地址等。
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_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
return (0);
}
9、print_cpuinfo, /* display cpu info (and speed) */
//cpu/arm926ejs/mx28/generic.c
//打印cpu的各种信息,比如cpu时钟、cpu生产商信息等。
int print_cpuinfo(void)
{
printf("Freescale i.MX28 family\n");
printf("CPU: %d MHz\n", mx28_get_pclk());
printf("BUS: %d MHz\n", mx28_get_hclk());
printf("EMI: %d MHz\n", mx28_get_emiclk());
printf("GPMI: %d MHz\n", mx28_get_gpmiclk());
return 0;
}
10、init_func_i2c
///lib_arm/board.c
//初始化I2C接口,对各种I2C接口
static int init_func_i2c (void)
{
puts ("I2C: ");
i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
puts ("ready\n");
return (0);
}
11、dram_init, /* configure available RAM banks */
//board/freescale/mx28_evk.c
//这里不是对内存设备的初始化,因为freescale已经有了SDRAM_Prep,
//这里是对 全局变量 gd->bd-bi_dram[0]的初始化,这个是要传递给内核kernel的
//bi_dram[0]是一个结构体,包含了内存起始地址和、内存大小
//zlg移值为了兼容性,所以支持2种内存大小。
int dram_init(void)
{
int iSizeMb = ddr2SizeDetect(); //Modify by zhangzhanwei
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
//Modify by zhangzhanwei
if (iSizeMb == 128) {
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
} else {
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE >> 1;
}
return 0;
}
12、display_dram_config,
//lib_arm/board.c
//打印显示DRAM的配置信息
static int display_dram_config (void)
{
int i;
#ifdef DEBUG
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");
}
#else
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");
#endif
return (0);
}
小结:从上可知,上述多数初始化函数还是要求 移值者去编写对应的具体函数的,这也是“移值”的本质,也就是u-boot提供整体框架和各种函数,而移值者根据具体情况编写对应的函数。比如在freescale中,移值主要的工作是要编写2个文件夹中的文件,分别为/board/freescale/mx28和/cpu/arm926ejs/mx28,当然也少不了/include/configs/mx28_evk.h 这个重要的配置头文件,前者是上述函数的实现,后者则是参数、函数编译等配置头文件。
标签:sequence,int,boot,mx28,init,dram,CONFIG,cpu 来源: https://blog.csdn.net/u012351051/article/details/87952015
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。