高通平台GPU动态调频DCVS . 篇2 . Framework Procedure
系列文章
高通平台GPU动态调频DCVS . 篇1 . Interface
高通平台GPU动态调频DCVS . 篇2 . Framework & Procedure
高通平台GPU动态调频DCVS . 篇3 . 一个无法调频问题的解决过程
1. 高通平台 GPU DCVS架构
GPU DCVS是基于Linux Devfreq来实现
- 高通的kgsl(kernel-graphics-support-layer)作为devfreq device
- msm-adreno-tz 作为devfreq governor
简单的架构如下
如上图所示
- 首先 KGSL 作为device,msm-adreno-tz 作为governor注册到devfreq core
- KGSL driver通过notify机制去调用 governor msm-adreno-tz 的tz_notify() 函数
- tz_notify() 调用 devfreq core的 update_devfreq()
- update_devfreq() 调用governor的 get_target_freq()来计算处理目标频率
- update_devfreq() 调用KGSL的target回调来传递目标频率,并实施调频
2. Adreno 部分
Anreno作为平台相关的GPU驱动,提供了读取和操作GPU硬件的interface
2.1 频率解析
- 频率表
频率表位于dtsarch/arm64/boot/dts/qcom/sm8150-v2.dtsi
qcom,gpu-pwrlevels {#address-cells = <1>;#size-cells = <0>;compatible = "qcom,gpu-pwrlevels";qcom,gpu-pwrlevel@0 {reg = <0>;qcom,gpu-freq = <810000000>;qcom,bus-freq = <11>;qcom,bus-min = <11>;qcom,bus-max = <11>;};qcom,gpu-pwrlevel@1 {reg = <1>;qcom,gpu-freq = <585000000>;qcom,bus-freq = <11>;qcom,bus-min = <11>;qcom,bus-max = <11>;};qcom,gpu-pwrlevel@2 {reg = <2>;qcom,gpu-freq = <499200000>;qcom,bus-freq = <9>;qcom,bus-min = <8>;qcom,bus-max = <11>;};qcom,gpu-pwrlevel@3 {reg = <3>;qcom,gpu-freq = <427000000>;qcom,bus-freq = <6>;qcom,bus-min = <5>;qcom,bus-max = <7>;};qcom,gpu-pwrlevel@4 {reg = <4>;qcom,gpu-freq = <345000000>;qcom,bus-freq = <3>;qcom,bus-min = <3>;qcom,bus-max = <5>;};qcom,gpu-pwrlevel@5 {reg = <5>;qcom,gpu-freq = <257000000>;qcom,bus-freq = <3>;qcom,bus-min = <2>;qcom,bus-max = <4>;};qcom,gpu-pwrlevel@6 {reg = <6>;qcom,gpu-freq = <0>;qcom,bus-freq = <0>;qcom,bus-min = <0>;qcom,bus-max = <0>;};/delete-node/ qcom,gpu-pwrlevel@7;};
- 驱动解析
drivers/gpu/msm/adreno.c
adreno 驱动对应的设备名为qcom,kgsl-3d0
static const struct of_device_id adreno_match_table[] = {{ .compatible = "qcom,kgsl-3d0", .data = &device_3d0 },{}
};
adreno_probe()-> adreno_of_get_power()-> adreno_of_get_pwrlevels()-> adreno_of_parse_pwrlevels()
结果保存在 adreno_device
->kgsl_device
->kgsl_pwrctrl
结构体的kgsl_pwrlevel
结构体类型的的数组中,pwrlevel作为这个数组的index
/*** struct kgsl_pwrlevel - Struct holding different pwrlevel info obtained from* from dtsi file* @gpu_freq: GPU frequency vote in Hz* @bus_freq: Bus bandwidth vote index* @bus_min: Min bus index @gpu_freq* @bus_max: Max bus index @gpu_freq*/
struct kgsl_pwrlevel {unsigned int gpu_freq;unsigned int bus_freq;unsigned int bus_min;unsigned int bus_max;
};
3. kgsl 部分
kgsl是抽象层,代码位于drivers/gpu/msm
3.1 注册devfreq device
kgsl是作为Devfreq的device存在, 在kgsl_pwrscale_init()
函数,就会去注册kgsl device到devfreq framework
devfreq = devfreq_add_device(dev, &pwrscale->gpu_profile.profile,governor, pwrscale->gpu_profile.private_data);
3.2 Notify 定义和注册、通知方法
在DCVS架构中,GPU调频实际上是由adreno-kgsl发起,进而通知msm-adreno-tz governor
- 定义notify head
在kgsl_pwrscale_init()
中
srcu_init_notifier_head(&pwrscale->nh);
- 提供notify register方法
提供kgsl_devfreq_add_notifier()
方法,供governor使用
/** kgsl_devfreq_add_notifier - add a fine grained notifier.* @dev: The device* @nb: Notifier block that will recieve updates.** Add a notifier to recieve ADRENO_DEVFREQ_NOTIFY_* events* from the device.*/
int kgsl_devfreq_add_notifier(struct device *dev,struct notifier_block *nb)
{struct kgsl_device *device = dev_get_drvdata(dev);if (device == NULL)return -ENODEV;if (nb == NULL)return -EINVAL;return srcu_notifier_chain_register(&device->pwrscale.nh, nb);
}
EXPORT_SYMBOL(kgsl_devfreq_add_notifier);
- 提供notify call chain 方法
触发governor notify 处理函数tz_notify()工作
static void do_devfreq_notify(struct work_struct *work)
{struct kgsl_pwrscale *pwrscale = container_of(work,struct kgsl_pwrscale, devfreq_notify_ws);struct devfreq *devfreq = pwrscale->devfreqptr;srcu_notifier_call_chain(&pwrscale->nh,ADRENO_DEVFREQ_NOTIFY_RETIRE,devfreq);
}
3.3 提供调频回调方法
Devfreq 框架需要device端提供target() 回调, 获取并处理来自devfreq的目标频率
#define KGSL_PWRSCALE_INIT(_priv_data) { \.enabled = true, \.gpu_profile = { \.private_data = _priv_data, \.profile = { \.target = kgsl_devfreq_target, \.get_dev_status = kgsl_devfreq_get_dev_status, \.get_cur_freq = kgsl_devfreq_get_cur_freq, \} }, \
/** kgsl_devfreq_target - devfreq_dev_profile.target callback* @dev: see devfreq.h* @freq: see devfreq.h* @flags: see devfreq.h** This function expects the device mutex to be unlocked.*/
int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags)
{struct kgsl_device *device = dev_get_drvdata(dev);struct kgsl_pwrctrl *pwr;struct kgsl_pwrlevel *pwr_level;int level;unsigned int i;unsigned long cur_freq;if (device == NULL)return -ENODEV;if (freq == NULL)return -EINVAL;if (!device->pwrscale.enabled)return 0;pwr = &device->pwrctrl;if (_check_maxfreq(flags)) {/** The GPU is about to get suspended,* but it needs to be at the max power level when waking up*/pwr->wakeup_maxpwrlevel = 1;return 0;}mutex_lock(&device->mutex);cur_freq = kgsl_pwrctrl_active_freq(pwr);level = pwr->active_pwrlevel;pwr_level = &pwr->pwrlevels[level];/* If the governor recommends a new frequency, update it here */if (*freq != cur_freq) {level = pwr->max_pwrlevel;/** Array index of pwrlevels[] should be within the permitted* power levels, i.e., from max_pwrlevel to min_pwrlevel.*/for (i = pwr->min_pwrlevel; (i >= pwr->max_pwrlevel&& i <= pwr->min_pwrlevel); i--)if (*freq <= pwr->pwrlevels[i].gpu_freq) {if (pwr->thermal_cycle == CYCLE_ACTIVE)level = _thermal_adjust(pwr, i);elselevel = popp_trans2(device, i);break;}if (level != pwr->active_pwrlevel)kgsl_pwrctrl_pwrlevel_change(device, level);} else if (popp_stable(device)) {popp_trans1(device);}*freq = kgsl_pwrctrl_active_freq(pwr);mutex_unlock(&device->mutex);return 0;
}
EXPORT_SYMBOL(kgsl_devfreq_target);
4. msm-adreno-tz 部分
代码位于drivers/devfreq/governor_msm_adreno_tz.c
4.1 注册devfreq governor
static int __init msm_adreno_tz_init(void)
{workqueue = create_freezable_workqueue("governor_msm_adreno_tz_wq");if (workqueue == NULL)return -ENOMEM;return devfreq_add_governor(&msm_adreno_tz);
}
4.2 实现notify callback function
实现notify callback function tz_notify()
static int tz_notify(struct notifier_block *nb, unsigned long type, void *devp)
{int result = 0;struct devfreq *devfreq = devp;switch (type) {case ADRENO_DEVFREQ_NOTIFY_IDLE:case ADRENO_DEVFREQ_NOTIFY_RETIRE:mutex_lock(&devfreq->lock);result = update_devfreq(devfreq);mutex_unlock(&devfreq->lock);/* Nofifying partner bus governor if any */if (partner_gpu_profile && partner_gpu_profile->bus_devfreq) {mutex_lock(&partner_gpu_profile->bus_devfreq->lock);update_devfreq(partner_gpu_profile->bus_devfreq);mutex_unlock(&partner_gpu_profile->bus_devfreq->lock);}break;/* ignored by this governor */case ADRENO_DEVFREQ_NOTIFY_SUBMIT:default:break;}return notifier_from_errno(result);
}
tz_notify()
会调用到 update_devfreq()
update_devfreq()
是devfreq core提供通用调频方法, governor通过update_devfreq() 来实现对频率的处理运算以及调用device的target() 回调传递频率到device端.
- 频率处理运算
/* Reevaluate the proper frequency */err = devfreq->governor->get_target_freq(devfreq, &freq, &flags);
- 通过target回调传递目标频率到device
err = devfreq->profile->target(devfreq->dev.parent, &freq, flags);
5. DEVFREQ Framework
Devfreq是该机制的核心框架,所以需要了解,可以参考下文
Linux DEVFREQ - 通用DVFS Framework
6. 流程简述
调频实际上是由Adreno发起,governor是为了满足devfreq标准框架而存在,流程图如下,从上到下的执行顺序
核心的DCVS决策算法位于TrustZone
adreno_dispatcher_work->kgsl_pwrscale_update->queue_work(devfreq_notify_ws)->do_devfreq_notify(ADRENO_DEVFREQ_NOTIFY_RETIRE)->tz_notify()->update_devfreq(devfreq)->profile->get_dev_status()->profile.target()
最后: 代码来源
Linux 内核部分分析用的代码来源于内核开源代码,这里是以最新的SM8150作为例子
手机厂商内核开源代码
高通平台GPU动态调频DCVS . 篇2 . Framework Procedure相关推荐
- 高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)
本系列导航: 高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) 高通平台8953 Linux DTS(Device Tree Source ...
- 高通平台android开发总结
http://www.cnblogs.com/yuzaipiaofei/archive/2012/07/24/4124179.html 1.高通平台android开发总结 1.1 搭建高通平台环境开发 ...
- 高通平台android 环境配置编译及开发经验总结
完全转自:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通 ...
- 高通平台android开发总结 .
http://blog.csdn.net/mirkerson/article/details/7691029 http://blog.csdn.net/mirkerson/article/detail ...
- 高通平台android 环境配置编译及开发经验总结【转】
1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通开发板上烧录文件系统 建立高通平台开发环境 高通平台,android和 modem 编译流程分析 高通平台 7620 启动流 ...
- 高通android开源代码下载,高通平台Android源码bootloader分析之sbl1(三)
前两篇博文分析了启动流程.代码流程.cdt,接下来就分析另外几个需要格外关注的部分. ##log系统 sbl1中的log系统也是sbl1部分调试会经常接触得部分高通平台在sbl中做的log系统并不是很 ...
- android 系统gpu 调试_基于Android系统的GPU动态调频方案 | Imagination中文技术社区
针对移动终端上GPU的高功耗问题,提出一种基于Android系统的GPU动态调频方案.方案根据各种应用对GPU的性能需求,引入了GPU的频率一性能模型,包括选择工作频率和测量相对性能的方法.动态调频算 ...
- 高通平台sensor学习
刚入行驱动时最先接触调试的外设模块便是sensor,一直都是零零散散的记录,这次终于下定决心对自己所学做一个系统的总结. sensor作为一款常用的外设,虽不起眼但是很多功能确实离不开它.比如我们手机 ...
- 高通芯片GPU是否有类似于HSR功能
1)高通芯片GPU是否有类似于HSR的功能 2)UGUI上的RT动图会不会导致UI更新 3)UI经常迭代外观,如何尽量少改代码 4)开发过程中该使用AssetBundle包模式,还是模拟模式? 这是 ...
最新文章
- 用Quartus II Timequest Timing Analyzer进行时序分析 :实例讲解 (一)
- pandas pivot 计算占比_数据分析Pandas 基础(二)
- Be the Winner(结论:反nim博弈)
- 对多个WCF服务进行统一的连接测试
- Vlookup函数多返回值处理
- Java千百问_05面向对象(013)_泛型如何使用
- 使用Log Parase 结合 Log Parase Studio 查询IIS日志
- 状态机finite-state machine学习笔记1
- 如何在Excel 2007中创建数据透视表
- Python时钟代码——利用python turtle实现模拟时钟
- Vue实现 TodoList
- webdriver中的截图截图方法
- python父亲节快乐_打算送亲戚家孩子新年礼物,有哪些礼物孩子喜欢且有意义?...
- poi操作word实现分页
- SeedLab10: Linux Firewall Exploration Lab
- Word中㎡的上标²变成了2该如何处理
- 招收2名远程学术实习生!1名硕士(2022春) 美国肯特州立大学认知机器人和人工智能实验室...
- linux mint能用安卓,如何在Ubuntu和Linux Mint上安装Android Studio
- java实现qq聊天室功能
- 高新技术企业的优惠政策