一、参考资料
- PLL硬件设计:《Rockchip RV1109&RV1126TRM V1.0 Part1》中的【Fig. 5-3 PLL Block Diagram】。
- PLL相关描述:《Rockchip Clock 开发指南》中的【2.2.1 PLL】,注意,该文档的表示和RV1126略有差异,仅作基本参考。
- Linux中的时钟配置:《Rockchip 时钟配置详细说明》,注意,目前的SDK下,该文档版本为1.0,是RK3399参考文档,仅作基本参考。
二、问题起因
隔壁老哥想要将RV1126的dclk_vop
修改为65MHz
,以适配1024x768@60Hz
的分辨率。但在使用命令echo 65000000 > /sys/kernel/debug/clk/dclk_vop/clk_rate
设置的时候,得到的频率是:62526316
。但是如果设置54MHz(1024x768@50)
或者74.25MHz(1920x1080@60)
都可以正常配置。
因此我们有如下假设:
- 驱动是正常的,包括
clk_change_rate()
和clk_round_rate()
; - 芯片中从PLL到dclk_vop的时钟频率无法分配
65MHz
。
三、验证问题
我们使用cat /sys/kernel/debug/clk/clk_summary
来查看当前的时钟树(这里只显示了一部分):
enable prepare protect duty
clock count count count rate accuracy phase cycle
---------------------------------------------------------------------------------------------
pll_hpll 1 1 0 1400000000 0 0 50000
hpll 1 2 0 1400000000 0 0 50000
clk_npu_np5 0 0 0 186666667 0 0 50000
clk_npu_div 0 1 0 700000000 0 0 50000
clk_core_npu 0 2 0 700000000 0 0 50000
clk_core_npupvtm 0 0 0 700000000 0 0 50000
pll_gpll 1 1 0 1188000000 0 0 50000
gpll 14 36 0 1188000000 0 0 50000
dclk_vop_div 1 1 0 62526316 0 0 50000
dclk_vop_mux 1 1 0 62526316 0 0 50000
dclk_vop 1 3 0 62526316 0 0 50000
dclk_vop_fracdiv 0 0 0 62526316 0 0 50000
我们可以看到,dclk_vop
使用的时钟源来自gpll
,其时钟是1188000000
。如果按照54MHz
分频,其分频倍数为22;如果按照74.25MHz
分配,其分频倍数为16;如果按照65MHz
分频,其分频倍数为18.27,因为PLL out后的分频器只能按照整数倍分频,因此将其调整为19,得到62526315
,和cat
出来的数据差1Hz
,属于误差范围。
四、解决问题
4.1 修改vop的时钟源
我们翻阅dtsi
和文档2可以发现,RV1126有以下几个PLL:
- APLL,CPU的时钟:一般只给CPU使用,因为CPU会变频,APLL会根据CPU要求的频率变化。
- DPLL,DDR的时钟:一般只给DDR使用,因为DDR会变频,DPLL会根据DDR要求的频率变化。
- GPLL,提供总线、外设时钟做备份:一般设置在594M或者1200M,保证基本的100、200、300、400M的时钟都有输出。
- CPLL,GMAC或者其他设备做备份:一般可能是400、500、800、1000M,或者是给Lcdc独占使用。
- NPLL(HPLL),给其他设备做备份:一般可能是1188M,或者给Lcdc独占使用。
因此,我们从时钟树中发现hpll
的设备最少,我们将dclk_vop_div
迁移至hpll
之后倍频更容易更改。
进一步的,如果我们不想要修改dclk_vop_div
的时钟源,那么就需要保证当前时钟源gpll
可以分频出65MHz
、同时兼容1188000000
。我们计算发现,我们需要PLL
出77.22GHz
才能满足要求。我们通过文档1中的PLL架构可以计算出,其最大频率支持到38.4GHz
,因此无法实现兼容。于是我们选择将dclk_vop_div
的时钟源替换为hpll
,计算发现,只需要将其时钟提升到18.2GHz
即可满足兼容65MHz
和700MHz
的需求。但在设备树中,其使用32bits的数据来存放时钟,因此最高上限只有4GHz
多一些,因此我将其修改为1.82GHz
,以避免PLL之后后分频器不够做到更高比例的分频。
我们在rv1126.dtsi
中做如下修改:
cru: clock-controller@ff490000 {
compatible = "rockchip,rv1126-cru";
reg = <0xff490000 0x1000>;
rockchip,grf = <&grf>;
#clock-cells = <1>;
#reset-cells = <1>;
assigned-clocks =
<&pmucru CLK_RTC32K>, <&pmucru PLL_GPLL>,
<&pmucru PCLK_PDPMU>, <&cru PLL_CPLL>,
<&cru PLL_HPLL>, <&cru ARMCLK>,
<&cru ACLK_PDBUS>, <&cru HCLK_PDBUS>,
<&cru PCLK_PDBUS>, <&cru ACLK_PDPHP>,
<&cru HCLK_PDPHP>, <&cru HCLK_PDAUDIO>,
<&cru HCLK_PDCORE_NIU>;
assigned-clock-rates =
<32768>, <1188000000>,
<100000000>, <500000000>,
// <1400000000>, <600000000>,
<1820000000>, <600000000>,
<500000000>, <200000000>,
<100000000>, <300000000>,
<200000000>, <150000000>,
<200000000>;
assigned-clock-parents =
<&pmucru CLK_OSC0_DIV32K>;
};
4.2 修改dclk_vop_div的时钟源
经过我们在4.1中的分析,现在我们需要将dclk_vop_div
的PLL修改为hpll
。我们修改的文件是kernel/driver/clk/rockchip/clk-rv1126.c
,首先添加仅有hpll
的定义:
#ifndef CONFIG_ROCKCHIP_LOW_PERFORMANCE
PNAME(mux_gpll_usb480m_cpll_xin24m_p) = { "gpll", "usb480m", "cpll", "xin24m" };
PNAME(mux_armclk_p) = { "gpll", "cpll", "apll" };
PNAME(mux_gpll_cpll_dpll_p) = { "gpll", "cpll", "dummy_dpll" };
PNAME(mux_gpll_cpll_p) = { "gpll", "cpll" };
PNAME(mux_gpll_cpll_usb480m_xin24m_p) = { "gpll", "cpll", "usb480m", "xin24m" };
PNAME(mux_cpll_gpll_p) = { "cpll", "gpll" };
PNAME(mux_gpll_cpll_xin24m_p) = { "gpll", "cpll", "xin24m" };
PNAME(mux_cpll_hpll_gpll_p) = { "cpll", "hpll", "gpll" };
PNAME(mux_cpll_gpll_hpll_p) = { "cpll", "gpll", "hpll" };
PNAME(mux_gpll_cpll_hpll_p) = { "gpll", "cpll", "hpll" };
PNAME(mux_gpll_cpll_apll_hpll_p) = { "gpll", "cpll", "dummy_apll", "hpll" };
// ADD BEGIN
PNAME(mux_hpll_p) = { "hpll" };
// ADD END
接着我们将dclk_vop_div
绑定的PLL设置为mux_hpll_p
即可。
// Original: Bind to mux_gpll_cpll_p
COMPOSITE(DCLK_VOP_DIV, "dclk_vop_div", mux_gpll_cpll_p, 0,
RV1126_CLKSEL_CON(47), 8, 1, MFLAGS, 0, 8, DFLAGS,
RV1126_CLKGATE_CON(14), 11, GFLAGS),
// Modify: Bind to mux_hpll_p
COMPOSITE(DCLK_VOP_DIV, "dclk_vop_div", mux_hpll_p, 0,
RV1126_CLKSEL_CON(47), 8, 1, MFLAGS, 0, 8, DFLAGS,
RV1126_CLKGATE_CON(14), 11, GFLAGS),
Comments | NOTHING