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

电源管理基本观念之二

2014年09月05日 ⁄ 综合 ⁄ 共 5017字 ⁄ 字号 评论关闭

转载:http://blog.sina.com.cn/s/blog_a6559d920101i58f.html

1. SOC 时钟体系与功耗

用黑盒子来看待PLL,PLL的功能是从一个时钟输入,经过相位同步等一系列物理变化获得新的频率的时钟。特征是输出时钟的频率依赖于输入实在的频率,会有整数倍的线性约束关系,并且倍频,调频是时间的因子。PLL树则是有多个PLL组成的硬件树形结构,能够输出多种不同频率的时钟,从而满足多数需要。SOC的时钟体系设计是大量PLL,MUX,DIV的集合。

基于ARM核的SOC大都遵循AMBA总线协议,因此在整个时钟体系的设计都会遵循AMBA协议,并在AMBA协议上来进行扩展。AMBA协议定义了两组总线,分别适用于不同的通信需求:


一条高速总线AHB用于arm core, on-chip memory,dma之间的通讯。一条从AHBA桥接出来的低速总线APB用于跟外部IP之间的通讯。所以在时钟源的设置上,必须针对这两条总线的要求提供时钟源。因此ARM体系结构的SOC,两个PLL是必须的,一个是直接提供给ARM
Core使用的PLL。
另一个是输出给AMBA协议定义的两条总线使用的PLL。使用AMBA协议通讯的IP所需要的时钟原则上都可以从提供总线时钟的PLL分频得到。另外,系统存在一些需要特殊频率的IP是,还会再增加PLL来专门为这些IP提供时钟。原则上讲,时钟树就是PLL,MUX,DIV的集合。从SOC层面的功耗情况看,根据系统的具体运行场景需求合理的调整来操作PLL和MUX来合理的关掉某些时钟是降低功耗的一个途径。Linux系统进入S3的情况,这部分操作放在了global
platform阶段。 另外,运行时的某些特定状态,也可以在软件上增加一些状态,针对时钟做一些配置来降低功耗。例如在长时间播放音乐的场景下,则可以只打开CODEC IP的时钟,而关掉其它IP的时钟,总而达到降低场景功耗的目的。

2. DDR耗电分析

传统DDR跟mobile DDR在功耗上存在较大区别。 mobile DDR 又称为lpddr,针对嵌入式设备做了很多优化。 DDR的功耗主要由工作电压和刷新方式决定。

下面工作电压的一个参考:

 

TYPE Core Voltage
(VDD)
IO Voltage
(VIO)
DDR 2.5V 2.5V
LPDDR 1.8V 1.8V/1.2V
DDR2 1.8V 1.8V
LPDDR2 1.2V 1.2V
DDR3 1.5V/1.35V 1.5V/1.35V
LPDDR3 1.2V 1.2V


 

 

另外在工作方式上也作出了优化,去掉DLL,DLL 消失后带来读写时序上的一些变化,另外对于时延要求控制更严。

DLL (Delay Locked Loop,延时锁定回路)本来在DDR引入,主要目的就是用来提供DQS信号与CLK之间同步。

LPDDR去掉DLL带来如下好处:

(a). active mode power saving (~10mA)

(b). DDR内部时钟可以随着接口时钟(CK/CK_)的变化而调整(可以被改变,甚至停止);


 LPDDR针对功耗优化增加了两种刷新方式

温度补偿刷新Temperature Compensated Self-Refresh (TCSR)

相比DDR加入的feature,on-chip 温度感应,在低温下降低刷新率,降低在自刷新模式下的功耗(在手持设备里,自刷新模式的LPDDR功耗是设备待机功耗的主要来源).

 

部分区域的自刷新PASR (partial array self refresh)

相比DDR来说,PASR提供用户可控的部分区域自刷新,而非整个区域(ARRAY),比如1/2, 1/4, 1/8, 1/16 array; 同时也意味着,未能及时refresh的部分内容会丢失。

这里的1~1/6 array,可以覆盖从整个die(all banks) 到某个bank的部分row. 基本上每个level提供相对上一个级别50%的 power down.

 

超低功耗 模式(DPD ,deep power down"),在系统供电仍然保持的状态下,牺牲掉所有的内存内容。 具体实现是可以切断对于具体的存储部分的电源;但是在退出DPD时需要重新做部分初始化 –因此相应Memory Controller部分需要重写。


切换到S3状态,针对DDR的功耗优化,软件代码一般也放在global platform阶段完成。



3. CPU Core耗电分析-Cortex A15电源状态



ARMCortex A15 Core部分 定义了多个电压域,针对不同的电压域,提供了多种Power Mode。基于ARMCortex A15的SOC定义的电源状态则是ARM Cortex A15定义的电源状态的子集。不同Power Mode的区别就是在于上图各个模块的打开和关断状态。

从模块图看有如下几个模块:

  • integer core: 也就通常所说的运算器,用于做整数运算的逻辑单元,包括了指令cache,数据cache,TLB cache等。Cortex
    A15上把这一部分电压域称为Processor,这一部分的时钟可以单独控制。从模块图上可以看出时钟是CK_GCLKCR
  • NEON & VFP:这一部分用于浮点数以及向量运算。时钟控制逻辑是CK_GCLKCX。
  • DEBUG APB,CTI,and CTM:调试模块。时钟控制逻辑是PCLKDBG。
  • L2 RAMs: 二级缓存
  • L2 Control,IC,Timer: 二级缓存控制器,硬件定时器等。

电源状态的定义原则即使这几个模块开关状态的排列组合和cpu的工作场景。Cortex A15正好定义了10种电源状态。


cpu core 切换到不同的电源状态,ARM CORE有专门的汇编指令来完成,并且还要配合硬件时序。切换到S3状态下,针对cpu core的软件实现也放在global platform阶段。


4. Linux cupfreq driver

Linux有专门的cpufreq子系统来针对cpu的运行状态来调节cpu的工作频率,从而降低功耗。cpufreq子系统有如下组件来描述调频过程中的各个功能模块:

  • cpufreq notifier  :触发频率调节的源头
  • cpufreq_policy    :描述有cpu频率状态的数据结构
  • cpufreq governor :cpu频率调控器
  • cpufreq_driver   :描述平台相关的cpufreq驱动的数据结构
  • frequency table   :频率表


cpufreq core

跟大多数Linux子系统一样,cpufreq core部分出要是抽象出平台无关的操作上述组件的接口。

cpufreq core 的代码在driver/cpufreq/cpufreq.c种。


cpufreq core定义了两条通知链,一条是处理cpu的工作频率切换到一个新的policy,另一条是用来处理当cpu频率切换后,受影响的设备的状态。

cpufreq core导出了相应的注册通知的API


cpufreq core定义了一个governor链表来保存多种频率策略。Linux内核本身也提供了多种频率调节策略,在配置内核时可选择。

在配置内核是可针对不同的需求选择不同的频率策略。就我个人的理解,在嵌入式的手持设备上,很多情况都没有使用内核提供的电源策略。governor部分,IBM Linux有一个系列文章描述的很详细。

减少
Linux 电耗,第 1 部分: CPUfreq 子系统

减少
Linux 耗电,第 2 部分: 一般设置和与调控器相关的设置

减少
Linux 耗电,第 3 部分: 调优结果

cpufreq core定义了静态全局结构体指针cpufreq_driver用于记录注册到cpufreq
core中的驱动:


并导出注册驱动符号用于注册平台相关驱动:

具体代码如下:

 

  1.   
  2.   
  3.   
  4. int cpufreq_register_driver(struct cpufreq_driver *driver_data)  
  5.  
  6.     unsigned long flags;  
  7.     int ret;  
  8.   
  9.     if (cpufreq_disabled())  
  10.         return -ENODEV;  
  11.   
  12.     if (!driver_data || !driver_data->verify || !driver_data->init ||  
  13.         ((!driver_data->setpolicy) && (!driver_data->target)))  
  14.         return -EINVAL;  
  15.   
  16.     pr_debug("trying to register driver %s\n"driver_data->name);  
  17.   
  18.     if (driver_data->setpolicy)  
  19.         driver_data->flags |= CPUFREQ_CONST_LOOPS;  
  20.   
  21.     spin_lock_irqsave(&cpufreq_driver_lock, flags);  
  22.     if (cpufreq_driver)  
  23.         spin_unlock_irqrestore(&cpufreq_driver_lock, flags);  
  24.         return -EBUSY;  
  25.      
  26.     cpufreq_driver driver_data;  
  27.     spin_unlock_irqrestore(&cpufreq_driver_lock, flags);  
  28.   
  29.     ret subsys_interface_register(&cpufreq_interface);  
  30.     if (ret)  
  31.         goto err_null_driver;  
  32.   
  33.     if (!(cpufreq_driver->flags CPUFREQ_STICKY))  
  34.         int i;  
  35.         ret -ENODEV;  
  36.   
  37.           
  38.         for (i 0; nr_cpu_ids; i++)  
  39.             if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i))  
  40.                 ret 0;  
  41.                 break 
  42.              
  43.   
  44.           
  45.         if (ret)  
  46.             pr_debug("no CPU initialized for driver %s\n" 
  47.                             driver_data->name);  
  48.             goto err_if_unreg;  
  49.          
  50.      
  51.   
  52.     register_hotcpu_notifier(&cpufreq_cpu_notifier);  
  53.     pr_debug("driver %s up and running\n"driver_data->name);  
  54.   
  55.     return 0;  
  56. err_if_unreg:  
  57.     subsys_interface_unregister(&cpufreq_interface);  
  58. err_null_driver:  
  59.     spin_lock_irqsave(&cpufreq_driver_lock, flags);  
  60.     cpufreq_driver NULL;  
  61.     spin_unlock_irqrestore(&cpufreq_driver_lock, flags);  
  62.     return ret;  
  63.  

整个注册过程的关键有三部分:

a)把平台相关的struct cpufreq_driver类指针driver_data赋值给全局指针cpufreq_driver

b)调用平台相关cpufreq_driver中的init成员函数

c)注册cpufreq_cpu_notifier


抱歉!评论已关闭.