1/** @file
2
3  The UHCI register operation routines.
4
5Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
6This program and the accompanying materials
7are licensed and made available under the terms and conditions of the BSD License
8which accompanies this distribution.  The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14**/
15
16#include "Uhci.h"
17
18
19/**
20  Read a UHCI register.
21
22  @param  PciIo        The EFI_PCI_IO_PROTOCOL to use.
23  @param  Offset       Register offset to USB_BAR_INDEX.
24
25  @return Content of register.
26
27**/
28UINT16
29UhciReadReg (
30  IN EFI_PCI_IO_PROTOCOL     *PciIo,
31  IN UINT32                  Offset
32  )
33{
34  UINT16      Data;
35  EFI_STATUS  Status;
36
37  Status = PciIo->Io.Read (
38                      PciIo,
39                      EfiPciIoWidthUint16,
40                      USB_BAR_INDEX,
41                      Offset,
42                      1,
43                      &Data
44                      );
45
46  if (EFI_ERROR (Status)) {
47    DEBUG ((EFI_D_ERROR, "UhciReadReg: PciIo Io.Read error: %r at offset %d\n", Status, Offset));
48
49    Data = 0xFFFF;
50  }
51
52  return Data;
53}
54
55
56/**
57  Write data to UHCI register.
58
59  @param  PciIo        The EFI_PCI_IO_PROTOCOL to use.
60  @param  Offset       Register offset to USB_BAR_INDEX.
61  @param  Data         Data to write.
62
63**/
64VOID
65UhciWriteReg (
66  IN EFI_PCI_IO_PROTOCOL     *PciIo,
67  IN UINT32                  Offset,
68  IN UINT16                  Data
69  )
70{
71  EFI_STATUS  Status;
72
73  Status = PciIo->Io.Write (
74                      PciIo,
75                      EfiPciIoWidthUint16,
76                      USB_BAR_INDEX,
77                      Offset,
78                      1,
79                      &Data
80                      );
81
82  if (EFI_ERROR (Status)) {
83    DEBUG ((EFI_D_ERROR, "UhciWriteReg: PciIo Io.Write error: %r at offset %d\n", Status, Offset));
84  }
85}
86
87
88/**
89  Set a bit of the UHCI Register.
90
91  @param  PciIo        The EFI_PCI_IO_PROTOCOL to use.
92  @param  Offset       Register offset to USB_BAR_INDEX.
93  @param  Bit          The bit to set.
94
95**/
96VOID
97UhciSetRegBit (
98  IN EFI_PCI_IO_PROTOCOL     *PciIo,
99  IN UINT32                  Offset,
100  IN UINT16                  Bit
101  )
102{
103  UINT16  Data;
104
105  Data = UhciReadReg (PciIo, Offset);
106  Data = (UINT16) (Data |Bit);
107  UhciWriteReg (PciIo, Offset, Data);
108}
109
110
111/**
112  Clear a bit of the UHCI Register.
113
114  @param  PciIo        The PCI_IO protocol to access the PCI.
115  @param  Offset       Register offset to USB_BAR_INDEX.
116  @param  Bit          The bit to clear.
117
118**/
119VOID
120UhciClearRegBit (
121  IN EFI_PCI_IO_PROTOCOL     *PciIo,
122  IN UINT32                  Offset,
123  IN UINT16                  Bit
124  )
125{
126  UINT16  Data;
127
128  Data = UhciReadReg (PciIo, Offset);
129  Data = (UINT16) (Data & ~Bit);
130  UhciWriteReg (PciIo, Offset, Data);
131}
132
133
134/**
135  Clear all the interrutp status bits, these bits
136  are Write-Clean.
137
138  @param  Uhc          The UHCI device.
139
140**/
141VOID
142UhciAckAllInterrupt (
143  IN  USB_HC_DEV          *Uhc
144  )
145{
146  UhciWriteReg (Uhc->PciIo, USBSTS_OFFSET, 0x3F);
147
148  //
149  // If current HC is halted, re-enable it. Host Controller Process Error
150  // is a temporary error status.
151  //
152  if (!UhciIsHcWorking (Uhc->PciIo)) {
153    DEBUG ((EFI_D_ERROR, "UhciAckAllInterrupt: re-enable the UHCI from system error\n"));
154    Uhc->Usb2Hc.SetState (&Uhc->Usb2Hc, EfiUsbHcStateOperational);
155  }
156}
157
158
159/**
160  Stop the host controller.
161
162  @param  Uhc          The UHCI device.
163  @param  Timeout      Max time allowed.
164
165  @retval EFI_SUCCESS  The host controller is stopped.
166  @retval EFI_TIMEOUT  Failed to stop the host controller.
167
168**/
169EFI_STATUS
170UhciStopHc (
171  IN USB_HC_DEV        *Uhc,
172  IN UINTN             Timeout
173  )
174{
175  UINT16                UsbSts;
176  UINTN                 Index;
177
178  UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS);
179
180  //
181  // ensure the HC is in halt status after send the stop command
182  // Timeout is in us unit.
183  //
184  for (Index = 0; Index < (Timeout / 50) + 1; Index++) {
185    UsbSts = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET);
186
187    if ((UsbSts & USBSTS_HCH) == USBSTS_HCH) {
188      return EFI_SUCCESS;
189    }
190
191    gBS->Stall (50);
192  }
193
194  return EFI_TIMEOUT;
195}
196
197
198/**
199  Check whether the host controller operates well.
200
201  @param  PciIo        The PCI_IO protocol to use.
202
203  @retval TRUE         Host controller is working.
204  @retval FALSE        Host controller is halted or system error.
205
206**/
207BOOLEAN
208UhciIsHcWorking (
209  IN EFI_PCI_IO_PROTOCOL     *PciIo
210  )
211{
212  UINT16                UsbSts;
213
214  UsbSts = UhciReadReg (PciIo, USBSTS_OFFSET);
215
216  if ((UsbSts & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) != 0) {
217    DEBUG ((EFI_D_ERROR, "UhciIsHcWorking: current USB state is %x\n", UsbSts));
218    return FALSE;
219  }
220
221  return TRUE;
222}
223
224
225/**
226  Set the UHCI frame list base address. It can't use
227  UhciWriteReg which access memory in UINT16.
228
229  @param  PciIo        The EFI_PCI_IO_PROTOCOL to use.
230  @param  Addr         Address to set.
231
232**/
233VOID
234UhciSetFrameListBaseAddr (
235  IN EFI_PCI_IO_PROTOCOL     *PciIo,
236  IN VOID                    *Addr
237  )
238{
239  EFI_STATUS              Status;
240  UINT32                  Data;
241
242  Data = (UINT32) ((UINTN) Addr & 0xFFFFF000);
243
244  Status = PciIo->Io.Write (
245                       PciIo,
246                       EfiPciIoWidthUint32,
247                       USB_BAR_INDEX,
248                       (UINT64) USB_FRAME_BASE_OFFSET,
249                       1,
250                       &Data
251                       );
252
253  if (EFI_ERROR (Status)) {
254    DEBUG ((EFI_D_ERROR, "UhciSetFrameListBaseAddr: PciIo Io.Write error: %r\n", Status));
255  }
256}
257
258
259/**
260  Disable USB Emulation.
261
262  @param  PciIo        The EFI_PCI_IO_PROTOCOL protocol to use.
263
264**/
265VOID
266UhciTurnOffUsbEmulation (
267  IN EFI_PCI_IO_PROTOCOL     *PciIo
268  )
269{
270  UINT16            Command;
271
272  Command = 0;
273
274  PciIo->Pci.Write (
275               PciIo,
276               EfiPciIoWidthUint16,
277               USB_EMULATION_OFFSET,
278               1,
279               &Command
280               );
281}
282