]> git.proxmox.com Git - mirror_edk2.git/blame - CorebootModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c
CorebootModulePkg: Fix various typos
[mirror_edk2.git] / CorebootModulePkg / Library / BaseSerialPortLib16550 / BaseSerialPortLib16550.c
CommitLineData
12460e22
LL
1/** @file
2 16550 UART Serial Port library functions
3
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2006 - 2016, 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 <Base.h>
17#include <IndustryStandard/Pci.h>
18#include <Library/SerialPortLib.h>
19#include <Library/PcdLib.h>
20#include <Library/IoLib.h>
21#include <Library/PciLib.h>
22#include <Library/PlatformHookLib.h>
23#include <Library/BaseLib.h>
24
25//
06516768 26// PCI Definitions.\r
12460e22
LL
27//
28#define PCI_BRIDGE_32_BIT_IO_SPACE 0x01
29
30//
31// 16550 UART register offsets and bitfields
32//
33#define R_UART_RXBUF 0
34#define R_UART_TXBUF 0
35#define R_UART_BAUD_LOW 0
36#define R_UART_BAUD_HIGH 1
37#define R_UART_FCR 2
38#define B_UART_FCR_FIFOE BIT0
39#define B_UART_FCR_FIFO64 BIT5
40#define R_UART_LCR 3
41#define B_UART_LCR_DLAB BIT7
42#define R_UART_MCR 4
43#define B_UART_MCR_DTRC BIT0
44#define B_UART_MCR_RTS BIT1
45#define R_UART_LSR 5
46#define B_UART_LSR_RXRDY BIT0
47#define B_UART_LSR_TXRDY BIT5
48#define B_UART_LSR_TEMT BIT6
49#define R_UART_MSR 6
50#define B_UART_MSR_CTS BIT4
51#define B_UART_MSR_DSR BIT5
52#define B_UART_MSR_RI BIT6
53#define B_UART_MSR_DCD BIT7
54
55//
56// 4-byte structure for each PCI node in PcdSerialPciDeviceInfo
57//
58typedef struct {
59 UINT8 Device;
60 UINT8 Function;
61 UINT16 PowerManagementStatusAndControlRegister;
62} PCI_UART_DEVICE_INFO;
63
64/**
b08993bd 65 Read an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is read from
12460e22 66 MMIO space. If PcdSerialUseMmio is FALSE, then the value is read from I/O space. The
b08993bd
LL
67 parameter Offset is added to the base address of the 16550 registers that is specified
68 by PcdSerialRegisterBase.
69
12460e22
LL
70 @param Base The base address register of UART device.
71 @param Offset The offset of the 16550 register to read.
72
73 @return The value read from the 16550 register.
74
75**/
76UINT8
77SerialPortReadRegister (
78 UINTN Base,
79 UINTN Offset
80 )
81{
82 if (PcdGetBool (PcdSerialUseMmio)) {
83 return MmioRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
84 } else {
85 return IoRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
86 }
87}
88
89/**
90 Write an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is written to
91 MMIO space. If PcdSerialUseMmio is FALSE, then the value is written to I/O space. The
b08993bd
LL
92 parameter Offset is added to the base address of the 16550 registers that is specified
93 by PcdSerialRegisterBase.
94
12460e22
LL
95 @param Base The base address register of UART device.
96 @param Offset The offset of the 16550 register to write.
97 @param Value The value to write to the 16550 register specified by Offset.
98
99 @return The value written to the 16550 register.
100
101**/
102UINT8
103SerialPortWriteRegister (
104 UINTN Base,
105 UINTN Offset,
106 UINT8 Value
107 )
108{
109 if (PcdGetBool (PcdSerialUseMmio)) {
110 return MmioWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);
111 } else {
112 return IoWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);
113 }
114}
115
116/**
b08993bd
LL
117 Update the value of an 16-bit PCI configuration register in a PCI device. If the
118 PCI Configuration register specified by PciAddress is already programmed with a
119 non-zero value, then return the current value. Otherwise update the PCI configuration
12460e22 120 register specified by PciAddress with the value specified by Value and return the
b08993bd 121 value programmed into the PCI configuration register. All values must be masked
12460e22
LL
122 using the bitmask specified by Mask.
123
124 @param PciAddress PCI Library address of the PCI Configuration register to update.
125 @param Value The value to program into the PCI Configuration Register.
126 @param Mask Bitmask of the bits to check and update in the PCI configuration register.
127
128**/
129UINT16
130SerialPortLibUpdatePciRegister16 (
131 UINTN PciAddress,
132 UINT16 Value,
133 UINT16 Mask
134 )
135{
136 UINT16 CurrentValue;
b08993bd 137
12460e22
LL
138 CurrentValue = PciRead16 (PciAddress) & Mask;
139 if (CurrentValue != 0) {
140 return CurrentValue;
141 }
142 return PciWrite16 (PciAddress, Value & Mask);
143}
144
145/**
b08993bd
LL
146 Update the value of an 32-bit PCI configuration register in a PCI device. If the
147 PCI Configuration register specified by PciAddress is already programmed with a
148 non-zero value, then return the current value. Otherwise update the PCI configuration
12460e22 149 register specified by PciAddress with the value specified by Value and return the
b08993bd 150 value programmed into the PCI configuration register. All values must be masked
12460e22
LL
151 using the bitmask specified by Mask.
152
153 @param PciAddress PCI Library address of the PCI Configuration register to update.
154 @param Value The value to program into the PCI Configuration Register.
155 @param Mask Bitmask of the bits to check and update in the PCI configuration register.
156
157 @return The Secondary bus number that is actually programed into the PCI to PCI Bridge device.
158
159**/
160UINT32
161SerialPortLibUpdatePciRegister32 (
162 UINTN PciAddress,
163 UINT32 Value,
164 UINT32 Mask
165 )
166{
167 UINT32 CurrentValue;
b08993bd 168
12460e22
LL
169 CurrentValue = PciRead32 (PciAddress) & Mask;
170 if (CurrentValue != 0) {
171 return CurrentValue;
172 }
173 return PciWrite32 (PciAddress, Value & Mask);
174}
175
176/**
b08993bd
LL
177 Retrieve the I/O or MMIO base address register for the PCI UART device.
178
179 This function assumes Root Bus Numer is Zero, and enables I/O and MMIO in PCI UART
180 Device if they are not already enabled.
181
12460e22
LL
182 @return The base address register of the UART device.
183
184**/
185UINTN
186GetSerialRegisterBase (
187 VOID
188 )
189{
190 UINTN PciLibAddress;
191 UINTN BusNumber;
192 UINTN SubordinateBusNumber;
193 UINT32 ParentIoBase;
194 UINT32 ParentIoLimit;
195 UINT16 ParentMemoryBase;
196 UINT16 ParentMemoryLimit;
197 UINT32 IoBase;
198 UINT32 IoLimit;
199 UINT16 MemoryBase;
200 UINT16 MemoryLimit;
201 UINTN SerialRegisterBase;
202 UINTN BarIndex;
203 UINT32 RegisterBaseMask;
204 PCI_UART_DEVICE_INFO *DeviceInfo;
205
206 //
207 // Get PCI Device Info
208 //
209 DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);
b08993bd 210
12460e22
LL
211 //
212 // If PCI Device Info is empty, then assume fixed address UART and return PcdSerialRegisterBase
b08993bd 213 //
12460e22
LL
214 if (DeviceInfo->Device == 0xff) {
215 return (UINTN)PcdGet64 (PcdSerialRegisterBase);
216 }
217
218 //
219 // Assume PCI Bus 0 I/O window is 0-64KB and MMIO windows is 0-4GB
220 //
221 ParentMemoryBase = 0 >> 16;
222 ParentMemoryLimit = 0xfff00000 >> 16;
223 ParentIoBase = 0 >> 12;
224 ParentIoLimit = 0xf000 >> 12;
b08993bd 225
12460e22
LL
226 //
227 // Enable I/O and MMIO in PCI Bridge
b08993bd 228 // Assume Root Bus Numer is Zero.
12460e22
LL
229 //
230 for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {
231 //
232 // Compute PCI Lib Address to PCI to PCI Bridge
233 //
234 PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
b08993bd 235
12460e22
LL
236 //
237 // Retrieve and verify the bus numbers in the PCI to PCI Bridge
238 //
239 BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
240 SubordinateBusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
241 if (BusNumber == 0 || BusNumber > SubordinateBusNumber) {
242 return 0;
243 }
244
245 //
246 // Retrieve and verify the I/O or MMIO decode window in the PCI to PCI Bridge
247 //
248 if (PcdGetBool (PcdSerialUseMmio)) {
249 MemoryLimit = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit)) & 0xfff0;
250 MemoryBase = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase)) & 0xfff0;
251
252 //
253 // If PCI Bridge MMIO window is disabled, then return 0
254 //
255 if (MemoryLimit < MemoryBase) {
256 return 0;
257 }
b08993bd 258
12460e22
LL
259 //
260 // If PCI Bridge MMIO window is not in the address range decoded by the parent PCI Bridge, then return 0
b08993bd 261 //
12460e22
LL
262 if (MemoryBase < ParentMemoryBase || MemoryBase > ParentMemoryLimit || MemoryLimit > ParentMemoryLimit) {
263 return 0;
264 }
265 ParentMemoryBase = MemoryBase;
266 ParentMemoryLimit = MemoryLimit;
267 } else {
268 IoLimit = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimit));
269 if ((IoLimit & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {
270 IoLimit = IoLimit >> 4;
271 } else {
272 IoLimit = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimitUpper16)) << 4) | (IoLimit >> 4);
273 }
274 IoBase = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase));
275 if ((IoBase & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {
276 IoBase = IoBase >> 4;
277 } else {
278 IoBase = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBaseUpper16)) << 4) | (IoBase >> 4);
279 }
b08993bd 280
12460e22
LL
281 //
282 // If PCI Bridge I/O window is disabled, then return 0
283 //
284 if (IoLimit < IoBase) {
285 return 0;
286 }
b08993bd 287
12460e22
LL
288 //
289 // If PCI Bridge I/O window is not in the address range decoded by the parent PCI Bridge, then return 0
b08993bd 290 //
12460e22
LL
291 if (IoBase < ParentIoBase || IoBase > ParentIoLimit || IoLimit > ParentIoLimit) {
292 return 0;
293 }
294 ParentIoBase = IoBase;
295 ParentIoLimit = IoLimit;
296 }
297 }
298
299 //
300 // Compute PCI Lib Address to PCI UART
301 //
302 PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
b08993bd 303
12460e22
LL
304 //
305 // Find the first IO or MMIO BAR
306 //
307 RegisterBaseMask = 0xFFFFFFF0;
308 for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex ++) {
309 SerialRegisterBase = PciRead32 (PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4);
310 if (PcdGetBool (PcdSerialUseMmio) && ((SerialRegisterBase & BIT0) == 0)) {
311 //
312 // MMIO BAR is found
313 //
314 RegisterBaseMask = 0xFFFFFFF0;
315 break;
316 }
317
318 if ((!PcdGetBool (PcdSerialUseMmio)) && ((SerialRegisterBase & BIT0) != 0)) {
319 //
320 // IO BAR is found
321 //
322 RegisterBaseMask = 0xFFFFFFF8;
323 break;
324 }
325 }
326
327 //
328 // MMIO or IO BAR is not found.
329 //
330 if (BarIndex == PCI_MAX_BAR) {
331 return 0;
332 }
333
334 //
335 // Program UART BAR
b08993bd 336 //
12460e22
LL
337 SerialRegisterBase = SerialPortLibUpdatePciRegister32 (
338 PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4,
b08993bd 339 (UINT32)PcdGet64 (PcdSerialRegisterBase),
12460e22
LL
340 RegisterBaseMask
341 );
342
343 //
344 // Verify that the UART BAR is in the address range decoded by the parent PCI Bridge
b08993bd 345 //
12460e22
LL
346 if (PcdGetBool (PcdSerialUseMmio)) {
347 if (((SerialRegisterBase >> 16) & 0xfff0) < ParentMemoryBase || ((SerialRegisterBase >> 16) & 0xfff0) > ParentMemoryLimit) {
348 return 0;
349 }
350 } else {
351 if ((SerialRegisterBase >> 12) < ParentIoBase || (SerialRegisterBase >> 12) > ParentIoLimit) {
352 return 0;
353 }
354 }
b08993bd 355
12460e22
LL
356 //
357 // Enable I/O and MMIO in PCI UART Device if they are not already enabled
358 //
359 PciOr16 (
360 PciLibAddress + PCI_COMMAND_OFFSET,
361 PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE
362 );
363
364 //
365 // Force D0 state if a Power Management and Status Register is specified
366 //
367 if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {
368 if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {
369 PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));
370 //
371 // If PCI UART was not in D0, then make sure FIFOs are enabled, but do not reset FIFOs
372 //
373 SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));
374 }
375 }
b08993bd 376
12460e22
LL
377 //
378 // Get PCI Device Info
379 //
380 DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);
381
382 //
383 // Enable I/O or MMIO in PCI Bridge
b08993bd 384 // Assume Root Bus Numer is Zero.
12460e22
LL
385 //
386 for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {
387 //
388 // Compute PCI Lib Address to PCI to PCI Bridge
389 //
390 PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
b08993bd 391
12460e22
LL
392 //
393 // Enable the I/O or MMIO decode windows in the PCI to PCI Bridge
394 //
395 PciOr16 (
b08993bd 396 PciLibAddress + PCI_COMMAND_OFFSET,
12460e22
LL
397 PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE
398 );
b08993bd 399
12460e22
LL
400 //
401 // Force D0 state if a Power Management and Status Register is specified
402 //
403 if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {
404 if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {
405 PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));
406 }
407 }
b08993bd 408
12460e22
LL
409 BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
410 }
b08993bd 411
12460e22
LL
412 return SerialRegisterBase;
413}
414
415/**
416 Return whether the hardware flow control signal allows writing.
417
418 @param SerialRegisterBase The base address register of UART device.
419
420 @retval TRUE The serial port is writable.
421 @retval FALSE The serial port is not writable.
422**/
423BOOLEAN
424SerialPortWritable (
425 UINTN SerialRegisterBase
426 )
427{
428 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
429 if (PcdGetBool (PcdSerialDetectCable)) {
430 //
431 // Wait for both DSR and CTS to be set
432 // DSR is set if a cable is connected.
433 // CTS is set if it is ok to transmit data
434 //
435 // DSR CTS Description Action
436 // === === ======================================== ========
437 // 0 0 No cable connected. Wait
438 // 0 1 No cable connected. Wait
439 // 1 0 Cable connected, but not clear to send. Wait
440 // 1 1 Cable connected, and clear to send. Transmit
441 //
442 return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) == (B_UART_MSR_DSR | B_UART_MSR_CTS));
443 } else {
444 //
b08993bd 445 // Wait for both DSR and CTS to be set OR for DSR to be clear.
12460e22
LL
446 // DSR is set if a cable is connected.
447 // CTS is set if it is ok to transmit data
448 //
449 // DSR CTS Description Action
450 // === === ======================================== ========
451 // 0 0 No cable connected. Transmit
452 // 0 1 No cable connected. Transmit
453 // 1 0 Cable connected, but not clear to send. Wait
06516768 454 // 1 1 Cable connected, and clear to send. Transmit\r
12460e22
LL
455 //
456 return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) != (B_UART_MSR_DSR));
457 }
458 }
459
460 return TRUE;
461}
462
463/**
464 Initialize the serial device hardware.
b08993bd 465
12460e22
LL
466 If no initialization is required, then return RETURN_SUCCESS.
467 If the serial device was successfully initialized, then return RETURN_SUCCESS.
468 If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
b08993bd 469
12460e22
LL
470 @retval RETURN_SUCCESS The serial device was initialized.
471 @retval RETURN_DEVICE_ERROR The serial device could not be initialized.
472
473**/
474RETURN_STATUS
475EFIAPI
476SerialPortInitialize (
477 VOID
478 )
479{
480 RETURN_STATUS Status;
481 UINTN SerialRegisterBase;
482 UINT32 Divisor;
b08993bd 483 UINT32 CurrentDivisor;
12460e22
LL
484 BOOLEAN Initialized;
485
486 //
487 // Perform platform specific initialization required to enable use of the 16550 device
488 // at the location specified by PcdSerialUseMmio and PcdSerialRegisterBase.
489 //
490 Status = PlatformHookSerialPortInitialize ();
491 if (RETURN_ERROR (Status)) {
492 return Status;
493 }
494
495 //
496 // Calculate divisor for baud generator
497 // Ref_Clk_Rate / Baud_Rate / 16
498 //
499 Divisor = PcdGet32 (PcdSerialClockRate) / (PcdGet32 (PcdSerialBaudRate) * 16);
500 if ((PcdGet32 (PcdSerialClockRate) % (PcdGet32 (PcdSerialBaudRate) * 16)) >= PcdGet32 (PcdSerialBaudRate) * 8) {
501 Divisor++;
502 }
503
504 //
505 // Get the base address of the serial port in either I/O or MMIO space
506 //
507 SerialRegisterBase = GetSerialRegisterBase ();
508 if (SerialRegisterBase ==0) {
509 return RETURN_DEVICE_ERROR;
510 }
511
512 //
513 // See if the serial port is already initialized
514 //
515 Initialized = TRUE;
516 if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & 0x3F) != (PcdGet8 (PcdSerialLineControl) & 0x3F)) {
517 Initialized = FALSE;
518 }
519 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) | B_UART_LCR_DLAB));
520 CurrentDivisor = SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_HIGH) << 8;
521 CurrentDivisor |= (UINT32) SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_LOW);
522 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & ~B_UART_LCR_DLAB));
523 if (CurrentDivisor != Divisor) {
524 Initialized = FALSE;
525 }
526 if (Initialized) {
527 return RETURN_SUCCESS;
528 }
529
530 //
531 // Wait for the serial port to be ready.
532 // Verify that both the transmit FIFO and the shift register are empty.
533 //
534 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));
b08993bd 535
12460e22
LL
536 //
537 // Configure baud rate
538 //
539 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
540 SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));
541 SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));
542
543 //
544 // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
545 // Strip reserved bits from PcdSerialLineControl
546 //
547 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(PcdGet8 (PcdSerialLineControl) & 0x3F));
548
549 //
550 // Enable and reset FIFOs
551 // Strip reserved bits from PcdSerialFifoControl
552 //
553 SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, 0x00);
554 SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));
555
556 //
bb083167 557 // Set RTS and DTR in Modem Control Register(MCR)
b08993bd 558 //
bb083167
LL
559 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR,
560 EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY);
12460e22
LL
561
562 return RETURN_SUCCESS;
563}
564
565/**
b08993bd 566 Write data from buffer to serial device.
12460e22 567
b08993bd 568 Writes NumberOfBytes data bytes from Buffer to the serial device.
12460e22
LL
569 The number of bytes actually written to the serial device is returned.
570 If the return value is less than NumberOfBytes, then the write operation failed.
571
b08993bd 572 If Buffer is NULL, then ASSERT().
12460e22
LL
573
574 If NumberOfBytes is zero, then return 0.
575
576 @param Buffer Pointer to the data buffer to be written.
577 @param NumberOfBytes Number of bytes to written to the serial device.
578
579 @retval 0 NumberOfBytes is 0.
b08993bd 580 @retval >0 The number of bytes written to the serial device.
12460e22
LL
581 If this value is less than NumberOfBytes, then the write operation failed.
582
583**/
584UINTN
585EFIAPI
586SerialPortWrite (
587 IN UINT8 *Buffer,
588 IN UINTN NumberOfBytes
589 )
590{
591 UINTN SerialRegisterBase;
592 UINTN Result;
593 UINTN Index;
594 UINTN FifoSize;
595
596 if (Buffer == NULL) {
597 return 0;
598 }
599
600 SerialRegisterBase = GetSerialRegisterBase ();
601 if (SerialRegisterBase ==0) {
602 return 0;
603 }
b08993bd 604
12460e22
LL
605 if (NumberOfBytes == 0) {
606 //
607 // Flush the hardware
608 //
609
610 //
611 // Wait for both the transmit FIFO and shift register empty.
612 //
613 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));
614
615 //
616 // Wait for the hardware flow control signal
617 //
618 while (!SerialPortWritable (SerialRegisterBase));
619 return 0;
620 }
621
622 //
623 // Compute the maximum size of the Tx FIFO
624 //
625 FifoSize = 1;
626 if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFOE) != 0) {
627 if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) {
628 FifoSize = 16;
629 } else {
630 FifoSize = PcdGet32 (PcdSerialExtendedTxFifoSize);
631 }
632 }
633
634 Result = NumberOfBytes;
635 while (NumberOfBytes != 0) {
636 //
637 // Wait for the serial port to be ready, to make sure both the transmit FIFO
638 // and shift register empty.
639 //
640 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_TEMT) == 0);
641
642 //
643 // Fill then entire Tx FIFO
644 //
645 for (Index = 0; Index < FifoSize && NumberOfBytes != 0; Index++, NumberOfBytes--, Buffer++) {
646 //
647 // Wait for the hardware flow control signal
648 //
649 while (!SerialPortWritable (SerialRegisterBase));
650
651 //
652 // Write byte to the transmit buffer.
653 //
654 SerialPortWriteRegister (SerialRegisterBase, R_UART_TXBUF, *Buffer);
655 }
656 }
657 return Result;
658}
659
660/**
661 Reads data from a serial device into a buffer.
662
663 @param Buffer Pointer to the data buffer to store the data read from the serial device.
664 @param NumberOfBytes Number of bytes to read from the serial device.
665
666 @retval 0 NumberOfBytes is 0.
b08993bd 667 @retval >0 The number of bytes read from the serial device.
12460e22
LL
668 If this value is less than NumberOfBytes, then the read operation failed.
669
670**/
671UINTN
672EFIAPI
673SerialPortRead (
674 OUT UINT8 *Buffer,
675 IN UINTN NumberOfBytes
676 )
677{
678 UINTN SerialRegisterBase;
679 UINTN Result;
680 UINT8 Mcr;
681
682 if (NULL == Buffer) {
683 return 0;
684 }
685
686 SerialRegisterBase = GetSerialRegisterBase ();
687 if (SerialRegisterBase ==0) {
688 return 0;
689 }
690
691 Mcr = (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS);
b08993bd 692
12460e22
LL
693 for (Result = 0; NumberOfBytes-- != 0; Result++, Buffer++) {
694 //
695 // Wait for the serial port to have some data.
696 //
697 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) == 0) {
698 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
699 //
700 // Set RTS to let the peer send some data
701 //
702 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(Mcr | B_UART_MCR_RTS));
703 }
704 }
705 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
706 //
707 // Clear RTS to prevent peer from sending data
708 //
709 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
710 }
b08993bd 711
12460e22
LL
712 //
713 // Read byte from the receive buffer.
714 //
715 *Buffer = SerialPortReadRegister (SerialRegisterBase, R_UART_RXBUF);
716 }
b08993bd 717
12460e22
LL
718 return Result;
719}
720
721
722/**
723 Polls a serial device to see if there is any data waiting to be read.
724
06516768 725 Polls a serial device to see if there is any data waiting to be read.\r
12460e22
LL
726 If there is data waiting to be read from the serial device, then TRUE is returned.
727 If there is no data waiting to be read from the serial device, then FALSE is returned.
728
729 @retval TRUE Data is waiting to be read from the serial device.
730 @retval FALSE There is no data waiting to be read from the serial device.
731
732**/
733BOOLEAN
734EFIAPI
735SerialPortPoll (
736 VOID
737 )
738{
739 UINTN SerialRegisterBase;
b08993bd 740
12460e22
LL
741 SerialRegisterBase = GetSerialRegisterBase ();
742 if (SerialRegisterBase ==0) {
743 return FALSE;
744 }
745
746 //
747 // Read the serial port status
748 //
749 if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) != 0) {
750 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
751 //
752 // Clear RTS to prevent peer from sending data
753 //
754 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS));
755 }
756 return TRUE;
b08993bd
LL
757 }
758
12460e22
LL
759 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
760 //
761 // Set RTS to let the peer send some data
762 //
763 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) | B_UART_MCR_RTS));
764 }
b08993bd 765
12460e22
LL
766 return FALSE;
767}
768
769/**
770 Sets the control bits on a serial device.
771
772 @param Control Sets the bits of Control that are settable.
773
774 @retval RETURN_SUCCESS The new control bits were set on the serial device.
775 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
776 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
777
778**/
779RETURN_STATUS
780EFIAPI
781SerialPortSetControl (
782 IN UINT32 Control
783 )
784{
785 UINTN SerialRegisterBase;
786 UINT8 Mcr;
787
788 //
789 // First determine the parameter is invalid.
790 //
791 if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
792 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) {
793 return RETURN_UNSUPPORTED;
794 }
795
796 SerialRegisterBase = GetSerialRegisterBase ();
797 if (SerialRegisterBase ==0) {
798 return RETURN_UNSUPPORTED;
799 }
800
801 //
802 // Read the Modem Control Register.
803 //
804 Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
805 Mcr &= (~(B_UART_MCR_DTRC | B_UART_MCR_RTS));
806
807 if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
808 Mcr |= B_UART_MCR_DTRC;
809 }
810
811 if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
812 Mcr |= B_UART_MCR_RTS;
813 }
814
815 //
816 // Write the Modem Control Register.
817 //
818 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
819
820 return RETURN_SUCCESS;
821}
822
823/**
824 Retrieve the status of the control bits on a serial device.
825
826 @param Control A pointer to return the current control signals from the serial device.
827
828 @retval RETURN_SUCCESS The control bits were read from the serial device.
829 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
830 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
831
832**/
833RETURN_STATUS
834EFIAPI
835SerialPortGetControl (
836 OUT UINT32 *Control
837 )
838{
839 UINTN SerialRegisterBase;
840 UINT8 Msr;
841 UINT8 Mcr;
842 UINT8 Lsr;
843
844 SerialRegisterBase = GetSerialRegisterBase ();
845 if (SerialRegisterBase ==0) {
846 return RETURN_UNSUPPORTED;
847 }
848
849 *Control = 0;
850
851 //
852 // Read the Modem Status Register.
853 //
854 Msr = SerialPortReadRegister (SerialRegisterBase, R_UART_MSR);
855
856 if ((Msr & B_UART_MSR_CTS) == B_UART_MSR_CTS) {
857 *Control |= EFI_SERIAL_CLEAR_TO_SEND;
858 }
859
860 if ((Msr & B_UART_MSR_DSR) == B_UART_MSR_DSR) {
861 *Control |= EFI_SERIAL_DATA_SET_READY;
862 }
863
864 if ((Msr & B_UART_MSR_RI) == B_UART_MSR_RI) {
865 *Control |= EFI_SERIAL_RING_INDICATE;
866 }
867
868 if ((Msr & B_UART_MSR_DCD) == B_UART_MSR_DCD) {
869 *Control |= EFI_SERIAL_CARRIER_DETECT;
870 }
871
872 //
873 // Read the Modem Control Register.
874 //
875 Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
876
877 if ((Mcr & B_UART_MCR_DTRC) == B_UART_MCR_DTRC) {
878 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
879 }
880
881 if ((Mcr & B_UART_MCR_RTS) == B_UART_MCR_RTS) {
882 *Control |= EFI_SERIAL_REQUEST_TO_SEND;
883 }
884
885 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
886 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
887 }
888
889 //
890 // Read the Line Status Register.
891 //
892 Lsr = SerialPortReadRegister (SerialRegisterBase, R_UART_LSR);
893
894 if ((Lsr & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) == (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) {
895 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
896 }
897
898 if ((Lsr & B_UART_LSR_RXRDY) == 0) {
899 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
900 }
901
902 return RETURN_SUCCESS;
903}
904
905/**
06516768 906 Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,\r
12460e22
LL
907 data bits, and stop bits on a serial device.
908
909 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the
910 device's default interface speed.
911 On output, the value actually set.
06516768 912 @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the\r
12460e22
LL
913 serial interface. A ReceiveFifoDepth value of 0 will use
914 the device's default FIFO depth.
915 On output, the value actually set.
916 @param Timeout The requested time out for a single character in microseconds.
917 This timeout applies to both the transmit and receive side of the
918 interface. A Timeout value of 0 will use the device's default time
919 out value.
920 On output, the value actually set.
921 @param Parity The type of parity to use on this serial device. A Parity value of
922 DefaultParity will use the device's default parity value.
923 On output, the value actually set.
924 @param DataBits The number of data bits to use on the serial device. A DataBits
06516768 925 value of 0 will use the device's default data bit setting.\r
12460e22
LL
926 On output, the value actually set.
927 @param StopBits The number of stop bits to use on this serial device. A StopBits
928 value of DefaultStopBits will use the device's default number of
929 stop bits.
930 On output, the value actually set.
931
932 @retval RETURN_SUCCESS The new attributes were set on the serial device.
933 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
934 @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value.
935 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
936
937**/
938RETURN_STATUS
939EFIAPI
940SerialPortSetAttributes (
941 IN OUT UINT64 *BaudRate,
942 IN OUT UINT32 *ReceiveFifoDepth,
943 IN OUT UINT32 *Timeout,
944 IN OUT EFI_PARITY_TYPE *Parity,
945 IN OUT UINT8 *DataBits,
946 IN OUT EFI_STOP_BITS_TYPE *StopBits
947 )
948{
949 UINTN SerialRegisterBase;
950 UINT32 SerialBaudRate;
951 UINTN Divisor;
952 UINT8 Lcr;
953 UINT8 LcrData;
954 UINT8 LcrParity;
955 UINT8 LcrStop;
956
957 SerialRegisterBase = GetSerialRegisterBase ();
958 if (SerialRegisterBase ==0) {
959 return RETURN_UNSUPPORTED;
960 }
961
962 //
963 // Check for default settings and fill in actual values.
964 //
965 if (*BaudRate == 0) {
966 *BaudRate = PcdGet32 (PcdSerialBaudRate);
967 }
968 SerialBaudRate = (UINT32) *BaudRate;
969
970 if (*DataBits == 0) {
971 LcrData = (UINT8) (PcdGet8 (PcdSerialLineControl) & 0x3);
972 *DataBits = LcrData + 5;
973 } else {
974 if ((*DataBits < 5) || (*DataBits > 8)) {
975 return RETURN_INVALID_PARAMETER;
976 }
977 //
978 // Map 5..8 to 0..3
979 //
980 LcrData = (UINT8) (*DataBits - (UINT8) 5);
981 }
982
983 if (*Parity == DefaultParity) {
984 LcrParity = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 3) & 0x7);
985 switch (LcrParity) {
986 case 0:
987 *Parity = NoParity;
988 break;
989
990 case 3:
991 *Parity = EvenParity;
992 break;
993
994 case 1:
995 *Parity = OddParity;
996 break;
997
998 case 7:
999 *Parity = SpaceParity;
1000 break;
1001
1002 case 5:
1003 *Parity = MarkParity;
1004 break;
1005
1006 default:
1007 break;
1008 }
1009 } else {
1010 switch (*Parity) {
1011 case NoParity:
1012 LcrParity = 0;
1013 break;
1014
1015 case EvenParity:
1016 LcrParity = 3;
1017 break;
1018
1019 case OddParity:
1020 LcrParity = 1;
1021 break;
1022
1023 case SpaceParity:
1024 LcrParity = 7;
1025 break;
1026
1027 case MarkParity:
1028 LcrParity = 5;
1029 break;
1030
1031 default:
1032 return RETURN_INVALID_PARAMETER;
1033 }
1034 }
1035
1036 if (*StopBits == DefaultStopBits) {
1037 LcrStop = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 2) & 0x1);
1038 switch (LcrStop) {
1039 case 0:
1040 *StopBits = OneStopBit;
1041 break;
1042
1043 case 1:
1044 if (*DataBits == 5) {
1045 *StopBits = OneFiveStopBits;
1046 } else {
1047 *StopBits = TwoStopBits;
1048 }
1049 break;
1050
1051 default:
1052 break;
1053 }
1054 } else {
1055 switch (*StopBits) {
1056 case OneStopBit:
1057 LcrStop = 0;
1058 break;
1059
1060 case OneFiveStopBits:
1061 case TwoStopBits:
1062 LcrStop = 1;
1063 break;
1064
1065 default:
1066 return RETURN_INVALID_PARAMETER;
1067 }
1068 }
1069
1070 //
1071 // Calculate divisor for baud generator
1072 // Ref_Clk_Rate / Baud_Rate / 16
1073 //
1074 Divisor = PcdGet32 (PcdSerialClockRate) / (SerialBaudRate * 16);
1075 if ((PcdGet32 (PcdSerialClockRate) % (SerialBaudRate * 16)) >= SerialBaudRate * 8) {
1076 Divisor++;
1077 }
1078
1079 //
1080 // Configure baud rate
1081 //
1082 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
1083 SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));
1084 SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));
1085
1086 //
1087 // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
1088 // Strip reserved bits from line control value
1089 //
1090 Lcr = (UINT8) ((LcrParity << 3) | (LcrStop << 2) | LcrData);
1091 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8) (Lcr & 0x3F));
1092
1093 return RETURN_SUCCESS;
1094}
1095