amldwusb.c revision 1.2
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 115struct amldwusb_softc { 116 struct simplebus_softc sc_sbus; 117 bus_space_tag_t sc_iot; 118 bus_space_handle_t sc_ioh; 119}; 120 121int amldwusb_match(struct device *, void *, void *); 122void amldwusb_attach(struct device *, struct device *, void *); 123 124struct cfattach amldwusb_ca = { 125 sizeof(struct amldwusb_softc), amldwusb_match, amldwusb_attach 126}; 127 128struct cfdriver amldwusb_cd = { 129 NULL, "amldwusb", DV_DULL 130}; 131 132void amldwusb_init_usb2(struct amldwusb_softc *); 133void amldwusb_init_usb3(struct amldwusb_softc *); 134void amldwusb_init_phys(struct amldwusb_softc *); 135 136int 137amldwusb_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 144void 145amldwusb_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 199void 200amldwusb_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 214void 215amldwusb_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