Module Name: src Committed By: jmcneill Date: Sat Sep 9 11:58:34 UTC 2017
Modified Files: src/sys/arch/arm/sunxi: sunxi_usbphy.c Log Message: Add PHY init for OTG ports in host mode. To generate a diff of this commit: cvs rdiff -u -r1.7 -r1.8 src/sys/arch/arm/sunxi/sunxi_usbphy.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/sunxi/sunxi_usbphy.c diff -u src/sys/arch/arm/sunxi/sunxi_usbphy.c:1.7 src/sys/arch/arm/sunxi/sunxi_usbphy.c:1.8 --- src/sys/arch/arm/sunxi/sunxi_usbphy.c:1.7 Thu Sep 7 10:30:46 2017 +++ src/sys/arch/arm/sunxi/sunxi_usbphy.c Sat Sep 9 11:58:34 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sunxi_usbphy.c,v 1.7 2017/09/07 10:30:46 jmcneill Exp $ */ +/* $NetBSD: sunxi_usbphy.c,v 1.8 2017/09/09 11:58:34 jmcneill Exp $ */ /*- * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> @@ -28,7 +28,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sunxi_usbphy.c,v 1.7 2017/09/07 10:30:46 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sunxi_usbphy.c,v 1.8 2017/09/09 11:58:34 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -39,14 +39,34 @@ __KERNEL_RCSID(0, "$NetBSD: sunxi_usbphy #include <dev/fdt/fdtvar.h> -#define OTG_PHY_CFG 0x20 -#define OTG_PHY_ROUTE_OTG __BIT(0) - -#define HCI_ICR 0x00 -#define HCI_AHB_INCR8 __BIT(10) -#define HCI_AHB_INCR4 __BIT(9) -#define HCI_AHB_INCRX_ALIGN __BIT(8) -#define HCI_ULPI_BYPASS __BIT(0) +/* PHY control registers */ +#define PHYCTL_ICR 0x00 +#define PHYCTL_ICR_ID_PULLUP __BIT(17) +#define PHYCTL_ICR_DPDM_PULLUP __BIT(16) +#define PHYCTL_ICR_FORCE_ID __BITS(15,14) +#define PHYCTL_ICR_FORCE_ID_LOW 2 +#define PHYCTL_ICR_FORCE_ID_HIGH 3 +#define PHYCTL_ICR_FORCE_VBUS __BITS(13,12) +#define PHYCTL_ICR_FORCE_VBUS_LOW 2 +#define PHYCTL_ICR_FORCE_VBUS_HIGH 3 +#define PHYCTL_A10 0x04 +#define PHYCTL_A33 0x10 +#define PHYCTL_ADDR __BITS(15,8) +#define PHYCTL_DATA __BIT(7) +#define PHYCTL_OTG_CFG 0x20 +#define PHYCTL_OTG_ROUTE_OTG __BIT(0) + +/* PHY registers */ +#define PHY_RES45_CAL_EN 0x0c +#define PHY_TX_AMPLITUDE_TUNE 0x20 +#define PHY_DISCON_TH_SEL 0x2a + +/* PMU registers */ +#define PMU_CFG 0x00 +#define AHB_INCR8 __BIT(10) +#define AHB_INCR4 __BIT(9) +#define AHB_INCRX_ALIGN __BIT(8) +#define ULPI_BYPASS __BIT(0) #define PMU_UNK_H3 0x10 #define PMU_UNK_H3_CLR __BIT(1) @@ -89,16 +109,68 @@ struct sunxi_usbphy_softc { struct fdtbus_gpio_pin *sc_gpio_vbus_det; }; -#define USBPHY_READ(sc, id, reg) \ +#define PHYCTL_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, \ + (sc)->sc_bsh_phy_ctrl, (reg)) +#define PHYCTL_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, \ + (sc)->sc_bsh_phy_ctrl, (reg), (val)) +#define PMU_READ(sc, id, reg) \ bus_space_read_4((sc)->sc_bst, \ (sc)->sc_phys[(id)].phy_bsh, (reg)) -#define USBPHY_WRITE(sc, id, reg, val) \ +#define PMU_WRITE(sc, id, reg, val) \ bus_space_write_4((sc)->sc_bst, \ (sc)->sc_phys[(id)].phy_bsh, (reg), (val)) CFATTACH_DECL_NEW(sunxi_usbphy, sizeof(struct sunxi_usbphy_softc), sunxi_usbphy_match, sunxi_usbphy_attach, NULL, NULL); +static void +sunxi_usbphy_write(struct sunxi_usbphy_softc *sc, + struct sunxi_usbphy *phy, u_int bit_addr, u_int bits, + u_int len) +{ + const uint32_t usbc_mask = __BIT(phy->phy_index * 2);; + bus_size_t reg; + uint32_t val; + + switch (sc->sc_type) { + case USBPHY_A13: + case USBPHY_A31: + reg = PHYCTL_A10; + break; + case USBPHY_H3: + case USBPHY_A64: + reg = PHYCTL_A33; + break; + default: + panic("unsupported phy type"); + } + + if (reg == PHYCTL_A33) + PHYCTL_WRITE(sc, reg, 0); + + for (; len > 0; bit_addr++, bits >>= 1, len--) { + val = PHYCTL_READ(sc, reg); + val &= ~PHYCTL_ADDR; + val |= __SHIFTIN(bit_addr, PHYCTL_ADDR); + PHYCTL_WRITE(sc, reg, val); + + val = PHYCTL_READ(sc, reg); + val &= ~PHYCTL_DATA; + val |= __SHIFTIN(bits & 1, PHYCTL_DATA); + PHYCTL_WRITE(sc, reg, val); + + PHYCTL_READ(sc, reg); + val |= usbc_mask; + PHYCTL_WRITE(sc, reg, val); + + PHYCTL_READ(sc, reg); + val &= ~usbc_mask; + PHYCTL_WRITE(sc, reg, val); + } +} + static bool sunxi_usbphy_vbus_detect(struct sunxi_usbphy_softc *sc) { @@ -132,29 +204,83 @@ sunxi_usbphy_enable(device_t dev, void * { struct sunxi_usbphy_softc * const sc = device_private(dev); struct sunxi_usbphy * const phy = priv; + u_int disc_thresh; + bool phy0_reroute; uint32_t val; - if (phy->phy_index > 0) { - /* Enable passby */ - val = USBPHY_READ(sc, phy->phy_index, HCI_ICR); - val |= HCI_ULPI_BYPASS; - val |= HCI_AHB_INCR8; - val |= HCI_AHB_INCR4; - val |= HCI_AHB_INCRX_ALIGN; - USBPHY_WRITE(sc, phy->phy_index, HCI_ICR, val); + switch (sc->sc_type) { + case USBPHY_A13: + disc_thresh = 0x2; + phy0_reroute = false; + break; + case USBPHY_A31: + disc_thresh = 0x3; + phy0_reroute = false; + break; + case USBPHY_A64: + case USBPHY_H3: + disc_thresh = 0x3; + phy0_reroute = true; + break; + } + + if (phy->phy_bsh) { + /* Enable/disable passby */ + const uint32_t mask = + ULPI_BYPASS|AHB_INCR8|AHB_INCR4|AHB_INCRX_ALIGN; + val = PMU_READ(sc, phy->phy_index, PMU_CFG); + if (enable) + val |= mask; + else + val &= ~mask; + PMU_WRITE(sc, phy->phy_index, PMU_CFG, val); } switch (sc->sc_type) { case USBPHY_H3: case USBPHY_A64: - val = USBPHY_READ(sc, phy->phy_index, PMU_UNK_H3); - val &= ~PMU_UNK_H3_CLR; - USBPHY_WRITE(sc, phy->phy_index, PMU_UNK_H3, val); + if (enable && phy->phy_bsh) { + val = PMU_READ(sc, phy->phy_index, PMU_UNK_H3); + val &= ~PMU_UNK_H3_CLR; + PMU_WRITE(sc, phy->phy_index, PMU_UNK_H3, val); + } break; default: break; } + if (enable) { + if (phy->phy_index == 0) + sunxi_usbphy_write(sc, phy, PHY_RES45_CAL_EN, 0x1, 1); + sunxi_usbphy_write(sc, phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5); + sunxi_usbphy_write(sc, phy, PHY_DISCON_TH_SEL, disc_thresh, 2); + } + + if (phy->phy_index == 0) { + const uint32_t mask = + PHYCTL_ICR_ID_PULLUP|PHYCTL_ICR_DPDM_PULLUP; + val = PHYCTL_READ(sc, PHYCTL_ICR); + + if (enable) + val |= mask; + else + val &= ~mask; + + /* XXX only host mode is supported */ + val &= ~PHYCTL_ICR_FORCE_ID; + val |= __SHIFTIN(PHYCTL_ICR_FORCE_ID_LOW, PHYCTL_ICR_FORCE_ID); + val &= ~PHYCTL_ICR_FORCE_VBUS; + val |= __SHIFTIN(PHYCTL_ICR_FORCE_VBUS_HIGH, PHYCTL_ICR_FORCE_VBUS); + + PHYCTL_WRITE(sc, PHYCTL_ICR, val); + + if (phy0_reroute) { + val = PHYCTL_READ(sc, PHYCTL_OTG_CFG); + val &= ~PHYCTL_OTG_ROUTE_OTG; + PHYCTL_WRITE(sc, PHYCTL_OTG_CFG, val); + } + } + if (phy->phy_reg == NULL) return 0;