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