下面我们从am33xx_voltagedomains_init(),am33xx_powerdomains_init(),am33xx_clockdomains_init()等几个函数分析。下面的文档定义了什么是Voltage Domain【参考TI的PRCM文档SPRUFA5】。根据这个定义,我们可以得出Voltage Domain的功能包括下面几项:一个Voltage Domain由一个Voltage Regulator供电有一个独立的可控开关不同Voltage Domain可以有不同电压Voltage Domain的电压可以Scale ,可以基于普通DVFS,或者OPP,当然也可固定当选定某个电压后,还可用类似SmartReflex的技术微调(软件透明,也可不透明)可以完全关闭可以支持唤醒(wake-up)一个Voltage Domain可以有多个Power Domain因此,如果要自己设计一个Voltage Domain的结构,可以考虑在其中支持一个voltage_control()的接口,参数可以是0到最大OPP电压,而全范围的OPP可以作为该结构的附加数据提供。不过我们还是先来看Linux的实现如何。首先是am33xx_voltagedomains_init()的Voltage Domain初始化,在内核的linux-3.8.1/arch/arm/mach-omap2/voltagedomains33xx_data.c。这里将MPU和CORE分成单独的Voltage Domain。但是实际上,根据《AM335x ARM? Cortex?-A8 Microprocessors (MPUs)》文档在"Power-Up Sequencing"一节中描述,应该可以合并这两个Voltage Domain。{When using the ZCZ package opTIon, VDD_MPU and VDD_CORE power inputs may be powered from the same source if the applicaTIon only uses operaTIng performance points (OPPs) that define a common power supply voltage for VDD_MPU and VDD_CORE. The ZCE package opTIon has the VDD_MPU domain merged with the VDD_CORE domain.}每个Voltage Domain由一个struct voltagedomain来表示。注意,尽管TPS65910的文档上说明了该PMIC支持8个可编程的LDO,且在AM335xStarterKit开发板上的确通过AM335X_I2C0链接了这个PMIC的I2C,但是由于这些LDO连接的都是些常规I/O,限定了要求的电压范围(不可使用DVFS这样的方式来类似调整Voltage Domain的电压一样来调整输出电压),因此这里不把这些LDO看做独立的Voltage Domain。但是,实际上如果这些对应的模块不需要的话,应该还是可以在初始化时将其LDO电源关掉。再注意到,TPS65910的文档上说明了该PMIC支持通过SmartReflex接口(实际上是独立的I2C接口)来控制Processor Core的Power。但是实际的AM335xStarterKit开发板上却没有连接这个SmartReflex接口。有一点需要注意,TPS65910实现的是SmartReflex Class-3,而AM335x实现的是SmartReflex Class-2B。下面的文字来自TPS65910文档。关于SmartReflex的支持,可以参考这个GitHub的patch,但是这是针对AM335X EVM或者BeagleBone开发板的。在AM3359 - TMDXIDK3359开发板中,SmartReflex的I2C接口是接上的。https://github.com/Angstrom-distribution/meta-ti/blob/master/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am33xx-Add-SmartReflex-support.patch实际上,在TPS65910的文档中还说明了这个PMIC的SmartReflex寄存器是可以通过Control I2C和SmartReflex I2C访问的,但是需要通过Control I2C先配置其DEVCTRL_REG寄存器的SR_CTL_I2C_SEL位来选择。下面简单分析对struct voltagedomain的管理。首先是平台初始化代码通过voltdm_init()来把自己支持的Voltage Domain注册到系统中,实际上这是通过调用_voltdm_register()来实现的,并且是将这个struct voltagedomain加入到一个全局的voltdm_list中。从而,也就可以对这个voltdm_list进行查找,所以又有voltdm_lookup()函数。另外,为了方便起见,还提供一个voltdm_for_each()函数,通过扫描这个voltdm_list,每当发现一个Voltage Domain,就调用指定的函数指针,从而可以实现对所有的Voltage Domain都执行某种操作的功能。由于每个Voltage Domain可以有多个Power Domain,因此voltdm_add_pwrdm()就被用来向一个Voltage Domain添加一个Power Domain(将这些Power Domain连接到这个Voltage Domain的pwrdm_list中)。类似的,还提供了一个voltdm_for_each_pwrdm()来对一个Voltage Domain的所有Power Domain执行指定的操作函数。对于每个Voltage Domain,由于可以有不同的Scale的方法(比如可以使用Voltage Controller,也可以用Voltage Processor来实现),因此提供omap_change_voltscale_method()来改变相应的Scale方法。其实这一点,如果为了通用起见,应该让平台代码直接实现Scale方法就行了,也就是可以直接用xxx_set_scale_method()就可以。omap_voltage_register_pmic()被用来设置struct voltagedomain的pmic字段。omap_voltage_get_voltdata()用来返回对应电压的相关数据(这里使用voltage table实现),即OPP数据。omap_voltage_get_volttable()就是用来返回这个voltage table的。voltdm_reset()将这个Voltage Domain的电压设置为当前OPP,实际调用的是voltdm_scale()实现的。voltdm_scale()就是用来实现Voltage Scale功能的,根据参数指定电压,在该Voltage Domain自己的voltage table中找到一项恰好大于该指定电压的"标称电压",用来设置对应的Regulator。voltdm_get_voltage()用来获得该Voltage Domain的当前标称电压nominal_volt。
下面我们从am33xx_voltagedomains_init(),am33xx_powerdomains_init(),am33xx_clockdomains_init()等几个函数分析。下面的文档定义了什么是Voltage Domain【参考TI的PRCM文档SPRUFA5】。根据这个定义,我们可以得出Voltage Domain的功能包括下面几项:一个Voltage Domain由一个Voltage Regulator供电有一个独立的可控开关不同Voltage Domain可以有不同电压Voltage Domain的电压可以Scale ,可以基于普通DVFS,或者OPP,当然也可固定当选定某个电压后,还可用类似SmartReflex的技术微调(软件透明,也可不透明)可以完全关闭可以支持唤醒(wake-up)一个Voltage Domain可以有多个Power Domain因此,如果要自己设计一个Voltage Domain的结构,可以考虑在其中支持一个voltage_control()的接口,参数可以是0到最大OPP电压,而全范围的OPP可以作为该结构的附加数据提供。不过我们还是先来看Linux的实现如何。首先是am33xx_voltagedomains_init()的Voltage Domain初始化,在内核的linux-3.8.1/arch/arm/mach-omap2/voltagedomains33xx_data.c。这里将MPU和CORE分成单独的Voltage Domain。但是实际上,根据《AM335x ARM? Cortex?-A8 Microprocessors (MPUs)》文档在"Power-Up Sequencing"一节中描述,应该可以合并这两个Voltage Domain。{When using the ZCZ package opTIon, VDD_MPU and VDD_CORE power inputs may be powered from the same source if the applicaTIon only uses operaTIng performance points (OPPs) that define a common power supply voltage for VDD_MPU and VDD_CORE. The ZCE package opTIon has the VDD_MPU domain merged with the VDD_CORE domain.}每个Voltage Domain由一个struct voltagedomain来表示。注意,尽管TPS65910的文档上说明了该PMIC支持8个可编程的LDO,且在AM335xStarterKit开发板上的确通过AM335X_I2C0链接了这个PMIC的I2C,但是由于这些LDO连接的都是些常规I/O,限定了要求的电压范围(不可使用DVFS这样的方式来类似调整Voltage Domain的电压一样来调整输出电压),因此这里不把这些LDO看做独立的Voltage Domain。但是,实际上如果这些对应的模块不需要的话,应该还是可以在初始化时将其LDO电源关掉。再注意到,TPS65910的文档上说明了该PMIC支持通过SmartReflex接口(实际上是独立的I2C接口)来控制Processor Core的Power。但是实际的AM335xStarterKit开发板上却没有连接这个SmartReflex接口。有一点需要注意,TPS65910实现的是SmartReflex Class-3,而AM335x实现的是SmartReflex Class-2B。下面的文字来自TPS65910文档。关于SmartReflex的支持,可以参考这个GitHub的patch,但是这是针对AM335X EVM或者BeagleBone开发板的。在AM3359 - TMDXIDK3359开发板中,SmartReflex的I2C接口是接上的。https://github.com/Angstrom-distribution/meta-ti/blob/master/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am33xx-Add-SmartReflex-support.patch实际上,在TPS65910的文档中还说明了这个PMIC的SmartReflex寄存器是可以通过Control I2C和SmartReflex I2C访问的,但是需要通过Control I2C先配置其DEVCTRL_REG寄存器的SR_CTL_I2C_SEL位来选择。下面简单分析对struct voltagedomain的管理。首先是平台初始化代码通过voltdm_init()来把自己支持的Voltage Domain注册到系统中,实际上这是通过调用_voltdm_register()来实现的,并且是将这个struct voltagedomain加入到一个全局的voltdm_list中。从而,也就可以对这个voltdm_list进行查找,所以又有voltdm_lookup()函数。另外,为了方便起见,还提供一个voltdm_for_each()函数,通过扫描这个voltdm_list,每当发现一个Voltage Domain,就调用指定的函数指针,从而可以实现对所有的Voltage Domain都执行某种操作的功能。由于每个Voltage Domain可以有多个Power Domain,因此voltdm_add_pwrdm()就被用来向一个Voltage Domain添加一个Power Domain(将这些Power Domain连接到这个Voltage Domain的pwrdm_list中)。类似的,还提供了一个voltdm_for_each_pwrdm()来对一个Voltage Domain的所有Power Domain执行指定的操作函数。对于每个Voltage Domain,由于可以有不同的Scale的方法(比如可以使用Voltage Controller,也可以用Voltage Processor来实现),因此提供omap_change_voltscale_method()来改变相应的Scale方法。其实这一点,如果为了通用起见,应该让平台代码直接实现Scale方法就行了,也就是可以直接用xxx_set_scale_method()就可以。omap_voltage_register_pmic()被用来设置struct voltagedomain的pmic字段。omap_voltage_get_voltdata()用来返回对应电压的相关数据(这里使用voltage table实现),即OPP数据。omap_voltage_get_volttable()就是用来返回这个voltage table的。voltdm_reset()将这个Voltage Domain的电压设置为当前OPP,实际调用的是voltdm_scale()实现的。voltdm_scale()就是用来实现Voltage Scale功能的,根据参数指定电压,在该Voltage Domain自己的voltage table中找到一项恰好大于该指定电压的"标称电压",用来设置对应的Regulator。voltdm_get_voltage()用来获得该Voltage Domain的当前标称电压nominal_volt。