1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <device/mmio.h>
5 #include <console/console.h>
32 check_member(utmip_ctlr
, pmc_wakeup
, 0x84c - 0x800);
39 u32 txbuf
; /* 0x010 */
42 u16 ehci_caplen
; /* 0x100 */
47 u32 dci_version
; /* 0x120 */
51 u32 ehci_usbcmd
; /* 0x130 */
55 u32 _rsv3
; /* 0x140 */
56 u32 ehci_periodic_base
;
59 u32 burst_size
; /* 0x150 */
63 u32 ulpi_viewport
; /* 0x160 */
72 u32 ep_nak
; /* 0x200 */
81 u32 suspend_ctrl
; /* 0x400 */
87 u32 interpacket_delay
;
95 struct utmip_ctlr utmip
; /* 0x800 */
97 check_member(usb_ctlr
, utmip
, 0x800);
100 * Tegra EHCI controllers need their usb_mode, lpm_ctrl and tx_fill_tuning
101 * registers initialized after every EHCI reset and before any other actions
102 * (such as Run/Stop bit) are taken. We reset the controller here, set those
103 * registers and rely on the fact that libpayload doesn't reset EHCI controllers
104 * on initialization for whatever weird reason. This is ugly, fragile, and I
105 * really don't like it, but making this work will require an ugly hack one way
106 * or another so we might as well take the path of least resistance for now.
108 static void usb_ehci_reset_and_prepare(struct usb_ctlr
*usb
, enum usb_phy_type type
)
112 write32(&usb
->ehci_usbcmd
, 1 << 1); /* Host Controller Reset */
113 /* TODO: Resets are long, find way to parallelize... or just use XHCI */
114 while (--timeout
&& (read32(&usb
->ehci_usbcmd
) & 1 << 1))
115 /* wait for HC to reset */;
118 printk(BIOS_ERR
, "EHCI(%p) reset timeout", usb
);
122 /* Controller mode: HOST */
123 write32(&usb
->usb_mode
, 3 << 0);
124 /* Parallel transceiver selct */
125 write32(&usb
->lpm_ctrl
, type
<< 29);
126 /* Tx FIFO Burst thresh */
127 write32(&usb
->tx_fill_tuning
, 0x10 << 16);
130 /* Assume USBx clocked, out of reset, UTMI+ PLL set up, SAMP_x out of pwrdn */
131 void usb_setup_utmip(void *usb_base
)
133 struct usb_ctlr
*usb
= (struct usb_ctlr
*)usb_base
;
135 /* KHz formulas were guessed from U-Boot constants. Formats unclear. */
136 int khz
= clock_get_pll_input_khz();
138 /* Stop UTMI+ crystal clock while we mess with its settings */
139 clrbits32(&usb
->utmip
.misc1
, 1 << 30); /* PHY_XTAL_CLKEN */
142 /* Take stuff out of pwrdn and add some magic numbers from U-Boot */
143 write32(&usb
->utmip
.xcvr0
,
144 0x8 << 25 | /* HS slew rate [10:4] */
145 0x3 << 22 | /* HS driver output 'SETUP' [6:4] */
146 0 << 21 | /* LS bias selection */
147 0 << 18 | /* PDZI pwrdn */
148 0 << 16 | /* PD2 pwrdn */
149 0 << 14 | /* PD pwrdn */
150 1 << 13 | /* (rst) HS receiver terminations */
151 0x1 << 10 | /* (rst) LS falling slew rate */
152 0x1 << 8 | /* (rst) LS rising slew rate */
153 0x4 << 0); /* HS driver output 'SETUP' [3:0] */
154 write32(&usb
->utmip
.xcvr1
,
155 0x7 << 18 | /* Termination range adjustment */
156 0 << 4 | /* PDDR pwrdn */
157 0 << 2 | /* PDCHRP pwrdn */
158 0 << 0); /* PDDISC pwrdn */
159 write32(&usb
->utmip
.tx
,
160 1 << 19 | /* FS send initial J before sync(?) */
161 1 << 16 | /* (rst) Allow stuff error on SoP */
162 1 << 9); /* (rst) Check disc only on EoP */
163 write32(&usb
->utmip
.hsrx0
,
164 0x2 << 30 | /* (rst) Keep pattern on active */
165 1 << 28 | /* (rst) Realign inertia on pkt */
166 0x0 << 24 | /* (rst) edges-1 to move sampling */
167 0x3 << 21 | /* (rst) squelch delay on EoP */
168 0x11 << 15 | /* cycles until IDLE */
169 0x10 << 10); /* elastic input depth */
171 /* U-Boot claims the USBD values for these are used across all UTMI+
172 * PHYs. That sounds so horribly wrong that I'm not going to implement
173 * it, but keep it in mind if we're ever not using the USBD port. */
174 write32(&usb
->utmip
.bias0
,
175 0x1 << 24 | /* HS disconnect detect level [2] */
176 1 << 23 | /* (rst) IDPD value */
177 1 << 22 | /* (rst) IDPD select */
178 1 << 11 | /* (rst) OTG pwrdn */
179 0 << 10 | /* bias pwrdn */
180 0x1 << 2 | /* HS disconnect detect level [1:0] */
181 0x2 << 0); /* HS squelch detect level */
183 write32(&usb
->utmip
.bias1
,
184 khz
/ 2200 << 3 | /* bias pwrdn cycles (20us?) */
185 1 << 2 | /* (rst) VBUS wakeup pwrdn */
186 0 << 0); /* PDTRK pwrdn */
188 write32(&usb
->utmip
.debounce
,
189 0xffff << 16 | /* (rst) */
190 25 * khz
/ 10 << 0); /* TODO: what's this, really? */
193 setbits32(&usb
->utmip
.misc1
, 1 << 30); /* PHY_XTAL_CLKEN */
195 write32(&usb
->suspend_ctrl
,
196 1 << 12 | /* UTMI+ enable */
197 0 << 11); /* UTMI+ reset */
199 usb_ehci_reset_and_prepare(usb
, USB_PHY_UTMIP
);
200 printk(BIOS_DEBUG
, "USB controller @ %p set up with UTMI+ PHY\n",usb_base
);