xref: /freebsd/sys/arm/nvidia/tegra_usbphy.c (revision f8759facd2126e067fe09f66643af75826036a1e)
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