新闻  |   论坛  |   博客  |   在线研讨会
U-BOOT学习笔记(2)--PowerPrep分析
mihu525 | 2017-04-30 16:48:36    阅读:775   发布文章

经过最近几天的学习,发现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);
}

 

虽然写的不是很详细,但是真的已经看吐血了。。。





*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客