系列文章
高通平台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 频率解析

  • 频率表
    频率表位于dts arch/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相关推荐

  1. 高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)

    本系列导航: 高通平台8953  Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) 高通平台8953 Linux DTS(Device Tree Source ...

  2. 高通平台android开发总结

    http://www.cnblogs.com/yuzaipiaofei/archive/2012/07/24/4124179.html 1.高通平台android开发总结 1.1 搭建高通平台环境开发 ...

  3. 高通平台android 环境配置编译及开发经验总结

    完全转自:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通 ...

  4. 高通平台android开发总结 .

    http://blog.csdn.net/mirkerson/article/details/7691029 http://blog.csdn.net/mirkerson/article/detail ...

  5. 高通平台android 环境配置编译及开发经验总结【转】

    1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通开发板上烧录文件系统 建立高通平台开发环境 高通平台,android和 modem 编译流程分析 高通平台 7620 启动流 ...

  6. 高通android开源代码下载,高通平台Android源码bootloader分析之sbl1(三)

    前两篇博文分析了启动流程.代码流程.cdt,接下来就分析另外几个需要格外关注的部分. ##log系统 sbl1中的log系统也是sbl1部分调试会经常接触得部分高通平台在sbl中做的log系统并不是很 ...

  7. android 系统gpu 调试_基于Android系统的GPU动态调频方案 | Imagination中文技术社区

    针对移动终端上GPU的高功耗问题,提出一种基于Android系统的GPU动态调频方案.方案根据各种应用对GPU的性能需求,引入了GPU的频率一性能模型,包括选择工作频率和测量相对性能的方法.动态调频算 ...

  8. 高通平台sensor学习

    刚入行驱动时最先接触调试的外设模块便是sensor,一直都是零零散散的记录,这次终于下定决心对自己所学做一个系统的总结. sensor作为一款常用的外设,虽不起眼但是很多功能确实离不开它.比如我们手机 ...

  9. 高通芯片GPU是否有类似于HSR功能

    1)高通芯片GPU是否有类似于HSR的功能 ​2)UGUI上的RT动图会不会导致UI更新 3)UI经常迭代外观,如何尽量少改代码 4)开发过程中该使用AssetBundle包模式,还是模拟模式? 这是 ...

最新文章

  1. 用Quartus II Timequest Timing Analyzer进行时序分析 :实例讲解 (一)
  2. pandas pivot 计算占比_数据分析Pandas 基础(二)
  3. Be the Winner(结论:反nim博弈)
  4. 对多个WCF服务进行统一的连接测试
  5. Vlookup函数多返回值处理
  6. Java千百问_05面向对象(013)_泛型如何使用
  7. 使用Log Parase 结合 Log Parase Studio 查询IIS日志
  8. 状态机finite-state machine学习笔记1
  9. 如何在Excel 2007中创建数据透视表
  10. Python时钟代码——利用python turtle实现模拟时钟
  11. Vue实现 TodoList
  12. webdriver中的截图截图方法
  13. python父亲节快乐_打算送亲戚家孩子新年礼物,有哪些礼物孩子喜欢且有意义?...
  14. poi操作word实现分页
  15. SeedLab10: Linux Firewall Exploration Lab
  16. Word中㎡的上标²变成了2该如何处理
  17. 招收2名远程学术实习生!1名硕士(2022春) 美国肯特州立大学认知机器人和人工智能实验室...
  18. linux mint能用安卓,如何在Ubuntu和Linux Mint上安装Android Studio
  19. java实现qq聊天室功能
  20. 高新技术企业的优惠政策

热门文章

  1. JavaScript charCodeAt() 方法
  2. 全球治理指标WGI(1996-2018年)
  3. 阿里四面总结-200215
  4. linux下make用法
  5. 物联网开发笔记(96)- Micropython ESP32开发之SPI接口控制Micro SD卡TF卡模块挂载内存卡
  6. 夜神模拟器运行flutter花屏,线条问题
  7. CS1.5 登录器From alanTeamV.2022
  8. java输出x的值或无解,你所不知道的Java之Integer
  9. 视频播放如何横竖屏切换
  10. vue项目中onscroll的坑