[RK3288][Android6.0] DDR Frequency控制流程小结

Platform: RK3288
OS: Android 6.0
Kernel: 3.10.92

DVFS即Dynamic Voltage and Frequency Scaling.

有看到RK将DDR的控制也放在DVFS中,也就是说DDR会在系统运行时被根据不同的情况
做出不同的频率调整以降低系统功耗.DVFS驱动在dvfs.c中,这里不做描述,只要关注调用的接口即可.


相关文件:

ddr_rk32.c
ddr驱动,直接和硬件打交道.
rk3288.c
ddr控制接口.
ddr_freq.c
ddr和用户空间交互接口.
dvfs.c
dvfs驱动.
rk_system_status.c
system status控制接口.


dts:
&clk_ddr_dvfs_table {
    /*不同的频率需要对应不同的电压.*/
    operating-points = <
        /* KHz    uV */
        200000 1050000
        300000 1050000
        400000 1100000
        533000 1150000
        >;

    /*系统有两种控制方法:

    一种是根据当前的video 分辨率(这里称作系统状态)来决定ddr freq;

    还有一种就是下面的auto-freq-table,系统根据当前的loading来自动控制频率.

   前者会被优先判断,当系统状态不是前者任何一种时,再选择使用后者策略。

*/

    freq-table = <
        /*status        freq(KHz)*/
        SYS_STATUS_NORMAL    400000
        SYS_STATUS_SUSPEND    200000
        SYS_STATUS_VIDEO_1080P  240000
        SYS_STATUS_VIDEO_4K     400000
        SYS_STATUS_PERFORMANCE  528000
        SYS_STATUS_DUALVIEW    400000
        SYS_STATUS_BOOST    324000
        SYS_STATUS_ISP        400000
        >;
    auto-freq-table = <
        240000
        324000
        396000
        528000
        >;
    auto-freq=<1>;
    status="okay";
};


DVFS初始化:
解析rk3288.dtsi中的dvfs node.
rk3288_dt_init_timer ->     rk3288.c
    of_dvfs_init -> dvfs.c
        of_find_node_by_name    //找到dts中的dvfs node.
        for_each_available_child_of_node    //依次查找dvfs下的vd node, 有vd_arm, vd_logic, vd_gpu.
        of_property_read_string        //获取regulator_name
        vd->vd_dvfs_target = dvfs_target    //vd对应的vd_dvfs_target()函数是dvfs_target, 后面会大量用到.
        rk_regist_vd    //注册vd到rk_dvfs_tree list中
            for_each_available_child_of_node    //依次查找vd node下的pd node, 有pd_core, pd_ddr, pd_vio, pd_gpu.
            rk_regist_pd    //注册pd到vd->pd_list中.
                for_each_available_child_of_node    //依次查找pd下的clk node, 有clk_core, clk_ddr, clk_gpu, aclk_vio1.
                    dvfs_node_parse_dt    //解析clk node下的各个属性, 注意,主dts中(比如rk3288-tb_8846.dts)中也有一部分配置要一起解析.
                    rk_regist_clk    //注册clk node到pd->clk_list中.

ddr frequnecy的初始化:
ddrfreq_init ->    ddr_freq.c
    clk_get_dvfs_node    //获取名字是clk_core的node,dvfs.c中获取的和这个是两个变量,不是全局的。
    clk_get_dvfs_node    //获取名字为clk_ddr的node.
    clk_enable_dvfs   -> //enable ddr dvfs,  clk gpu/core也会在各自驱动中相应被enable.
        dvfs_regulator_get    //获取对应的regulator,失败的话会enable failed.之所以把这句拿出来强调是因为项目有遇到过vd_gpu没有被开起来导致整个kernel都起不来的问题,后来发现是dts配置不对.
    dvfs_clk_register_set_rate_callback    //callback是ddrfreq_scale_rate_for_dvfs,后面看到set ddr rate是会被调用.
    ddr.normal_rate = dvfs_clk_get_rate    //系统根据不同的模式有不同ddr rate,比如video 4k rate, video 1080 rate等,这里获取ddr normal类型的rate.
    rockchip_get_system_status    //通过不同的system status来得知当前不同的mode, mode是指当前在待机状态,播放1080p video,4k video等.
    of_init_ddr_freq_table    //从dts的clk_ddr_dvfs_table node中获取"auto-freq", "auto-freq-table", "freq-table"这些配置信息,后面调整ddr rate会用上.
    input_register_handler    //注册一个ddr_freq_input_handler,只要匹配ddr_freq_ids变量中的flag,input事件就会调用ddr_freq_input_event(). 开机后有input事件就在boost_rate(of_init_ddr_freq_table()中赋值)和new rate取一个最大值(ddr_auto_freq()中比较),不太理解为什么input影响ddr rate选择?
    misc_register(&video_state_dev);    //注册一个video 字符设备,播放视频的时候通过它来改变ddr freq.
    misc_register(&ddr_freq_dev);    //注册一个ddr freq的字符设备,目前看到display有使用它来改变ddr freq.
    kthread_create    //创建名为ddrfreqd的thread,处理函数是ddrfreq_task,它会根据不同running status来调用设置ddr freq接口.
    rockchip_register_system_status_notifier        //设置system status时会调用此callback:ddrfreq_system_status_notifier_call,然后它会唤醒上面提到的thread ddrfreqd.
    fb_register_client        //callback是ddr_freq_suspend_notifier_call, display suspend/wakeup的时候也会调用它,进而唤醒ddrfreqd thread去设置ddr freq.

设置频率:
ddr freq字符设备例子:
ddr_freq_ioctl ->
    wake_up(&ddr.wait) ->
        ddrfreq_task ->
            ddrfreq_work ->
                ddrfreq_mode ->
                    dvfs_clk_set_rate ->    dvfs.c
                        clk_dvfs_node->vd->vd_dvfs_target ->
                            dvfs_target ->    //of_dvfs_init()初始化时赋值
                                clk_dvfs_node->clk_dvfs_target    ->    
                                    ddrfreq_scale_rate_for_dvfs ->    ddrfreq_init()初始化中设置
                                        ddr_change_freq  ->
                                            _ddr_change_freq ->     rk3288.c //rk3288_ddr_init()中初始化
                                                __ddr_change_freq ->
                                                    call_with_single_cpu ->
                                                        ddr_change_freq_sram

video state字符设备控制例子(1080p):
video_state_write ->
    update_video_info ->    
        rockchip_set_system_status ->    //status是SYS_STATUS_VIDEO_1080P
            rockchip_system_status_notifier_call_chain ->    
                ddrfreq_system_status_notifier_call ->
                    wake_up(&ddr.wait) ->
                        ddrfreq_task ->
                            ddrfreq_work ->
                                ddrfreq_mode //同上

另外,display的休眠和唤醒也会引起ddr freq的改变.

不过不管哪种方式,最终都是调用thread ddrfreqd来实现ddr freq的改变.


你可能感兴趣的:(子类__DDR_DVFS)