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