u-boot-1.1.4代码阅读(转)

写在前面:通过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_arm\board.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.4\cpu\arm920t\cpu.c
      这个函数的功能是设置irq和fiq模式的堆栈起始点。AT91SAM9260EK 没有使用U-boot的中断机制,所以这个函数实际上什么也没做。
    (2)board_init \u-boot-1.1.4\board\at91rm9200dk\at91rm9200dk.c
    (3)interrupt_init \cpu\arm926ejs\interrupts.c
    (4)env_init \common\env_dataflash.c
    (5)serial_init \cpu\arm920t\at91rm9200\serial.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()在\board\at91rm9200dk\at45.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,stdout,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!\n\r");
  return -1;
 }
 else
    printf ("PHY is connected!\n\r");
 
/ * 调用 PHY芯片的初始化函数:读取 PHY芯片的工作模式,把 MAC的工作模式设
为和 PHY一致 */
 
  ret = PhyOps.Init (p_mac);
  if ( !ret && 0 )
 {
    printf ("MAC: error during MAC initialization\n");
  return -1;
 }
 
/ * MAC初始化 */
  AT91F_EMACInit(bd, (unsigned int)RxtdList, (unsigned int)TxtdList);
   
 return 0;
}
int AT91F_EMACInit(bd_t * bd,
     unsigned int pRxTdList,
  

转载于:https://www.cnblogs.com/c1230v/articles/1550749.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值