1ef2ee5d0SMichal Meloun /*- 2ef2ee5d0SMichal Meloun * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org> 3ef2ee5d0SMichal Meloun * All rights reserved. 4ef2ee5d0SMichal Meloun * 5ef2ee5d0SMichal Meloun * Redistribution and use in source and binary forms, with or without 6ef2ee5d0SMichal Meloun * modification, are permitted provided that the following conditions 7ef2ee5d0SMichal Meloun * are met: 8ef2ee5d0SMichal Meloun * 1. Redistributions of source code must retain the above copyright 9ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer. 10ef2ee5d0SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 11ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer in the 12ef2ee5d0SMichal Meloun * documentation and/or other materials provided with the distribution. 13ef2ee5d0SMichal Meloun * 14ef2ee5d0SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ef2ee5d0SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ef2ee5d0SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ef2ee5d0SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ef2ee5d0SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ef2ee5d0SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ef2ee5d0SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ef2ee5d0SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ef2ee5d0SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ef2ee5d0SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ef2ee5d0SMichal Meloun * SUCH DAMAGE. 25ef2ee5d0SMichal Meloun */ 26ef2ee5d0SMichal Meloun 27ef2ee5d0SMichal Meloun #include <sys/cdefs.h> 28ef2ee5d0SMichal Meloun __FBSDID("$FreeBSD$"); 29ef2ee5d0SMichal Meloun 30ef2ee5d0SMichal Meloun 31ef2ee5d0SMichal Meloun /* 32ef2ee5d0SMichal Meloun * USB phy driver for Tegra SoCs. 33ef2ee5d0SMichal Meloun */ 34ef2ee5d0SMichal Meloun #include <sys/param.h> 35ef2ee5d0SMichal Meloun #include <sys/systm.h> 36ef2ee5d0SMichal Meloun #include <sys/bus.h> 37ef2ee5d0SMichal Meloun #include <sys/kernel.h> 38ef2ee5d0SMichal Meloun #include <sys/module.h> 39ef2ee5d0SMichal Meloun #include <sys/malloc.h> 40ef2ee5d0SMichal Meloun #include <sys/rman.h> 41ef2ee5d0SMichal Meloun 42ef2ee5d0SMichal Meloun #include <machine/bus.h> 43ef2ee5d0SMichal Meloun #include <machine/fdt.h> 44ef2ee5d0SMichal Meloun 45ef2ee5d0SMichal Meloun #include <dev/extres/clk/clk.h> 46ef2ee5d0SMichal Meloun #include <dev/extres/hwreset/hwreset.h> 47ef2ee5d0SMichal Meloun #include <dev/extres/phy/phy.h> 48ef2ee5d0SMichal Meloun #include <dev/extres/regulator/regulator.h> 49ef2ee5d0SMichal Meloun #include <dev/fdt/fdt_pinctrl.h> 50ef2ee5d0SMichal Meloun #include <dev/ofw/openfirm.h> 51ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus.h> 52ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 53ef2ee5d0SMichal Meloun 54*f8759facSMichal Meloun #include "phynode_if.h" 55ef2ee5d0SMichal Meloun 56ef2ee5d0SMichal Meloun #define CTRL_ICUSB_CTRL 0x15c 57ef2ee5d0SMichal Meloun #define ICUSB_CTR_IC_ENB1 (1 << 3) 58ef2ee5d0SMichal Meloun 59ef2ee5d0SMichal Meloun #define CTRL_USB_USBMODE 0x1f8 60ef2ee5d0SMichal Meloun #define USB_USBMODE_MASK (3 << 0) 61ef2ee5d0SMichal Meloun #define USB_USBMODE_HOST (3 << 0) 62ef2ee5d0SMichal Meloun #define USB_USBMODE_DEVICE (2 << 0) 63ef2ee5d0SMichal Meloun 64ef2ee5d0SMichal Meloun #define CTRL_USB_HOSTPC1_DEVLC 0x1b4 65ef2ee5d0SMichal Meloun #define USB_HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29) 66ef2ee5d0SMichal Meloun #define USB_HOSTPC1_DEVLC_STS (1 << 28) 67ef2ee5d0SMichal Meloun #define USB_HOSTPC1_DEVLC_PHCD (1 << 22) 68ef2ee5d0SMichal Meloun 69ef2ee5d0SMichal Meloun 70ef2ee5d0SMichal Meloun #define IF_USB_SUSP_CTRL 0x400 71ef2ee5d0SMichal Meloun #define FAST_WAKEUP_RESP (1 << 26) 72ef2ee5d0SMichal Meloun #define UTMIP_SUSPL1_SET (1 << 25) 73ef2ee5d0SMichal Meloun #define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16) 74ef2ee5d0SMichal Meloun #define USB_SUSP_SET (1 << 14) 75ef2ee5d0SMichal Meloun #define UTMIP_PHY_ENB (1 << 12) 76ef2ee5d0SMichal Meloun #define UTMIP_RESET (1 << 11) 77ef2ee5d0SMichal Meloun #define USB_SUSP_POL (1 << 10) 78ef2ee5d0SMichal Meloun #define USB_PHY_CLK_VALID_INT_ENB (1 << 9) 79ef2ee5d0SMichal Meloun #define USB_PHY_CLK_VALID_INT_STS (1 << 8) 80ef2ee5d0SMichal Meloun #define USB_PHY_CLK_VALID (1 << 7) 81ef2ee5d0SMichal Meloun #define USB_CLKEN (1 << 6) 82ef2ee5d0SMichal Meloun #define USB_SUSP_CLR (1 << 5) 83ef2ee5d0SMichal Meloun #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) 84ef2ee5d0SMichal Meloun #define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) 85ef2ee5d0SMichal Meloun #define USB_WAKE_ON_RESUME_EN (1 << 2) 86ef2ee5d0SMichal Meloun #define USB_WAKEUP_INT_ENB (1 << 1) 87ef2ee5d0SMichal Meloun #define USB_WAKEUP_INT_STS (1 << 0) 88ef2ee5d0SMichal Meloun 89ef2ee5d0SMichal Meloun #define IF_USB_PHY_VBUS_SENSORS 0x404 90ef2ee5d0SMichal Meloun #define B_SESS_END_SW_VALUE (1 << 4) 91ef2ee5d0SMichal Meloun #define B_SESS_END_SW_EN (1 << 3) 92ef2ee5d0SMichal Meloun 93ef2ee5d0SMichal Meloun 94ef2ee5d0SMichal Meloun #define UTMIP_XCVR_CFG0 0x808 95ef2ee5d0SMichal Meloun #define UTMIP_XCVR_HSSLEW_MSB(x) ((((x) & 0x1fc) >> 2) << 25) 96ef2ee5d0SMichal Meloun #define UTMIP_XCVR_SETUP_MSB(x) ((((x) & 0x70) >> 4) << 22) 97ef2ee5d0SMichal Meloun #define UTMIP_XCVR_LSBIAS_SEL (1 << 21) 98ef2ee5d0SMichal Meloun #define UTMIP_XCVR_DISCON_METHOD (1 << 20) 99ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PDZI_POWERUP (1 << 19) 100ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18) 101ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PD2_POWERUP (1 << 17) 102ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PD2_POWERDOWN (1 << 16) 103ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PD_POWERUP (1 << 15) 104ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PD_POWERDOWN (1 << 14) 105ef2ee5d0SMichal Meloun #define UTMIP_XCVR_TERMEN (1 << 13) 106ef2ee5d0SMichal Meloun #define UTMIP_XCVR_HSLOOPBACK (1 << 12) 107ef2ee5d0SMichal Meloun #define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10) 108ef2ee5d0SMichal Meloun #define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8) 109ef2ee5d0SMichal Meloun #define UTMIP_XCVR_FSSLEW(x) (((x) & 0x3) << 6) 110ef2ee5d0SMichal Meloun #define UTMIP_XCVR_HSSLEW(x) (((x) & 0x3) << 4) 111ef2ee5d0SMichal Meloun #define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0) 112ef2ee5d0SMichal Meloun 113ef2ee5d0SMichal Meloun #define UTMIP_BIAS_CFG0 0x80C 114ef2ee5d0SMichal Meloun #define UTMIP_IDDIG_C_VAL (1 << 30) 115ef2ee5d0SMichal Meloun #define UTMIP_IDDIG_C_SEL (1 << 29) 116ef2ee5d0SMichal Meloun #define UTMIP_IDDIG_B_VAL (1 << 28) 117ef2ee5d0SMichal Meloun #define UTMIP_IDDIG_B_SEL (1 << 27) 118ef2ee5d0SMichal Meloun #define UTMIP_IDDIG_A_VAL (1 << 26) 119ef2ee5d0SMichal Meloun #define UTMIP_IDDIG_A_SEL (1 << 25) 120ef2ee5d0SMichal Meloun #define UTMIP_HSDISCON_LEVEL_MSB(x) ((((x) & 0x4) >> 2) << 24) 121ef2ee5d0SMichal Meloun #define UTMIP_IDPD_VAL (1 << 23) 122ef2ee5d0SMichal Meloun #define UTMIP_IDPD_SEL (1 << 22) 123ef2ee5d0SMichal Meloun #define UTMIP_IDDIG_VAL (1 << 21) 124ef2ee5d0SMichal Meloun #define UTMIP_IDDIG_SEL (1 << 20) 125ef2ee5d0SMichal Meloun #define UTMIP_GPI_VAL (1 << 19) 126ef2ee5d0SMichal Meloun #define UTMIP_GPI_SEL (1 << 18) 127ef2ee5d0SMichal Meloun #define UTMIP_ACTIVE_TERM_OFFSET(x) (((x) & 0x7) << 15) 128ef2ee5d0SMichal Meloun #define UTMIP_ACTIVE_PULLUP_OFFSET(x) (((x) & 0x7) << 12) 129ef2ee5d0SMichal Meloun #define UTMIP_OTGPD (1 << 11) 130ef2ee5d0SMichal Meloun #define UTMIP_BIASPD (1 << 10) 131ef2ee5d0SMichal Meloun #define UTMIP_VBUS_LEVEL_LEVEL(x) (((x) & 0x3) << 8) 132ef2ee5d0SMichal Meloun #define UTMIP_SESS_LEVEL_LEVEL(x) (((x) & 0x3) << 6) 133ef2ee5d0SMichal Meloun #define UTMIP_HSCHIRP_LEVEL(x) (((x) & 0x3) << 4) 134ef2ee5d0SMichal Meloun #define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2) 135ef2ee5d0SMichal Meloun #define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0) 136ef2ee5d0SMichal Meloun 137ef2ee5d0SMichal Meloun 138ef2ee5d0SMichal Meloun #define UTMIP_HSRX_CFG0 0x810 139ef2ee5d0SMichal Meloun #define UTMIP_KEEP_PATT_ON_ACTIVE(x) (((x) & 0x3) << 30) 140ef2ee5d0SMichal Meloun #define UTMIP_ALLOW_CONSEC_UPDN (1 << 29) 141ef2ee5d0SMichal Meloun #define UTMIP_REALIGN_ON_NEW_PKT (1 << 28) 142ef2ee5d0SMichal Meloun #define UTMIP_PCOUNT_UPDN_DIV(x) (((x) & 0xf) << 24) 143ef2ee5d0SMichal Meloun #define UTMIP_SQUELCH_EOP_DLY(x) (((x) & 0x7) << 21) 144ef2ee5d0SMichal Meloun #define UTMIP_NO_STRIPPING (1 << 20) 145ef2ee5d0SMichal Meloun #define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15) 146ef2ee5d0SMichal Meloun #define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10) 147ef2ee5d0SMichal Meloun #define UTMIP_ELASTIC_OVERRUN_DISABLE (1 << 9) 148ef2ee5d0SMichal Meloun #define UTMIP_ELASTIC_UNDERRUN_DISABLE (1 << 8) 149ef2ee5d0SMichal Meloun #define UTMIP_PASS_CHIRP (1 << 7) 150ef2ee5d0SMichal Meloun #define UTMIP_PASS_FEEDBACK (1 << 6) 151ef2ee5d0SMichal Meloun #define UTMIP_PCOUNT_INERTIA(x) (((x) & 0x3) << 4) 152ef2ee5d0SMichal Meloun #define UTMIP_PHASE_ADJUST(x) (((x) & 0x3) << 2) 153ef2ee5d0SMichal Meloun #define UTMIP_THREE_SYNCBITS (1 << 1) 154ef2ee5d0SMichal Meloun #define UTMIP_USE4SYNC_TRAN (1 << 0) 155ef2ee5d0SMichal Meloun 156ef2ee5d0SMichal Meloun #define UTMIP_HSRX_CFG1 0x814 157ef2ee5d0SMichal Meloun #define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1F) << 1) 158ef2ee5d0SMichal Meloun #define UTMIP_HS_ALLOW_KEEP_ALIVE (1 << 0) 159ef2ee5d0SMichal Meloun 160ef2ee5d0SMichal Meloun #define UTMIP_TX_CFG0 0x820 161ef2ee5d0SMichal Meloun #define UTMIP_FS_PREAMBLE_J (1 << 19) 162ef2ee5d0SMichal Meloun #define UTMIP_FS_POSTAMBLE_OUTPUT_ENABLE (1 << 18) 163ef2ee5d0SMichal Meloun #define UTMIP_FS_PREAMBLE_OUTPUT_ENABLE (1 << 17) 164ef2ee5d0SMichal Meloun #define UTMIP_FSLS_ALLOW_SOP_TX_STUFF_ERR (1 << 16) 165ef2ee5d0SMichal Meloun #define UTMIP_HS_READY_WAIT_FOR_VALID (1 << 15) 166ef2ee5d0SMichal Meloun #define UTMIP_HS_TX_IPG_DLY(x) (((x) & 0x1f) << 10) 167ef2ee5d0SMichal Meloun #define UTMIP_HS_DISCON_EOP_ONLY (1 << 9) 168ef2ee5d0SMichal Meloun #define UTMIP_HS_DISCON_DISABLE (1 << 8) 169ef2ee5d0SMichal Meloun #define UTMIP_HS_POSTAMBLE_OUTPUT_ENABLE (1 << 7) 170ef2ee5d0SMichal Meloun #define UTMIP_HS_PREAMBLE_OUTPUT_ENABLE (1 << 6) 171ef2ee5d0SMichal Meloun #define UTMIP_SIE_RESUME_ON_LINESTATE (1 << 5) 172ef2ee5d0SMichal Meloun #define UTMIP_SOF_ON_NO_STUFF (1 << 4) 173ef2ee5d0SMichal Meloun #define UTMIP_SOF_ON_NO_ENCODE (1 << 3) 174ef2ee5d0SMichal Meloun #define UTMIP_NO_STUFFING (1 << 2) 175ef2ee5d0SMichal Meloun #define UTMIP_NO_ENCODING (1 << 1) 176ef2ee5d0SMichal Meloun #define UTMIP_NO_SYNC_NO_EOP (1 << 0) 177ef2ee5d0SMichal Meloun 178ef2ee5d0SMichal Meloun #define UTMIP_MISC_CFG0 0x824 179ef2ee5d0SMichal Meloun #define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27) 180ef2ee5d0SMichal Meloun #define UTMIP_DPDM_OBSERVE (1 << 26) 181ef2ee5d0SMichal Meloun #define UTMIP_KEEP_XCVR_PD_ON_SOFT_DISCON (1 << 25) 182ef2ee5d0SMichal Meloun #define UTMIP_ALLOW_LS_ON_SOFT_DISCON (1 << 24) 183ef2ee5d0SMichal Meloun #define UTMIP_FORCE_FS_DISABLE_ON_DEV_CHIRP (1 << 23) 184ef2ee5d0SMichal Meloun #define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22) 185ef2ee5d0SMichal Meloun #define UTMIP_LS_TO_FS_SKIP_4MS (1 << 21) 186ef2ee5d0SMichal Meloun #define UTMIP_INJECT_ERROR_TYPE(x) (((x) & 0x3) << 19) 187ef2ee5d0SMichal Meloun #define UTMIP_FORCE_HS_CLOCK_ON (1 << 18) 188ef2ee5d0SMichal Meloun #define UTMIP_DISABLE_HS_TERM (1 << 17) 189ef2ee5d0SMichal Meloun #define UTMIP_FORCE_HS_TERM (1 << 16) 190ef2ee5d0SMichal Meloun #define UTMIP_DISABLE_PULLUP_DP (1 << 15) 191ef2ee5d0SMichal Meloun #define UTMIP_DISABLE_PULLUP_DM (1 << 14) 192ef2ee5d0SMichal Meloun #define UTMIP_DISABLE_PULLDN_DP (1 << 13) 193ef2ee5d0SMichal Meloun #define UTMIP_DISABLE_PULLDN_DM (1 << 12) 194ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PULLUP_DP (1 << 11) 195ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PULLUP_DM (1 << 10) 196ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PULLDN_DP (1 << 9) 197ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PULLDN_DM (1 << 8) 198ef2ee5d0SMichal Meloun #define UTMIP_STABLE_COUNT(x) (((x) & 0x7) << 5) 199ef2ee5d0SMichal Meloun #define UTMIP_STABLE_ALL (1 << 4) 200ef2ee5d0SMichal Meloun #define UTMIP_NO_FREE_ON_SUSPEND (1 << 3) 201ef2ee5d0SMichal Meloun #define UTMIP_NEVER_FREE_RUNNING_TERMS (1 << 2) 202ef2ee5d0SMichal Meloun #define UTMIP_ALWAYS_FREE_RUNNING_TERMS (1 << 1) 203ef2ee5d0SMichal Meloun #define UTMIP_COMB_TERMS (1 << 0) 204ef2ee5d0SMichal Meloun 205ef2ee5d0SMichal Meloun #define UTMIP_MISC_CFG1 0x828 206ef2ee5d0SMichal Meloun #define UTMIP_PHY_XTAL_CLOCKEN (1 << 30) 207ef2ee5d0SMichal Meloun 208ef2ee5d0SMichal Meloun #define UTMIP_DEBOUNCE_CFG0 0x82C 209ef2ee5d0SMichal Meloun #define UTMIP_BIAS_DEBOUNCE_B(x) (((x) & 0xffff) << 16) 210ef2ee5d0SMichal Meloun #define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0) 211ef2ee5d0SMichal Meloun 212ef2ee5d0SMichal Meloun #define UTMIP_BAT_CHRG_CFG0 0x830 213ef2ee5d0SMichal Meloun #define UTMIP_CHRG_DEBOUNCE_TIMESCALE(x) (((x) & 0x1f) << 8) 214ef2ee5d0SMichal Meloun #define UTMIP_OP_I_SRC_ENG (1 << 5) 215ef2ee5d0SMichal Meloun #define UTMIP_ON_SRC_ENG (1 << 4) 216ef2ee5d0SMichal Meloun #define UTMIP_OP_SRC_ENG (1 << 3) 217ef2ee5d0SMichal Meloun #define UTMIP_ON_SINK_ENG (1 << 2) 218ef2ee5d0SMichal Meloun #define UTMIP_OP_SINK_ENG (1 << 1) 219ef2ee5d0SMichal Meloun #define UTMIP_PD_CHRG (1 << 0) 220ef2ee5d0SMichal Meloun 221ef2ee5d0SMichal Meloun #define UTMIP_SPARE_CFG0 0x834 222ef2ee5d0SMichal Meloun #define FUSE_HS_IREF_CAP_CFG (1 << 7) 223ef2ee5d0SMichal Meloun #define FUSE_HS_SQUELCH_LEVEL (1 << 6) 224ef2ee5d0SMichal Meloun #define FUSE_SPARE (1 << 5) 225ef2ee5d0SMichal Meloun #define FUSE_TERM_RANGE_ADJ_SEL (1 << 4) 226ef2ee5d0SMichal Meloun #define FUSE_SETUP_SEL (1 << 3) 227ef2ee5d0SMichal Meloun #define HS_RX_LATE_SQUELCH (1 << 2) 228ef2ee5d0SMichal Meloun #define HS_RX_FLUSH_ALAP (1 << 1) 229ef2ee5d0SMichal Meloun #define HS_RX_IPG_ERROR_ENABLE (1 << 0) 230ef2ee5d0SMichal Meloun 231ef2ee5d0SMichal Meloun #define UTMIP_XCVR_CFG1 0x838 232ef2ee5d0SMichal Meloun #define UTMIP_XCVR_RPU_RANGE_ADJ(x) (((x) & 0x3) << 26) 233ef2ee5d0SMichal Meloun #define UTMIP_XCVR_HS_IREF_CAP(x) (((x) & 0x3) << 24) 234ef2ee5d0SMichal Meloun #define UTMIP_XCVR_SPARE(x) (((x) & 0x3) << 22) 235ef2ee5d0SMichal Meloun #define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18) 236ef2ee5d0SMichal Meloun #define UTMIP_RCTRL_SW_SET (1 << 17) 237ef2ee5d0SMichal Meloun #define UTMIP_RCTRL_SW_VAL(x) (((x) & 0x1f) << 12) 238ef2ee5d0SMichal Meloun #define UTMIP_TCTRL_SW_SET (1 << 11) 239ef2ee5d0SMichal Meloun #define UTMIP_TCTRL_SW_VAL(x) (((x) & 0x1f) << 6) 240ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PDDR_POWERUP (1 << 5) 241ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4) 242ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PDCHRP_POWERUP (1 << 3) 243ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2) 244ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PDDISC_POWERUP (1 << 1) 245ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0) 246ef2ee5d0SMichal Meloun 247ef2ee5d0SMichal Meloun #define UTMIP_BIAS_CFG1 0x83c 248ef2ee5d0SMichal Meloun #define UTMIP_BIAS_DEBOUNCE_TIMESCALE(x) (((x) & 0x3f) << 8) 249ef2ee5d0SMichal Meloun #define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3) 250ef2ee5d0SMichal Meloun #define UTMIP_VBUS_WAKEUP_POWERDOWN (1 << 2) 251ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PDTRK_POWERUP (1 << 1) 252ef2ee5d0SMichal Meloun #define UTMIP_FORCE_PDTRK_POWERDOWN (1 << 0) 253ef2ee5d0SMichal Meloun 254ef2ee5d0SMichal Meloun static int usbpby_enable_cnt; 255ef2ee5d0SMichal Meloun 256ef2ee5d0SMichal Meloun enum usb_ifc_type { 257ef2ee5d0SMichal Meloun USB_IFC_TYPE_UNKNOWN = 0, 258ef2ee5d0SMichal Meloun USB_IFC_TYPE_UTMI, 259ef2ee5d0SMichal Meloun USB_IFC_TYPE_ULPI 260ef2ee5d0SMichal Meloun }; 261ef2ee5d0SMichal Meloun 262ef2ee5d0SMichal Meloun enum usb_dr_mode { 263ef2ee5d0SMichal Meloun USB_DR_MODE_UNKNOWN = 0, 264ef2ee5d0SMichal Meloun USB_DR_MODE_DEVICE, 265ef2ee5d0SMichal Meloun USB_DR_MODE_HOST, 266ef2ee5d0SMichal Meloun USB_DR_MODE_OTG 267ef2ee5d0SMichal Meloun }; 268ef2ee5d0SMichal Meloun 269ef2ee5d0SMichal Meloun struct usbphy_softc { 270ef2ee5d0SMichal Meloun device_t dev; 271ef2ee5d0SMichal Meloun struct resource *mem_res; 272ef2ee5d0SMichal Meloun struct resource *pads_res; 273ef2ee5d0SMichal Meloun clk_t clk_reg; 274ef2ee5d0SMichal Meloun clk_t clk_pads; 275ef2ee5d0SMichal Meloun clk_t clk_pllu; 276ef2ee5d0SMichal Meloun regulator_t supply_vbus; 277ef2ee5d0SMichal Meloun hwreset_t reset_usb; 278ef2ee5d0SMichal Meloun hwreset_t reset_pads; 279ef2ee5d0SMichal Meloun enum usb_ifc_type ifc_type; 280ef2ee5d0SMichal Meloun enum usb_dr_mode dr_mode; 281ef2ee5d0SMichal Meloun bool have_utmi_regs; 282ef2ee5d0SMichal Meloun 283ef2ee5d0SMichal Meloun /* UTMI params */ 284ef2ee5d0SMichal Meloun int hssync_start_delay; 285ef2ee5d0SMichal Meloun int elastic_limit; 286ef2ee5d0SMichal Meloun int idle_wait_delay; 287ef2ee5d0SMichal Meloun int term_range_adj; 288ef2ee5d0SMichal Meloun int xcvr_lsfslew; 289ef2ee5d0SMichal Meloun int xcvr_lsrslew; 290ef2ee5d0SMichal Meloun int xcvr_hsslew; 291ef2ee5d0SMichal Meloun int hssquelch_level; 292ef2ee5d0SMichal Meloun int hsdiscon_level; 293ef2ee5d0SMichal Meloun int xcvr_setup; 294ef2ee5d0SMichal Meloun int xcvr_setup_use_fuses; 295ef2ee5d0SMichal Meloun }; 296ef2ee5d0SMichal Meloun 297ef2ee5d0SMichal Meloun static struct ofw_compat_data compat_data[] = { 298ef2ee5d0SMichal Meloun {"nvidia,tegra30-usb-phy", 1}, 299ef2ee5d0SMichal Meloun {NULL, 0}, 300ef2ee5d0SMichal Meloun }; 301ef2ee5d0SMichal Meloun 302*f8759facSMichal Meloun /* Phy controller class and methods. */ 303*f8759facSMichal Meloun static int usbphy_phy_enable(struct phynode *phy, bool enable); 304*f8759facSMichal Meloun static phynode_method_t usbphy_phynode_methods[] = { 305*f8759facSMichal Meloun PHYNODEMETHOD(phynode_enable, usbphy_phy_enable), 306*f8759facSMichal Meloun 307*f8759facSMichal Meloun PHYNODEMETHOD_END 308*f8759facSMichal Meloun }; 309*f8759facSMichal Meloun DEFINE_CLASS_1(usbphy_phynode, usbphy_phynode_class, usbphy_phynode_methods, 310*f8759facSMichal Meloun 0, phynode_class); 311*f8759facSMichal Meloun 312ef2ee5d0SMichal Meloun #define RD4(sc, offs) \ 313ef2ee5d0SMichal Meloun bus_read_4(sc->mem_res, offs) 314ef2ee5d0SMichal Meloun 315ef2ee5d0SMichal Meloun #define WR4(sc, offs, val) \ 316ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, offs, val) 317ef2ee5d0SMichal Meloun 318ef2ee5d0SMichal Meloun static int 319ef2ee5d0SMichal Meloun reg_wait(struct usbphy_softc *sc, uint32_t reg, uint32_t mask, uint32_t val) 320ef2ee5d0SMichal Meloun { 321ef2ee5d0SMichal Meloun int i; 322ef2ee5d0SMichal Meloun 323ef2ee5d0SMichal Meloun for (i = 0; i < 1000; i++) { 324ef2ee5d0SMichal Meloun if ((RD4(sc, reg) & mask) == val) 325ef2ee5d0SMichal Meloun return (0); 326ef2ee5d0SMichal Meloun DELAY(10); 327ef2ee5d0SMichal Meloun } 328ef2ee5d0SMichal Meloun return (ETIMEDOUT); 329ef2ee5d0SMichal Meloun } 330ef2ee5d0SMichal Meloun 331ef2ee5d0SMichal Meloun static int 332ef2ee5d0SMichal Meloun usbphy_utmi_phy_clk(struct usbphy_softc *sc, bool enable) 333ef2ee5d0SMichal Meloun { 334ef2ee5d0SMichal Meloun uint32_t val; 335ef2ee5d0SMichal Meloun int rv; 336ef2ee5d0SMichal Meloun 337ef2ee5d0SMichal Meloun val = RD4(sc, CTRL_USB_HOSTPC1_DEVLC); 338ef2ee5d0SMichal Meloun if (enable) 339ef2ee5d0SMichal Meloun val &= ~USB_HOSTPC1_DEVLC_PHCD; 340ef2ee5d0SMichal Meloun else 341ef2ee5d0SMichal Meloun val |= USB_HOSTPC1_DEVLC_PHCD; 342ef2ee5d0SMichal Meloun WR4(sc, CTRL_USB_HOSTPC1_DEVLC, val); 343ef2ee5d0SMichal Meloun 344ef2ee5d0SMichal Meloun rv = reg_wait(sc, IF_USB_SUSP_CTRL, USB_PHY_CLK_VALID, 345ef2ee5d0SMichal Meloun enable ? USB_PHY_CLK_VALID: 0); 346ef2ee5d0SMichal Meloun if (rv != 0) { 347ef2ee5d0SMichal Meloun device_printf(sc->dev, "USB phy clock timeout.\n"); 348ef2ee5d0SMichal Meloun return (ETIMEDOUT); 349ef2ee5d0SMichal Meloun } 350ef2ee5d0SMichal Meloun return (0); 351ef2ee5d0SMichal Meloun } 352ef2ee5d0SMichal Meloun 353ef2ee5d0SMichal Meloun static int 354ef2ee5d0SMichal Meloun usbphy_utmi_enable(struct usbphy_softc *sc) 355ef2ee5d0SMichal Meloun { 356ef2ee5d0SMichal Meloun int rv; 357ef2ee5d0SMichal Meloun uint32_t val; 358ef2ee5d0SMichal Meloun 359ef2ee5d0SMichal Meloun /* Reset phy */ 360ef2ee5d0SMichal Meloun val = RD4(sc, IF_USB_SUSP_CTRL); 361ef2ee5d0SMichal Meloun val |= UTMIP_RESET; 362ef2ee5d0SMichal Meloun WR4(sc, IF_USB_SUSP_CTRL, val); 363ef2ee5d0SMichal Meloun 364ef2ee5d0SMichal Meloun 365ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_TX_CFG0); 366ef2ee5d0SMichal Meloun val |= UTMIP_FS_PREAMBLE_J; 367ef2ee5d0SMichal Meloun WR4(sc, UTMIP_TX_CFG0, val); 368ef2ee5d0SMichal Meloun 369ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_HSRX_CFG0); 370ef2ee5d0SMichal Meloun val &= ~UTMIP_IDLE_WAIT(~0); 371ef2ee5d0SMichal Meloun val &= ~UTMIP_ELASTIC_LIMIT(~0); 372ef2ee5d0SMichal Meloun val |= UTMIP_IDLE_WAIT(sc->idle_wait_delay); 373ef2ee5d0SMichal Meloun val |= UTMIP_ELASTIC_LIMIT(sc->elastic_limit); 374ef2ee5d0SMichal Meloun WR4(sc, UTMIP_HSRX_CFG0, val); 375ef2ee5d0SMichal Meloun 376ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_HSRX_CFG1); 377ef2ee5d0SMichal Meloun val &= ~UTMIP_HS_SYNC_START_DLY(~0); 378ef2ee5d0SMichal Meloun val |= UTMIP_HS_SYNC_START_DLY(sc->hssync_start_delay); 379ef2ee5d0SMichal Meloun WR4(sc, UTMIP_HSRX_CFG1, val); 380ef2ee5d0SMichal Meloun 381ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_DEBOUNCE_CFG0); 382ef2ee5d0SMichal Meloun val &= ~UTMIP_BIAS_DEBOUNCE_A(~0); 383ef2ee5d0SMichal Meloun val |= UTMIP_BIAS_DEBOUNCE_A(0x7530); /* For 12MHz */ 384ef2ee5d0SMichal Meloun WR4(sc, UTMIP_DEBOUNCE_CFG0, val); 385ef2ee5d0SMichal Meloun 386ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_MISC_CFG0); 387ef2ee5d0SMichal Meloun val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE; 388ef2ee5d0SMichal Meloun WR4(sc, UTMIP_MISC_CFG0, val); 389ef2ee5d0SMichal Meloun 390ef2ee5d0SMichal Meloun if (sc->dr_mode == USB_DR_MODE_DEVICE) { 391ef2ee5d0SMichal Meloun val = RD4(sc,IF_USB_SUSP_CTRL); 392ef2ee5d0SMichal Meloun val &= ~USB_WAKE_ON_CNNT_EN_DEV; 393ef2ee5d0SMichal Meloun val &= ~USB_WAKE_ON_DISCON_EN_DEV; 394ef2ee5d0SMichal Meloun WR4(sc, IF_USB_SUSP_CTRL, val); 395ef2ee5d0SMichal Meloun 396ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_BAT_CHRG_CFG0); 397ef2ee5d0SMichal Meloun val &= ~UTMIP_PD_CHRG; 398ef2ee5d0SMichal Meloun WR4(sc, UTMIP_BAT_CHRG_CFG0, val); 399ef2ee5d0SMichal Meloun } else { 400ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_BAT_CHRG_CFG0); 401ef2ee5d0SMichal Meloun val |= UTMIP_PD_CHRG; 402ef2ee5d0SMichal Meloun WR4(sc, UTMIP_BAT_CHRG_CFG0, val); 403ef2ee5d0SMichal Meloun } 404ef2ee5d0SMichal Meloun 405ef2ee5d0SMichal Meloun usbpby_enable_cnt++; 406ef2ee5d0SMichal Meloun if (usbpby_enable_cnt == 1) { 407ef2ee5d0SMichal Meloun rv = hwreset_deassert(sc->reset_pads); 408ef2ee5d0SMichal Meloun if (rv != 0) { 409ef2ee5d0SMichal Meloun device_printf(sc->dev, 410ef2ee5d0SMichal Meloun "Cannot unreset 'utmi-pads' reset\n"); 411ef2ee5d0SMichal Meloun return (rv); 412ef2ee5d0SMichal Meloun } 413ef2ee5d0SMichal Meloun rv = clk_enable(sc->clk_pads); 414ef2ee5d0SMichal Meloun if (rv != 0) { 415ef2ee5d0SMichal Meloun device_printf(sc->dev, 416ef2ee5d0SMichal Meloun "Cannot enable 'utmi-pads' clock\n"); 417ef2ee5d0SMichal Meloun return (rv); 418ef2ee5d0SMichal Meloun } 419ef2ee5d0SMichal Meloun 420ef2ee5d0SMichal Meloun val = bus_read_4(sc->pads_res, UTMIP_BIAS_CFG0); 421ef2ee5d0SMichal Meloun val &= ~UTMIP_OTGPD; 422ef2ee5d0SMichal Meloun val &= ~UTMIP_BIASPD; 423ef2ee5d0SMichal Meloun val &= ~UTMIP_HSSQUELCH_LEVEL(~0); 424ef2ee5d0SMichal Meloun val &= ~UTMIP_HSDISCON_LEVEL(~0); 425ef2ee5d0SMichal Meloun val &= ~UTMIP_HSDISCON_LEVEL_MSB(~0); 426ef2ee5d0SMichal Meloun val |= UTMIP_HSSQUELCH_LEVEL(sc->hssquelch_level); 427ef2ee5d0SMichal Meloun val |= UTMIP_HSDISCON_LEVEL(sc->hsdiscon_level); 428ef2ee5d0SMichal Meloun val |= UTMIP_HSDISCON_LEVEL_MSB(sc->hsdiscon_level); 429ef2ee5d0SMichal Meloun bus_write_4(sc->pads_res, UTMIP_BIAS_CFG0, val); 430ef2ee5d0SMichal Meloun 431ef2ee5d0SMichal Meloun rv = clk_disable(sc->clk_pads); 432ef2ee5d0SMichal Meloun if (rv != 0) { 433ef2ee5d0SMichal Meloun device_printf(sc->dev, 434ef2ee5d0SMichal Meloun "Cannot disable 'utmi-pads' clock\n"); 435ef2ee5d0SMichal Meloun return (rv); 436ef2ee5d0SMichal Meloun } 437ef2ee5d0SMichal Meloun } 438ef2ee5d0SMichal Meloun 439ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_XCVR_CFG0); 440ef2ee5d0SMichal Meloun val &= ~UTMIP_FORCE_PD_POWERDOWN; 441ef2ee5d0SMichal Meloun val &= ~UTMIP_FORCE_PD2_POWERDOWN ; 442ef2ee5d0SMichal Meloun val &= ~UTMIP_FORCE_PDZI_POWERDOWN; 443ef2ee5d0SMichal Meloun val &= ~UTMIP_XCVR_LSBIAS_SEL; 444ef2ee5d0SMichal Meloun val &= ~UTMIP_XCVR_LSFSLEW(~0); 445ef2ee5d0SMichal Meloun val &= ~UTMIP_XCVR_LSRSLEW(~0); 446ef2ee5d0SMichal Meloun val &= ~UTMIP_XCVR_HSSLEW(~0); 447ef2ee5d0SMichal Meloun val &= ~UTMIP_XCVR_HSSLEW_MSB(~0); 448ef2ee5d0SMichal Meloun val |= UTMIP_XCVR_LSFSLEW(sc->xcvr_lsfslew); 449ef2ee5d0SMichal Meloun val |= UTMIP_XCVR_LSRSLEW(sc->xcvr_lsrslew); 450ef2ee5d0SMichal Meloun val |= UTMIP_XCVR_HSSLEW(sc->xcvr_hsslew); 451ef2ee5d0SMichal Meloun val |= UTMIP_XCVR_HSSLEW_MSB(sc->xcvr_hsslew); 452ef2ee5d0SMichal Meloun if (!sc->xcvr_setup_use_fuses) { 453ef2ee5d0SMichal Meloun val &= ~UTMIP_XCVR_SETUP(~0); 454ef2ee5d0SMichal Meloun val &= ~UTMIP_XCVR_SETUP_MSB(~0); 455ef2ee5d0SMichal Meloun val |= UTMIP_XCVR_SETUP(sc->xcvr_setup); 456ef2ee5d0SMichal Meloun val |= UTMIP_XCVR_SETUP_MSB(sc->xcvr_setup); 457ef2ee5d0SMichal Meloun } 458ef2ee5d0SMichal Meloun WR4(sc, UTMIP_XCVR_CFG0, val); 459ef2ee5d0SMichal Meloun 460ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_XCVR_CFG1); 461ef2ee5d0SMichal Meloun val &= ~UTMIP_FORCE_PDDISC_POWERDOWN; 462ef2ee5d0SMichal Meloun val &= ~UTMIP_FORCE_PDCHRP_POWERDOWN; 463ef2ee5d0SMichal Meloun val &= ~UTMIP_FORCE_PDDR_POWERDOWN; 464ef2ee5d0SMichal Meloun val &= ~UTMIP_XCVR_TERM_RANGE_ADJ(~0); 465ef2ee5d0SMichal Meloun val |= UTMIP_XCVR_TERM_RANGE_ADJ(sc->term_range_adj); 466ef2ee5d0SMichal Meloun WR4(sc, UTMIP_XCVR_CFG1, val); 467ef2ee5d0SMichal Meloun 468ef2ee5d0SMichal Meloun 469ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_BIAS_CFG1); 470ef2ee5d0SMichal Meloun val &= ~UTMIP_BIAS_PDTRK_COUNT(~0); 471ef2ee5d0SMichal Meloun val |= UTMIP_BIAS_PDTRK_COUNT(0x5); 472ef2ee5d0SMichal Meloun WR4(sc, UTMIP_BIAS_CFG1, val); 473ef2ee5d0SMichal Meloun 474ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_SPARE_CFG0); 475ef2ee5d0SMichal Meloun if (sc->xcvr_setup_use_fuses) 476ef2ee5d0SMichal Meloun val |= FUSE_SETUP_SEL; 477ef2ee5d0SMichal Meloun else 478ef2ee5d0SMichal Meloun val &= ~FUSE_SETUP_SEL; 479ef2ee5d0SMichal Meloun WR4(sc, UTMIP_SPARE_CFG0, val); 480ef2ee5d0SMichal Meloun 481ef2ee5d0SMichal Meloun val = RD4(sc, IF_USB_SUSP_CTRL); 482ef2ee5d0SMichal Meloun val |= UTMIP_PHY_ENB; 483ef2ee5d0SMichal Meloun WR4(sc, IF_USB_SUSP_CTRL, val); 484ef2ee5d0SMichal Meloun 485ef2ee5d0SMichal Meloun val = RD4(sc, IF_USB_SUSP_CTRL); 486ef2ee5d0SMichal Meloun val &= ~UTMIP_RESET; 487ef2ee5d0SMichal Meloun WR4(sc, IF_USB_SUSP_CTRL, val); 488ef2ee5d0SMichal Meloun 489ef2ee5d0SMichal Meloun usbphy_utmi_phy_clk(sc, true); 490ef2ee5d0SMichal Meloun 491ef2ee5d0SMichal Meloun val = RD4(sc, CTRL_USB_USBMODE); 492ef2ee5d0SMichal Meloun val &= ~USB_USBMODE_MASK; 493ef2ee5d0SMichal Meloun if (sc->dr_mode == USB_DR_MODE_HOST) 494ef2ee5d0SMichal Meloun val |= USB_USBMODE_HOST; 495ef2ee5d0SMichal Meloun else 496ef2ee5d0SMichal Meloun val |= USB_USBMODE_DEVICE; 497ef2ee5d0SMichal Meloun WR4(sc, CTRL_USB_USBMODE, val); 498ef2ee5d0SMichal Meloun 499ef2ee5d0SMichal Meloun val = RD4(sc, CTRL_USB_HOSTPC1_DEVLC); 500ef2ee5d0SMichal Meloun val &= ~USB_HOSTPC1_DEVLC_PTS(~0); 501ef2ee5d0SMichal Meloun val |= USB_HOSTPC1_DEVLC_PTS(0); 502ef2ee5d0SMichal Meloun WR4(sc, CTRL_USB_HOSTPC1_DEVLC, val); 503ef2ee5d0SMichal Meloun 504ef2ee5d0SMichal Meloun return (0); 505ef2ee5d0SMichal Meloun } 506ef2ee5d0SMichal Meloun 507ef2ee5d0SMichal Meloun static int 508ef2ee5d0SMichal Meloun usbphy_utmi_disable(struct usbphy_softc *sc) 509ef2ee5d0SMichal Meloun { 510ef2ee5d0SMichal Meloun int rv; 511ef2ee5d0SMichal Meloun uint32_t val; 512ef2ee5d0SMichal Meloun 513ef2ee5d0SMichal Meloun usbphy_utmi_phy_clk(sc, false); 514ef2ee5d0SMichal Meloun 515ef2ee5d0SMichal Meloun if (sc->dr_mode == USB_DR_MODE_DEVICE) { 516ef2ee5d0SMichal Meloun val = RD4(sc, IF_USB_SUSP_CTRL); 517ef2ee5d0SMichal Meloun val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); 518ef2ee5d0SMichal Meloun val |= USB_WAKE_ON_CNNT_EN_DEV; 519ef2ee5d0SMichal Meloun val |= USB_WAKEUP_DEBOUNCE_COUNT(5); 520ef2ee5d0SMichal Meloun WR4(sc, IF_USB_SUSP_CTRL, val); 521ef2ee5d0SMichal Meloun } 522ef2ee5d0SMichal Meloun 523ef2ee5d0SMichal Meloun val = RD4(sc, IF_USB_SUSP_CTRL); 524ef2ee5d0SMichal Meloun val |= UTMIP_RESET; 525ef2ee5d0SMichal Meloun WR4(sc, IF_USB_SUSP_CTRL, val); 526ef2ee5d0SMichal Meloun 527ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_BAT_CHRG_CFG0); 528ef2ee5d0SMichal Meloun val |= UTMIP_PD_CHRG; 529ef2ee5d0SMichal Meloun WR4(sc, UTMIP_BAT_CHRG_CFG0, val); 530ef2ee5d0SMichal Meloun 531ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_XCVR_CFG0); 532ef2ee5d0SMichal Meloun val |= UTMIP_FORCE_PD_POWERDOWN; 533ef2ee5d0SMichal Meloun val |= UTMIP_FORCE_PD2_POWERDOWN; 534ef2ee5d0SMichal Meloun val |= UTMIP_FORCE_PDZI_POWERDOWN; 535ef2ee5d0SMichal Meloun WR4(sc, UTMIP_XCVR_CFG0, val); 536ef2ee5d0SMichal Meloun 537ef2ee5d0SMichal Meloun val = RD4(sc, UTMIP_XCVR_CFG1); 538ef2ee5d0SMichal Meloun val |= UTMIP_FORCE_PDDISC_POWERDOWN; 539ef2ee5d0SMichal Meloun val |= UTMIP_FORCE_PDCHRP_POWERDOWN; 540ef2ee5d0SMichal Meloun val |= UTMIP_FORCE_PDDR_POWERDOWN; 541ef2ee5d0SMichal Meloun WR4(sc, UTMIP_XCVR_CFG1, val); 542ef2ee5d0SMichal Meloun 543ef2ee5d0SMichal Meloun usbpby_enable_cnt--; 544ef2ee5d0SMichal Meloun if (usbpby_enable_cnt <= 0) { 545ef2ee5d0SMichal Meloun rv = clk_enable(sc->clk_pads); 546ef2ee5d0SMichal Meloun if (rv != 0) { 547ef2ee5d0SMichal Meloun device_printf(sc->dev, 548ef2ee5d0SMichal Meloun "Cannot enable 'utmi-pads' clock\n"); 549ef2ee5d0SMichal Meloun return (rv); 550ef2ee5d0SMichal Meloun } 551ef2ee5d0SMichal Meloun val =bus_read_4(sc->pads_res, UTMIP_BIAS_CFG0); 552ef2ee5d0SMichal Meloun val |= UTMIP_OTGPD; 553ef2ee5d0SMichal Meloun val |= UTMIP_BIASPD; 554ef2ee5d0SMichal Meloun bus_write_4(sc->pads_res, UTMIP_BIAS_CFG0, val); 555ef2ee5d0SMichal Meloun 556ef2ee5d0SMichal Meloun rv = clk_disable(sc->clk_pads); 557ef2ee5d0SMichal Meloun if (rv != 0) { 558ef2ee5d0SMichal Meloun device_printf(sc->dev, 559ef2ee5d0SMichal Meloun "Cannot disable 'utmi-pads' clock\n"); 560ef2ee5d0SMichal Meloun return (rv); 561ef2ee5d0SMichal Meloun } 562ef2ee5d0SMichal Meloun } 563ef2ee5d0SMichal Meloun return (0); 564ef2ee5d0SMichal Meloun } 565ef2ee5d0SMichal Meloun 566ef2ee5d0SMichal Meloun static int 567*f8759facSMichal Meloun usbphy_phy_enable(struct phynode *phy, bool enable) 568ef2ee5d0SMichal Meloun { 569*f8759facSMichal Meloun device_t dev; 570ef2ee5d0SMichal Meloun struct usbphy_softc *sc; 571ef2ee5d0SMichal Meloun int rv = 0; 572ef2ee5d0SMichal Meloun 573*f8759facSMichal Meloun dev = phynode_get_device(phy); 574ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 575ef2ee5d0SMichal Meloun 576ef2ee5d0SMichal Meloun if (sc->ifc_type != USB_IFC_TYPE_UTMI) { 577ef2ee5d0SMichal Meloun device_printf(sc->dev, 578ef2ee5d0SMichal Meloun "Only UTMI interface is supported.\n"); 579ef2ee5d0SMichal Meloun return (ENXIO); 580ef2ee5d0SMichal Meloun } 581ef2ee5d0SMichal Meloun if (enable) 582ef2ee5d0SMichal Meloun rv = usbphy_utmi_enable(sc); 583ef2ee5d0SMichal Meloun else 584ef2ee5d0SMichal Meloun rv = usbphy_utmi_disable(sc); 585ef2ee5d0SMichal Meloun 586ef2ee5d0SMichal Meloun return (rv); 587ef2ee5d0SMichal Meloun } 588ef2ee5d0SMichal Meloun 589ef2ee5d0SMichal Meloun static enum usb_ifc_type 590ef2ee5d0SMichal Meloun usb_get_ifc_mode(device_t dev, phandle_t node, char *name) 591ef2ee5d0SMichal Meloun { 592ef2ee5d0SMichal Meloun char *tmpstr; 593ef2ee5d0SMichal Meloun int rv; 594ef2ee5d0SMichal Meloun enum usb_ifc_type ret; 595ef2ee5d0SMichal Meloun 596ef2ee5d0SMichal Meloun rv = OF_getprop_alloc(node, name, 1, (void **)&tmpstr); 597ef2ee5d0SMichal Meloun if (rv <= 0) 598ef2ee5d0SMichal Meloun return (USB_IFC_TYPE_UNKNOWN); 599ef2ee5d0SMichal Meloun 600ef2ee5d0SMichal Meloun ret = USB_IFC_TYPE_UNKNOWN; 601ef2ee5d0SMichal Meloun if (strcmp(tmpstr, "utmi") == 0) 602ef2ee5d0SMichal Meloun ret = USB_IFC_TYPE_UTMI; 603ef2ee5d0SMichal Meloun else if (strcmp(tmpstr, "ulpi") == 0) 604ef2ee5d0SMichal Meloun ret = USB_IFC_TYPE_ULPI; 605ef2ee5d0SMichal Meloun else 606ef2ee5d0SMichal Meloun device_printf(dev, "Unsupported phy type: %s\n", tmpstr); 607bebd5269SOleksandr Tymoshenko OF_prop_free(tmpstr); 608ef2ee5d0SMichal Meloun return (ret); 609ef2ee5d0SMichal Meloun } 610ef2ee5d0SMichal Meloun 611ef2ee5d0SMichal Meloun static enum usb_dr_mode 612ef2ee5d0SMichal Meloun usb_get_dr_mode(device_t dev, phandle_t node, char *name) 613ef2ee5d0SMichal Meloun { 614ef2ee5d0SMichal Meloun char *tmpstr; 615ef2ee5d0SMichal Meloun int rv; 616ef2ee5d0SMichal Meloun enum usb_dr_mode ret; 617ef2ee5d0SMichal Meloun 618ef2ee5d0SMichal Meloun rv = OF_getprop_alloc(node, name, 1, (void **)&tmpstr); 619ef2ee5d0SMichal Meloun if (rv <= 0) 620ef2ee5d0SMichal Meloun return (USB_DR_MODE_UNKNOWN); 621ef2ee5d0SMichal Meloun 622ef2ee5d0SMichal Meloun ret = USB_DR_MODE_UNKNOWN; 623ef2ee5d0SMichal Meloun if (strcmp(tmpstr, "device") == 0) 624ef2ee5d0SMichal Meloun ret = USB_DR_MODE_DEVICE; 625ef2ee5d0SMichal Meloun else if (strcmp(tmpstr, "host") == 0) 626ef2ee5d0SMichal Meloun ret = USB_DR_MODE_HOST; 627ef2ee5d0SMichal Meloun else if (strcmp(tmpstr, "otg") == 0) 628ef2ee5d0SMichal Meloun ret = USB_DR_MODE_OTG; 629ef2ee5d0SMichal Meloun else 630ef2ee5d0SMichal Meloun device_printf(dev, "Unknown dr mode: %s\n", tmpstr); 631bebd5269SOleksandr Tymoshenko OF_prop_free(tmpstr); 632ef2ee5d0SMichal Meloun return (ret); 633ef2ee5d0SMichal Meloun } 634ef2ee5d0SMichal Meloun 635ef2ee5d0SMichal Meloun static int 636ef2ee5d0SMichal Meloun usbphy_utmi_read_params(struct usbphy_softc *sc, phandle_t node) 637ef2ee5d0SMichal Meloun { 638ef2ee5d0SMichal Meloun int rv; 639ef2ee5d0SMichal Meloun 640ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "nvidia,hssync-start-delay", 641ef2ee5d0SMichal Meloun &sc->hssync_start_delay, sizeof (sc->hssync_start_delay)); 642ef2ee5d0SMichal Meloun if (rv <= 0) 643ef2ee5d0SMichal Meloun return (ENXIO); 644ef2ee5d0SMichal Meloun 645ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "nvidia,elastic-limit", 646ef2ee5d0SMichal Meloun &sc->elastic_limit, sizeof (sc->elastic_limit)); 647ef2ee5d0SMichal Meloun if (rv <= 0) 648ef2ee5d0SMichal Meloun return (ENXIO); 649ef2ee5d0SMichal Meloun 650ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "nvidia,idle-wait-delay", 651ef2ee5d0SMichal Meloun &sc->idle_wait_delay, sizeof (sc->idle_wait_delay)); 652ef2ee5d0SMichal Meloun if (rv <= 0) 653ef2ee5d0SMichal Meloun return (ENXIO); 654ef2ee5d0SMichal Meloun 655ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "nvidia,term-range-adj", 656ef2ee5d0SMichal Meloun &sc->term_range_adj, sizeof (sc->term_range_adj)); 657ef2ee5d0SMichal Meloun if (rv <= 0) 658ef2ee5d0SMichal Meloun return (ENXIO); 659ef2ee5d0SMichal Meloun 660ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "nvidia,xcvr-lsfslew", 661ef2ee5d0SMichal Meloun &sc->xcvr_lsfslew, sizeof (sc->xcvr_lsfslew)); 662ef2ee5d0SMichal Meloun if (rv <= 0) 663ef2ee5d0SMichal Meloun return (ENXIO); 664ef2ee5d0SMichal Meloun 665ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "nvidia,xcvr-lsrslew", 666ef2ee5d0SMichal Meloun &sc->xcvr_lsrslew, sizeof (sc->xcvr_lsrslew)); 667ef2ee5d0SMichal Meloun if (rv <= 0) 668ef2ee5d0SMichal Meloun return (ENXIO); 669ef2ee5d0SMichal Meloun 670ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "nvidia,xcvr-hsslew", 671ef2ee5d0SMichal Meloun &sc->xcvr_hsslew, sizeof (sc->xcvr_hsslew)); 672ef2ee5d0SMichal Meloun if (rv <= 0) 673ef2ee5d0SMichal Meloun return (ENXIO); 674ef2ee5d0SMichal Meloun 675ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "nvidia,hssquelch-level", 676ef2ee5d0SMichal Meloun &sc->hssquelch_level, sizeof (sc->hssquelch_level)); 677ef2ee5d0SMichal Meloun if (rv <= 0) 678ef2ee5d0SMichal Meloun return (ENXIO); 679ef2ee5d0SMichal Meloun 680ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "nvidia,hsdiscon-level", 681ef2ee5d0SMichal Meloun &sc->hsdiscon_level, sizeof (sc->hsdiscon_level)); 682ef2ee5d0SMichal Meloun if (rv <= 0) 683ef2ee5d0SMichal Meloun return (ENXIO); 684ef2ee5d0SMichal Meloun 685ef2ee5d0SMichal Meloun rv = OF_getproplen(node, "nvidia,xcvr-setup-use-fuses"); 686ef2ee5d0SMichal Meloun if (rv >= 1) { 687ef2ee5d0SMichal Meloun sc->xcvr_setup_use_fuses = 1; 688ef2ee5d0SMichal Meloun } else { 689ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "nvidia,xcvr-setup", 690ef2ee5d0SMichal Meloun &sc->xcvr_setup, sizeof (sc->xcvr_setup)); 691ef2ee5d0SMichal Meloun if (rv <= 0) 692ef2ee5d0SMichal Meloun return (ENXIO); 693ef2ee5d0SMichal Meloun } 694ef2ee5d0SMichal Meloun 695ef2ee5d0SMichal Meloun return (0); 696ef2ee5d0SMichal Meloun } 697ef2ee5d0SMichal Meloun 698ef2ee5d0SMichal Meloun static int 699ef2ee5d0SMichal Meloun usbphy_probe(device_t dev) 700ef2ee5d0SMichal Meloun { 701ef2ee5d0SMichal Meloun 702ef2ee5d0SMichal Meloun if (!ofw_bus_status_okay(dev)) 703ef2ee5d0SMichal Meloun return (ENXIO); 704ef2ee5d0SMichal Meloun 705ef2ee5d0SMichal Meloun if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 706ef2ee5d0SMichal Meloun return (ENXIO); 707ef2ee5d0SMichal Meloun 708ef2ee5d0SMichal Meloun device_set_desc(dev, "Tegra USB phy"); 709ef2ee5d0SMichal Meloun return (BUS_PROBE_DEFAULT); 710ef2ee5d0SMichal Meloun } 711ef2ee5d0SMichal Meloun 712ef2ee5d0SMichal Meloun static int 713ef2ee5d0SMichal Meloun usbphy_attach(device_t dev) 714ef2ee5d0SMichal Meloun { 715ef2ee5d0SMichal Meloun struct usbphy_softc *sc; 716ef2ee5d0SMichal Meloun int rid, rv; 717ef2ee5d0SMichal Meloun phandle_t node; 718*f8759facSMichal Meloun struct phynode *phynode; 719*f8759facSMichal Meloun struct phynode_init_def phy_init; 720ef2ee5d0SMichal Meloun 721ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 722ef2ee5d0SMichal Meloun sc->dev = dev; 723ef2ee5d0SMichal Meloun 724ef2ee5d0SMichal Meloun rid = 0; 725ef2ee5d0SMichal Meloun sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 726ef2ee5d0SMichal Meloun RF_ACTIVE | RF_SHAREABLE); 727ef2ee5d0SMichal Meloun if (sc->mem_res == NULL) { 728ef2ee5d0SMichal Meloun device_printf(dev, "Cannot allocate memory resources\n"); 729ef2ee5d0SMichal Meloun return (ENXIO); 730ef2ee5d0SMichal Meloun } 731ef2ee5d0SMichal Meloun 732ef2ee5d0SMichal Meloun rid = 1; 733ef2ee5d0SMichal Meloun sc->pads_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 734ef2ee5d0SMichal Meloun RF_ACTIVE | RF_SHAREABLE); 735ef2ee5d0SMichal Meloun if (sc->mem_res == NULL) { 736ef2ee5d0SMichal Meloun device_printf(dev, "Cannot allocate memory resources\n"); 737ef2ee5d0SMichal Meloun return (ENXIO); 738ef2ee5d0SMichal Meloun } 739ef2ee5d0SMichal Meloun 740ef2ee5d0SMichal Meloun node = ofw_bus_get_node(dev); 741ef2ee5d0SMichal Meloun 742dac93553SMichal Meloun rv = hwreset_get_by_ofw_name(sc->dev, 0, "usb", &sc->reset_usb); 743ef2ee5d0SMichal Meloun if (rv != 0) { 744ef2ee5d0SMichal Meloun device_printf(dev, "Cannot get 'usb' reset\n"); 745ef2ee5d0SMichal Meloun return (ENXIO); 746ef2ee5d0SMichal Meloun } 747dac93553SMichal Meloun rv = hwreset_get_by_ofw_name(sc->dev, 0, "utmi-pads", &sc->reset_pads); 748ef2ee5d0SMichal Meloun if (rv != 0) { 749ef2ee5d0SMichal Meloun device_printf(dev, "Cannot get 'utmi-pads' reset\n"); 750ef2ee5d0SMichal Meloun return (ENXIO); 751ef2ee5d0SMichal Meloun } 752ef2ee5d0SMichal Meloun 753dac93553SMichal Meloun rv = clk_get_by_ofw_name(sc->dev, 0, "reg", &sc->clk_reg); 754ef2ee5d0SMichal Meloun if (rv != 0) { 755ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot get 'reg' clock\n"); 756ef2ee5d0SMichal Meloun return (ENXIO); 757ef2ee5d0SMichal Meloun } 758dac93553SMichal Meloun rv = clk_get_by_ofw_name(sc->dev, 0, "pll_u", &sc->clk_pllu); 759ef2ee5d0SMichal Meloun if (rv != 0) { 760ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot get 'pll_u' clock\n"); 761ef2ee5d0SMichal Meloun return (ENXIO); 762ef2ee5d0SMichal Meloun } 763dac93553SMichal Meloun rv = clk_get_by_ofw_name(sc->dev, 0, "utmi-pads", &sc->clk_pads); 764ef2ee5d0SMichal Meloun if (rv != 0) { 765ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot get 'utmi-pads' clock\n"); 766ef2ee5d0SMichal Meloun return (ENXIO); 767ef2ee5d0SMichal Meloun } 768ef2ee5d0SMichal Meloun 769ef2ee5d0SMichal Meloun rv = hwreset_deassert(sc->reset_usb); 770ef2ee5d0SMichal Meloun if (rv != 0) { 771ef2ee5d0SMichal Meloun device_printf(dev, "Cannot unreset 'usb' reset\n"); 772ef2ee5d0SMichal Meloun return (ENXIO); 773ef2ee5d0SMichal Meloun } 774ef2ee5d0SMichal Meloun 775ef2ee5d0SMichal Meloun rv = clk_enable(sc->clk_pllu); 776ef2ee5d0SMichal Meloun if (rv != 0) { 777ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot enable 'pllu' clock\n"); 778ef2ee5d0SMichal Meloun return (ENXIO); 779ef2ee5d0SMichal Meloun } 780ef2ee5d0SMichal Meloun rv = clk_enable(sc->clk_reg); 781ef2ee5d0SMichal Meloun if (rv != 0) { 782ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot enable 'reg' clock\n"); 783ef2ee5d0SMichal Meloun return (ENXIO); 784ef2ee5d0SMichal Meloun } 785ef2ee5d0SMichal Meloun if (OF_hasprop(node, "nvidia,has-utmi-pad-registers")) 786ef2ee5d0SMichal Meloun sc->have_utmi_regs = true; 787ef2ee5d0SMichal Meloun 788ef2ee5d0SMichal Meloun sc->dr_mode = usb_get_dr_mode(dev, node, "dr_mode"); 789ef2ee5d0SMichal Meloun if (sc->dr_mode == USB_DR_MODE_UNKNOWN) 790ef2ee5d0SMichal Meloun sc->dr_mode = USB_DR_MODE_HOST; 791ef2ee5d0SMichal Meloun 792ef2ee5d0SMichal Meloun sc->ifc_type = usb_get_ifc_mode(dev, node, "phy_type"); 793ef2ee5d0SMichal Meloun 794ef2ee5d0SMichal Meloun /* We supports only utmi phy mode for now .... */ 795ef2ee5d0SMichal Meloun if (sc->ifc_type != USB_IFC_TYPE_UTMI) { 796ef2ee5d0SMichal Meloun device_printf(dev, "Unsupported phy type\n"); 797ef2ee5d0SMichal Meloun return (ENXIO); 798ef2ee5d0SMichal Meloun } 799ef2ee5d0SMichal Meloun rv = usbphy_utmi_read_params(sc, node); 800ef2ee5d0SMichal Meloun if (rv < 0) 801ef2ee5d0SMichal Meloun return rv; 802ef2ee5d0SMichal Meloun 803ef2ee5d0SMichal Meloun if (OF_hasprop(node, "vbus-supply")) { 804dac93553SMichal Meloun rv = regulator_get_by_ofw_property(sc->dev, 0, "vbus-supply", 805ef2ee5d0SMichal Meloun &sc->supply_vbus); 806ef2ee5d0SMichal Meloun if (rv != 0) { 807ef2ee5d0SMichal Meloun device_printf(sc->dev, 808ef2ee5d0SMichal Meloun "Cannot get \"vbus\" regulator\n"); 809ef2ee5d0SMichal Meloun return (ENXIO); 810ef2ee5d0SMichal Meloun } 811ef2ee5d0SMichal Meloun rv = regulator_enable(sc->supply_vbus); 812ef2ee5d0SMichal Meloun if (rv != 0) { 813ef2ee5d0SMichal Meloun device_printf(sc->dev, 814ef2ee5d0SMichal Meloun "Cannot enable \"vbus\" regulator\n"); 815ef2ee5d0SMichal Meloun return (rv); 816ef2ee5d0SMichal Meloun } 817ef2ee5d0SMichal Meloun } 818ef2ee5d0SMichal Meloun 819*f8759facSMichal Meloun /* Create and register phy. */ 820*f8759facSMichal Meloun bzero(&phy_init, sizeof(phy_init)); 821*f8759facSMichal Meloun phy_init.id = 1; 822*f8759facSMichal Meloun phy_init.ofw_node = node; 823*f8759facSMichal Meloun phynode = phynode_create(dev, &usbphy_phynode_class, &phy_init); 824*f8759facSMichal Meloun if (phynode == NULL) { 825*f8759facSMichal Meloun device_printf(sc->dev, "Cannot create phy\n"); 826*f8759facSMichal Meloun return (ENXIO); 827*f8759facSMichal Meloun } 828*f8759facSMichal Meloun if (phynode_register(phynode) == NULL) { 829*f8759facSMichal Meloun device_printf(sc->dev, "Cannot create phy\n"); 830*f8759facSMichal Meloun return (ENXIO); 831*f8759facSMichal Meloun } 832*f8759facSMichal Meloun 833ef2ee5d0SMichal Meloun return (0); 834ef2ee5d0SMichal Meloun } 835ef2ee5d0SMichal Meloun 836ef2ee5d0SMichal Meloun static int 837ef2ee5d0SMichal Meloun usbphy_detach(device_t dev) 838ef2ee5d0SMichal Meloun { 839ef2ee5d0SMichal Meloun 840ef2ee5d0SMichal Meloun /* This device is always present. */ 841ef2ee5d0SMichal Meloun return (EBUSY); 842ef2ee5d0SMichal Meloun } 843ef2ee5d0SMichal Meloun 844ef2ee5d0SMichal Meloun static device_method_t tegra_usbphy_methods[] = { 845ef2ee5d0SMichal Meloun /* Device interface */ 846ef2ee5d0SMichal Meloun DEVMETHOD(device_probe, usbphy_probe), 847ef2ee5d0SMichal Meloun DEVMETHOD(device_attach, usbphy_attach), 848ef2ee5d0SMichal Meloun DEVMETHOD(device_detach, usbphy_detach), 849ef2ee5d0SMichal Meloun 850ef2ee5d0SMichal Meloun DEVMETHOD_END 851ef2ee5d0SMichal Meloun }; 852ef2ee5d0SMichal Meloun 853ef2ee5d0SMichal Meloun static devclass_t tegra_usbphy_devclass; 8544bda238aSMichal Meloun static DEFINE_CLASS_0(usbphy, tegra_usbphy_driver, tegra_usbphy_methods, 8554bda238aSMichal Meloun sizeof(struct usbphy_softc)); 856ef2ee5d0SMichal Meloun EARLY_DRIVER_MODULE(tegra_usbphy, simplebus, tegra_usbphy_driver, 8574bda238aSMichal Meloun tegra_usbphy_devclass, NULL, NULL, 79); 858