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