u-boot的USB模块在需要的时候才会进行初始化。也就是调用usb start命令时才会进行初始化。
以2013.01版本为例,说明下初始化的过程
首先是usb命令的定义
U_BOOT_CMD(
usb, 5, 1, do_usb,
"USB sub-system",
"start - start (scan) USB controller\n"
"usb reset - reset (rescan) USB controller\n"
"usb stop [f] - stop USB [f]=force stop\n"
"usb tree - show USB device tree\n"
"usb info [dev] - show available USB devices\n"
"usb storage - show details of USB storage devices\n"
"usb dev [dev] - show or set current USB storage device\n"
"usb part [dev] - print partition table of one or all USB storage"
" devices\n"
"usb read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n"
" to memory address `addr'\n"
"usb write addr blk# cnt - write `cnt' blocks starting at block `blk#'\n"
" from memory address `addr'"
);
可以看到usb命令的入口都是在do_usb函数实现
static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int i;
struct usb_device *dev = NULL;
extern char usb_started;
#ifdef CONFIG_USB_STORAGE
block_dev_desc_t *stor_dev;
#endif
if (argc < 2)
return CMD_RET_USAGE;
if ((strncmp(argv[1], "reset", 5) == 0) ||
(strncmp(argv[1], "start", 5) == 0)) {
bootstage_mark_name(BOOTSTAGE_ID_USB_START, "usb_start");
usb_stop();
printf("(Re)start USB...\n");
if (usb_init() >= 0) {
#ifdef CONFIG_USB_STORAGE
/* try to recognize storage devices immediately */
usb_stor_curr_dev = usb_stor_scan(1);
#endif
#ifdef CONFIG_USB_HOST_ETHER
/* try to recognize ethernet devices immediately */
usb_ether_curr_dev = usb_host_eth_scan(1);
#endif
#ifdef CONFIG_USB_KEYBOARD
drv_usb_kbd_init();
#endif
}
return 0;
}
在进行usb start时会调用usb_init来初始化usb控制器,usb_init 作为一个设备抽象层初始化在common/usb.c中定义
int usb_init(void)
{
void *ctrl;
struct usb_device *dev;
int i, start_index = 0;
dev_index = 0;
asynch_allowed = 1;
usb_hub_reset();
/* first make all devices unknown */
for (i = 0; i < USB_MAX_DEVICE; i++) {
memset(&usb_dev[i], 0, sizeof(struct usb_device));
usb_dev[i].devnum = -1;
}
/* init low_level USB */
for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
/* init low_level USB */
printf("USB%d: ", i);
if (usb_lowlevel_init(i, &ctrl)) {
puts("lowlevel init failed\n");
continue;
}
/*
* lowlevel init is OK, now scan the bus for devices
* i.e. search HUBs and configure them
*/
start_index = dev_index;
printf("scanning bus %d for devices... ", i);
dev = usb_alloc_new_device(ctrl);
初始化的实质工作由具体的设备实现usb_lowlevel_init来负责,这个函数由具体的USB控制器规格来定义,P2020的USB控制器采用EHCI规格,usb_lowlevel_init由drivers/usb/host/ehci-hcd.c定义
if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor))
return -1;
ehci_hcd_init由CPU级驱动来实现,定义在drivers/usb/host/ehci-fsl.c中
/*
* Create the appropriate control structures to manage
* a new EHCI host controller.
*
* Excerpts from linux ehci fsl driver.
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
struct ehci_ctrl *ehci_ctrl = container_of(hccr,
struct ehci_ctrl, hccr);
struct usb_ehci *ehci;
const char *phy_type = NULL;
size_t len;
#ifdef CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY
char usb_phy[5];
usb_phy[0] = '\0';
#endif
ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR;
*hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
*hcor = (struct ehci_hcor *)((uint32_t) *hccr +
HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
/* Set to Host mode */
setbits_le32(&ehci->usbmode, CM_HOST);
out_be32(&ehci->snoop1, SNOOP_SIZE_2GB);
out_be32(&ehci->snoop2, 0x80000000 | SNOOP_SIZE_2GB);
/* Init phy */
if (hwconfig_sub("usb1", "phy_type"))
phy_type = hwconfig_subarg("usb1", "phy_type", &len);
else
phy_type = getenv("usb_phy_type");
if (!phy_type) {
#ifdef CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY
/* if none specified assume internal UTMI */
strcpy(usb_phy, "utmi");
phy_type = usb_phy;
#else
printf("WARNING: USB phy type not defined !!\n");
return -1;
#endif
}
if (!strncmp(phy_type, "utmi", 4)) {
#if defined(CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY)
setbits_be32(&ehci->control, PHY_CLK_SEL_UTMI);
setbits_be32(&ehci->control, UTMI_PHY_EN);
udelay(1000); /* delay required for PHY Clk to appear */
#endif
out_le32(&(*hcor)->or_portsc[0], PORT_PTS_UTMI);
setbits_be32(&ehci->control, USB_EN);
} else {
setbits_be32(&ehci->control, PHY_CLK_SEL_ULPI);
clrsetbits_be32(&ehci->control, UTMI_PHY_EN, USB_EN);
udelay(1000); /* delay required for PHY Clk to appear */
if (!usb_phy_clk_valid(ehci))
return -EINVAL;
out_le32(&(*hcor)->or_portsc[0], PORT_PTS_ULPI);
}
out_be32(&ehci->prictrl, 0x0000000c);
out_be32(&ehci->age_cnt_limit, 0x00000040);
out_be32(&ehci->sictrl, 0x00000001);
in_le32(&ehci->usbmode);
/* enable/disable USB Erratum USB A-005275 workaround;
* workaround can be disabled by mentioning "no_usb_hs_errata"
* in hwconfig string
*/
if (!hwconfig("no_erratum_a005275")) {
if (has_erratum_a005275())
ehci_ctrl->has_fsl_erratum_a005275 = 1;
} else {
ehci_ctrl->has_fsl_erratum_a005275 = 0;
}
return 0;
}
这个版本的usb需要在环境变量中设置phy_type,P2020RDB-PC使用的ULPI类型的PHY芯片USB3300.
USB的协议实现在usb.c,主机控制器在drivers/usb/host/文件夹实现
整个usb部分由抽象层(usb.c),规格定义(ehci-hcd.c)和具体实现(ehci-fsl.c)来分工实现