1 /* $OpenBSD: amldwusb.c,v 1.4 2021/10/24 17:52:26 mpi 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 const 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 135 int 136 amldwusb_match(struct device *parent, void *match, void *aux) 137 { 138 struct fdt_attach_args *faa = aux; 139 140 return OF_is_compatible(faa->fa_node, "amlogic,meson-g12a-usb-ctrl"); 141 } 142 143 void 144 amldwusb_attach(struct device *parent, struct device *self, void *aux) 145 { 146 struct amldwusb_softc *sc = (struct amldwusb_softc *)self; 147 struct fdt_attach_args *faa = aux; 148 uint32_t vbus_supply; 149 uint32_t reg; 150 151 if (faa->fa_nreg < 1) { 152 printf(": no registers\n"); 153 return; 154 } 155 156 sc->sc_iot = faa->fa_iot; 157 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 158 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 159 printf(": can't map registers\n"); 160 return; 161 } 162 163 power_domain_enable(faa->fa_node); 164 clock_enable_all(faa->fa_node); 165 166 reset_assert_all(faa->fa_node); 167 delay(10); 168 reset_deassert_all(faa->fa_node); 169 170 vbus_supply = OF_getpropint(faa->fa_node, "vbus-supply", 0); 171 if (vbus_supply) 172 regulator_enable(vbus_supply); 173 174 amldwusb_init_usb2(sc); 175 176 reg = HREAD4(sc, USB_R1); 177 reg &= ~USB_R1_U3H_FLADJ_30MHZ_REG_MASK; 178 reg |= (0x20 << USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT); 179 HWRITE4(sc, USB_R1, reg); 180 181 HSET4(sc, USB_R5, USB_R5_ID_DIG_EN_0); 182 HSET4(sc, USB_R5, USB_R5_ID_DIG_EN_1); 183 reg = HREAD4(sc, USB_R5); 184 reg &= ~USB_R5_ID_DIG_TH_MASK; 185 reg |= (0xff << USB_R5_ID_DIG_TH_SHIFT); 186 HWRITE4(sc, USB_R5, reg); 187 188 /* Initialize PHYs. */ 189 phy_enable(faa->fa_node, "usb2-phy0"); 190 phy_enable(faa->fa_node, "usb2-phy1"); 191 192 /* Only enable USB 3.0 logic and PHY if we have one. */ 193 if (OF_getindex(faa->fa_node, "usb3-phy0", "phy-names") >= 0) { 194 amldwusb_init_usb3(sc); 195 phy_enable(faa->fa_node, "usb3-phy0"); 196 } 197 198 simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa); 199 } 200 201 void 202 amldwusb_init_usb2(struct amldwusb_softc *sc) 203 { 204 int i; 205 206 for (i = 0; i < 3; i++) { 207 HSET4(sc, U2P_R0(i), U2P_R0_POWER_ON_RESET); 208 209 /* We don't support device mode, so always force host mode. */ 210 HSET4(sc, U2P_R0(i), U2P_R0_HOST_DEVICE); 211 212 HCLR4(sc, U2P_R0(i), U2P_R0_POWER_ON_RESET); 213 } 214 } 215 216 void 217 amldwusb_init_usb3(struct amldwusb_softc *sc) 218 { 219 uint32_t reg; 220 221 reg = HREAD4(sc, USB_R3); 222 reg &= ~USB_R3_P30_SSC_RANGE_MASK; 223 reg |= USB_R3_P30_SSC_ENABLE; 224 reg |= (2 << USB_R3_P30_SSC_RANGE_SHIFT); 225 reg |= USB_R3_P30_REF_SSP_EN; 226 HWRITE4(sc, USB_R3, reg); 227 228 delay(2); 229 230 reg = HREAD4(sc, USB_R2); 231 reg &= ~USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK; 232 reg |= (0x15 << USB_R2_P30_PCS_TX_DEEMPH_3P5DB_SHIFT); 233 HWRITE4(sc, USB_R2, reg); 234 reg = HREAD4(sc, USB_R2); 235 reg &= ~USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK; 236 reg |= (0x15 << USB_R2_P30_PCS_TX_DEEMPH_6DB_SHIFT); 237 HWRITE4(sc, USB_R2, reg); 238 239 delay(2); 240 241 HSET4(sc, USB_R1, USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT); 242 reg = HREAD4(sc, USB_R1); 243 reg &= ~USB_R1_P30_PCS_TX_SWING_FULL_MASK; 244 reg |= (0x7f << USB_R1_P30_PCS_TX_SWING_FULL_SHIFT); 245 HWRITE4(sc, USB_R1, reg); 246 } 247