rk3128 平臺rk818電源管理驅動移植
一、rk3128加上rk818電源管理驅動
RK3128 加上rk818電源管理驅動之後,導致核心宕機、工作各種穩定。宕機現象各不相同,核心起來之後跑一下死在printk 列印函式裡面、遇到NULL kernel painc
記憶體異常、Internal error: Oops 等等異常情況。基本上斷定電源管理部分出問題
出現這些問題兩種情況
1、 電源驅動RK818 沒有載入上去
a) 需要檢查驅動和gpio有沒有配置對
2、 電源管理晶片輸出的 電壓不穩定 CPU、DDR、GPU 等電壓太低,導致跑飛
主要是設計電路板是要嚴格配置阻抗,同時微調RK818 輸出電壓
CPU 啟動的時候,從低的主頻經過幾次跳頻,電壓太低導致CPU、DDR工作異常
二、驅動移植
1、配置驅動
make menuconfig
Linux/arm 3.10.0Kernel Configuration
Device Drivers --->
Multifunction device drivers
*]RK818 Power Management chip
Device Drivers --->
-*-Power supply class support --->
[*] RK818Battery driver
Device Drivers --->
[*] Real Time Clock --->
-*- rk818 rtc for rk
2、 修改dts檔案gpio
Rk818 sleep 接到主控 PMIC_SLEEP(GPIO3_C1)
INT_OC接到主控 PMIC_INT(GPIO1_B1)
&rk818 {
gpios =<&gpio1 GPIO_B1GPIO_ACTIVE_HIGH>,<&gpio3 GPIO_C1 GPIO_ACTIVE_LOW>;
}
RK818掛載在I2C0上
&i2c0 {
status = "okay";
rk818: [email protected] {
reg = <0x1c>; /*從機地址*/
status = "okay";
};
}
三、配置RK818輸出電壓
vim rk3128-box.dts
&clk_core_dvfs_table {
operating-points = <
/* KHz uV */ /*描述主控工作頻率時RK818輸出電壓*/
816000 1000000
1008000 1200000
/*1000000 1425000*/
>;
/*動態調整頻率的時候,對應匹配的電壓*/
virt-temp-limit-1-cpu-busy = <
/* target-temp limit-freq */
75 1008000
85 1200000
95 1200000
100 1200000
>;
virt-temp-limit-2-cpu-busy = <
/* target-temp limit-freq */
75 912000
85 1008000
95 1104000
100 1200000
>;
virt-temp-limit-3-cpu-busy= <
/* target-temp limit-freq */
75 816000
85 912000
95 100800
100 110400
>;
virt-temp-limit-4-cpu-busy = <
/* target-temp limit-freq */
75 696000
85 816000
95 912000
100 100800
>;
temp-limit-enable =<1>;
target-temp =<85>;
status="okay";
};
rk818 當中配置主控的工作電壓,operating-points 在變動cpu工作頻率的時候,輸出電壓,限定工作在 816Mhz(1.2V) 到1008000 (1.5V) 。temp-limit-enable 使能臨時變動CPU 工作主頻,以表當中的target-temp=85裡面的值來做參考
這樣最終跳動的頻率表如下:
virt-temp-limit-1-cpu-busy[85]=1200000 (高於實際設定的operating-points,不會設定進去)
virt-temp-limit-2-cpu-busy=1008000
virt-temp-limit-3-cpu-busy=912000
virt-temp-limit-4-cpu-busy=816000
gpu頻率和電壓如下設定:
&clk_gpu_dvfs_table {
operating-points = <
/* KHz uV */
200000 950000
300000 975000
400000 1075000
>;
status="okay";
};
DDR 頻率對應的工作表:(檢視ddr手冊,在533Mhz 時候工作電壓為1.5V)
&clk_ddr_dvfs_table {
operating-points = <
/* KHz uV */
200000 1000000
300000 1100000
400000 1200000
533000 1250000
>;
}
根據跑飛現象相應的都將這個表裡面的電壓往上提供0.1-0.2v左右
DDR電壓在533Mhz 設定RK818輸出在1.5V,才能正常工作
從新編譯之後,不會出現記憶體崩潰現象
啟動之後,一直列印如下資訊
[ 7.671300] vdd_logic: unsupportable voltagerange: 1500000-1425000uV
[ 7.671317] DVFS ERR: dvfs_regulator_set_voltage_readback:now read back to check voltage
[ 7.673312] DVFS ERR: dvfs_regulator_set_voltage_readback:set ERROR AND NOT effected, volt=1300000
[ 7.673720] DVFS ERR: dvfs_scale_volt_direct: vd_logic setvoltage up err ret = -22, Vnew = 1500000(was 1300000)mV
[ 7.680868] DVFS WARNING: dvfs_reset_volt:vd(vd_logic) try to reloadvolt = 1300000
[ 7.700680] enter dvfs_target: clk(clk_gpu)new_rate = 297000000 Hz, old_rate = 200000000 Hz
設定vdd_am和vdd_logic 電壓錯誤
[ 7.218360] dvfs_clk_set_rate:dvfsnode(clk_gpu) set rate(400000000)
[ 7.218405] DVFS WARNING: dvfs_reset_volt:vd(vd_logic) try to reloadvolt = 1300000
[ 7.218441] regulator_set_voltage rdev-min_uV=1500000 max_uV=1500000
[ 7.218462] vdd_logic: unsupportable voltagerange: 1500000-1425000uV
[ 7.218480] DVFS ERR: dvfs_regulator_set_voltage_readback:now read back to check voltage
[ 7.220468] DVFS ERR: dvfs_regulator_set_voltage_readback:set ERROR AND NOT effected, volt=1300000 (dvfs_regulator_set_voltage_readback 先設定再讀取電壓,讀取出來的電壓為1.3V 函式異常退出)
[ 7.220875] DVFS ERR: dvfs_scale_volt_direct: vd_logic setvoltage up err ret = -22, Vnew = 1500000(was 1300000)mV
根據頻率設定電壓錯誤 ,最小電壓是 1.5V 最大電壓是 1.3V
查詢程式碼呼叫過程
vim arch/arm/mach-rockchip/dvfs.c當中如下
1645 intof_dvfs_init(void)
{
1681 vd->vd_dvfs_target =dvfs_target;
}
//根據時鐘來調整rk818電壓輸出
int dvfs_clk_set_rate(struct dvfs_node*clk_dvfs_node, unsigned long rate)
{
printk("%s:dvfs node(%s) setrate(%lu)\n", // gpu 400M 出錯
__func__,clk_dvfs_node->name, rate);
ret =clk_dvfs_node->vd->vd_dvfs_target(clk_dvfs_node, rate);
}
static intdvfs_target(struct dvfs_node *clk_dvfs_node, unsigned long rate)
{
//呼叫dvfs_scale_volt_direct 函式根據頻率設定電壓
//最後一次載入vdd_logic 錯誤,需要回復設定
ret =dvfs_reset_volt(clk_dvfs_node->vd);
//獲取新的電壓(打印出來的值一直是1.5V,獲取配置表當中最大電壓)
volt_new =dvfs_vd_get_newvolt_byclk(clk_dvfs_node);
//將最大電壓設定進去,
ret = dvfs_scale_volt_direct(clk_dvfs_node->vd, volt_new);
}
//根據頻率設定電壓
static intdvfs_scale_volt_direct(struct vd_node *vd_clk, int volt_new)
{
……………………………………………….
if(!IS_ERR_OR_NULL(vd_clk->regulator)) {
ret =dvfs_regulator_set_voltage_readback(vd_clk->regulator, volt_new, volt_new);
…………………………………………………
}
static intdvfs_regulator_set_voltage_readback(struct regulator *regulator, int min_uV,int max_uV)
{
ret = dvfs_regulator_set_voltage(regulator,max_uV, max_uV);
if (ret < 0) {
DVFS_ERR("%s: now readback to check voltage\n", __func__);
mdelay(2);
read_back =dvfs_regulator_get_voltage(regulator);
if (read_back == max_uV) {
DVFS_ERR("%s: setERROR but already effected, volt=%d\n", __func__, read_back);
ret = 0;
} else {
DVFS_ERR("%s: setERROR AND NOT effected, volt=%d\n", __func__, read_back);
}
}
return ret;
}
//根據頻率設定電壓錯誤 ,最小電壓是 1.5V 最大電壓是 1.3V
#definedvfs_regulator_set_voltage regulator_set_voltage
跟蹤到drivers/regulator/core.c
int regulator_set_voltage(struct regulator*regulator, int min_uV, int max_uV)
進去 min_uV =1500000 max_uV=1500000
這個函式regulator_set_voltage 這兩個值寫入到regulator->min_uV ,regulator->max_uV
傳人的值不對導致dvfs_regulator_set_voltage_readback 函式裡面異常退出
從列印資訊來看vdd_logic 和gpu 設定電壓錯誤,根據整個過程,加上除錯資訊,cpu和gpu頻率和電壓一直跳動
將DDR的電壓表設定如下:
&clk_ddr_dvfs_table {
operating-points = <
/* KHz uV */
200000 1200000
300000 1300000
400000 1400000
533000 1500000
>;
}
提高core 主控電壓
&clk_core_dvfs_table {
operating-points = <
/* KHz uV */ /*描述主控工作頻率時RK818輸出電壓*/
816000 1200000
1008000 1500000
/*1000000 1425000*/
>;
關閉動態調整的頻率和電壓
重新編譯,更新韌體,開機基本正常