一、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: rk818@1c {
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)
", // 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
", __func__);
mdelay(2);
read_back =dvfs_regulator_get_voltage(regulator);
if (read_back == max_uV) {
DVFS_ERR("%s: setERROR but already effected, volt=%d
", __func__, read_back);
ret = 0;
} else {
DVFS_ERR("%s: setERROR AND NOT effected, volt=%d
", __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*/
>;
关闭动态调整的频率和电压
重新编译,更新固件,开机基本正常