现在的位置: 首页 > 综合 > 正文

Freescale i.mx28 Boot-stream分析

2013年10月05日 ⁄ 综合 ⁄ 共 4392字 ⁄ 字号 评论关闭

            
Freescale i.mx28 Boot-stream
分析 

      


摘要

基于freescale的i.MX28处理器,ARM926EJ-S内核,最高主频400MHZ,内存DDR2 128MB,NAND FLASH 128MB,i.MX28有极高的集成度,可以降低系统总体成本,低功耗平台,能满足电池供电环境。内嵌L2 Switch,支持双网口;双CAN总线;多达6个UART,便于工控产品系统集成。平台软件丰富稳定,为降低客户设计要求,在linux操作系统之上封装了丰富的协议、基础库、应用程序框架和应用程序支撑层。无需熟悉底层繁琐的基础性,linux
API,只需要会C++即可设计出完美的客户应用程序。工业级和汽车级环境,宽温度范围,高稳定性,非常适合于工业控制、汽车电子、医疗器械、仪器仪表。 


imx28 启动模式提供了2种引导linux kernel 的方法


1:Boot-stream:

直接启动linux,使用imx-boolets 生成_linux.sb包含了硬件初始化和kernel引导代码。Linux_prep阶段将内核启动参数传递给kernel,然后跳到kernel (zImage) 处运行。

2U-boot

对于i.MX28U-Boot是用于在网络上的Linux内核映像加载到SDRAM,因为i.MX28内置ROM固件中没有实现的TCP / IP网络协议栈。i.MX28 U-Boot实现了FEC以太网控制器内置的驱动程序,可以使用TCP / IP网络下载kernel. (NFS,TFTP)

   本文的主角是Boot-stream,所以U-boot就此飘过.......


二:启动流程

   Boot stream 启动经历四个阶段; 这里直接引用IMX28 USER'S GUIDE 文档的说明:

 

  •  power_prep — This bootlet configures the power supply. 

  •  boot_prep — This bootlet configures the clocks and SDRAM. 

  •  linux_prep — This bootlet prepares to boot Linux




三:代码分析

  (1)power_prep

 国际惯例,先来查看linker script ,

     在./imx-bootlets-src/power_prep目录下:link.lds文件:

  1.   OUTPUT_ARCH(arm)
  2.   ENTRY(_start)
  3.   SECTIONS
  4.   {
  5.    . = 0x00000000;
  6.    . = ALIGN(4);
  7.    .text : { *(.text) }
  8.    .data : { *(.data) }
  9.    .bss : { *(.bss) }
  10.   }

OUTPUT_ARCH(arm);指定输出可执行文件的平台为ARM  

=号前的"."为地址计数器(location counter ), 该符号只能用于SECTIONS命令内部,初始值为‘0’,可以对该符号进行赋值,也可以使用该符号进行计算或赋值给其他符号。它会自动根据SECTIONS命令内部所描述的输出段的大小来计算当前的地址。  

可以看出,代码的执行地址和存储地址就是0x00000000,以4字节对齐方式存储,依次存放text,data,bbs段。

ENTRY(_start)指定代码执行的入为_start


    进入imx-bootlets-src/power_prep/power_prep.c   


_start:对寄存器的设置


PowerPrep_CPUClock2XTAL();

//设置时钟为外部时钟源。

PowerPrep_ClearAutoRestart();

//clear RTC ALARM wakeup or AUTORESTART bits here

hw_power_SetPowerClkGate( false );

//空函数,采用默认的设置

HW_POWER_VDDDCTRL.B.LINREG_OFFSET= HW_POWER_LINREG_OFFSET_STEP_BELOW;

HW_POWER_VDDACTRL.B.LINREG_OFFSET =

HW_POWER_LINREG_OFFSET_STEP_BELOW;

HW_POWER_VDDIOCTRL.B.LINREG_OFFSET =

HW_POWER_LINREG_OFFSET_STEP_BELOW;

//如果没在这个范围,将产生一个FIQ,可以参照 i.MX28 Datasheet 在不同频率时设置这个掉电

//电压。即设置电源的波动范围

/*关于VDDD VDDA VDDIO,这里引用数据手册的解释:

• VDDD—provides power to the digital components of the i.MX28 processor. The system clocks 

use the VDDD power rail.

• VDDA—provides power specifically to the audio systems, headphone amp. The VDDA power rail 

also provides power to regulate the VDDMEM rail.

• VDDIO—provides power to the I/O peripherals and also to the NAND Flash and external Secure 

Digital/MultiMedia Cards (SD/MMC).

*/

PowerPrep_Setup5vDetect();

PowerPrep_SetupBattDetect();

//设置电源探测的初始化。

PowerPrep_ConfigurePowerSource();

//探测可用的电源:

//内部电池或者外部充电电源。

//如果探测到可用的电池,就将电池作为供电电源,否则用外部电池。

//但是电池需要开发板的支持,IMX28 EVK没自带电池。

//探测过程的PMU寄存器的设置繁琐的"令人发指"。但只要依据数据手册的设置就没问

//题了。

PowerPrep_EnableOutputRailProtection();

//开启了三路电源vddio vdda vddd的browout的中断,但是如果在插入SD卡时候,导//致板子重

//启,那是因为插入SD卡,VDDIO负载变大,导致出现电压变化 。可以在

//PowerPrep_EnableOutputRailProtection()中禁止掉VDDIO的browout中断。

ddi_power_SetVddio(3300, 3150);  

ddi_power_SetVddd(1350, 1200);

//设置VDDIO和VDDD的值和brownout level 。

HW_POWER_CTRL_CLR(

BM_POWER_CTRL_VDDD_BO_IRQ |

BM_POWER_CTRL_VDDA_BO_IRQ |

BM_POWER_CTRL_VDDIO_BO_IRQ |

BM_POWER_CTRL_VDD5V_DROOP_IRQ |

BM_POWER_CTRL_VBUSVALID_IRQ |

BM_POWER_CTRL_BATT_BO_IRQ |

BM_POWER_CTRL_DCDC4P2_BO_IRQ

);

//清除不必要中断。

if (!bBatteryReady)

    HW_POWER_5VCTRL_SET(BM_POWER_5VCTRL_PWDN_5VBRNOUT);

//如果电池没输入,就自动关闭电池电压。注意只是关闭电池。如果外部电源有输入,

//系统启动没影响。

return iRtn;


  

(2) boot_prep

    依旧查看imx-bootlets-src/boot_prep 目录下的link.lds


  1.   OUTPUT_ARCH(arm)
  2.   ENTRY(_start)
  3.   SECTIONS
  4.   {
  5.    . = 0x00000000;
  6.    . = ALIGN(4);
  7.    .text : { *(.text) }
  8.    .data : { *(.data) }
  9.    .bss : { *(.bss) }
  10.   }

link.ldspowe_prep下的link.lds一样,毫无压力,你们懂得。

代码到此将进入boot_prep_start()

过程很简单,结果很完美。


    1:设置RAMDDR2模式

    2:设置CPU CLK 

    3:设置DDR2 的频率为166MHZ

    4:测试RAM


设置完全就是寄存器的配置。这里就不一一分析了,参照数据手册很好就明白了。

这里测试RAM的方法很简单,

volatile int *pTest = 0x40000000;

0x40000000写入1000个数,在读出来,没有错误就说明RAM正常。


(3) linux_prep


   向kernel传递正确的参数,引导linux kernel设置好标记列表后就要调用内核了。但调用内核前,CPU寄存器的设置必须满足下面的条件:

  Ø r0=0

  Ø r1=机器码

  Ø r2=内核参数标记列表在RAM中的起始地址

imx-bootlets-src/linux_prep/core/entry.S 承载着这一使命。


_start:

stmdbsp!, {r4-r12, lr}

/* Check entry counter */

ldrr4, entry_count

cmpr4, #0

bnestart_kernel

//如果从休眠启动内核,entry_count > 0跳到try_to_resume; 

//否则entry_count = 0;直接start_kernel

bltry_to_resume

/* Update counter to show we were here */

addr4, r4, #1

strr4, entry_count

//增加entry_count,用以标示内核从什么状态启动。

/* Return to ROM */

ldmiasp!, {r4-r12, lr}

bxlr

//在来看看start_kernel 做了哪些工作呢?

start_kernel:

blclear_bss

//首选清除BBS段,如果不清除,以后程序会出现执行错误

/* Initialize HW modules relevant for linux_prep */

blhw_init

/* Setup tags for Linux kernel and save tags pointer in r2 */

blsetup_tags

抱歉!评论已关闭.