加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

u-boot-1.1.4代码阅读

发布时间:2020-12-15 06:52:37 所属栏目:百科 来源:网络整理
导读:? 写在前面:通过uboot的阅读我学到了很多东西,高手写的代码就是不一样。 代码阅读顺序: 1.第一阶段(Stage 1) 第一阶段的启动代码在 cpucpu typestart.s中,完成的工作主要有: ? ? CPU自身初始化:包括 MMU,Cache,时钟系统,SDRAM 控制器等的初始化
?

写在前面:通过uboot的阅读我学到了很多东西,高手写的代码就是不一样。

代码阅读顺序:
1.第一阶段(Stage 1)
第一阶段的启动代码在 cpu&;cpu type>start.s中,完成的工作主要有:
??CPU自身初始化:包括 MMU,Cache,时钟系统,SDRAM 控制器等的初始化
? ?重定位:把自己从非易失性存储器搬移到 RAM中
? ?分配堆栈空间,设置堆栈指针
? ?清零 BSS 数据段
? ?跳转到第二阶段入口函数 start_armboot()
/Uboot114/u-boot-1.1.4/cpu/arm926ejs/start.S

2.第二阶段(Stage 2)
第二阶段是 u-boot 的主体,入口点是 lib_armboard.c 中的 start_armboot()函数,完成的主要工作包括:
??为 U-boot 内部私有数据分配存储空间,并清零
??依次调用函数指针数组 init_sequence 中定义的函数进行一系列的初始化
??如果系统支持 NOR Flash,调用 flash_init ()和 display_flash_config ()初始化并显示检测到的器件信息(AT91SAM9260EK不需要)
??如果系统支持LCD或VFD,调用lcd_setmem()或vfd_setmem()计算帧缓冲(Framebuffer)大小,然后在 BSS 数据段之后为 Framebuffer 分配空间,初始化 gd->fb_base 为Framebuffer的起始地址(AT91SAM9260EK不需要)
??调用 mem_malloc_init()进行存储分配系统(类似于 C 语言中的堆)的初始化和空间分配
??如果系统支持 NAND Flash,调用 nand_init()进行初始化
??如果系统支持 DataFlash,调用 AT91F_DataflashInit()和 dataflash_print_info()进行初始化并显示检测到的器件信息
??调用 env_relocate ()进行环境变量的重定位,即从 Flash中搬移到 RAM 中
??如果系统支持 VFD,调用 drv_vfd_init()进行 VFD 设备初始化(AT91SAM9260EK 不需要)
? ?从环境变量中读取 IP 地址和 MAC 地址,初始化 gd->bd->bi_ip_addr和gd->bd->bi_enetaddr
? ?调用 jumptable_init()进行跳转表初始化,跳转表在global_data中,具体用途尚不清楚
? ?调用 console_init_r()进行控制台初始化
? ?如果需要,调用 misc_init_r()进行杂项初始化
? ?调用enable_interrupts()打开中断
? ?如果需要,调用 board_late_init()进行单板后期初始化,对于 AT91SAM9260EK,主要是以太网初始化
? ?进入主循环:根据用户的选择启动 linux,或者进入命令循环执行用户输入的命令
/Uboot114/u-boot-1.1.4/lib_arm/board.c

3.U-boot 的初始化
?3.1? 私有数据 global_data
?global_data?/Uboot114/u-boot-1.1.4/include/asm-arm/global_data.h
?bd_info?/Uboot114/u-boot-1.1.4/include/asm-arm/u-boot.h
?3.2? 初始化序列 init_sequence
?Init_sequence是一个函数指针数组,数组中每一个元素都指向一个初始化函数。
?init_sequence /Uboot114/u-boot-1.1.4/lib_arm/board.c?
???(1)cpu_init u-boot-1.1.4cpuarm920tcpu.c
??????这个函数的功能是设置irq和fiq模式的堆栈起始点。AT91SAM9260EK 没有使用U-boot的中断机制,所以这个函数实际上什么也没做。
????(2)board_init?u-boot-1.1.4boardat91rm9200dkat91rm9200dk.c
????(3)interrupt_init?cpuarm926ejsinterrupts.c
????(4)env_init commonenv_dataflash.c
????(5)serial_init cpuarm920tat91rm9200serial.c
?3.3? NAND Flash 初始化
?首先初始化NAND Flash接口,包括分配片选,设置片选的时序和模式,配置一些相关的IO口,然后调用nand_probe()检测NAND Flash。nand_probe()函数在common/cmd_nand.c中定义(这个文件实现了所有和NAND Flash相关的功能),调用NanD_ScanChips()函数搜索系统中的NAND Flash芯片(NanD_ScanChips()又调用NanD_IdentChip()检测芯片,实际上就是向NAND FLASH芯片发复位和读 ID命令,根据返回值判断芯片的型号和容量),具体实现细节不再描述。在这个版本的uboot中有一些出入,但是基本过程都差不多
?nand_init()完成NAND Flash的初始化。这个函数在board/at91rm9200dk/at91rm9200dk.c中。
?3.4? DataFlash 初始化
?AT91F_DataflashInit()完成 DataFlash 的初始化。这个函数在 drivers/dataflash.c 中。首先调用AT91F_SpiInit ()初始化SPI接口,然后调用AT91F_DataflashProbe()扫描所有的 SPI 片选,检测DataFlash是否存在,实现原理和NAND Flash类似,都是向芯片发送查询ID命令,根据返回值判断芯片的类型和容量。
?AT91F_SpiInit ()函数的定义在 cpu/arm926ejs/at91sam9260/spi.c中,但是我这套代码中没有,我就把源码粘贴到这里了.
void AT91F_SpiInit(void) {
?? volatile unsigned int dummy;
????
? AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA,
????????? (AT91C_PA0_SPI0_MISO | AT91C_PA1_SPI0_MOSI |?
?????????? AT91C_PA2_SPI0_SPCK | AT91C_PA3_SPI0_NPCS0 |
?????????? AT91C_PC11_SPI0_NPCS1 | AT91C_PC16_SPI0_NPCS2 |?
?????????? AT91C_PC17_SPI0_NPCS3),
????????? 0);
? ????
?? AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_SPI0;
??? ????
? AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SWRST;
?? ????
???
? AT91C_BASE_SPI0->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS |
AT91C_SPI_PCS;
?? ??
? AT91C_BASE_SPI0->SPI_CSR[0] = (AT91C_SPI_CPOL | (AT91C_SPI_DLYBS &
DATAFLASH_TCSS) |??
???? (AT91C_SPI_DLYBCT & DATAFLASH_TCHS) |?
???? (AT91C_MASTER_CLOCK / AT91C_SPI_CS0_CLK) << 8);
? AT91C_BASE_SPI0->SPI_CSR[3] = (AT91C_SPI_CPOL | (AT91C_SPI_DLYBS &
DATAFLASH_TCSS) |??
???? (AT91C_SPI_DLYBCT & DATAFLASH_TCHS) |?
???? (AT91C_MASTER_CLOCK / AT91C_SPI_CS3_CLK) << 8);
?? ??
? AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SPIEN;
? while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_SPIENS)); ?
? // Add tempo to get SPI in a safe state.
??? // Should be removed for new silicon (Rev B)
? udelay(500000);
? dummy = AT91C_BASE_SPI0->SPI_SR;
? dummy = AT91C_BASE_SPI0->SPI_RDR;
}
??AT91F_DataflashProbe()在boardat91rm9200dkat45.c

?3.5? 环境变量重
?common/env_common.c 中的 env_relocate()函数实现环境变量的重定位:
?3.6? 初始化设备?
?U-boot中设备的类型是 device_t,在 include/devices.h 中定义:
?device_t 的主体是一系列操作设备的函数指针,另外还包含了设备名称,标记和私有数据等等。
?common/devices.c 中的 devices_init 函数实现设备的初始化
?函数 drv_system_init ()总是要执行的,这个函数创建并注册了一个串行口设备和一个空设备(空设备是可选的),在common/devices.c 中定义:
?3.7? 控制台初始化
?控制台初始化分两个阶段:console_init_f()和console_init_r()。console_init_f()完成的功能很简单,只是根据环境变量设置了global_data中的一些数据成分(hasconsole,flag); console_init_r()在common/console.c中定义,完成主要的控制台初始化工作:在设备链表中搜索 stdin,stdout,stderr设备;将搜索结果分别设为置控制台的in,out和err设备。
?通过console_setfile()函数可以看出,控制台有一个包含 3 个 device_t 元素的数组stdio_devices,分别对应 stdin,stderr。通过 stdio_devices[file] = dev 就可以将dev设成设置控制台的某个设备。这样就实现了控制台任意选择设备的功能。这和 linux 的设计思想有点类似。
?3.8 单板后期初始化
?函数 board_late_init()完成单板后期的初始化,对于AT91SAM9260EK,这个函数在board/at91sam9260ek/at91sam9260ek.c中定义,调用 cpu/arm926ejs/at91sam9260/at91_emac.c中的函数 eth_init()完成以太网的初始化。
?我的版本中没有cpu/arm926ejs/at91sam9260/at91_emac.c这个文件下面是部分源码:
int eth_init (bd_t * bd)
{
? unsigned int periphAEnable,periphBEnable;
? unsigned int val,i;
?int ret;
?
?p_mac = AT91C_BASE_EMACB;
?

#ifdef CONFIG_AT91C_USE_RMII
? periphAEnable = ((unsigned int) AT91C_PA21_EMDIO???? ) |
? ((unsigned int) AT91C_PA20_EMDC??? ) |
? ((unsigned int) AT91C_PA19_ETXCK?? ) |
? ((unsigned int) AT91C_PA18_ERXER?? ) |
? ((unsigned int) AT91C_PA14_ERX0??? ) |
? ((unsigned int) AT91C_PA17_ERXDV?? ) |
? ((unsigned int) AT91C_PA15_ERX1??? ) |
? ((unsigned int) AT91C_PA16_ETXEN?? ) |
??? ((unsigned int) AT91C_PA12_ETX0??? ) |
??? ((unsigned int) AT91C_PA13_ETX1??? );
?
?periphBEnable = 0;
#else
? periphAEnable = ((unsigned int) AT91C_PA21_EMDIO???? ) |
? ((unsigned int) AT91C_PA19_ETXCK?? ) |
? ((unsigned int) AT91C_PA20_EMDC??? ) |
? ((unsigned int) AT91C_PA18_ERXER?? ) |
? ((unsigned int) AT91C_PA14_ERX0??? ) |
? ((unsigned int) AT91C_PA17_ERXDV?? ) |
? ((unsigned int) AT91C_PA15_ERX1??? ) |
?((unsigned int) AT91C_PA16_ETXEN?? ) |
??? ((unsigned int) AT91C_PA12_ETX0??? ) |
??? ((unsigned int) AT91C_PA13_ETX1??? );
??
? periphBEnable = ((unsigned int) AT91C_PA27_ERXCK???? ) |
??? ((unsigned int) AT91C_PA29_ECOL??? ) |
? ((unsigned int) AT91C_PA25_ERX2??? ) |
? ((unsigned int) AT91C_PA26_ERX3??? ) |
? ((unsigned int) AT91C_PA22_ETXER?? ) |
??? ((unsigned int) AT91C_PA10_ETX2??? ) |???
??? ((unsigned int) AT91C_PA11_ETX3??? ) |
? ((unsigned int) AT91C_PA28_ECRS??? );
#endif
? AT91C_BASE_PIOA->PIO_ASR = periphAEnable;
?AT91C_BASE_PIOA->PIO_BSR = periphBEnable;
? AT91C_BASE_PIOA->PIO_PDR = (periphAEnable | periphBEnable);
??
/ * 禁止收发,清除收发状态寄存器 */??
? p_mac->EMAC_NCR = 0;
? p_mac->EMAC_TSR = 0xFFFFFFFF;
?p_mac->EMAC_RSR = 0xFFFFFFFF;
?
/ * 打开 MAC模块的时钟 */??
? *AT91C_PMC_PCER = 1 << AT91C_ID_EMAC;?
?
/ * 禁止 PA17(RXDV)? 的上拉电阻 */
? AT91C_BASE_PIOA->PIO_PPUDR = 1 << 17;
?
? / *? 选择 MAC接口为 MII 模式 */
? p_mac->EMAC_USRIO = AT91C_EMAC_CLKEN;
?
#ifdef CONFIG_AT91C_USE_RMII
?p_mac->EMAC_USRIO |= AT91C_EMAC_RMII;
#endif
?
?
?RxBuffIndex = 0;
?TxBuffIndex = 0;
?
/ * 初始化接收缓冲区描述符链表 */
? for (i = 0; i < RBF_FRAMEMAX; ++i) {
? val = (unsigned int)(rbf_framebuf[i]);
??? RxtdList[i].addr = val & 0xFFFFFFF8;
???? RxtdList[i].U_Status.status = 0;
?}?
?
?RxtdList[RBF_FRAMEMAX-1].addr |= RBF_WRAP;
?
/ * 初始化发送缓冲区描述符链表 */
? for (i = 0; i < TBF_FRAMEMAX; ++i) {
? val = (unsigned int)(tbf_framebuf[i]);
??? TxtdList[i].addr = val & 0xFFFFFFF8;
? TxtdList[i].U_Status.status = 0;
? TxtdList[i].U_Status.S_Status.BuffUsed = 1;
?}
? TxtdList[0].U_Status.S_Status.BuffUsed = 0;
?
?TxtdList[TBF_FRAMEMAX-1].U_Status.S_Status.Wrap = 1;
?
? / *? 获取 PHY芯片的操作函数 */
?at91sam9260_GetPhyInterface (&PhyOps);
???
? / *? 判断 PHY芯片是否正常连接 */
? if (!PhyOps.IsPhyConnected (p_mac))
?{
??? printf ("PHY not connected!nr");
? return -1;
?}
?else
??? printf ("PHY is connected!nr");
?
/ * 调用 PHY芯片的初始化函数:读取 PHY芯片的工作模式,把 MAC的工作模式设
为和 PHY一致 */
?
? ret = PhyOps.Init (p_mac);
? if ( !ret && 0 )
?{
??? printf ("MAC: error during MAC initializationn");
? return -1;
?}
?
/ * MAC初始化 */
? AT91F_EMACInit(bd,(unsigned int)RxtdList,(unsigned int)TxtdList);
???
?return 0;
}
int AT91F_EMACInit(bd_t * bd,
???? unsigned int pRxTdList,
???

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读