OS: Android 7.1
Board: Firefly-RK3399
Kernel: v4.4.55
之前有提到loader中有设置ddr频率为800MHz,当kernel中开启了ddr devfreq之后,驱动加载时会获取ddr默认频率。
rockchip_dmc.c:
static int rockchip_dmcfreq_probe(struct platform_device *pdev)
{
//根据name获取对应的struct clk结构
data->dmc_clk = devm_clk_get(dev, "dmc_clk");
......
//获取clk的当前rate
data->rate = clk_get_rate(data->dmc_clk);
......
}
一开始有个误区,以为就是PCLK_DDR对应的默认rate,此rate在rk3399-vop-clk-set.dtsi中的cru node中定义,配置为200MHz,而开机打印的log是800MHz。后来找到了对应的clockc, id是SCLK_DDRCLK。
关于SCLK_DDRCLK的定义,在clk-rk3399.c中:
static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
......
COMPOSITE_DDRCLK(SCLK_DDRCLK, "sclk_ddrc", mux_ddrclk_p, 0,
RK3399_CLKSEL_CON(6), 4, 2, 0, 0, ROCKCHIP_DDRCLK_SIP),
};
它的注册过程有:
rockchip_clk_register_branches ->
rockchip_clk_register_ddrclk -> //branch_type:branch_ddrc
init.ops = &rockchip_ddrclk_sip_ops; //ddr_flag: ROCKCHIP_DDRCLK_SIP
clk_register //注册struct clk
其中的ops:
static const struct clk_ops rockchip_ddrclk_sip_ops = {
.recalc_rate = rockchip_ddrclk_sip_recalc_rate,
.set_rate = rockchip_ddrclk_sip_set_rate,
.round_rate = rockchip_ddrclk_sip_round_rate,
.get_parent = rockchip_ddrclk_get_parent,
};
这里就有recalc_rate函数指针,系统开机后devfreq monitor thread会调用此函数来获取当前ddr实际频率
static unsigned long
rockchip_ddrclk_sip_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct arm_smccc_res res;
arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE,
0, 0, 0, 0, &res);
return res.a0;
}
res.a0的值就是当前实际从寄存器读出来的ddr rate, 为800MHz.
而ddr频率的设置是通过set_rate回调接口来实现
static int rockchip_ddrclk_sip_set_rate(struct clk_hw *hw, unsigned long drate,
unsigned long prate)
{
struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
unsigned long flags;
struct arm_smccc_res res;
spin_lock_irqsave(ddrclk->lock, flags);
arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, drate, 0,
ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE,
0, 0, 0, 0, &res);
spin_unlock_irqrestore(ddrclk->lock, flags);
return res.a0;
}
原作者:KrisFei