xref: /netbsd-src/sys/arch/arm/imx/imx23_usbphy.c (revision 94de07308fa702688d56949a9efc73b223f72255)
1*94de0730Smatt /* $Id: imx23_usbphy.c,v 1.1 2013/10/07 17:36:40 matt Exp $ */
2*94de0730Smatt 
3*94de0730Smatt /*
4*94de0730Smatt * Copyright (c) 2013 The NetBSD Foundation, Inc.
5*94de0730Smatt * All rights reserved.
6*94de0730Smatt *
7*94de0730Smatt * This code is derived from software contributed to The NetBSD Foundation
8*94de0730Smatt * by Petri Laakso.
9*94de0730Smatt *
10*94de0730Smatt * Redistribution and use in source and binary forms, with or without
11*94de0730Smatt * modification, are permitted provided that the following conditions
12*94de0730Smatt * are met:
13*94de0730Smatt * 1. Redistributions of source code must retain the above copyright
14*94de0730Smatt *    notice, this list of conditions and the following disclaimer.
15*94de0730Smatt * 2. Redistributions in binary form must reproduce the above copyright
16*94de0730Smatt *    notice, this list of conditions and the following disclaimer in the
17*94de0730Smatt *    documentation and/or other materials provided with the distribution.
18*94de0730Smatt *
19*94de0730Smatt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*94de0730Smatt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*94de0730Smatt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*94de0730Smatt * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*94de0730Smatt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*94de0730Smatt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*94de0730Smatt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*94de0730Smatt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*94de0730Smatt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*94de0730Smatt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*94de0730Smatt * POSSIBILITY OF SUCH DAMAGE.
30*94de0730Smatt */
31*94de0730Smatt 
32*94de0730Smatt #include <sys/param.h>
33*94de0730Smatt #include <sys/types.h>
34*94de0730Smatt #include <sys/bus.h>
35*94de0730Smatt #include <sys/cdefs.h>
36*94de0730Smatt #include <sys/device.h>
37*94de0730Smatt #include <sys/errno.h>
38*94de0730Smatt 
39*94de0730Smatt #include <arm/imx/imx23_usbphyreg.h>
40*94de0730Smatt #include <arm/imx/imx23var.h>
41*94de0730Smatt 
42*94de0730Smatt typedef struct usbphy_softc {
43*94de0730Smatt 	device_t sc_dev;
44*94de0730Smatt 	bus_space_tag_t sc_iot;
45*94de0730Smatt 	bus_space_handle_t sc_hdl;
46*94de0730Smatt } *usbphy_softc_t;
47*94de0730Smatt 
48*94de0730Smatt static int	usbphy_match(device_t, cfdata_t, void *);
49*94de0730Smatt static void	usbphy_attach(device_t, device_t, void *);
50*94de0730Smatt static int	usbphy_activate(device_t, enum devact);
51*94de0730Smatt 
52*94de0730Smatt static void     usbphy_reset(struct usbphy_softc *);
53*94de0730Smatt static void     usbphy_init(struct usbphy_softc *);
54*94de0730Smatt 
55*94de0730Smatt CFATTACH_DECL3_NEW(usbphy,
56*94de0730Smatt         sizeof(struct usbphy_softc),
57*94de0730Smatt         usbphy_match,
58*94de0730Smatt         usbphy_attach,
59*94de0730Smatt         NULL,
60*94de0730Smatt         usbphy_activate,
61*94de0730Smatt         NULL,
62*94de0730Smatt         NULL,
63*94de0730Smatt         0
64*94de0730Smatt );
65*94de0730Smatt 
66*94de0730Smatt #define PHY_RD(sc, reg)                                                 \
67*94de0730Smatt         bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg))
68*94de0730Smatt #define PHY_WR(sc, reg, val)                                            \
69*94de0730Smatt         bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val))
70*94de0730Smatt 
71*94de0730Smatt #define USBPHY_SOFT_RST_LOOP 455   /* At least 1 us ... */
72*94de0730Smatt 
73*94de0730Smatt static int
usbphy_match(device_t parent,cfdata_t match,void * aux)74*94de0730Smatt usbphy_match(device_t parent, cfdata_t match, void *aux)
75*94de0730Smatt {
76*94de0730Smatt 	struct apb_attach_args *aa = aux;
77*94de0730Smatt 
78*94de0730Smatt 	if ((aa->aa_addr == HW_USBPHY_BASE) && (aa->aa_size == HW_USBPHY_SIZE))
79*94de0730Smatt 		return 1;
80*94de0730Smatt 
81*94de0730Smatt 	return 0;
82*94de0730Smatt }
83*94de0730Smatt 
84*94de0730Smatt static void
usbphy_attach(device_t parent,device_t self,void * aux)85*94de0730Smatt usbphy_attach(device_t parent, device_t self, void *aux)
86*94de0730Smatt {
87*94de0730Smatt 	struct usbphy_softc *sc = device_private(self);
88*94de0730Smatt 	struct apb_attach_args *aa = aux;
89*94de0730Smatt 	static int usbphy_attached = 0;
90*94de0730Smatt 	uint32_t phy_version;
91*94de0730Smatt 
92*94de0730Smatt 	sc->sc_dev = self;
93*94de0730Smatt 	sc->sc_iot = aa->aa_iot;
94*94de0730Smatt 
95*94de0730Smatt 	if (usbphy_attached) {
96*94de0730Smatt 		aprint_error_dev(sc->sc_dev, "already attached\n");
97*94de0730Smatt 		return;
98*94de0730Smatt 	}
99*94de0730Smatt 
100*94de0730Smatt 	if (bus_space_map(sc->sc_iot, aa->aa_addr, aa->aa_size, 0,
101*94de0730Smatt 	    &sc->sc_hdl))
102*94de0730Smatt 	{
103*94de0730Smatt 		aprint_error_dev(sc->sc_dev, "Unable to map bus space\n");
104*94de0730Smatt 		return;
105*94de0730Smatt 	}
106*94de0730Smatt 
107*94de0730Smatt 	usbphy_reset(sc);
108*94de0730Smatt 	usbphy_init(sc);
109*94de0730Smatt 
110*94de0730Smatt 	phy_version = PHY_RD(sc, HW_USBPHY_VERSION);
111*94de0730Smatt         aprint_normal(": USB PHY v%" __PRIuBIT ".%" __PRIuBIT "\n",
112*94de0730Smatt             __SHIFTOUT(phy_version, HW_USBPHY_VERSION_MAJOR),
113*94de0730Smatt             __SHIFTOUT(phy_version, HW_USBPHY_VERSION_MINOR));
114*94de0730Smatt 
115*94de0730Smatt 	usbphy_attached = 1;
116*94de0730Smatt 
117*94de0730Smatt 	return;
118*94de0730Smatt }
119*94de0730Smatt 
120*94de0730Smatt static int
usbphy_activate(device_t self,enum devact act)121*94de0730Smatt usbphy_activate(device_t self, enum devact act)
122*94de0730Smatt {
123*94de0730Smatt 
124*94de0730Smatt 	return EOPNOTSUPP;
125*94de0730Smatt }
126*94de0730Smatt 
127*94de0730Smatt /*
128*94de0730Smatt  * Reset the USB PHY.
129*94de0730Smatt  *
130*94de0730Smatt  * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
131*94de0730Smatt  */
132*94de0730Smatt static void
usbphy_reset(struct usbphy_softc * sc)133*94de0730Smatt usbphy_reset(struct usbphy_softc *sc)
134*94de0730Smatt {
135*94de0730Smatt         unsigned int loop;
136*94de0730Smatt 
137*94de0730Smatt         /* Prepare for soft-reset by making sure that SFTRST is not currently
138*94de0730Smatt          * asserted. Also clear CLKGATE so we can wait for its assertion below.
139*94de0730Smatt          */
140*94de0730Smatt         PHY_WR(sc, HW_USBPHY_CTRL_CLR, HW_USBPHY_CTRL_SFTRST);
141*94de0730Smatt 
142*94de0730Smatt         /* Wait at least a microsecond for SFTRST to deassert. */
143*94de0730Smatt         loop = 0;
144*94de0730Smatt         while ((PHY_RD(sc, HW_USBPHY_CTRL) & HW_USBPHY_CTRL_SFTRST) ||
145*94de0730Smatt             (loop < USBPHY_SOFT_RST_LOOP))
146*94de0730Smatt                 loop++;
147*94de0730Smatt 
148*94de0730Smatt         /* Clear CLKGATE so we can wait for its assertion below. */
149*94de0730Smatt         PHY_WR(sc, HW_USBPHY_CTRL_CLR, HW_USBPHY_CTRL_CLKGATE);
150*94de0730Smatt 
151*94de0730Smatt         /* Soft-reset the block. */
152*94de0730Smatt         PHY_WR(sc, HW_USBPHY_CTRL_SET, HW_USBPHY_CTRL_SFTRST);
153*94de0730Smatt 
154*94de0730Smatt         /* Wait until clock is in the gated state. */
155*94de0730Smatt         while (!(PHY_RD(sc, HW_USBPHY_CTRL) & HW_USBPHY_CTRL_CLKGATE));
156*94de0730Smatt 
157*94de0730Smatt         /* Bring block out of reset. */
158*94de0730Smatt         PHY_WR(sc, HW_USBPHY_CTRL_CLR, HW_USBPHY_CTRL_SFTRST);
159*94de0730Smatt 
160*94de0730Smatt         loop = 0;
161*94de0730Smatt         while ((PHY_RD(sc, HW_USBPHY_CTRL) & HW_USBPHY_CTRL_SFTRST) ||
162*94de0730Smatt             (loop < USBPHY_SOFT_RST_LOOP))
163*94de0730Smatt                 loop++;
164*94de0730Smatt 
165*94de0730Smatt         PHY_WR(sc, HW_USBPHY_CTRL_CLR, HW_USBPHY_CTRL_CLKGATE);
166*94de0730Smatt 
167*94de0730Smatt         /* Wait until clock is in the NON-gated state. */
168*94de0730Smatt         while (PHY_RD(sc, HW_USBPHY_CTRL) & HW_USBPHY_CTRL_CLKGATE);
169*94de0730Smatt 
170*94de0730Smatt         return;
171*94de0730Smatt }
172*94de0730Smatt 
173*94de0730Smatt /*
174*94de0730Smatt  * Enable USB PHY.
175*94de0730Smatt  */
176*94de0730Smatt static void
usbphy_init(struct usbphy_softc * sc)177*94de0730Smatt usbphy_init(struct usbphy_softc *sc)
178*94de0730Smatt {
179*94de0730Smatt 	/* Disable power down bits. */
180*94de0730Smatt 	PHY_WR(sc, HW_USBPHY_PWD_CLR,
181*94de0730Smatt 	    HW_USBPHY_PWD_RXPWDRX |
182*94de0730Smatt 	    HW_USBPHY_PWD_RXPWDDIFF |
183*94de0730Smatt 	    HW_USBPHY_PWD_RXPWD1PT1 |
184*94de0730Smatt 	    HW_USBPHY_PWD_RXPWDENV |
185*94de0730Smatt 	    HW_USBPHY_PWD_TXPWDV2I |
186*94de0730Smatt 	    HW_USBPHY_PWD_TXPWDIBIAS |
187*94de0730Smatt 	    HW_USBPHY_PWD_TXPWDFS
188*94de0730Smatt 	);
189*94de0730Smatt 
190*94de0730Smatt 	/* USB PLL Power on. */
191*94de0730Smatt 	PHY_WR(sc, HW_USBPHY_IP_SET,
192*94de0730Smatt 	    HW_USBPHY_IP_PLL_POWER);
193*94de0730Smatt 
194*94de0730Smatt 	/* Wait PLL to lock to 480MHz. */
195*94de0730Smatt 	delay(10);
196*94de0730Smatt 
197*94de0730Smatt 	PHY_WR(sc, HW_USBPHY_IP_SET, HW_USBPHY_IP_PLL_LOCKED);
198*94de0730Smatt 
199*94de0730Smatt 	/* Ungate PLL clock to USB PHY. */
200*94de0730Smatt 	PHY_WR(sc, HW_USBPHY_IP_SET, HW_USBPHY_IP_EN_USB_CLKS);
201*94de0730Smatt 
202*94de0730Smatt 	return;
203*94de0730Smatt }
204