Changeset View
Changeset View
Standalone View
Standalone View
head/sys/arm/allwinner/aw_usbphy.c
Show First 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | static const struct aw_usbphy_conf a31_usbphy_conf = { | ||||
.pmu_unk1 = false, | .pmu_unk1 = false, | ||||
.phy0_route = false, | .phy0_route = false, | ||||
}; | }; | ||||
static const struct aw_usbphy_conf h3_usbphy_conf = { | static const struct aw_usbphy_conf h3_usbphy_conf = { | ||||
.num_phys = 4, | .num_phys = 4, | ||||
.phy_type = AWUSBPHY_TYPE_H3, | .phy_type = AWUSBPHY_TYPE_H3, | ||||
.pmu_unk1 = true, | .pmu_unk1 = true, | ||||
.phy0_route = false, | .phy0_route = true, | ||||
}; | }; | ||||
static const struct aw_usbphy_conf a64_usbphy_conf = { | static const struct aw_usbphy_conf a64_usbphy_conf = { | ||||
.num_phys = 2, | .num_phys = 2, | ||||
.phy_type = AWUSBPHY_TYPE_A64, | .phy_type = AWUSBPHY_TYPE_A64, | ||||
.pmu_unk1 = true, | .pmu_unk1 = true, | ||||
.phy0_route = true, | .phy0_route = true, | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | |||||
#define SET4(res, o, m) WR4(res, o, RD4(res, o) | (m)) | #define SET4(res, o, m) WR4(res, o, RD4(res, o) | (m)) | ||||
#define PHY_CSR 0x00 | #define PHY_CSR 0x00 | ||||
#define ID_PULLUP_EN (1 << 17) | #define ID_PULLUP_EN (1 << 17) | ||||
#define DPDM_PULLUP_EN (1 << 16) | #define DPDM_PULLUP_EN (1 << 16) | ||||
#define FORCE_ID (0x3 << 14) | #define FORCE_ID (0x3 << 14) | ||||
#define FORCE_ID_SHIFT 14 | #define FORCE_ID_SHIFT 14 | ||||
#define FORCE_ID_LOW 2 | #define FORCE_ID_LOW 2 | ||||
#define FORCE_ID_HIGH 3 | |||||
#define FORCE_VBUS_VALID (0x3 << 12) | #define FORCE_VBUS_VALID (0x3 << 12) | ||||
#define FORCE_VBUS_VALID_SHIFT 12 | #define FORCE_VBUS_VALID_SHIFT 12 | ||||
#define FORCE_VBUS_VALID_LOW 2 | |||||
#define FORCE_VBUS_VALID_HIGH 3 | #define FORCE_VBUS_VALID_HIGH 3 | ||||
#define VBUS_CHANGE_DET (1 << 6) | #define VBUS_CHANGE_DET (1 << 6) | ||||
#define ID_CHANGE_DET (1 << 5) | #define ID_CHANGE_DET (1 << 5) | ||||
#define DPDM_CHANGE_DET (1 << 4) | #define DPDM_CHANGE_DET (1 << 4) | ||||
#define OTG_PHY_CFG 0x20 | #define OTG_PHY_CFG 0x20 | ||||
#define OTG_PHY_ROUTE_OTG (1 << 0) | #define OTG_PHY_ROUTE_OTG (1 << 0) | ||||
#define PMU_IRQ_ENABLE 0x00 | #define PMU_IRQ_ENABLE 0x00 | ||||
#define PMU_AHB_INCR8 (1 << 10) | #define PMU_AHB_INCR8 (1 << 10) | ||||
#define PMU_AHB_INCR4 (1 << 9) | #define PMU_AHB_INCR4 (1 << 9) | ||||
#define PMU_AHB_INCRX_ALIGN (1 << 8) | #define PMU_AHB_INCRX_ALIGN (1 << 8) | ||||
#define PMU_ULPI_BYPASS (1 << 0) | #define PMU_ULPI_BYPASS (1 << 0) | ||||
#define PMU_UNK_H3 0x10 | #define PMU_UNK_H3 0x10 | ||||
#define PMU_UNK_H3_CLR 0x2 | #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 | static void | ||||
awusbphy_configure(device_t dev, int phyno) | awusbphy_configure(device_t dev, int phyno) | ||||
{ | { | ||||
struct awusbphy_softc *sc; | struct awusbphy_softc *sc; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | if (error != 0) { | ||||
device_printf(dev, "Cannot get status of id pin %d\n", | device_printf(dev, "Cannot get status of id pin %d\n", | ||||
error); | error); | ||||
return (error); | return (error); | ||||
} | } | ||||
*val = active; | *val = active; | ||||
return (0); | return (0); | ||||
} | } | ||||
*val = 0; | /* TODO check vbus_power-supply. */ | ||||
/* | |||||
* If there is no way to detect, assume present. | |||||
*/ | |||||
*val = 1; | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
awusbphy_phy_enable(struct phynode *phynode, bool enable) | awusbphy_phy_enable(struct phynode *phynode, bool enable) | ||||
{ | { | ||||
device_t dev; | device_t dev; | ||||
intptr_t phy; | intptr_t phy; | ||||
Show All 17 Lines | if (reg == NULL) | ||||
return (0); | return (0); | ||||
if (phy == 0) { | if (phy == 0) { | ||||
/* If an external vbus is detected, do not enable phy 0 */ | /* If an external vbus is detected, do not enable phy 0 */ | ||||
error = awusbphy_vbus_detect(dev, &vbus_det); | error = awusbphy_vbus_detect(dev, &vbus_det); | ||||
if (error) | if (error) | ||||
goto out; | goto out; | ||||
if (vbus_det == 1) { | /* TODO check vbus_power-supply as well. */ | ||||
if (sc->vbus_det_valid && vbus_det == 1) { | |||||
if (bootverbose) | 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); | return (0); | ||||
} | } | ||||
} | } | ||||
if (enable) { | if (enable) { | ||||
/* Depending on the PHY we need to route OTG to OHCI/EHCI */ | /* Depending on the PHY we need to route OTG to OHCI/EHCI */ | ||||
error = regulator_enable(reg); | error = regulator_enable(reg); | ||||
} else | } else | ||||
error = regulator_disable(reg); | error = regulator_disable(reg); | ||||
Show All 37 Lines | awusbphy_set_mode(struct phynode *phynode, int mode) | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
if (phy != 0) { | if (phy != 0) { | ||||
if (mode != PHY_USB_MODE_HOST) | if (mode != PHY_USB_MODE_HOST) | ||||
return (EINVAL); | return (EINVAL); | ||||
return (0); | return (0); | ||||
} | } | ||||
switch (mode) { | if (sc->mode == mode) | ||||
case PHY_USB_MODE_HOST: | 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 = bus_read_4(sc->phy_ctrl, PHY_CSR); | ||||
val &= ~(VBUS_CHANGE_DET | ID_CHANGE_DET | DPDM_CHANGE_DET); | val &= ~(VBUS_CHANGE_DET | ID_CHANGE_DET | DPDM_CHANGE_DET); | ||||
val |= (ID_PULLUP_EN | DPDM_PULLUP_EN); | 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; | val &= ~FORCE_ID; | ||||
switch (mode) { | |||||
case PHY_USB_MODE_HOST: | |||||
val |= (FORCE_ID_LOW << FORCE_ID_SHIFT); | val |= (FORCE_ID_LOW << FORCE_ID_SHIFT); | ||||
val &= ~FORCE_VBUS_VALID; | if (sc->phy_conf->phy0_route) | ||||
val |= (FORCE_VBUS_VALID_HIGH << FORCE_VBUS_VALID_SHIFT); | CLR4(sc->phy_ctrl, OTG_PHY_CFG, OTG_PHY_ROUTE_OTG); | ||||
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); | |||||
} | |||||
break; | break; | ||||
case PHY_USB_MODE_OTG: | case PHY_USB_MODE_DEVICE: | ||||
/* TODO */ | 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; | break; | ||||
default: | |||||
return (EINVAL); | |||||
} | } | ||||
bus_write_4(sc->phy_ctrl, PHY_CSR, val); | |||||
sc->mode = mode; | sc->mode = mode; | ||||
out: | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
awusbphy_probe(device_t dev) | awusbphy_probe(device_t dev) | ||||
{ | { | ||||
if (!ofw_bus_status_okay(dev)) | if (!ofw_bus_status_okay(dev)) | ||||
return (ENXIO); | return (ENXIO); | ||||
▲ Show 20 Lines • Show All 64 Lines • Show Last 20 Lines |