1. 程式人生 > >[RK3399][Android7.1] 除錯筆記 --- DDR工作頻率的獲取和設定

[RK3399][Android7.1] 除錯筆記 --- DDR工作頻率的獲取和設定

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;
}