aw_usbphy: add support for device mode operation

OTG mode is not supported still.  It's easy to do it as a one-off
detection, but the proper support requires continuous monitoring and
communicating the current state to the USB layer.

Also, fix phy0_route setting for H3.  Remove duplicate register
definitions.

Tested on Orange Pi PC Plus with dr_mode="peripheral" using
  hw.usb.template=3
  umodem_load="YES"

Reviewed by:	manu
MFC after:	5 weeks
Differential Revision: https://reviews.freebsd.org/D26348
This commit is contained in:
Andriy Gapon 2020-09-21 10:02:11 +00:00
parent 2bd2b11335
commit aea49d9fed

View File

@ -102,7 +102,7 @@ static const struct aw_usbphy_conf h3_usbphy_conf = {
.num_phys = 4,
.phy_type = AWUSBPHY_TYPE_H3,
.pmu_unk1 = true,
.phy0_route = false,
.phy0_route = true,
};
static const struct aw_usbphy_conf a64_usbphy_conf = {
@ -175,8 +175,10 @@ DEFINE_CLASS_1(awusbphy_phynode, awusbphy_phynode_class, awusbphy_phynode_method
#define FORCE_ID (0x3 << 14)
#define FORCE_ID_SHIFT 14
#define FORCE_ID_LOW 2
#define FORCE_ID_HIGH 3
#define FORCE_VBUS_VALID (0x3 << 12)
#define FORCE_VBUS_VALID_SHIFT 12
#define FORCE_VBUS_VALID_LOW 2
#define FORCE_VBUS_VALID_HIGH 3
#define VBUS_CHANGE_DET (1 << 6)
#define ID_CHANGE_DET (1 << 5)
@ -190,18 +192,6 @@ DEFINE_CLASS_1(awusbphy_phynode, awusbphy_phynode_class, awusbphy_phynode_method
#define PMU_ULPI_BYPASS (1 << 0)
#define PMU_UNK_H3 0x10
#define PMU_UNK_H3_CLR 0x2
#define PHY_CSR 0x00
#define ID_PULLUP_EN (1 << 17)
#define DPDM_PULLUP_EN (1 << 16)
#define FORCE_ID (0x3 << 14)
#define FORCE_ID_SHIFT 14
#define FORCE_ID_LOW 2
#define FORCE_VBUS_VALID (0x3 << 12)
#define FORCE_VBUS_VALID_SHIFT 12
#define FORCE_VBUS_VALID_HIGH 3
#define VBUS_CHANGE_DET (1 << 6)
#define ID_CHANGE_DET (1 << 5)
#define DPDM_CHANGE_DET (1 << 4)
static void
awusbphy_configure(device_t dev, int phyno)
@ -335,7 +325,12 @@ awusbphy_vbus_detect(device_t dev, int *val)
return (0);
}
*val = 0;
/* TODO check vbus_power-supply. */
/*
* If there is no way to detect, assume present.
*/
*val = 1;
return (0);
}
@ -369,10 +364,11 @@ awusbphy_phy_enable(struct phynode *phynode, bool enable)
if (error)
goto out;
if (vbus_det == 1) {
/* TODO check vbus_power-supply as well. */
if (sc->vbus_det_valid && vbus_det == 1) {
if (bootverbose)
device_printf(dev, "External VBUS detected, not enabling the regulator\n");
device_printf(dev, "External VBUS detected, "
"not enabling the regulator\n");
return (0);
}
}
@ -426,36 +422,40 @@ awusbphy_set_mode(struct phynode *phynode, int mode)
return (0);
}
if (sc->mode == mode)
return (0);
if (mode == PHY_USB_MODE_OTG) /* TODO */
return (EOPNOTSUPP);
error = awusbphy_vbus_detect(dev, &vbus_det);
if (error != 0)
return (error);
val = bus_read_4(sc->phy_ctrl, PHY_CSR);
val &= ~(VBUS_CHANGE_DET | ID_CHANGE_DET | DPDM_CHANGE_DET);
val |= (ID_PULLUP_EN | DPDM_PULLUP_EN);
val &= ~FORCE_VBUS_VALID;
val |= (vbus_det ? FORCE_VBUS_VALID_HIGH : FORCE_VBUS_VALID_LOW) <<
FORCE_VBUS_VALID_SHIFT;
val &= ~FORCE_ID;
switch (mode) {
case PHY_USB_MODE_HOST:
val = bus_read_4(sc->phy_ctrl, PHY_CSR);
val &= ~(VBUS_CHANGE_DET | ID_CHANGE_DET | DPDM_CHANGE_DET);
val |= (ID_PULLUP_EN | DPDM_PULLUP_EN);
val &= ~FORCE_ID;
val |= (FORCE_ID_LOW << FORCE_ID_SHIFT);
val &= ~FORCE_VBUS_VALID;
val |= (FORCE_VBUS_VALID_HIGH << FORCE_VBUS_VALID_SHIFT);
bus_write_4(sc->phy_ctrl, PHY_CSR, val);
if (sc->phy_conf->phy0_route == true) {
error = awusbphy_vbus_detect(dev, &vbus_det);
if (error)
goto out;
if (vbus_det == 0)
CLR4(sc->phy_ctrl, OTG_PHY_CFG,
OTG_PHY_ROUTE_OTG);
else
SET4(sc->phy_ctrl, OTG_PHY_CFG,
OTG_PHY_ROUTE_OTG);
}
if (sc->phy_conf->phy0_route)
CLR4(sc->phy_ctrl, OTG_PHY_CFG, OTG_PHY_ROUTE_OTG);
break;
case PHY_USB_MODE_OTG:
/* TODO */
case PHY_USB_MODE_DEVICE:
val |= (FORCE_ID_HIGH << FORCE_ID_SHIFT);
if (sc->phy_conf->phy0_route)
SET4(sc->phy_ctrl, OTG_PHY_CFG, OTG_PHY_ROUTE_OTG);
break;
default:
return (EINVAL);
}
bus_write_4(sc->phy_ctrl, PHY_CSR, val);
sc->mode = mode;
out:
return (0);
}