电源管理基本观念之二
来源:互联网 发布:芒果台网络直播 编辑:程序博客网 时间:2024/06/06 15:04
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的功耗主要由工作电压和刷新方式决定。
下面工作电压的一个参考:
TYPECore Voltage
(VDD)IO Voltage
(VIO)DDR2.5V2.5VLPDDR1.8V1.8V/1.2VDDR21.8V1.8VLPDDR21.2V1.2VDDR31.5V/1.35V1.5V/1.35VLPDDR31.2V1.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 :频率表
跟大多数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中的驱动:
并导出注册驱动符号用于注册平台相关驱动:
具体代码如下:
/********************************************************************* * REGISTER / UNREGISTER CPUFREQ DRIVER * *********************************************************************//** * cpufreq_register_driver - register a CPU Frequency driver * @driver_data: A struct cpufreq_driver containing the values# * submitted by the CPU Frequency driver. * * Registers a CPU Frequency driver to this core code. This code * returns zero on success, -EBUSY when another driver got here first * (and isn't unregistered in the meantime). * */int cpufreq_register_driver(struct cpufreq_driver *driver_data){unsigned long flags;int ret;if (cpufreq_disabled())return -ENODEV;if (!driver_data || !driver_data->verify || !driver_data->init || ((!driver_data->setpolicy) && (!driver_data->target)))return -EINVAL;pr_debug("trying to register driver %s\n", driver_data->name);if (driver_data->setpolicy)driver_data->flags |= CPUFREQ_CONST_LOOPS;spin_lock_irqsave(&cpufreq_driver_lock, flags);if (cpufreq_driver) {spin_unlock_irqrestore(&cpufreq_driver_lock, flags);return -EBUSY;}cpufreq_driver = driver_data;spin_unlock_irqrestore(&cpufreq_driver_lock, flags);ret = subsys_interface_register(&cpufreq_interface);if (ret)goto err_null_driver;if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {int i;ret = -ENODEV;/* check for at least one working CPU */for (i = 0; i < nr_cpu_ids; i++)if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) {ret = 0;break;}/* if all ->init() calls failed, unregister */if (ret) {pr_debug("no CPU initialized for driver %s\n",driver_data->name);goto err_if_unreg;}}register_hotcpu_notifier(&cpufreq_cpu_notifier);pr_debug("driver %s up and running\n", driver_data->name);return 0;err_if_unreg:subsys_interface_unregister(&cpufreq_interface);err_null_driver:spin_lock_irqsave(&cpufreq_driver_lock, flags);cpufreq_driver = NULL;spin_unlock_irqrestore(&cpufreq_driver_lock, flags);return ret;}
整个注册过程的关键有三部分:
a)把平台相关的struct cpufreq_driver类指针driver_data赋值给全局指针cpufreq_driver
b)调用平台相关cpufreq_driver中的init成员函数
c)注册cpufreq_cpu_notifier
- 电源管理基本观念之二
- 电源管理基本观念之二
- 电源管理基本观念之二
- 电源管理基本观念之一
- 电源管理基本观念之一
- 电源管理基本观念之一
- 电源管理基本观念之一
- 工作笔记之电源管理二
- Windows CE的电源管理之二
- Wince电源管理(二) ---- Windows CE设备驱动开发之电源管理
- 【转】Windows CE的电源管理之二
- wince电源管理(二)
- Android之PowerManager电源管理
- Android之PowerManager电源管理
- Android之PowerManager电源管理
- Android之PowerManager电源管理
- Android7.0 电源管理-updatePowerStateLocked 基本流程图
- C++内存管理变革 之 allocator引起的观念变化
- Makefile学习笔记
- 黑马程序员---多态
- C/C++二维数组的动态分配及参数传递
- javascript面向对象写法--极简主义法
- Storyboards are unavailable on iOS 4.3 and prior的解决方法
- 电源管理基本观念之二
- Flurry 数据信息统计
- java Date 小结
- hibernate注解
- goldengate --file to replicat 初始化oracle数据到mysql
- Android USB Host
- php操作mysql函数简介
- Log4j – 如何配置多个logger?
- linux下编程获得本机IP地址