1/* $OpenBSD: amlusbphy.c,v 1.4 2024/05/13 01:15:50 jsg 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 22#include <machine/intr.h> 23#include <machine/bus.h> 24#include <machine/fdt.h> 25 26#include <dev/ofw/openfirm.h> 27#include <dev/ofw/ofw_clock.h> 28#include <dev/ofw/ofw_misc.h> 29#include <dev/ofw/ofw_regulator.h> 30#include <dev/ofw/fdt.h> 31 32/* Registers */ 33#define PHY_R3 0x0c 34#define PHY_R3_SQUELCH_REF_SHIFT 0 35#define PHY_R3_HDISC_REF_SHIFT 2 36#define PHY_R3_DISC_THRESH_SHIFT 4 37#define PHY_R4 0x10 38#define PHY_R4_CALIB_CODE_SHIFT 0 39#define PHY_R4_TEST_BYPASS_MODE_EN (1 << 27) 40#define PHY_R4_I_C2L_BIAS_TRIM_SHIFT 28 41#define PHY_R13 0x34 42#define PHY_R13_UPDATE_PMA_SIGNALS (1 << 15) 43#define PHY_R13_MIN_COUNT_FOR_SYNC_DET_SHIFT 16 44#define PHY_R14 0x38 45#define PHY_R16 0x40 46#define PHY_R16_MPLL_M_SHIFT 0 47#define PHY_R16_MPLL_N_SHIFT 10 48#define PHY_R16_MPLL_LOAD (1 << 22) 49#define PHY_R16_MPLL_LOCK_LONG_SHIFT 24 50#define PHY_R16_MPLL_FAST_LOCK (1 << 27) 51#define PHY_R16_MPLL_EN (1 << 28) 52#define PHY_R16_MPLL_RESET (1 << 29) 53#define PHY_R17 0x44 54#define PHY_R17_MPLL_FRAC_IN_SHIFT 0 55#define PHY_R17_MPLL_LAMBDA1_SHIFT 17 56#define PHY_R17_MPLL_LAMBDA0_SHIFT 20 57#define PHY_R17_MPLL_FILTER_PVT2_SHIFT 24 58#define PHY_R17_MPLL_FILTER_PVT1_SHIFT 28 59#define PHY_R18 0x48 60#define PHY_R18_MPLL_LKW_SEL_SHIFT 0 61#define PHY_R18_MPLL_LK_W_SHIFT 2 62#define PHY_R18_MPLL_LK_S_SHIFT 6 63#define PHY_R18_MPLL_PFD_GAIN_SHIFT 14 64#define PHY_R18_MPLL_ROU_SHIFT 16 65#define PHY_R18_MPLL_DATA_SEL_SHIFT 19 66#define PHY_R18_MPLL_BIAS_ADJ_SHIFT 22 67#define PHY_R18_MPLL_BB_MODE_SHIFT 24 68#define PHY_R18_MPLL_ALPHA_SHIFT 26 69#define PHY_R18_MPLL_ADJ_LDO_SHIFT 29 70#define PHY_R18_MPLL_ACG_RANGE (1U << 31) 71#define PHY_R20 0x50 72#define PHY_R20_USB2_ITG_VBUS_TRIM_SHIFT 1 73#define PHY_R20_USB2_OTG_VBUSDET_EN (1 << 4) 74#define PHY_R20_USB2_DMON_SEL_SHIFT 9 75#define PHY_R20_USB2_EDGE_DRV_EN (1 << 13) 76#define PHY_R20_USB2_EDGE_DRV_TRIM_SHIFT 14 77#define PHY_R20_USB2_BGR_ADJ_SHIFT 16 78#define PHY_R20_USB2_BGR_VREF_SHIFT 24 79#define PHY_R20_USB2_BGR_DBG_SHIFT 29 80#define PHY_R21 0x54 81#define PHY_R21_USB2_OTG_ACA_EN (1 << 2) 82 83#define HREAD4(sc, reg) \ 84 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 85#define HWRITE4(sc, reg, val) \ 86 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 87#define HSET4(sc, reg, bits) \ 88 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 89#define HCLR4(sc, reg, bits) \ 90 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 91 92struct amlusbphy_softc { 93 struct device sc_dev; 94 bus_space_tag_t sc_iot; 95 bus_space_handle_t sc_ioh; 96 97 struct phy_device sc_pd; 98}; 99 100int amlusbphy_match(struct device *, void *, void *); 101void amlusbphy_attach(struct device *, struct device *, void *); 102 103const struct cfattach amlusbphy_ca = { 104 sizeof (struct amlusbphy_softc), amlusbphy_match, amlusbphy_attach 105}; 106 107struct cfdriver amlusbphy_cd = { 108 NULL, "amlusbphy", DV_DULL 109}; 110 111int amlusbphy_enable(void *, uint32_t *); 112 113int 114amlusbphy_match(struct device *parent, void *match, void *aux) 115{ 116 struct fdt_attach_args *faa = aux; 117 118 return OF_is_compatible(faa->fa_node, "amlogic,g12a-usb2-phy"); 119} 120 121void 122amlusbphy_attach(struct device *parent, struct device *self, void *aux) 123{ 124 struct amlusbphy_softc *sc = (struct amlusbphy_softc *)self; 125 struct fdt_attach_args *faa = aux; 126 127 if (faa->fa_nreg < 1) { 128 printf(": no registers\n"); 129 return; 130 } 131 132 sc->sc_iot = faa->fa_iot; 133 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 134 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 135 printf(": can't map registers\n"); 136 return; 137 } 138 139 printf("\n"); 140 141 sc->sc_pd.pd_node = faa->fa_node; 142 sc->sc_pd.pd_cookie = sc; 143 sc->sc_pd.pd_enable = amlusbphy_enable; 144 phy_register(&sc->sc_pd); 145} 146 147int 148amlusbphy_enable(void *cookie, uint32_t *cells) 149{ 150 struct amlusbphy_softc *sc = cookie; 151 int node = sc->sc_pd.pd_node; 152 uint32_t phy_supply; 153 154 clock_enable_all(node); 155 156 reset_assert_all(node); 157 delay(10); 158 reset_deassert_all(node); 159 delay(1000); 160 161 phy_supply = OF_getpropint(node, "phy-supply", 0); 162 if (phy_supply) 163 regulator_enable(phy_supply); 164 165 HCLR4(sc, PHY_R21, PHY_R21_USB2_OTG_ACA_EN); 166 167 /* Set PLL to 480 MHz. */ 168 HWRITE4(sc, PHY_R16, (20 << PHY_R16_MPLL_M_SHIFT) | 169 (1 << PHY_R16_MPLL_N_SHIFT) | PHY_R16_MPLL_LOAD | 170 (1 << PHY_R16_MPLL_LOCK_LONG_SHIFT) | PHY_R16_MPLL_FAST_LOCK | 171 PHY_R16_MPLL_EN | PHY_R16_MPLL_RESET); 172 HWRITE4(sc, PHY_R17, (0 << PHY_R17_MPLL_FRAC_IN_SHIFT) | 173 (7 << PHY_R17_MPLL_LAMBDA0_SHIFT) | 174 (7 << PHY_R17_MPLL_LAMBDA1_SHIFT) | 175 (9 << PHY_R17_MPLL_FILTER_PVT1_SHIFT) | 176 (2 << PHY_R17_MPLL_FILTER_PVT2_SHIFT)); 177 HWRITE4(sc, PHY_R18, (1 << PHY_R18_MPLL_LKW_SEL_SHIFT) | 178 (9 << PHY_R18_MPLL_LK_W_SHIFT) | (39 << PHY_R18_MPLL_LK_S_SHIFT) | 179 (1 << PHY_R18_MPLL_PFD_GAIN_SHIFT) | 180 (7 << PHY_R18_MPLL_ROU_SHIFT) | 181 (3 << PHY_R18_MPLL_DATA_SEL_SHIFT) | 182 (1 << PHY_R18_MPLL_BIAS_ADJ_SHIFT) | 183 (0 << PHY_R18_MPLL_BB_MODE_SHIFT) | 184 (3 << PHY_R18_MPLL_ALPHA_SHIFT) | 185 (1 << PHY_R18_MPLL_ADJ_LDO_SHIFT) | 186 PHY_R18_MPLL_ACG_RANGE); 187 delay(100); 188 HWRITE4(sc, PHY_R16, (20 << PHY_R16_MPLL_M_SHIFT) | 189 (1 << PHY_R16_MPLL_N_SHIFT) | PHY_R16_MPLL_LOAD | 190 (1 << PHY_R16_MPLL_LOCK_LONG_SHIFT) | PHY_R16_MPLL_FAST_LOCK | 191 PHY_R16_MPLL_EN); 192 193 /* Tune PHY. */ 194 HWRITE4(sc, PHY_R20, (4 << PHY_R20_USB2_ITG_VBUS_TRIM_SHIFT) | 195 PHY_R20_USB2_OTG_VBUSDET_EN | (15 << PHY_R20_USB2_DMON_SEL_SHIFT) | 196 PHY_R20_USB2_EDGE_DRV_EN | 197 (3 << PHY_R20_USB2_EDGE_DRV_TRIM_SHIFT) | 198 (0 << PHY_R20_USB2_BGR_ADJ_SHIFT) | 199 (0 << PHY_R20_USB2_BGR_VREF_SHIFT) | 200 (0 << PHY_R20_USB2_BGR_DBG_SHIFT)); 201 HWRITE4(sc, PHY_R4, (0xfff << PHY_R4_CALIB_CODE_SHIFT) | 202 PHY_R4_TEST_BYPASS_MODE_EN | 203 (0 << PHY_R4_I_C2L_BIAS_TRIM_SHIFT)); 204 205 /* Tune disconnect threshold. */ 206 HWRITE4(sc, PHY_R3, (0 << PHY_R3_SQUELCH_REF_SHIFT) | 207 (1 << PHY_R3_HDISC_REF_SHIFT) | (3 << PHY_R3_DISC_THRESH_SHIFT)); 208 209 /* Analog settings. */ 210 HWRITE4(sc, PHY_R14, 0); 211 HWRITE4(sc, PHY_R13, PHY_R13_UPDATE_PMA_SIGNALS | 212 (7 << PHY_R13_MIN_COUNT_FOR_SYNC_DET_SHIFT)); 213 214 return 0; 215} 216