mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-13 15:03:58 +03:00
Merge branch 'master' of git://source.denx.de/u-boot-usb
- A fix for CDNS3 in correctly determining dr_mode for OTG.
This commit is contained in:
@@ -392,6 +392,52 @@ static const struct udevice_id cdns3_ids[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
/*
|
||||
* The VBUS Valid Bit in the OTG Status register can be used to determine
|
||||
* the role. When VBUS Valid is set, it indicates that a USB Host is supplying
|
||||
* power, so the Controller should assume the PERIPHERAL role. If it isn't set,
|
||||
* it indicates the absence of a USB Host, so the Controller should assume the
|
||||
* HOST role. If the OTG Status register is inaccessible, return an error.
|
||||
*/
|
||||
static int cdns3_get_otg_mode(struct udevice *parent, enum usb_dr_mode *mode)
|
||||
{
|
||||
/* Create a temporary child device for using devfdt_remap_addr_name() */
|
||||
struct udevice child = {
|
||||
.parent = parent,
|
||||
};
|
||||
struct cdns3 cdns, *cdnsp;
|
||||
void __iomem *otg_regs;
|
||||
|
||||
dev_set_ofnode(&child, ofnode_first_subnode(dev_ofnode(parent)));
|
||||
otg_regs = devfdt_remap_addr_name(&child, "otg");
|
||||
if (!otg_regs) {
|
||||
dev_err(parent, "failed to get otg registers for child node\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* As mentioned in drivers/usb/cdns3/drd.c, there are two versions
|
||||
* of the Controller. The following logic detects the version of the
|
||||
* Controller and interprets the register layout accordingly.
|
||||
*/
|
||||
cdnsp = &cdns;
|
||||
cdnsp->otg_v0_regs = otg_regs;
|
||||
if (!readl(&cdnsp->otg_v0_regs->cmd)) {
|
||||
cdnsp->otg_regs = otg_regs;
|
||||
} else {
|
||||
cdnsp->otg_v1_regs = otg_regs;
|
||||
cdnsp->otg_regs = (void *)&cdnsp->otg_v1_regs->cmd;
|
||||
}
|
||||
|
||||
/* Use VBUS Valid to determine role */
|
||||
if (readl(&cdnsp->otg_regs->sts) & OTGSTS_VBUS_VALID)
|
||||
*mode = USB_DR_MODE_PERIPHERAL;
|
||||
else
|
||||
*mode = USB_DR_MODE_HOST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cdns3_bind(struct udevice *parent)
|
||||
{
|
||||
enum usb_dr_mode dr_mode;
|
||||
@@ -413,6 +459,13 @@ int cdns3_bind(struct udevice *parent)
|
||||
if (dr_mode == USB_DR_MODE_UNKNOWN)
|
||||
dr_mode = usb_get_dr_mode(dev_ofnode(parent));
|
||||
|
||||
/* Use VBUS Valid to determine role */
|
||||
if (dr_mode == USB_DR_MODE_OTG) {
|
||||
ret = cdns3_get_otg_mode(parent, &dr_mode);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (dr_mode) {
|
||||
#if defined(CONFIG_SPL_USB_HOST) || \
|
||||
(!defined(CONFIG_XPL_BUILD) && defined(CONFIG_USB_HOST))
|
||||
|
||||
@@ -301,6 +301,17 @@ int cdns3_drd_init(struct cdns3 *cdns)
|
||||
cdns->dr_mode = USB_DR_MODE_PERIPHERAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the absence of STRAP configuration, use VBUS Valid to
|
||||
* determine the appropriate role to be assigned to dr_mode.
|
||||
*/
|
||||
if (cdns->dr_mode == USB_DR_MODE_OTG) {
|
||||
if (cdns3_get_vbus(cdns))
|
||||
cdns->dr_mode = USB_DR_MODE_PERIPHERAL;
|
||||
else
|
||||
cdns->dr_mode = USB_DR_MODE_HOST;
|
||||
}
|
||||
|
||||
state = readl(&cdns->otg_regs->sts);
|
||||
if (OTGSTS_OTG_NRDY(state) != 0) {
|
||||
dev_err(cdns->dev, "Cadence USB3 OTG device not ready\n");
|
||||
|
||||
Reference in New Issue
Block a user