xref: /netbsd-src/sys/arch/arm/nvidia/tegra_usbphy.c (revision 63aea4bd5b445e491ff0389fe27ec78b3099dba3)
1 /* $NetBSD: tegra_usbphy.c,v 1.4 2015/12/16 19:46:55 jmcneill Exp $ */
2 
3 /*-
4  * Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: tegra_usbphy.c,v 1.4 2015/12/16 19:46:55 jmcneill Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/bus.h>
34 #include <sys/device.h>
35 #include <sys/intr.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 
39 #include <arm/nvidia/tegra_reg.h>
40 #include <arm/nvidia/tegra_var.h>
41 #include <arm/nvidia/tegra_usbreg.h>
42 
43 #include <dev/fdt/fdtvar.h>
44 
45 /* XXX */
46 static int
47 tegra_usbphy_addr2port(bus_addr_t addr)
48 {
49 	switch (addr) {
50 	case TEGRA_AHB_A2_BASE + TEGRA_USB1_OFFSET:
51 		return 0;
52 	case TEGRA_AHB_A2_BASE + TEGRA_USB2_OFFSET:
53 		return 1;
54 	case TEGRA_AHB_A2_BASE + TEGRA_USB3_OFFSET:
55 		return 2;
56 	default:
57 		return -1;
58 	}
59 }
60 
61 static int	tegra_usbphy_match(device_t, cfdata_t, void *);
62 static void	tegra_usbphy_attach(device_t, device_t, void *);
63 
64 struct tegra_usbphy_softc {
65 	device_t		sc_dev;
66 	bus_space_tag_t		sc_bst;
67 	bus_space_handle_t	sc_bsh;
68 	int			sc_phandle;
69 	u_int			sc_port;
70 
71 	struct tegra_gpio_pin	*sc_pin_vbus;
72 	uint32_t		sc_hssync_start_delay;
73 	uint32_t		sc_idle_wait_delay;
74 	uint32_t		sc_elastic_limit;
75 	uint32_t		sc_term_range_adj;
76 	uint32_t		sc_xcvr_setup;
77 	uint32_t		sc_xcvr_lsfslew;
78 	uint32_t		sc_xcvr_lsrslew;
79 	uint32_t		sc_hssquelch_level;
80 	uint32_t		sc_hsdiscon_level;
81 	uint32_t		sc_xcvr_hsslew;
82 };
83 
84 static int	tegra_usbphy_parse_properties(struct tegra_usbphy_softc *);
85 static void	tegra_usbphy_utmip_init(struct tegra_usbphy_softc *);
86 
87 CFATTACH_DECL_NEW(tegra_usbphy, sizeof(struct tegra_usbphy_softc),
88 	tegra_usbphy_match, tegra_usbphy_attach, NULL, NULL);
89 
90 static int
91 tegra_usbphy_match(device_t parent, cfdata_t cf, void *aux)
92 {
93 	const char * const compatible[] = { "nvidia,tegra124-usb-phy", NULL };
94 	struct fdt_attach_args * const faa = aux;
95 
96 	return of_match_compatible(faa->faa_phandle, compatible);
97 }
98 
99 static void
100 tegra_usbphy_attach(device_t parent, device_t self, void *aux)
101 {
102 	struct tegra_usbphy_softc * const sc = device_private(self);
103 	struct fdt_attach_args * const faa = aux;
104 	struct fdtbus_regulator *reg;
105 	bus_addr_t addr;
106 	bus_size_t size;
107 	int error;
108 
109 	if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) {
110 		aprint_error(": couldn't get registers\n");
111 		return;
112 	}
113 
114 	sc->sc_dev = self;
115 	sc->sc_phandle = faa->faa_phandle;
116 	sc->sc_bst = faa->faa_bst;
117 	error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
118 	if (error) {
119 		aprint_error(": couldn't map %#llx: %d", (uint64_t)addr, error);
120 		return;
121 	}
122 	sc->sc_port = tegra_usbphy_addr2port(addr);
123 
124 	aprint_naive("\n");
125 	aprint_normal(": USB PHY%d\n", sc->sc_port + 1);
126 
127 	if (tegra_usbphy_parse_properties(sc) != 0)
128 		return;
129 
130 	tegra_car_periph_usb_enable(sc->sc_port);
131 	delay(2);
132 
133 	tegra_usbphy_utmip_init(sc);
134 
135 	reg = fdtbus_regulator_acquire(faa->faa_phandle, "vbus-supply");
136 	if (reg) {
137 		const uint32_t v = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
138 		    TEGRA_EHCI_PHY_VBUS_SENSORS_REG);
139 		if ((v & TEGRA_EHCI_PHY_VBUS_SENSORS_A_VBUS_VLD_STS) == 0) {
140 			fdtbus_regulator_enable(reg);
141 		} else {
142 			aprint_normal_dev(self, "VBUS input active\n");
143 		}
144         }
145 }
146 
147 static int
148 tegra_usbphy_parse_properties(struct tegra_usbphy_softc *sc)
149 {
150 #define PROPGET(k, v)							\
151 	if (of_getprop_uint32(sc->sc_phandle, (k), (v))) {		\
152 		aprint_error_dev(sc->sc_dev,				\
153 		    "missing property '%s'\n", (k));			\
154 		return EIO;						\
155 	}
156 
157 	PROPGET("nvidia,hssync-start-delay", &sc->sc_hssync_start_delay);
158 	PROPGET("nvidia,idle-wait-delay", &sc->sc_idle_wait_delay);
159 	PROPGET("nvidia,elastic-limit", &sc->sc_elastic_limit);
160 	PROPGET("nvidia,term-range-adj", &sc->sc_term_range_adj);
161 	PROPGET("nvidia,xcvr-setup", &sc->sc_xcvr_setup);
162 	PROPGET("nvidia,xcvr-lsfslew", &sc->sc_xcvr_lsfslew);
163 	PROPGET("nvidia,xcvr-lsrslew", &sc->sc_xcvr_lsrslew);
164 	PROPGET("nvidia,hssquelch-level", &sc->sc_hssquelch_level);
165 	PROPGET("nvidia,hsdiscon-level", &sc->sc_hsdiscon_level);
166 	PROPGET("nvidia,xcvr-hsslew", &sc->sc_xcvr_hsslew);
167 
168 	return 0;
169 #undef PROPGET
170 }
171 
172 static void
173 tegra_usbphy_utmip_init(struct tegra_usbphy_softc *sc)
174 {
175 	bus_space_tag_t bst = sc->sc_bst;
176 	bus_space_handle_t bsh = sc->sc_bsh;
177 	int retry;
178 
179 	/* Put UTMIP PHY into reset before programming UTMIP config registers */
180 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG,
181 	    TEGRA_EHCI_SUSP_CTRL_UTMIP_RESET, 0);
182 
183 	/* Enable UTMIP PHY mode */
184 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG,
185 	    TEGRA_EHCI_SUSP_CTRL_UTMIP_PHY_ENB, 0);
186 
187 	/* Stop crystal clock */
188 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_MISC_CFG1_REG,
189 	    0, TEGRA_EHCI_UTMIP_MISC_CFG1_PHY_XTAL_CLOCKEN);
190 	delay(1);
191 
192 	/* Clear session status */
193 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_PHY_VBUS_SENSORS_REG,
194 	    0,
195 	    TEGRA_EHCI_PHY_VBUS_SENSORS_B_VLD_SW_VALUE |
196 	    TEGRA_EHCI_PHY_VBUS_SENSORS_B_VLD_SW_EN);
197 
198 	/* PLL configuration */
199 	tegra_car_utmip_init();
200 
201 	/* Transceiver configuration */
202 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG0_REG,
203 	    __SHIFTIN(4, TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP) |
204 	    __SHIFTIN(3, TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP_MSB) |
205 	    __SHIFTIN(sc->sc_xcvr_hsslew,
206 		      TEGRA_EHCI_UTMIP_XCVR_CFG0_HSSLEW_MSB),
207 	    TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP |
208 	    TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP_MSB |
209 	    TEGRA_EHCI_UTMIP_XCVR_CFG0_HSSLEW_MSB);
210 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG1_REG,
211 	    __SHIFTIN(sc->sc_term_range_adj,
212 		      TEGRA_EHCI_UTMIP_XCVR_CFG1_TERM_RANGE_ADJ),
213 	    TEGRA_EHCI_UTMIP_XCVR_CFG1_TERM_RANGE_ADJ);
214 
215 	if (sc->sc_port == 0) {
216 		tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG0_REG,
217 		    TEGRA_EHCI_UTMIP_BIAS_CFG0_HSDISCON_LEVEL_MSB |
218 		    __SHIFTIN(sc->sc_hsdiscon_level,
219 			      TEGRA_EHCI_UTMIP_BIAS_CFG0_HSDISCON_LEVEL),
220 		    TEGRA_EHCI_UTMIP_BIAS_CFG0_HSDISCON_LEVEL);
221 	}
222 
223 	/* Misc config */
224 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_MISC_CFG0_REG,
225 	    0,
226 	    TEGRA_EHCI_UTMIP_MISC_CFG0_SUSPEND_EXIT_ON_EDGE);
227 
228 	/* BIAS cell power down lag */
229 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG1_REG,
230 	    __SHIFTIN(5, TEGRA_EHCI_UTMIP_BIAS_CFG1_PDTRK_COUNT),
231 	    TEGRA_EHCI_UTMIP_BIAS_CFG1_PDTRK_COUNT);
232 
233 	/* Debounce config */
234 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_DEBOUNCE_CFG0_REG,
235 	    __SHIFTIN(0x7530, TEGRA_EHCI_UTMIP_DEBOUNCE_CFG0_A),
236 	    TEGRA_EHCI_UTMIP_DEBOUNCE_CFG0_A);
237 
238 	/* Transmit signal preamble config */
239 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_TX_CFG0_REG,
240 	    TEGRA_EHCI_UTMIP_TX_CFG0_FS_PREAMBLE_J, 0);
241 
242 	/* Power-down battery charger circuit */
243 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BAT_CHRG_CFG0_REG,
244 	    TEGRA_EHCI_UTMIP_BAT_CHRG_CFG0_PD_CHRG, 0);
245 
246 	/* Select low speed bias method */
247 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG0_REG,
248 	    0, TEGRA_EHCI_UTMIP_XCVR_CFG0_LSBIAS_SEL);
249 
250 	/* High speed receive config */
251 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_HSRX_CFG0_REG,
252 	    __SHIFTIN(sc->sc_idle_wait_delay,
253 		      TEGRA_EHCI_UTMIP_HSRX_CFG0_IDLE_WAIT) |
254 	    __SHIFTIN(sc->sc_elastic_limit,
255 		      TEGRA_EHCI_UTMIP_HSRX_CFG0_ELASTIC_LIMIT),
256 	    TEGRA_EHCI_UTMIP_HSRX_CFG0_IDLE_WAIT |
257 	    TEGRA_EHCI_UTMIP_HSRX_CFG0_ELASTIC_LIMIT);
258 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_HSRX_CFG1_REG,
259 	    __SHIFTIN(sc->sc_hssync_start_delay,
260 		      TEGRA_EHCI_UTMIP_HSRX_CFG1_SYNC_START_DLY),
261 	    TEGRA_EHCI_UTMIP_HSRX_CFG1_SYNC_START_DLY);
262 
263 	/* Start crystal clock */
264 	delay(1);
265 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_MISC_CFG1_REG,
266 	    TEGRA_EHCI_UTMIP_MISC_CFG1_PHY_XTAL_CLOCKEN, 0);
267 
268 	/* Clear port PLL powerdown status */
269 	tegra_car_utmip_enable(sc->sc_port);
270 
271 	/* Bring UTMIP PHY out of reset */
272 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG,
273 	    0, TEGRA_EHCI_SUSP_CTRL_UTMIP_RESET);
274 	for (retry = 100000; retry > 0; retry--) {
275 		const uint32_t susp = bus_space_read_4(bst, bsh,
276 		    TEGRA_EHCI_SUSP_CTRL_REG);
277 		if (susp & TEGRA_EHCI_SUSP_CTRL_PHY_CLK_VALID)
278 			break;
279 		delay(1);
280 	}
281 	if (retry == 0) {
282 		aprint_error_dev(sc->sc_dev, "PHY clock is not valid\n");
283 		return;
284 	}
285 
286 	/* Disable ICUSB transceiver */
287 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_ICUSB_CTRL_REG,
288 	    0,
289 	    TEGRA_EHCI_ICUSB_CTRL_ENB1);
290 
291 	/* Power up UTMPI transceiver */
292 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG0_REG,
293 	    0,
294 	    TEGRA_EHCI_UTMIP_XCVR_CFG0_PD_POWERDOWN |
295 	    TEGRA_EHCI_UTMIP_XCVR_CFG0_PD2_POWERDOWN |
296 	    TEGRA_EHCI_UTMIP_XCVR_CFG0_PDZI_POWERDOWN);
297 	tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG1_REG,
298 	    0,
299 	    TEGRA_EHCI_UTMIP_XCVR_CFG1_PDDISC_POWERDOWN |
300 	    TEGRA_EHCI_UTMIP_XCVR_CFG1_PDCHRP_POWERDOWN |
301 	    TEGRA_EHCI_UTMIP_XCVR_CFG1_PDDR_POWERDOWN);
302 
303 	if (sc->sc_port == 0) {
304 		tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG0_REG,
305 		    0, TEGRA_EHCI_UTMIP_BIAS_CFG0_BIASPD);
306 		delay(25);
307 		tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG1_REG,
308 		    0, TEGRA_EHCI_UTMIP_BIAS_CFG1_PDTRK_POWERDOWN);
309 	}
310 }
311