The Pedigree Project  0.1
UsbUlpi.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "UsbUlpi.h"
21 #include "pedigree/kernel/Log.h"
22 #include "pedigree/kernel/process/Semaphore.h"
23 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
24 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
25 #include "pedigree/kernel/time/Time.h"
26 
28 #include <Gpio.h>
29 #include <I2C.h>
30 #include <Prcm.h>
31 
33 
34 bool usbWriteTwl4030(uint8_t addr, uint8_t data)
35 {
36  return I2C::instance(0).write(0x48, addr, data);
37 }
38 
39 uint8_t usbReadTwl4030(uint8_t addr)
40 {
41  return I2C::instance(0).read(0x48, addr);
42 }
43 
47 bool usbSetBits(uint8_t reg, uint8_t bits)
48 {
49  return usbWriteTwl4030(reg + 1, bits);
50 }
51 
53 bool usbClearBits(uint8_t reg, uint8_t bits)
54 {
55  return usbWriteTwl4030(reg + 2, bits);
56 }
57 
59 void enablePhyAccess(bool which)
60 {
61  uint8_t clock = usbReadTwl4030(0xFE);
62  if (clock)
63  {
64  if (which)
65  {
66  clock |= 1; // Request DPLL clock
67  usbWriteTwl4030(0xFE, clock);
68  while (!(usbReadTwl4030(0xFF) & 1))
69  Time::delay(10 * Time::Multiplier::MILLISECOND);
70  }
71  else
72  {
73  clock &= ~1;
74  usbWriteTwl4030(0xFE, clock);
75  }
76  }
77 }
78 
80 {
81  // Allocate the pages we need
82  if (!PhysicalMemoryManager::instance().allocateRegion(
83  m_MemRegionUHH, 1,
86  0x48064000))
87  {
88  ERROR("USB UHH_CONFIG: Couldn't get a memory region!");
89  return;
90  }
91  if (!PhysicalMemoryManager::instance().allocateRegion(
92  m_MemRegionTLL, 1,
95  0x48062000))
96  {
97  ERROR("USB TLL: Couldn't get a memory region!");
98  return;
99  }
100  if (!PhysicalMemoryManager::instance().allocateRegion(
101  m_MemRegionPCtl, 2,
104  0x48005000))
105  {
106  ERROR("USB Power Control: Couldn't get a memory region!");
107  return;
108  }
109 
110  NOTICE("Initialising USB Controller...");
111 
112  // 0x33 = LEDA, LEDB ON
113  // LEDA = nEN_USB_PWR, drives power to the USB port
114  // LEDB = PMU STAT LED on the BeagleBoard
115  uint8_t buffer[2] = {0xEE, 0x33};
116  I2C::instance(0).transmit(0x4A, reinterpret_cast<uintptr_t>(buffer), 2);
117 
118  // Enable the power configuration registers, so we can enable the voltage
119  // regulators for USB.
120  I2C::instance(0).write(0x4b, 0x44, 0xC0); // PROTECT_KEY
121  I2C::instance(0).write(0x4b, 0x44, 0x0C);
122 
123  // VUSB3V1 = active
124  I2C::instance(0).write(0x4b, VUSB_DEDICATED2, 0);
125 
126  // VUSB3V1 input = VBAT
127  I2C::instance(0).write(0x4b, VUSB_DEDICATED1, 0x14);
128 
129  // Turn on the 3.1 volt regulator
130  I2C::instance(0).write(0x4b, VUSB3V1_DEV_GRP, 0x20);
131  I2C::instance(0).write(0x4b, VUSB3V1_TYPE, 0);
132 
133  // Turn on the 1.5 volt regulator
134  I2C::instance(0).write(0x4b, VUSB1V5_DEV_GRP, 0x20);
135  I2C::instance(0).write(0x4b, VUSB1V5_TYPE, 0);
136 
137  // Turn on the 1.8 volt regulator
138  I2C::instance(0).write(0x4b, VUSB1V8_DEV_GRP, 0x20);
139  I2C::instance(0).write(0x4b, VUSB1V8_TYPE, 0);
140 
141  // Disable access to the power configuration registers... we're done
142  I2C::instance(0).write(0x4b, 0x44, 0);
143 
144  // Enable the USB PHY for all three ports
145  uint8_t power = usbReadTwl4030(0xFD);
146  power &= ~1;
147  usbWriteTwl4030(0xFD, power);
148  usbWriteTwl4030(0xFE, usbReadTwl4030(0xFE) | (1 << 2) | (1 << 1));
149 
150  // Setup ULPI
151  enablePhyAccess(true);
152  usbClearBits(InterfaceControl, 1 << 2); // Disable carkit mode
153 
154  // Set the controller as active
156  // usbClearBits(OtgControl, 2); // Disable the D+ pull-down resistor
157  usbSetBits(0xAC, 1 << 5); // Enable OTG - 0xAC = POWER_CTRL
158  usbSetBits(FunctionControl, 4); // FS termination enabled
159  usbClearBits(FunctionControl, 0x1B); // Enable the HS transceiver
160  enablePhyAccess(false);
161 
162  // Configure the DPLL5 clock
163  Prcm::instance().SelectClockPLL(4, (12 << 0) | (120 << 8));
164  Prcm::instance().SelectClockPLL(5, 1);
165  Prcm::instance().SetClockPLL(2, (7 << 4) | 7);
166  Prcm::instance().WaitPllIdleStatus(
167  2, 0, true); // Waiting for the bit to go to one
168 
169  // Configure the L3 and L4 clocks
170  Prcm::instance().SelectClockCORE(0, Prcm::L3_CLK_DIV2);
171  Prcm::instance().SelectClockCORE(2, Prcm::L3_CLK_DIV2);
172 
173  volatile uint32_t *pctl_base =
174  reinterpret_cast<volatile uint32_t *>(m_MemRegionPCtl.virtualAddress());
175  pctl_base[(0x400) / 4] = 3; // Both functional clocks enabled
176  pctl_base[(0x400 + 0x10) / 4] = 1; // Interface clock enabled
177  pctl_base[(0x400 + 0x30) / 4] =
178  0; // Disable automatic control of the interface clock enabled
179 
180  volatile uint32_t *tll_base =
181  reinterpret_cast<volatile uint32_t *>(m_MemRegionTLL.virtualAddress());
182  volatile uint8_t *ulpi_base = reinterpret_cast<volatile uint8_t *>(
183  reinterpret_cast<uintptr_t>(m_MemRegionTLL.virtualAddress()) + 0x800);
184 
185  // Perform a PHY reset
186  Gpio::instance().enableoutput(147);
187  Gpio::instance().clearpin(147);
188  Time::delay(10 * Time::Multiplier::MILLISECOND);
189 
190  // Enable the TLL clocks
191  Prcm::instance().SetFuncClockCORE(3, 2, true);
192  Prcm::instance().SetIfaceClockCORE(3, 2, true);
193 
194  // Wait for the TLL to come online - we must not access any TLL registers
195  // while it's still powering up
196  Prcm::instance().WaitCoreIdleStatus(3, 2, true);
197 
198  // Reset TLL
199  uint32_t rev = tll_base[0];
200  NOTICE(
201  "USB TLL: Revision " << Dec << ((rev >> 4) & 0xF) << "." << (rev & 0xF)
202  << Hex << ".");
203  tll_base[0x10 / 4] = 2;
204  while (!(tll_base[0x14 / 4]))
205  Time::delay(5 * Time::Multiplier::MILLISECOND);
206 
207  // Disable all IDLE modes
208  tll_base[0x10 / 4] = (1 << 2) | (1 << 3) | (1 << 8);
209 
210  volatile uint32_t *uhh_base =
211  reinterpret_cast<volatile uint32_t *>(m_MemRegionUHH.virtualAddress());
212  uint32_t uhh_version = uhh_base[0];
213  NOTICE(
214  "USB UHH: Revision " << Dec << ((uhh_version >> 4) & 0xF) << "."
215  << (uhh_version & 0xF) << Hex << ".");
216 
217  // Reset the entire USB module
218  uhh_base[0x10 / 4] = 2;
219  while (!(uhh_base[0x14 / 4]))
220  Time::delay(5 * Time::Multiplier::MILLISECOND);
221 
222  // Set up idle mode
223  uint32_t cfg = (1 << 2) | (1 << 3) | (1 << 8) | (1 << 12); // No idle
224  uhh_base[0x10 / 4] = cfg;
225 
226  // Configure ULPI bypass configuration
227  cfg = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 8) | (1 << 9) |
228  (1 << 10); // Connect all three ports, ULPI not UTMI
229  uhh_base[0x40 / 4] = cfg;
230 
231  // Restore the PHY
232  Time::delay(10 * Time::Multiplier::MILLISECOND);
233  Gpio::instance().drivepin(147);
234 }
static UsbUlpi m_Instance
Definition: UsbUlpi.h:46
static PhysicalMemoryManager & instance()
void WaitPllIdleStatus(size_t n, size_t clock, bool waitForOn)
Definition: Prcm.cc:269
void SetClockPLL(size_t n, size_t value)
Definition: Prcm.cc:335
void SelectClockPLL(size_t n, size_t value)
Definition: Prcm.cc:308
void SetFuncClockCORE(size_t n, size_t clock, bool enabled)
Definition: Prcm.cc:166
void SelectClockCORE(size_t clock, Clock which)
Definition: Prcm.cc:78
#define NOTICE(text)
Definition: Log.h:74
void WaitCoreIdleStatus(size_t n, size_t clock, bool waitForOn)
Definition: Prcm.cc:234
Definition: Log.h:136
void initialise()
Definition: UsbUlpi.cc:79
void SetIfaceClockCORE(size_t n, size_t clock, bool enabled)
Definition: Prcm.cc:200
void * virtualAddress() const
Definition: MemoryRegion.cc:39
#define ERROR(text)
Definition: Log.h:82
Definition: Log.h:138