1 /* $OpenBSD: amldwusb.c,v 1.1 2019/08/29 17:20:03 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_regulator.h> 32 #include <dev/ofw/fdt.h> 33 34 /* Glue registers. */ 35 36 #define U2P_R0(i) (0x00 + (i) * 0x20) 37 #define U2P_R0_HOST_DEVICE (1 << 0) 38 #define U2P_R0_POWER_OK (1 << 1) 39 #define U2P_R0_HAST_MODE (1 << 2) 40 #define U2P_R0_POWER_ON_RESET (1 << 3) 41 #define U2P_R0_ID_PULLUP (1 << 4) 42 #define U2P_R0_DRV_VBUS (1 << 5) 43 #define U2P_R1(i) (0x04 + (i) * 0x20) 44 #define U2P_R1_PHY_READY (1 << 0) 45 #define U2P_R1_ID_DIG (1 << 1) 46 #define U2P_R1_OTG_SESSION_VALID (1 << 2) 47 #define U2P_R1_VBUS_VALID (1 << 3) 48 49 #define USB_R0 0x80 50 #define USB_R0_P30_LANE0_TX2RX_LOOPBACK (1 << 17) 51 #define USB_R0_P30_LANE0_EXT_PCLK_REQ (1 << 18) 52 #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK (0x3ff << 19) 53 #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_SHIFT 19 54 #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK (0x3 << 29) 55 #define USB_R0_U2D_SS_SCALEDOWN_MODE_SHIFT 29 56 #define USB_R0_U2D_ACT (1U << 31) 57 #define USB_R1 0x84 58 #define USB_R1_U3H_BIGENDIAN_GS (1 << 0) 59 #define USB_R1_U3H_PME_ENABLE (1 << 1) 60 #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK (0x7 << 2) 61 #define USB_R1_U3H_HUB_PORT_OVERCURRENT_SHIFT 2 62 #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK (0x7 << 7) 63 #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_SHIFT 7 64 #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK (0x3 << 12) 65 #define USB_R1_U3H_HOST_U2_PORT_DISABLE_SHIFT 12 66 #define USB_R1_U3H_HOST_U3_PORT_DISABLE (1 << 16) 67 #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT (1 << 17) 68 #define USB_R1_U3H_HOST_MSI_ENABLE (1 << 18) 69 #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK (0x3f << 19) 70 #define USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT 19 71 #define USB_R1_P30_PCS_TX_SWING_FULL_MASK (0x7f << 25) 72 #define USB_R1_P30_PCS_TX_SWING_FULL_SHIFT 25 73 #define USB_R2 0x88 74 #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK (0x3f << 20) 75 #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_SHIFT 20 76 #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK (0x3f << 26) 77 #define USB_R2_P30_PCS_TX_DEEMPH_6DB_SHIFT 26 78 #define USB_R3 0x8c 79 #define USB_R3_P30_SSC_ENABLE (1 << 0) 80 #define USB_R3_P30_SSC_RANGE_MASK (0x7 << 1) 81 #define USB_R3_P30_SSC_RANGE_SHIFT 1 82 #define USB_R3_P30_SSC_REF_CLK_SEL_MASK (0x1ff << 4) 83 #define USB_R3_P30_SSC_REF_CLK_SEL_SHIFT 4 84 #define USB_R3_P30_REF_SSP_EN (1 << 13) 85 #define USB_R4 0x90 86 #define USB_R4_P21_PORT_RESET_0 (1 << 0) 87 #define USB_R4_P21_SLEEP_M0 (1 << 1) 88 #define USB_R4_MEM_PD_MASK (0x3 << 2) 89 #define USB_R4_MEM_PD_SHIFT 2 90 #define USB_R4_P21_ONLY (1 << 4) 91 #define USB_R5 0x94 92 #define USB_R5_ID_DIG_SYNC (1 << 0) 93 #define USB_R5_ID_DIG_REG (1 << 1) 94 #define USB_R5_ID_DIG_CFG_MASK (0x3 << 2) 95 #define USB_R5_ID_DIG_CFG_SHIFT 2 96 #define USB_R5_ID_DIG_EN_0 (1 << 4) 97 #define USB_R5_ID_DIG_EN_1 (1 << 5) 98 #define USB_R5_ID_DIG_CURR (1 << 6) 99 #define USB_R5_ID_DIG_IRQ (1 << 7) 100 #define USB_R5_ID_DIG_TH_MASK (0xff << 8) 101 #define USB_R5_ID_DIG_TH_SHIFT 8 102 #define USB_R5_ID_DIG_CNT_MASK (0xff << 16) 103 #define USB_R5_ID_DIG_CNT_SHIFT 16 104 105 #define HREAD4(sc, reg) \ 106 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 107 #define HWRITE4(sc, reg, val) \ 108 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 109 #define HSET4(sc, reg, bits) \ 110 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 111 #define HCLR4(sc, reg, bits) \ 112 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 113 114 struct amldwusb_softc { 115 struct simplebus_softc sc_sbus; 116 bus_space_tag_t sc_iot; 117 bus_space_handle_t sc_ioh; 118 }; 119 120 int amldwusb_match(struct device *, void *, void *); 121 void amldwusb_attach(struct device *, struct device *, void *); 122 123 struct cfattach amldwusb_ca = { 124 sizeof(struct amldwusb_softc), amldwusb_match, amldwusb_attach 125 }; 126 127 struct cfdriver amldwusb_cd = { 128 NULL, "amldwusb", DV_DULL 129 }; 130 131 void amldwusb_init_usb2(struct amldwusb_softc *); 132 void amldwusb_init_usb3(struct amldwusb_softc *); 133 void amldwusb_init_phys(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 clock_enable_all(faa->fa_node); 164 165 reset_assert_all(faa->fa_node); 166 delay(10); 167 reset_deassert_all(faa->fa_node); 168 169 vbus_supply = OF_getpropint(faa->fa_node, "vbus-supply", 0); 170 if (vbus_supply) 171 regulator_enable(vbus_supply); 172 173 amldwusb_init_usb2(sc); 174 175 reg = HREAD4(sc, USB_R1); 176 reg &= ~USB_R1_U3H_FLADJ_30MHZ_REG_MASK; 177 reg |= (0x20 << USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT); 178 HWRITE4(sc, USB_R1, reg); 179 180 HSET4(sc, USB_R5, USB_R5_ID_DIG_EN_0); 181 HSET4(sc, USB_R5, USB_R5_ID_DIG_EN_1); 182 reg = HREAD4(sc, USB_R5); 183 reg &= ~USB_R5_ID_DIG_TH_MASK; 184 reg |= (0xff << USB_R5_ID_DIG_TH_SHIFT); 185 HWRITE4(sc, USB_R5, reg); 186 187 amldwusb_init_usb3(sc); 188 189 /* Initialize PHYs. */ 190 phy_enable(faa->fa_node, "usb2-phy0"); 191 phy_enable(faa->fa_node, "usb2-phy1"); 192 phy_enable(faa->fa_node, "usb3-phy0"); 193 194 simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa); 195 } 196 197 void 198 amldwusb_init_usb2(struct amldwusb_softc *sc) 199 { 200 int i; 201 202 for (i = 0; i < 3; i++) { 203 HSET4(sc, U2P_R0(i), U2P_R0_POWER_ON_RESET); 204 205 /* We don't support device mode, so always force host mode. */ 206 HSET4(sc, U2P_R0(i), U2P_R0_HOST_DEVICE); 207 208 HCLR4(sc, U2P_R0(i), U2P_R0_POWER_ON_RESET); 209 } 210 } 211 212 void 213 amldwusb_init_usb3(struct amldwusb_softc *sc) 214 { 215 uint32_t reg; 216 217 reg = HREAD4(sc, USB_R3); 218 reg &= ~USB_R3_P30_SSC_RANGE_MASK; 219 reg |= USB_R3_P30_SSC_ENABLE; 220 reg |= (2 << USB_R3_P30_SSC_RANGE_SHIFT); 221 reg |= USB_R3_P30_REF_SSP_EN; 222 HWRITE4(sc, USB_R3, reg); 223 224 delay(2); 225 226 reg = HREAD4(sc, USB_R2); 227 reg &= ~USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK; 228 reg |= (0x15 << USB_R2_P30_PCS_TX_DEEMPH_3P5DB_SHIFT); 229 HWRITE4(sc, USB_R2, reg); 230 reg = HREAD4(sc, USB_R2); 231 reg &= ~USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK; 232 reg |= (0x15 << USB_R2_P30_PCS_TX_DEEMPH_6DB_SHIFT); 233 HWRITE4(sc, USB_R2, reg); 234 235 delay(2); 236 237 HSET4(sc, USB_R1, USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT); 238 reg = HREAD4(sc, USB_R1); 239 reg &= ~USB_R1_P30_PCS_TX_SWING_FULL_MASK; 240 reg |= (0x7f << USB_R1_P30_PCS_TX_SWING_FULL_SHIFT); 241 HWRITE4(sc, USB_R1, reg); 242 } 243