1 /** @file
2 
3   The UHCI register operation routines.
4 
5 Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT 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 **/
28 UINT16
UhciReadReg(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT32 Offset)29 UhciReadReg (
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 **/
64 VOID
UhciWriteReg(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT32 Offset,IN UINT16 Data)65 UhciWriteReg (
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 **/
96 VOID
UhciSetRegBit(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT32 Offset,IN UINT16 Bit)97 UhciSetRegBit (
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 **/
119 VOID
UhciClearRegBit(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT32 Offset,IN UINT16 Bit)120 UhciClearRegBit (
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 **/
141 VOID
UhciAckAllInterrupt(IN USB_HC_DEV * Uhc)142 UhciAckAllInterrupt (
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 **/
169 EFI_STATUS
UhciStopHc(IN USB_HC_DEV * Uhc,IN UINTN Timeout)170 UhciStopHc (
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 **/
207 BOOLEAN
UhciIsHcWorking(IN EFI_PCI_IO_PROTOCOL * PciIo)208 UhciIsHcWorking (
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 **/
233 VOID
UhciSetFrameListBaseAddr(IN EFI_PCI_IO_PROTOCOL * PciIo,IN VOID * Addr)234 UhciSetFrameListBaseAddr (
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 **/
265 VOID
UhciTurnOffUsbEmulation(IN EFI_PCI_IO_PROTOCOL * PciIo)266 UhciTurnOffUsbEmulation (
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