目录
背景介绍
rk3588有5个usb控制器,Type-C0/1接口可以简化成usb接口,作者项目中就是Type-C0作为usb2.0 only使用。
按照rk3588 usb开发参考文档进行配置
《Rockchip_RK3588_Developer_Guide_USB_CN.pdf》
Type-C USB 2.0 only DTS配置
配置3.硬件电路不带外置Type-C控制芯片,支持OTG
&usbdrd3_0 {
status = "okay";
};
&usbdrd_dwc3_0 {
status = "okay";
dr_mode = "otg";
phys = <&u2phy0_otg>;
phy-names = "usb2-phy";
maximum-speed = "high-speed";
extcon = <&u2phy0>;
};
&u2phy0 {
status = "okay";
};
&u2phy0_otg {
status = "okay";
};
&usbdp_phy0 {
status = "disabled";
};
&usbdp_phy0_dp {
status = "disabled";
};
&usbdp_phy0_u3 {
status = "disabled";
};
发现偶现usb不可用,概率大约20%
分析过程
日志分析
通过串口log对比正常和异常log,找到usb相关差异
异常log会有如下报错
dwc3 fc000000.usb: failed to enable ep0out
正常log没有报错,会有
dwc3 fc000000.usb: device reset
追踪代码
找到对应代码位置
driver/usb/dwc3/gadget.c
__dwc3_gadget_start()
{
........
dep = dwc->eps[0];
ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
goto err0;
}
........
}
添加log,找到最初报错位置
driver/usb/dwc3/gadget.c
dwc3_send_gadget_ep_cmd()
{
........
u32 timeout = 5000;
........
dwc3_writel(dep->regs, DWC3_DEPCMD, cmd);
do {
reg = dwc3_readl(dep->regs, DWC3_DEPCMD);
if (!(reg & DWC3_DEPCMD_CMDACT)) {
cmd_status = DWC3_DEPCMD_STATUS(reg);
switch (cmd_status) {
case 0:
ret = 0;
break;
case DEPEVT_TRANSFER_NO_RESOURCE:
dev_WARN(dwc->dev, "No resource for %s\n",
dep->name);
ret = -EINVAL;
break;
case DEPEVT_TRANSFER_BUS_EXPIRY:
/*
* SW issues START TRANSFER command to
* isochronous ep with future frame interval. If
* future interval time has already passed when
* core receives the command, it will respond
* with an error status of 'Bus Expiry'.
*
* Instead of always returning -EINVAL, let's
* give a hint to the gadget driver that this is
* the case by returning -EAGAIN.
*/
ret = -EAGAIN;
break;
default:
dev_WARN(dwc->dev, "UNKNOWN cmd status\n");
}
break;
}
} while (--timeout);
if (timeout == 0) {
ret = -ETIMEDOUT;
cmd_status = -ETIMEDOUT;
}
........
}
原因分析
从上面的代码可以看出,是读usb控制器的某个寄存器5000次都没有得到目标值
1. 检查函数传参以及代码流程
添加log,发现正常和异常时传入的参数和内部走的代码流程完全一致, 排除函数内部问题
2. 检查调用逻辑
增加dump_statck(),查看流程,就是正常的probe流程
[ 6.881962][ T1] Call trace:
[ 6.881970][ T1] dump_backtrace+0x0/0x1c8
[ 6.881974][ T1] show_stack+0x1c/0x2c
[ 6.881981][ T1] dump_stack_lvl+0xdc/0x12c
[ 6.881984][ T1] dump_stack+0x1c/0x64
[ 6.881990][ T1] dwc3_send_gadget_ep_cmd+0x5e0/0xa7c
[ 6.881994][ T1] __dwc3_gadget_ep_enable+0x3c8/0x568
[ 6.881998][ T1] __dwc3_gadget_start+0x1d8/0x5a8
[ 6.882002][ T1] dwc3_gadget_pullup+0xcc/0x310
[ 6.882007][ T1] usb_gadget_connect+0x3c/0x10c
[ 6.882010][ T1] udc_bind_to_driver+0x150/0x184
[ 6.882012][ T1] usb_gadget_probe_driver+0xa8/0x184
[ 6.882015][ T1] gadget_dev_desc_UDC_store+0xec/0x138
[ 6.882020][ T1] configfs_write_file+0x104/0x154
[ 6.882023][ T1] vfs_write+0x168/0x390
[ 6.882026][ T1] ksys_write+0x78/0xe8
[ 6.882028][ T1] __arm64_sys_write+0x20/0x30
[ 6.882032][ T1] el0_svc_common+0xc0/0x23c
[ 6.882035][ T1] do_el0_svc+0x28/0x88
[ 6.882038][ T1] el0_svc+0x14/0x24
[ 6.882041][ T1] el0_sync_handler+0x88/0xec
[ 6.882044][ T1] el0_sync+0x1a8/0x1c0
3. 增加延时
既然无法从原有代码找到问题,尝试用其他方法优化,首先根据代码是循环读取5000次,中间没有其他操作,说明需要时间,
尝试在while前增加延时,看是否可以优化。
结果:没有效果
4. 配置成usb3.0
由于之前做过的rk3588的两个项目都没有此问题,其中一个是结合外置type-c控制芯片配置成全功能接口(虽然硬件上只有usb2.0),另一个是配置成usb3.0接口。
他们都没有disabled掉usbdp相关的phy。
打开usbdp相关的phy
&usbdp_phy0 {
status = "okay";
};
&usbdp_phy0_dp {
status = "okay";
};
&usbdp_phy0_u3 {
status = "okay";
};
结果:没有效果
删除maximum-speed
从文档中看到,配置maximum-speed = "high-speed",通知dwc3驱动将usb限制为USB2.0 only
在上一步的基础上,把这个配置删除。
结果:usb一直不能用
删除usbdrd_dwc3_0中phy的配置
在上一步的基础上,结合另外两个项目的配置方式删除usbdrd_dwc3_0中phy的配置
&usbdrd_dwc3_0 {
status = "okay";
dr_mode = "otg";
extcon = <&u2phy0>;
};
结果:有效
这个配置按照文档中的说法属于type-c to usb3.0/dp的配置,后来又经过测试,可以disable掉usbdp_phy0_dp,最终的配置如下:
&usbdrd3_0 {
status = "okay";
};
&usbdrd_dwc3_0 {
status = "okay";
dr_mode = "otg";
extcon = <&u2phy0>;
};
&u2phy0 {
status = "okay";
};
&u2phy0_otg {
status = "okay";
};
&usbdp_phy0 {
status = "okay";
};
&usbdp_phy0_dp {
status = "okay";
};
&usbdp_phy0_u3 {
status = "disabled";
};
总结
经过这个问题,说明rk3588 type-c to usb2.0功能有bug,或者文档给出的参考配置不完整