"); //-->
经过最近几天的学习,发现MX28系列的启动方式和其他的芯片不是太一样。
其他的芯片启动方式通常是CPU读取启动设备中的一小部分uboot代码放在ocram中执行。这小段uboot代码,再将其他部分的uboot代码放到ddr中,然后通过重定位,到ddr中去执行。
而MX28这个芯片,需要用ivt_xxx.sb文件来作为启动程序,这个sb的具体内容可以查看《Secure Boot with i.MX28 HAB Version 4.pdf》,大体上讲,这个文件是通过Elftosb这个工具+uboot编译后的elf文件+bootlets编译后的Elf文件+bd文件(关于bd文件的描述查看《KBLELFTOSBUG.pdf》)生成的,最后生成的这个ivt_xxx.sb文件才是MX28这个芯片真正能使用的。
看了一下imx-bootlets-src-10.12.01下的文件,参照《Freescale i.mx28 Boot-stream分析》,以及bd文件。bootlets的启动顺序应该是power_prep、boot_prep然后接下来是uboot或者是linux_prep。
那么首先分析power_prep源代码,先查看一下他的链接脚本文件,这个脚本文件很简单,主要想找一下程序的入口地址_start。
OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { . = 0x00000000; . = ALIGN(4); .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss) } }
找到入口地址之后有些疑惑,竟然是个C函数,不是汇编,而且直接返回,我只能推测Elftosb似乎做了什么。这似乎和bd文件中的call命令有些关系。但原谅我还没有看懂,哪位大侠清楚这里,指点一下!
下面把_start函数和自己的分析放在这里
int _start( void ) { int iRtn = SUCCESS; #ifndef mx28 //这个在Makefile里定义了,所以下面这句肯定不执行了 HW_DIGCTL_CTRL_SET(BM_DIGCTL_CTRL_USE_SERIAL_JTAG); #else//执行下面的SSP0引脚配置
#define SSP0_PIN_DRIVE_12mA 0x2 // For EMI 200MHz,must enable SSP0 pin drive to 12mA,or the SD boot will fail. HW_PINCTRL_DRIVE8_CLR( BM_PINCTRL_DRIVE8_BANK2_PIN07_MA | BM_PINCTRL_DRIVE8_BANK2_PIN06_MA | BM_PINCTRL_DRIVE8_BANK2_PIN05_MA | BM_PINCTRL_DRIVE8_BANK2_PIN04_MA | BM_PINCTRL_DRIVE8_BANK2_PIN03_MA | BM_PINCTRL_DRIVE8_BANK2_PIN02_MA | BM_PINCTRL_DRIVE8_BANK2_PIN01_MA | BM_PINCTRL_DRIVE8_BANK2_PIN00_MA); HW_PINCTRL_DRIVE9_CLR( BM_PINCTRL_DRIVE9_BANK2_PIN10_MA | BM_PINCTRL_DRIVE9_BANK2_PIN09_MA | BM_PINCTRL_DRIVE9_BANK2_PIN08_MA); HW_PINCTRL_DRIVE8_SET( (SSP0_PIN_DRIVE_12mA << BP_PINCTRL_DRIVE8_BANK2_PIN07_MA) | (SSP0_PIN_DRIVE_12mA << BP_PINCTRL_DRIVE8_BANK2_PIN06_MA) | (SSP0_PIN_DRIVE_12mA << BP_PINCTRL_DRIVE8_BANK2_PIN05_MA) | (SSP0_PIN_DRIVE_12mA << BP_PINCTRL_DRIVE8_BANK2_PIN04_MA) | (SSP0_PIN_DRIVE_12mA << BP_PINCTRL_DRIVE8_BANK2_PIN03_MA) | (SSP0_PIN_DRIVE_12mA << BP_PINCTRL_DRIVE8_BANK2_PIN02_MA) | (SSP0_PIN_DRIVE_12mA << BP_PINCTRL_DRIVE8_BANK2_PIN01_MA) | (SSP0_PIN_DRIVE_12mA << BP_PINCTRL_DRIVE8_BANK2_PIN00_MA)); HW_PINCTRL_DRIVE9_SET( (SSP0_PIN_DRIVE_12mA << BP_PINCTRL_DRIVE9_BANK2_PIN10_MA) | (SSP0_PIN_DRIVE_12mA << BP_PINCTRL_DRIVE9_BANK2_PIN09_MA) | (SSP0_PIN_DRIVE_12mA << BP_PINCTRL_DRIVE9_BANK2_PIN08_MA)); #endif PowerPrep_CPUClock2XTAL();//选择外部时钟 PowerPrep_ClearAutoRestart();//貌似是给RTC软件复位,没太懂 hw_power_SetPowerClkGate( false );//全注释掉了,啥也没做 printf("\r\nPowerPrep start initialize power...\r\n");//串口还没有初始化,没打印出来
//电压波动范围在25mV以内 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; // Ready the power block for 5V detection. PowerPrep_Setup5vDetect();//电源比较器设为5V,检测的阈值设置为4.4V PowerPrep_SetupBattDetect();//分析内容见下一段 // Ensure the power source that turned on the device is sufficient to // power the device. PowerPrep_ConfigurePowerSource();//用三个宏确定了是使用5V单独供电,电池供电,还是二者一起 PowerPrep_EnableOutputRailProtection();//清中断,并且当VDDD,VDDA,VDDIO降低时,关断设备 /* 3.3V is necessary to achieve best power supply capability * and best EMI I/O performance. */ ddi_power_SetVddio(3300, 3150);//设置VDDIO为3.3V,掉电门限为3.15V #ifdef mx28 ddi_power_SetVddd(1350, 1200); //设置VDDD为1.35V,掉电门限为1.2V
#endif //清中断 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 Battery not ready,setup the auto power down if we lost 5V.*/ if (!bBatteryReady) { HW_POWER_5VCTRL_SET(BM_POWER_5VCTRL_PWDN_5VBRNOUT);//如果没有5V硬件自动关断 #if defined(NO_DCDC_BATT_SOURCE) && defined(mx28) /* On i.MX28, a new bit has been added to allow automatic hardware * shutdown if VDD4P2 browns out. If we permanently only have a VDD5V * source, we want to enable this bit. For devices with dead batteries, * we could also temporarily set this bit until the kernel battery * charger sufficiently charges the battery but we won't do this for * now as the latest release kernel versions aren't aware of it * and thus don't handle the proper setting/clearing of this bit. */ HW_POWER_REFCTRL_SET(1<<7);//貌似是用来检测4P2引脚的 #endif } return iRtn; }
首先是一大段的SSP0引脚配置,将SSP0所有的引脚配置为,高驱动能力(SSP0_PIN_DRIVE_12mA 0x2 ),每个数字引脚都有4,8,12mA的驱动能力可选择(《MCIMX28RM》)。这里选择的是12mA。
下面这段代码,看名字是建立电池检测,其中LRADC表示低分辨率AD,
hw_lradc_EnableBatteryMeasurement这个函数主要配置LRADC,采样频率,采样间隔,并开启对电池的检测。
void PowerPrep_SetupBattDetect( void ) { extern bool bHwLradcInitialized; // Initialize LRADC for battery monitoring. bHwLradcInitialized = false;//一个标识位,false表示lradc尚未被初始化 hw_lradc_Init(FALSE, LRADC_CLOCK_6MHZ);//设置两个通道分别检测VDDIO和BATTERY
hw_lradc_EnableBatteryMeasurement( hw_lradc_AcquireBatteryMonitorDelayTrigger(), 100); }
虽然写的不是很详细,但是真的已经看吐血了。。。
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。