blob: 39477e17d39e3a92a70b7f6a150970748ad60361 [file] [log] [blame]
Hung-Te Lin2fc3b622013-10-21 21:43:03 +08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2013 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <delay.h>
21#include <arch/io.h>
22#include <console/console.h>
23#include <soc/clock.h>
24
25#include "usb.h"
26
27/* Assume USBx clocked, out of reset, UTMI+ PLL set up, SAMP_x out of pwrdn */
28void usb_setup_utmip(struct usb_ctlr *usb)
29{
30 /* KHz formulas were guessed from U-Boot constants. Formats unclear. */
31 int khz = clock_get_osc_khz();
32
33 /* Stop UTMI+ crystal clock while we mess with its settings */
34 clrbits_le32(&usb->utmip.misc1, 1 << 30); /* PHY_XTAL_CLKEN */
35 udelay(1);
36
37 /* Take stuff out of pwrdn and add some magic numbers from U-Boot */
38 write32(0x8 << 25 | /* HS slew rate [10:4] */
39 0x3 << 22 | /* HS driver output 'SETUP' [6:4] */
40 0 << 21 | /* LS bias selection */
41 0 << 18 | /* PDZI pwrdn */
42 0 << 16 | /* PD2 pwrdn */
43 0 << 14 | /* PD pwrdn */
44 1 << 13 | /* (rst) HS receiver terminations */
45 0x1 << 10 | /* (rst) LS falling slew rate */
46 0x1 << 8 | /* (rst) LS rising slew rate */
47 0x4 << 0 | /* HS driver output 'SETUP' [3:0] */
48 0, &usb->utmip.xcvr0);
49 write32(0x7 << 18 | /* Termination range adjustment */
50 0 << 4 | /* PDDR pwrdn */
51 0 << 2 | /* PDCHRP pwrdn */
52 0 << 0 | /* PDDISC pwrdn */
53 0, &usb->utmip.xcvr1);
54 write32(1 << 19 | /* FS send initial J before sync(?) */
55 1 << 16 | /* (rst) Allow stuff error on SoP */
56 1 << 9 | /* (rst) Check disc only on EoP */
57 0, &usb->utmip.tx);
58 write32(0x2 << 30 | /* (rst) Keep pattern on active */
59 1 << 28 | /* (rst) Realign inertia on pkt */
60 0x1 << 24 | /* (rst) edges-1 to move sampling */
61 0x3 << 21 | /* (rst) squelch delay on EoP */
62 0x11 << 15 | /* cycles until IDLE */
63 0x10 << 10 | /* elastic input depth */
64 0, &usb->utmip.hsrx0);
65
66 /* U-Boot claims the USBD values for these are used across all UTMI+
67 * PHYs. That sounds so horribly wrong that I'm not going to implement
68 * it, but keep it in mind if we're ever not using the USBD port. */
69 write32(0x1 << 24 | /* HS disconnect detect level [2] */
70 1 << 23 | /* (rst) IDPD value */
71 1 << 22 | /* (rst) IDPD select */
72 1 << 11 | /* (rst) OTG pwrdn */
73 0 << 10 | /* bias pwrdn */
74 0x1 << 2 | /* HS disconnect detect level [1:0] */
75 0x2 << 0 | /* HS squelch detect level */
76 0, &usb->utmip.bias0);
77
78 write32(khz / 2200 << 3 | /* bias pwrdn cycles (20us?) */
79 1 << 2 | /* (rst) VBUS wakeup pwrdn */
80 0 << 0 | /* PDTRK pwrdn */
81 0, &usb->utmip.bias1);
82
83 write32(0xffff << 16 | /* (rst) */
84 25 * khz / 10 << 0 | /* TODO: what's this, really? */
85 0, &usb->utmip.debounce);
86
87 udelay(1);
88 setbits_le32(&usb->utmip.misc1, 1 << 30); /* PHY_XTAL_CLKEN */
89
90 write32(1 << 12 | /* UTMI+ enable */
91 0 << 11 | /* UTMI+ reset */
92 0, &usb->suspend_ctrl);
93}
94
95/*
Julius Werneredf6b572013-10-25 17:49:26 -070096 * Tegra EHCI controllers need their usb_mode, lpm_ctrl and tx_fill_tuning
97 * registers initialized after every EHCI reset and before any other actions
98 * (such as Run/Stop bit) are taken. We reset the controller here, set those
99 * registers and rely on the fact that libpayload doesn't reset EHCI controllers
100 * on initialization for whatever weird reason. This is ugly, fragile, and I
101 * really don't like it, but making this work will require an ugly hack one way
102 * or another so we might as well take the path of least resistance for now.
Hung-Te Lin2fc3b622013-10-21 21:43:03 +0800103 */
104void usb_ehci_reset_and_prepare(struct usb_ctlr *usb, enum usb_phy_type type)
105{
106 int timeout = 1000;
107
108 write32(1 << 1, &usb->ehci_usbcmd); /* Host Controller Reset */
109 /* TODO: Resets are long, find way to parallelize... or just use XHCI */
110 while (--timeout && (read32(&usb->ehci_usbcmd) & 1 << 1))
111 /* wait for HC to reset */;
112
113 if (!timeout) {
114 printk(BIOS_ERR, "ERROR: EHCI(%p) reset timeout", usb);
115 return;
116 }
117
118 write32(3 << 0, &usb->usb_mode); /* Controller mode: HOST */
119 write32(type << 29, &usb->lpm_ctrl); /* Parallel transceiver selct */
Julius Werneredf6b572013-10-25 17:49:26 -0700120 write32(0x10 << 16, &usb->tx_fill_tuning); /* Tx FIFO Burst thresh */
Hung-Te Lin2fc3b622013-10-21 21:43:03 +0800121}