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