配置USB Host和USB Device full-speed工作

在开发嵌入式产品的时候,有时因为干扰而遇到严重的USB兼容性问题时,我们需要将USB速度从high-speed降到full-speed,在保证数据的可靠性的前提下进行测试。
本文以i.MX6为例,讲述怎么配置使其USB Host Controller和USB Device Controller工作在full-speed。


PORTSC寄存器

关于PORTSC寄存器的定义,可以从EHCI SPEC上找到,也可以从芯片的datasheet上查找到。下面的定义主要是参照i.MX6。
寄存器定义
寄存器定义

其中BIT24的定义如下
BIT24

将其设置为1,那么端口将强制运行在full-speed上。
另外,这个寄存器USB Host Controller和USB Device Controller都可以使用,并且该寄存器是标准的EHCI规定的。详见ehci-specification-for-usb.pdf


配置USB Host工作在full-speed

有寄存器上的依据,接下来就可以配置USB Host工作在full-speed上了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 6e834b83..b81c84a 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -586,6 +586,7 @@ static int ehci_run (struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 temp;
u32 hcc_params;
+ u32 port_status_control_value;

hcd->uses_new_polling = 1;

@@ -656,6 +657,11 @@ static int ehci_run (struct usb_hcd *hcd)
ehci_writel(ehci, INTR_MASK,
&ehci->regs->intr_enable); /* Turn On Interrupts */

+#define PFSC (1<<24)
+ printk("[xxx-ehci] set USB EHCI work in full speed ========\n");
+ port_status_control_value = ehci_readl(ehci, &ehci->regs->port_status[0]);
+ ehci_writel(ehci, port_status_control_value | PFSC, &ehci->regs->port_status[0]);
+
/* GRR this is run-once init(), being done every time the HC starts.
* So long as they're part of class devices, we can't do it init()
* since the class device isn't created that early.

ehci_run()函数会在ehci-hcd驱动加载的时候去执行,此时将port_status寄存器的bit24写入1,那么就可以将其端口设置在full-speed。至于有几个端口,可以读出HCSPARAMS寄存器N_PORTS的值。
HCSPARAMS寄存器


配置USB Device工作在full-speed

配置USB Device工作在full-speed下,也同样是要配置PORTSC寄存器。配置的地方在udc控制器驱动里面。比如i.MX6的配置在drivers/usb/gadget/udc/fsl_udc_core.c中的.udc_start或者.pullup所指定的函数。

1
2
3
4
5
6
7
8
9
10
static const struct usb_gadget_ops fsl_gadget_ops = {
.get_frame = fsl_get_frame,
.wakeup = fsl_wakeup,
/* .set_selfpowered = fsl_set_selfpowered, */ /* Always selfpowered */
.vbus_session = fsl_vbus_session,
.vbus_draw = fsl_vbus_draw,
.pullup = fsl_pullup,
.udc_start = fsl_udc_start,
.udc_stop = fsl_udc_stop,
};

修改后如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
index 6f2f71c..94a3ae3 100644
--- a/drivers/usb/gadget/udc/fsl_udc_core.c
+++ b/drivers/usb/gadget/udc/fsl_udc_core.c
@@ -1223,9 +1223,13 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
return -EOPNOTSUPP;

udc->softconnect = (is_on != 0);
- if (can_pullup(udc))
+ if (can_pullup(udc)) {
fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
&dr_regs->usbcmd);
+ fsl_writel((fsl_readl(&dr_regs->portsc1) | PORTSCX_PORT_FORCE_FULL_SPEED),
+ &dr_regs->portsc1);
+ printk("[xxx-udc] set USB udc work in full speed ========")
+ }
else
fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),
&dr_regs->usbcmd);

Title:配置USB Host和USB Device full-speed工作

Author:Victor Huang

Time:2019-06-09 / 17:06

Link:http://wowothink.com/892013c5/

License: Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)