1 /* $OpenBSD: amldwusb.c,v 1.2 2020/05/18 10:41:29 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2019 Mark kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/malloc.h> 22 23 #include <machine/bus.h> 24 #include <machine/fdt.h> 25 26 #include <arm64/dev/simplebusvar.h> 27 28 #include <dev/ofw/openfirm.h> 29 #include <dev/ofw/ofw_clock.h> 30 #include <dev/ofw/ofw_misc.h> 31 #include <dev/ofw/ofw_power.h> 32 #include <dev/ofw/ofw_regulator.h> 33 #include <dev/ofw/fdt.h> 34 35 /* Glue registers. */ 36 37 #define U2P_R0(i) (0x00 + (i) * 0x20) 38 #define U2P_R0_HOST_DEVICE (1 << 0) 39 #define U2P_R0_POWER_OK (1 << 1) 40 #define U2P_R0_HAST_MODE (1 << 2) 41 #define U2P_R0_POWER_ON_RESET (1 << 3) 42 #define U2P_R0_ID_PULLUP (1 << 4) 43 #define U2P_R0_DRV_VBUS (1 << 5) 44 #define U2P_R1(i) (0x04 + (i) * 0x20) 45 #define U2P_R1_PHY_READY (1 << 0) 46 #define U2P_R1_ID_DIG (1 << 1) 47 #define U2P_R1_OTG_SESSION_VALID (1 << 2) 48 #define U2P_R1_VBUS_VALID (1 << 3) 49 50 #define USB_R0 0x80 51 #define USB_R0_P30_LANE0_TX2RX_LOOPBACK (1 << 17) 52 #define USB_R0_P30_LANE0_EXT_PCLK_REQ (1 << 18) 53 #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK (0x3ff << 19) 54 #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_SHIFT 19 55 #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK (0x3 << 29) 56 #define USB_R0_U2D_SS_SCALEDOWN_MODE_SHIFT 29 57 #define USB_R0_U2D_ACT (1U << 31) 58 #define USB_R1 0x84 59 #define USB_R1_U3H_BIGENDIAN_GS (1 << 0) 60 #define USB_R1_U3H_PME_ENABLE (1 << 1) 61 #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK (0x7 << 2) 62 #define USB_R1_U3H_HUB_PORT_OVERCURRENT_SHIFT 2 63 #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK (0x7 << 7) 64 #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_SHIFT 7 65 #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK (0x3 << 12) 66 #define USB_R1_U3H_HOST_U2_PORT_DISABLE_SHIFT 12 67 #define USB_R1_U3H_HOST_U3_PORT_DISABLE (1 << 16) 68 #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT (1 << 17) 69 #define USB_R1_U3H_HOST_MSI_ENABLE (1 << 18) 70 #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK (0x3f << 19) 71 #define USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT 19 72 #define USB_R1_P30_PCS_TX_SWING_FULL_MASK (0x7f << 25) 73 #define USB_R1_P30_PCS_TX_SWING_FULL_SHIFT 25 74 #define USB_R2 0x88 75 #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK (0x3f << 20) 76 #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_SHIFT 20 77 #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK (0x3f << 26) 78 #define USB_R2_P30_PCS_TX_DEEMPH_6DB_SHIFT 26 79 #define USB_R3 0x8c 80 #define USB_R3_P30_SSC_ENABLE (1 << 0) 81 #define USB_R3_P30_SSC_RANGE_MASK (0x7 << 1) 82 #define USB_R3_P30_SSC_RANGE_SHIFT 1 83 #define USB_R3_P30_SSC_REF_CLK_SEL_MASK (0x1ff << 4) 84 #define USB_R3_P30_SSC_REF_CLK_SEL_SHIFT 4 85 #define USB_R3_P30_REF_SSP_EN (1 << 13) 86 #define USB_R4 0x90 87 #define USB_R4_P21_PORT_RESET_0 (1 << 0) 88 #define USB_R4_P21_SLEEP_M0 (1 << 1) 89 #define USB_R4_MEM_PD_MASK (0x3 << 2) 90 #define USB_R4_MEM_PD_SHIFT 2 91 #define USB_R4_P21_ONLY (1 << 4) 92 #define USB_R5 0x94 93 #define USB_R5_ID_DIG_SYNC (1 << 0) 94 #define USB_R5_ID_DIG_REG (1 << 1) 95 #define USB_R5_ID_DIG_CFG_MASK (0x3 << 2) 96 #define USB_R5_ID_DIG_CFG_SHIFT 2 97 #define USB_R5_ID_DIG_EN_0 (1 << 4) 98 #define USB_R5_ID_DIG_EN_1 (1 << 5) 99 #define USB_R5_ID_DIG_CURR (1 << 6) 100 #define USB_R5_ID_DIG_IRQ (1 << 7) 101 #define USB_R5_ID_DIG_TH_MASK (0xff << 8) 102 #define USB_R5_ID_DIG_TH_SHIFT 8 103 #define USB_R5_ID_DIG_CNT_MASK (0xff << 16) 104 #define USB_R5_ID_DIG_CNT_SHIFT 16 105 106 #define HREAD4(sc, reg) \ 107 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 108 #define HWRITE4(sc, reg, val) \ 109 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 110 #define HSET4(sc, reg, bits) \ 111 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 112 #define HCLR4(sc, reg, bits) \ 113 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 114 115 struct amldwusb_softc { 116 struct simplebus_softc sc_sbus; 117 bus_space_tag_t sc_iot; 118 bus_space_handle_t sc_ioh; 119 }; 120 121 int amldwusb_match(struct device *, void *, void *); 122 void amldwusb_attach(struct device *, struct device *, void *); 123 124 struct cfattach amldwusb_ca = { 125 sizeof(struct amldwusb_softc), amldwusb_match, amldwusb_attach 126 }; 127 128 struct cfdriver amldwusb_cd = { 129 NULL, "amldwusb", DV_DULL 130 }; 131 132 void amldwusb_init_usb2(struct amldwusb_softc *); 133 void amldwusb_init_usb3(struct amldwusb_softc *); 134 void amldwusb_init_phys(struct amldwusb_softc *); 135 136 int 137 amldwusb_match(struct device *parent, void *match, void *aux) 138 { 139 struct fdt_attach_args *faa = aux; 140 141 return OF_is_compatible(faa->fa_node, "amlogic,meson-g12a-usb-ctrl"); 142 } 143 144 void 145 amldwusb_attach(struct device *parent, struct device *self, void *aux) 146 { 147 struct amldwusb_softc *sc = (struct amldwusb_softc *)self; 148 struct fdt_attach_args *faa = aux; 149 uint32_t vbus_supply; 150 uint32_t reg; 151 152 if (faa->fa_nreg < 1) { 153 printf(": no registers\n"); 154 return; 155 } 156 157 sc->sc_iot = faa->fa_iot; 158 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 159 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 160 printf(": can't map registers\n"); 161 return; 162 } 163 164 power_domain_enable(faa->fa_node); 165 clock_enable_all(faa->fa_node); 166 167 reset_assert_all(faa->fa_node); 168 delay(10); 169 reset_deassert_all(faa->fa_node); 170 171 vbus_supply = OF_getpropint(faa->fa_node, "vbus-supply", 0); 172 if (vbus_supply) 173 regulator_enable(vbus_supply); 174 175 amldwusb_init_usb2(sc); 176 177 reg = HREAD4(sc, USB_R1); 178 reg &= ~USB_R1_U3H_FLADJ_30MHZ_REG_MASK; 179 reg |= (0x20 << USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT); 180 HWRITE4(sc, USB_R1, reg); 181 182 HSET4(sc, USB_R5, USB_R5_ID_DIG_EN_0); 183 HSET4(sc, USB_R5, USB_R5_ID_DIG_EN_1); 184 reg = HREAD4(sc, USB_R5); 185 reg &= ~USB_R5_ID_DIG_TH_MASK; 186 reg |= (0xff << USB_R5_ID_DIG_TH_SHIFT); 187 HWRITE4(sc, USB_R5, reg); 188 189 amldwusb_init_usb3(sc); 190 191 /* Initialize PHYs. */ 192 phy_enable(faa->fa_node, "usb2-phy0"); 193 phy_enable(faa->fa_node, "usb2-phy1"); 194 phy_enable(faa->fa_node, "usb3-phy0"); 195 196 simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa); 197 } 198 199 void 200 amldwusb_init_usb2(struct amldwusb_softc *sc) 201 { 202 int i; 203 204 for (i = 0; i < 3; i++) { 205 HSET4(sc, U2P_R0(i), U2P_R0_POWER_ON_RESET); 206 207 /* We don't support device mode, so always force host mode. */ 208 HSET4(sc, U2P_R0(i), U2P_R0_HOST_DEVICE); 209 210 HCLR4(sc, U2P_R0(i), U2P_R0_POWER_ON_RESET); 211 } 212 } 213 214 void 215 amldwusb_init_usb3(struct amldwusb_softc *sc) 216 { 217 uint32_t reg; 218 219 reg = HREAD4(sc, USB_R3); 220 reg &= ~USB_R3_P30_SSC_RANGE_MASK; 221 reg |= USB_R3_P30_SSC_ENABLE; 222 reg |= (2 << USB_R3_P30_SSC_RANGE_SHIFT); 223 reg |= USB_R3_P30_REF_SSP_EN; 224 HWRITE4(sc, USB_R3, reg); 225 226 delay(2); 227 228 reg = HREAD4(sc, USB_R2); 229 reg &= ~USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK; 230 reg |= (0x15 << USB_R2_P30_PCS_TX_DEEMPH_3P5DB_SHIFT); 231 HWRITE4(sc, USB_R2, reg); 232 reg = HREAD4(sc, USB_R2); 233 reg &= ~USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK; 234 reg |= (0x15 << USB_R2_P30_PCS_TX_DEEMPH_6DB_SHIFT); 235 HWRITE4(sc, USB_R2, reg); 236 237 delay(2); 238 239 HSET4(sc, USB_R1, USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT); 240 reg = HREAD4(sc, USB_R1); 241 reg &= ~USB_R1_P30_PCS_TX_SWING_FULL_MASK; 242 reg |= (0x7f << USB_R1_P30_PCS_TX_SWING_FULL_SHIFT); 243 HWRITE4(sc, USB_R1, reg); 244 } 245