[RK3399][Android7.1] DDR动态频率调节驱动小结

时间:2020-12-02 08:52:05

OS: Android 7.1
Board: Firefly-RK3399
Kernel: v4.4.55

devfreq介绍:

rk3288平台上, gpu和ddr有自己的一套dvfs机制,而在rk3399平台,使用了系统的devfreq框架。

devfreq 是内核开发者定义的一套支持动态调整设备频率和电压的的框架模型。它能有效的降
低该设备的功耗,同时兼顾其性能。
devfreq 通过不同的变频策略,选择一个合适的频率供设备使用,目前的内核版本提供了以下
几种策略:

  • Simple Ondemand :根据负载动态调频调压;
  • Userspace:用户自己设置电压和频率,系统不会自动调整;
  • Powersave:功耗优先,始终将频率设置在最低值;
  • Performance:性能优先,始终将频率设置为最高值。

devfreq和cpufreq的功能类似,只是前者用来控制cpu,后者用于控制device的clock.

[RK3399][Android7.1] DDR动态频率调节驱动小结


dts配置:
dmc, dynamic memory controller

    dmc: dmc {
compatible = "rockchip,rk3399-dmc";
devfreq-events = <&dfi>;
interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru SCLK_DDRCLK>;
clock-names = "dmc_clk";
ddr_timing = <&ddr_timing>;
status = "disabled";
};

dfi,全称不晓得,用于监控dmc的loading模块

    dfi: dfi@ff630000 {
reg = <0x00 0xff630000 0x00 0x4000>;
compatible = "rockchip,rk3399-dfi";
rockchip,pmu = <&pmugrf>;
clocks = <&cru PCLK_DDR_MON>;
clock-names = "pclk_ddr_mon";
status = "disabled";
};

ddr timing:

ddr_timing: ddr_timing {
compatible = "rockchip,ddr-timing";
ddr3_speed_bin = <21>;
pd_idle = <0>;
sr_idle = <0>;
sr_mc_gate_idle = <0>;
srpd_lite_idle = <0>;
standby_idle = <0>;
dram_dll_dis_freq = <300>;
phy_dll_dis_freq = <125>;

ddr3_odt_dis_freq = <333>;
ddr3_drv = <DDR3_DS_40ohm>;
ddr3_odt = <DDR3_ODT_120ohm>;
phy_ddr3_ca_drv = <PHY_DRV_ODT_40>;
phy_ddr3_dq_drv = <PHY_DRV_ODT_40>;
phy_ddr3_odt = <PHY_DRV_ODT_240>;

lpddr3_odt_dis_freq = <333>;
lpddr3_drv = <LP3_DS_34ohm>;
lpddr3_odt = <LP3_ODT_240ohm>;
phy_lpddr3_ca_drv = <PHY_DRV_ODT_40>;
phy_lpddr3_dq_drv = <PHY_DRV_ODT_40>;
phy_lpddr3_odt = <PHY_DRV_ODT_240>;

lpddr4_odt_dis_freq = <333>;
lpddr4_drv = <LP4_PDDS_60ohm>;
lpddr4_dq_odt = <LP4_DQ_ODT_40ohm>;
lpddr4_ca_odt = <LP4_CA_ODT_40ohm>;
phy_lpddr4_ca_drv = <PHY_DRV_ODT_40>;
phy_lpddr4_ck_cs_drv = <PHY_DRV_ODT_80>;
phy_lpddr4_dq_drv = <PHY_DRV_ODT_80>;
phy_lpddr4_odt = <PHY_DRV_ODT_60>;
};

freq table:

    dmc_opp_table: opp-table3 {
compatible = "operating-points-v2";

opp@200000000 {
opp-hz = /bits/ 64 <200000000>;
opp-microvolt = <825000>;
};
opp@297000000 {
opp-hz = /bits/ 64 <297000000>;
opp-microvolt = <850000>;
};
opp@400000000 {
opp-hz = /bits/ 64 <400000000>;
opp-microvolt = <850000>;
};
opp@594000000 {
opp-hz = /bits/ 64 <594000000>;
opp-microvolt = <900000>;
};
opp@800000000 {
opp-hz = /bits/ 64 <800000000>;
opp-microvolt = <900000>;
};
};

功能开启参见:
[RK3399][Android7.1] 调试笔记 — DDR动态调节功能开启


驱动文件:
目录:
kernel/drivers/devfreq
文件:
governor_simpleondemand.c: 策略控制
devfreq.c: devfreq framework
devfreq-event.c:  event驱动,结合dfi
rockchip_dmc.c: rk dmc驱动
rockchip-dfi.c: rk dfi驱动


驱动流程:

  • dmc注册:
rockchip_dmcfreq_probe -> rockchip_dmc.c
devm_regulator_get(dev, "center");  //需要在dts中配置center-supply 属性
devfreq_event_get_edev_by_phandle //获取dfi device
devfreq_event_enable_edev //使能dfi监测
of_get_ddr_timings //获取ddr timing
rockchip_dmcfreq_init_freq_table //读取scaling table表
clk_get_rate(data->dmc_clk); //获取要设置的默认ddr频率
devm_devfreq_add_device //添加到devfreq框架中,默认策略是 "simple_ondemand"。

核心在于profile结构:

static struct devfreq_dev_profile rockchip_devfreq_dmc_profile = {
.polling_ms = 200, //loading查询周期
.target = rockchip_dmcfreq_target,//设置电压和频率
.get_dev_status = rockchip_dmcfreq_get_dev_status, //获取loading
.get_cur_freq = rockchip_dmcfreq_get_cur_freq, //获取当前频率
};
  • dfi注册:
rockchip_dfi_probe -> rockchip-dfi.c
devm_devfreq_event_add_edev //作为一个event device添加到devfreq框架中

核心在于event ops:

static const struct devfreq_event_ops rockchip_dfi_ops = {
.disable = rockchip_dfi_disable,
.enable = rockchip_dfi_enable,
.get_event = rockchip_dfi_get_event,
.set_event = rockchip_dfi_set_event,
};
  • loading获取及频率设置:

系统会在polling_ms个周期也就是200ms读取一次loading,然后决定是否需要调整电压和频率。

devfreq_simple_ondemand_handler -> governor_simpleondemand.c
devfreq_monitor_start -> devfreq.c
queue_delayed_work ->
devfreq_monitor ->
update_devfreq ->
devfreq->governor->get_target_freq ->
devfreq_simple_ondemand_func -> governor_simpleondemand.c
devfreq_update_stats ->
df->profile->get_dev_status ->
rockchip_dmcfreq_get_dev_status -> rockchip_dmc.c
devfreq_event_get_event -> devfreq-event.c
edev->desc->ops->get_event ->
rockchip_dfi_get_event ->
rockchip_dfi_get_busier_ch //获取dmc每个channel的busy情况,也就是loading
devfreq->profile->get_cur_freq -> //获取当前频率
rockchip_dmcfreq_get_cur_freq rockchip_dmc.c
devfreq->profile->target ->  //设置频率和电压
  rockchip_dmcfreq_target -> rockchip_dmc.c