]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciSioSerialDxe / SerialIo.c
1 /** @file
2 SerialIo implementation for PCI or SIO UARTs.
3
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "Serial.h"
10
11 /**
12 Skip the optional Controller device path node and return the
13 pointer to the next device path node.
14
15 @param DevicePath Pointer to the device path.
16 @param ContainsControllerNode Returns TRUE if the Controller device path exists.
17 @param ControllerNumber Returns the Controller Number if Controller device path exists.
18
19 @return Pointer to the next device path node.
20 **/
21 UART_DEVICE_PATH *
22 SkipControllerDevicePathNode (
23 EFI_DEVICE_PATH_PROTOCOL *DevicePath,
24 BOOLEAN *ContainsControllerNode,
25 UINT32 *ControllerNumber
26 )
27 {
28 if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) &&
29 (DevicePathSubType (DevicePath) == HW_CONTROLLER_DP)
30 ) {
31 if (ContainsControllerNode != NULL) {
32 *ContainsControllerNode = TRUE;
33 }
34 if (ControllerNumber != NULL) {
35 *ControllerNumber = ((CONTROLLER_DEVICE_PATH *) DevicePath)->ControllerNumber;
36 }
37 DevicePath = NextDevicePathNode (DevicePath);
38 } else {
39 if (ContainsControllerNode != NULL) {
40 *ContainsControllerNode = FALSE;
41 }
42 }
43 return (UART_DEVICE_PATH *) DevicePath;
44 }
45
46 /**
47 Checks whether the UART parameters are valid and computes the Divisor.
48
49 @param ClockRate The clock rate of the serial device used to verify
50 the BaudRate. Do not verify the BaudRate if it's 0.
51 @param BaudRate The requested baudrate of the serial device.
52 @param DataBits Number of databits used in serial device.
53 @param Parity The type of parity used in serial device.
54 @param StopBits Number of stopbits used in serial device.
55 @param Divisor Return the divisor if ClockRate is not 0.
56 @param ActualBaudRate Return the actual supported baudrate without
57 exceeding BaudRate. NULL means baudrate degradation
58 is not allowed.
59 If the requested BaudRate is not supported, the routine
60 returns TRUE and the Actual Baud Rate when ActualBaudRate
61 is not NULL, returns FALSE when ActualBaudRate is NULL.
62
63 @retval TRUE The UART parameters are valid.
64 @retval FALSE The UART parameters are not valid.
65 **/
66 BOOLEAN
67 VerifyUartParameters (
68 IN UINT32 ClockRate,
69 IN UINT64 BaudRate,
70 IN UINT8 DataBits,
71 IN EFI_PARITY_TYPE Parity,
72 IN EFI_STOP_BITS_TYPE StopBits,
73 OUT UINT64 *Divisor,
74 OUT UINT64 *ActualBaudRate
75 )
76 {
77 UINT64 Remainder;
78 UINT32 ComputedBaudRate;
79 UINT64 ComputedDivisor;
80 UINT64 Percent;
81
82 if ((DataBits < 5) || (DataBits > 8) ||
83 (Parity < NoParity) || (Parity > SpaceParity) ||
84 (StopBits < OneStopBit) || (StopBits > TwoStopBits) ||
85 ((DataBits == 5) && (StopBits == TwoStopBits)) ||
86 ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits))
87 ) {
88 return FALSE;
89 }
90
91 //
92 // Do not verify the baud rate if clock rate is unknown (0).
93 //
94 if (ClockRate == 0) {
95 return TRUE;
96 }
97
98 //
99 // Compute divisor use to program the baud rate using a round determination
100 // Divisor = ClockRate / 16 / BaudRate = ClockRate / (16 * BaudRate)
101 // = ClockRate / (BaudRate << 4)
102 //
103 ComputedDivisor = DivU64x64Remainder (ClockRate, LShiftU64 (BaudRate, 4), &Remainder);
104 //
105 // Round Divisor up by 1 if the Remainder is more than half (16 * BaudRate)
106 // BaudRate * 16 / 2 = BaudRate * 8 = (BaudRate << 3)
107 //
108 if (Remainder >= LShiftU64 (BaudRate, 3)) {
109 ComputedDivisor++;
110 }
111 //
112 // If the computed divisor is larger than the maximum value that can be programmed
113 // into the UART, then the requested baud rate can not be supported.
114 //
115 if (ComputedDivisor > MAX_UINT16) {
116 return FALSE;
117 }
118
119 //
120 // If the computed divisor is 0, then use a computed divisor of 1, which will select
121 // the maximum supported baud rate.
122 //
123 if (ComputedDivisor == 0) {
124 ComputedDivisor = 1;
125 }
126
127 //
128 // Actual baud rate that the serial port will be programmed for
129 // should be with in 4% of requested one.
130 //
131 ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4);
132 if (ComputedBaudRate == 0) {
133 return FALSE;
134 }
135
136 Percent = DivU64x32 (MultU64x32 (BaudRate, 100), ComputedBaudRate);
137 DEBUG ((EFI_D_INFO, "ClockRate = %d\n", ClockRate));
138 DEBUG ((EFI_D_INFO, "Divisor = %ld\n", ComputedDivisor));
139 DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent));
140
141 //
142 // If the requested BaudRate is not supported:
143 // Returns TRUE and the Actual Baud Rate when ActualBaudRate is not NULL;
144 // Returns FALSE when ActualBaudRate is NULL.
145 //
146 if ((Percent >= 96) && (Percent <= 104)) {
147 if (ActualBaudRate != NULL) {
148 *ActualBaudRate = BaudRate;
149 }
150 if (Divisor != NULL) {
151 *Divisor = ComputedDivisor;
152 }
153 return TRUE;
154 }
155 if (ComputedBaudRate < BaudRate) {
156 if (ActualBaudRate != NULL) {
157 *ActualBaudRate = ComputedBaudRate;
158 }
159 if (Divisor != NULL) {
160 *Divisor = ComputedDivisor;
161 }
162 return TRUE;
163 }
164
165 //
166 // ActualBaudRate is higher than requested baud rate and more than 4%
167 // higher than the requested value. Increment Divisor if it is less
168 // than MAX_UINT16 and computed baud rate with new divisor.
169 //
170 if (ComputedDivisor == MAX_UINT16) {
171 return FALSE;
172 }
173 ComputedDivisor++;
174 ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4);
175 if (ComputedBaudRate == 0) {
176 return FALSE;
177 }
178
179 DEBUG ((EFI_D_INFO, "ClockRate = %d\n", ClockRate));
180 DEBUG ((EFI_D_INFO, "Divisor = %ld\n", ComputedDivisor));
181 DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent));
182
183 if (ActualBaudRate != NULL) {
184 *ActualBaudRate = ComputedBaudRate;
185 }
186 if (Divisor != NULL) {
187 *Divisor = ComputedDivisor;
188 }
189 return TRUE;
190 }
191
192 /**
193 Detect whether specific FIFO is full or not.
194
195 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
196
197 @return whether specific FIFO is full or not
198 **/
199 BOOLEAN
200 SerialFifoFull (
201 IN SERIAL_DEV_FIFO *Fifo
202 )
203 {
204 return (BOOLEAN) (((Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE) == Fifo->Head);
205 }
206
207 /**
208 Detect whether specific FIFO is empty or not.
209
210 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
211
212 @return whether specific FIFO is empty or not
213 **/
214 BOOLEAN
215 SerialFifoEmpty (
216 IN SERIAL_DEV_FIFO *Fifo
217 )
218
219 {
220 return (BOOLEAN) (Fifo->Head == Fifo->Tail);
221 }
222
223 /**
224 Add data to specific FIFO.
225
226 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
227 @param Data the data added to FIFO
228
229 @retval EFI_SUCCESS Add data to specific FIFO successfully
230 @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full
231 **/
232 EFI_STATUS
233 SerialFifoAdd (
234 IN OUT SERIAL_DEV_FIFO *Fifo,
235 IN UINT8 Data
236 )
237 {
238 //
239 // if FIFO full can not add data
240 //
241 if (SerialFifoFull (Fifo)) {
242 return EFI_OUT_OF_RESOURCES;
243 }
244 //
245 // FIFO is not full can add data
246 //
247 Fifo->Data[Fifo->Tail] = Data;
248 Fifo->Tail = (Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE;
249 return EFI_SUCCESS;
250 }
251
252 /**
253 Remove data from specific FIFO.
254
255 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
256 @param Data the data removed from FIFO
257
258 @retval EFI_SUCCESS Remove data from specific FIFO successfully
259 @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty
260
261 **/
262 EFI_STATUS
263 SerialFifoRemove (
264 IN OUT SERIAL_DEV_FIFO *Fifo,
265 OUT UINT8 *Data
266 )
267 {
268 //
269 // if FIFO is empty, no data can remove
270 //
271 if (SerialFifoEmpty (Fifo)) {
272 return EFI_OUT_OF_RESOURCES;
273 }
274 //
275 // FIFO is not empty, can remove data
276 //
277 *Data = Fifo->Data[Fifo->Head];
278 Fifo->Head = (Fifo->Head + 1) % SERIAL_MAX_FIFO_SIZE;
279 return EFI_SUCCESS;
280 }
281
282 /**
283 Reads and writes all available data.
284
285 @param SerialDevice The device to transmit.
286
287 @retval EFI_SUCCESS Data was read/written successfully.
288 @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when
289 this happens, pending writes are not done.
290
291 **/
292 EFI_STATUS
293 SerialReceiveTransmit (
294 IN SERIAL_DEV *SerialDevice
295 )
296
297 {
298 SERIAL_PORT_LSR Lsr;
299 UINT8 Data;
300 BOOLEAN ReceiveFifoFull;
301 SERIAL_PORT_MSR Msr;
302 SERIAL_PORT_MCR Mcr;
303 UINTN TimeOut;
304
305 Data = 0;
306
307 //
308 // Begin the read or write
309 //
310 if (SerialDevice->SoftwareLoopbackEnable) {
311 do {
312 ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);
313 if (!SerialFifoEmpty (&SerialDevice->Transmit)) {
314 SerialFifoRemove (&SerialDevice->Transmit, &Data);
315 if (ReceiveFifoFull) {
316 return EFI_OUT_OF_RESOURCES;
317 }
318
319 SerialFifoAdd (&SerialDevice->Receive, Data);
320 }
321 } while (!SerialFifoEmpty (&SerialDevice->Transmit));
322 } else {
323 ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);
324 //
325 // For full handshake flow control, tell the peer to send data
326 // if receive buffer is available.
327 //
328 if (SerialDevice->HardwareFlowControl &&
329 !FeaturePcdGet(PcdSerialUseHalfHandshake)&&
330 !ReceiveFifoFull
331 ) {
332 Mcr.Data = READ_MCR (SerialDevice);
333 Mcr.Bits.Rts = 1;
334 WRITE_MCR (SerialDevice, Mcr.Data);
335 }
336 do {
337 Lsr.Data = READ_LSR (SerialDevice);
338
339 //
340 // Flush incomming data to prevent a an overrun during a long write
341 //
342 if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) {
343 ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);
344 if (!ReceiveFifoFull) {
345 if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Oe == 1 || Lsr.Bits.Pe == 1 || Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
346 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
347 EFI_ERROR_CODE,
348 EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
349 SerialDevice->DevicePath
350 );
351 if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Pe == 1|| Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
352 Data = READ_RBR (SerialDevice);
353 continue;
354 }
355 }
356
357 Data = READ_RBR (SerialDevice);
358
359 SerialFifoAdd (&SerialDevice->Receive, Data);
360
361 //
362 // For full handshake flow control, if receive buffer full
363 // tell the peer to stop sending data.
364 //
365 if (SerialDevice->HardwareFlowControl &&
366 !FeaturePcdGet(PcdSerialUseHalfHandshake) &&
367 SerialFifoFull (&SerialDevice->Receive)
368 ) {
369 Mcr.Data = READ_MCR (SerialDevice);
370 Mcr.Bits.Rts = 0;
371 WRITE_MCR (SerialDevice, Mcr.Data);
372 }
373
374
375 continue;
376 } else {
377 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
378 EFI_PROGRESS_CODE,
379 EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT,
380 SerialDevice->DevicePath
381 );
382 }
383 }
384 //
385 // Do the write
386 //
387 if (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&SerialDevice->Transmit)) {
388 //
389 // Make sure the transmit data will not be missed
390 //
391 if (SerialDevice->HardwareFlowControl) {
392 //
393 // For half handshake flow control assert RTS before sending.
394 //
395 if (FeaturePcdGet(PcdSerialUseHalfHandshake)) {
396 Mcr.Data = READ_MCR (SerialDevice);
397 Mcr.Bits.Rts= 0;
398 WRITE_MCR (SerialDevice, Mcr.Data);
399 }
400 //
401 // Wait for CTS
402 //
403 TimeOut = 0;
404 Msr.Data = READ_MSR (SerialDevice);
405 while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) {
406 gBS->Stall (TIMEOUT_STALL_INTERVAL);
407 TimeOut++;
408 if (TimeOut > 5) {
409 break;
410 }
411
412 Msr.Data = READ_MSR (SerialDevice);
413 }
414
415 if ((Msr.Bits.Dcd == 0) || ((Msr.Bits.Cts == 1) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) {
416 SerialFifoRemove (&SerialDevice->Transmit, &Data);
417 WRITE_THR (SerialDevice, Data);
418 }
419
420 //
421 // For half handshake flow control, tell DCE we are done.
422 //
423 if (FeaturePcdGet(PcdSerialUseHalfHandshake)) {
424 Mcr.Data = READ_MCR (SerialDevice);
425 Mcr.Bits.Rts = 1;
426 WRITE_MCR (SerialDevice, Mcr.Data);
427 }
428 } else {
429 SerialFifoRemove (&SerialDevice->Transmit, &Data);
430 WRITE_THR (SerialDevice, Data);
431 }
432 }
433 } while (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&SerialDevice->Transmit));
434 }
435
436 return EFI_SUCCESS;
437 }
438
439 //
440 // Interface Functions
441 //
442 /**
443 Reset serial device.
444
445 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
446
447 @retval EFI_SUCCESS Reset successfully
448 @retval EFI_DEVICE_ERROR Failed to reset
449
450 **/
451 EFI_STATUS
452 EFIAPI
453 SerialReset (
454 IN EFI_SERIAL_IO_PROTOCOL *This
455 )
456 {
457 EFI_STATUS Status;
458 SERIAL_DEV *SerialDevice;
459 SERIAL_PORT_LCR Lcr;
460 SERIAL_PORT_IER Ier;
461 SERIAL_PORT_MCR Mcr;
462 SERIAL_PORT_FCR Fcr;
463 EFI_TPL Tpl;
464 UINT32 Control;
465
466 SerialDevice = SERIAL_DEV_FROM_THIS (This);
467
468 //
469 // Report the status code reset the serial
470 //
471 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
472 EFI_PROGRESS_CODE,
473 EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT,
474 SerialDevice->DevicePath
475 );
476
477 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
478
479 //
480 // Make sure DLAB is 0.
481 //
482 Lcr.Data = READ_LCR (SerialDevice);
483 Lcr.Bits.DLab = 0;
484 WRITE_LCR (SerialDevice, Lcr.Data);
485
486 //
487 // Turn off all interrupts
488 //
489 Ier.Data = READ_IER (SerialDevice);
490 Ier.Bits.Ravie = 0;
491 Ier.Bits.Theie = 0;
492 Ier.Bits.Rie = 0;
493 Ier.Bits.Mie = 0;
494 WRITE_IER (SerialDevice, Ier.Data);
495
496 //
497 // Reset the FIFO
498 //
499 Fcr.Data = 0;
500 Fcr.Bits.TrFIFOE = 0;
501 WRITE_FCR (SerialDevice, Fcr.Data);
502
503 //
504 // Turn off loopback and disable device interrupt.
505 //
506 Mcr.Data = READ_MCR (SerialDevice);
507 Mcr.Bits.Out1 = 0;
508 Mcr.Bits.Out2 = 0;
509 Mcr.Bits.Lme = 0;
510 WRITE_MCR (SerialDevice, Mcr.Data);
511
512 //
513 // Clear the scratch pad register
514 //
515 WRITE_SCR (SerialDevice, 0);
516
517 //
518 // Enable FIFO
519 //
520 Fcr.Bits.TrFIFOE = 1;
521 if (SerialDevice->ReceiveFifoDepth > 16) {
522 Fcr.Bits.TrFIFO64 = 1;
523 }
524 Fcr.Bits.ResetRF = 1;
525 Fcr.Bits.ResetTF = 1;
526 WRITE_FCR (SerialDevice, Fcr.Data);
527
528 //
529 // Go set the current attributes
530 //
531 Status = This->SetAttributes (
532 This,
533 This->Mode->BaudRate,
534 This->Mode->ReceiveFifoDepth,
535 This->Mode->Timeout,
536 (EFI_PARITY_TYPE) This->Mode->Parity,
537 (UINT8) This->Mode->DataBits,
538 (EFI_STOP_BITS_TYPE) This->Mode->StopBits
539 );
540
541 if (EFI_ERROR (Status)) {
542 gBS->RestoreTPL (Tpl);
543 return EFI_DEVICE_ERROR;
544 }
545 //
546 // Go set the current control bits
547 //
548 Control = 0;
549 if (SerialDevice->HardwareFlowControl) {
550 Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
551 }
552 if (SerialDevice->SoftwareLoopbackEnable) {
553 Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
554 }
555 Status = This->SetControl (
556 This,
557 Control
558 );
559
560 if (EFI_ERROR (Status)) {
561 gBS->RestoreTPL (Tpl);
562 return EFI_DEVICE_ERROR;
563 }
564
565 //
566 // Reset the software FIFO
567 //
568 SerialDevice->Receive.Head = SerialDevice->Receive.Tail = 0;
569 SerialDevice->Transmit.Head = SerialDevice->Transmit.Tail = 0;
570 gBS->RestoreTPL (Tpl);
571
572 //
573 // Device reset is complete
574 //
575 return EFI_SUCCESS;
576 }
577
578 /**
579 Set new attributes to a serial device.
580
581 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
582 @param BaudRate The baudrate of the serial device
583 @param ReceiveFifoDepth The depth of receive FIFO buffer
584 @param Timeout The request timeout for a single char
585 @param Parity The type of parity used in serial device
586 @param DataBits Number of databits used in serial device
587 @param StopBits Number of stopbits used in serial device
588
589 @retval EFI_SUCCESS The new attributes were set
590 @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value
591 @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6
592 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return)
593
594 **/
595 EFI_STATUS
596 EFIAPI
597 SerialSetAttributes (
598 IN EFI_SERIAL_IO_PROTOCOL *This,
599 IN UINT64 BaudRate,
600 IN UINT32 ReceiveFifoDepth,
601 IN UINT32 Timeout,
602 IN EFI_PARITY_TYPE Parity,
603 IN UINT8 DataBits,
604 IN EFI_STOP_BITS_TYPE StopBits
605 )
606 {
607 EFI_STATUS Status;
608 SERIAL_DEV *SerialDevice;
609 UINT64 Divisor;
610 SERIAL_PORT_LCR Lcr;
611 UART_DEVICE_PATH *Uart;
612 EFI_TPL Tpl;
613
614 SerialDevice = SERIAL_DEV_FROM_THIS (This);
615
616 //
617 // Check for default settings and fill in actual values.
618 //
619 if (BaudRate == 0) {
620 BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
621 }
622
623 if (ReceiveFifoDepth == 0) {
624 ReceiveFifoDepth = SerialDevice->ReceiveFifoDepth;
625 }
626
627 if (Timeout == 0) {
628 Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
629 }
630
631 if (Parity == DefaultParity) {
632 Parity = (EFI_PARITY_TYPE) PcdGet8 (PcdUartDefaultParity);
633 }
634
635 if (DataBits == 0) {
636 DataBits = PcdGet8 (PcdUartDefaultDataBits);
637 }
638
639 if (StopBits == DefaultStopBits) {
640 StopBits = (EFI_STOP_BITS_TYPE) PcdGet8 (PcdUartDefaultStopBits);
641 }
642
643 if (!VerifyUartParameters (SerialDevice->ClockRate, BaudRate, DataBits, Parity, StopBits, &Divisor, &BaudRate)) {
644 return EFI_INVALID_PARAMETER;
645 }
646
647 if ((ReceiveFifoDepth == 0) || (ReceiveFifoDepth > SerialDevice->ReceiveFifoDepth)) {
648 return EFI_INVALID_PARAMETER;
649 }
650
651 if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {
652 return EFI_INVALID_PARAMETER;
653 }
654
655 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
656
657 //
658 // Put serial port on Divisor Latch Mode
659 //
660 Lcr.Data = READ_LCR (SerialDevice);
661 Lcr.Bits.DLab = 1;
662 WRITE_LCR (SerialDevice, Lcr.Data);
663
664 //
665 // Write the divisor to the serial port
666 //
667 WRITE_DLL (SerialDevice, (UINT8) Divisor);
668 WRITE_DLM (SerialDevice, (UINT8) ((UINT16) Divisor >> 8));
669
670 //
671 // Put serial port back in normal mode and set remaining attributes.
672 //
673 Lcr.Bits.DLab = 0;
674
675 switch (Parity) {
676 case NoParity:
677 Lcr.Bits.ParEn = 0;
678 Lcr.Bits.EvenPar = 0;
679 Lcr.Bits.SticPar = 0;
680 break;
681
682 case EvenParity:
683 Lcr.Bits.ParEn = 1;
684 Lcr.Bits.EvenPar = 1;
685 Lcr.Bits.SticPar = 0;
686 break;
687
688 case OddParity:
689 Lcr.Bits.ParEn = 1;
690 Lcr.Bits.EvenPar = 0;
691 Lcr.Bits.SticPar = 0;
692 break;
693
694 case SpaceParity:
695 Lcr.Bits.ParEn = 1;
696 Lcr.Bits.EvenPar = 1;
697 Lcr.Bits.SticPar = 1;
698 break;
699
700 case MarkParity:
701 Lcr.Bits.ParEn = 1;
702 Lcr.Bits.EvenPar = 0;
703 Lcr.Bits.SticPar = 1;
704 break;
705
706 default:
707 break;
708 }
709
710 switch (StopBits) {
711 case OneStopBit:
712 Lcr.Bits.StopB = 0;
713 break;
714
715 case OneFiveStopBits:
716 case TwoStopBits:
717 Lcr.Bits.StopB = 1;
718 break;
719
720 default:
721 break;
722 }
723 //
724 // DataBits
725 //
726 Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03);
727 WRITE_LCR (SerialDevice, Lcr.Data);
728
729 //
730 // Set the Serial I/O mode
731 //
732 This->Mode->BaudRate = BaudRate;
733 This->Mode->ReceiveFifoDepth = ReceiveFifoDepth;
734 This->Mode->Timeout = Timeout;
735 This->Mode->Parity = Parity;
736 This->Mode->DataBits = DataBits;
737 This->Mode->StopBits = StopBits;
738
739 //
740 // See if Device Path Node has actually changed
741 //
742 if (SerialDevice->UartDevicePath.BaudRate == BaudRate &&
743 SerialDevice->UartDevicePath.DataBits == DataBits &&
744 SerialDevice->UartDevicePath.Parity == Parity &&
745 SerialDevice->UartDevicePath.StopBits == StopBits
746 ) {
747 gBS->RestoreTPL (Tpl);
748 return EFI_SUCCESS;
749 }
750 //
751 // Update the device path
752 //
753 SerialDevice->UartDevicePath.BaudRate = BaudRate;
754 SerialDevice->UartDevicePath.DataBits = DataBits;
755 SerialDevice->UartDevicePath.Parity = (UINT8) Parity;
756 SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;
757
758 Status = EFI_SUCCESS;
759 if (SerialDevice->Handle != NULL) {
760
761 //
762 // Skip the optional Controller device path node
763 //
764 Uart = SkipControllerDevicePathNode (
765 (EFI_DEVICE_PATH_PROTOCOL *) (
766 (UINT8 *) SerialDevice->DevicePath + GetDevicePathSize (SerialDevice->ParentDevicePath) - END_DEVICE_PATH_LENGTH
767 ),
768 NULL,
769 NULL
770 );
771 CopyMem (Uart, &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));
772 Status = gBS->ReinstallProtocolInterface (
773 SerialDevice->Handle,
774 &gEfiDevicePathProtocolGuid,
775 SerialDevice->DevicePath,
776 SerialDevice->DevicePath
777 );
778 }
779
780 gBS->RestoreTPL (Tpl);
781
782 return Status;
783 }
784
785 /**
786 Set Control Bits.
787
788 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
789 @param Control Control bits that can be settable
790
791 @retval EFI_SUCCESS New Control bits were set successfully
792 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported
793
794 **/
795 EFI_STATUS
796 EFIAPI
797 SerialSetControl (
798 IN EFI_SERIAL_IO_PROTOCOL *This,
799 IN UINT32 Control
800 )
801 {
802 SERIAL_DEV *SerialDevice;
803 SERIAL_PORT_MCR Mcr;
804 EFI_TPL Tpl;
805 UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
806 EFI_STATUS Status;
807
808 //
809 // The control bits that can be set are :
810 // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO
811 // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO
812 // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW
813 // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW
814 // EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW
815 //
816 SerialDevice = SERIAL_DEV_FROM_THIS (This);
817
818 //
819 // first determine the parameter is invalid
820 //
821 if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
822 EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
823 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) {
824 return EFI_UNSUPPORTED;
825 }
826
827 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
828
829 Mcr.Data = READ_MCR (SerialDevice);
830 Mcr.Bits.DtrC = 0;
831 Mcr.Bits.Rts = 0;
832 Mcr.Bits.Lme = 0;
833 SerialDevice->SoftwareLoopbackEnable = FALSE;
834 SerialDevice->HardwareFlowControl = FALSE;
835
836 if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
837 Mcr.Bits.DtrC = 1;
838 }
839
840 if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
841 Mcr.Bits.Rts = 1;
842 }
843
844 if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
845 Mcr.Bits.Lme = 1;
846 }
847
848 if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
849 SerialDevice->HardwareFlowControl = TRUE;
850 }
851
852 WRITE_MCR (SerialDevice, Mcr.Data);
853
854 if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
855 SerialDevice->SoftwareLoopbackEnable = TRUE;
856 }
857
858 Status = EFI_SUCCESS;
859 if (SerialDevice->Handle != NULL) {
860 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) (
861 (UINTN) SerialDevice->DevicePath
862 + GetDevicePathSize (SerialDevice->ParentDevicePath)
863 - END_DEVICE_PATH_LENGTH
864 + sizeof (UART_DEVICE_PATH)
865 );
866 if (IsUartFlowControlDevicePathNode (FlowControl) &&
867 ((BOOLEAN) (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) != SerialDevice->HardwareFlowControl)) {
868 //
869 // Flow Control setting is changed, need to reinstall device path protocol
870 //
871 WriteUnaligned32 (&FlowControl->FlowControlMap, SerialDevice->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0);
872 Status = gBS->ReinstallProtocolInterface (
873 SerialDevice->Handle,
874 &gEfiDevicePathProtocolGuid,
875 SerialDevice->DevicePath,
876 SerialDevice->DevicePath
877 );
878 }
879 }
880
881 gBS->RestoreTPL (Tpl);
882
883 return Status;
884 }
885
886 /**
887 Get ControlBits.
888
889 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
890 @param Control Control signals of the serial device
891
892 @retval EFI_SUCCESS Get Control signals successfully
893
894 **/
895 EFI_STATUS
896 EFIAPI
897 SerialGetControl (
898 IN EFI_SERIAL_IO_PROTOCOL *This,
899 OUT UINT32 *Control
900 )
901 {
902 SERIAL_DEV *SerialDevice;
903 SERIAL_PORT_MSR Msr;
904 SERIAL_PORT_MCR Mcr;
905 EFI_TPL Tpl;
906
907 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
908
909 SerialDevice = SERIAL_DEV_FROM_THIS (This);
910
911 *Control = 0;
912
913 //
914 // Read the Modem Status Register
915 //
916 Msr.Data = READ_MSR (SerialDevice);
917
918 if (Msr.Bits.Cts == 1) {
919 *Control |= EFI_SERIAL_CLEAR_TO_SEND;
920 }
921
922 if (Msr.Bits.Dsr == 1) {
923 *Control |= EFI_SERIAL_DATA_SET_READY;
924 }
925
926 if (Msr.Bits.Ri == 1) {
927 *Control |= EFI_SERIAL_RING_INDICATE;
928 }
929
930 if (Msr.Bits.Dcd == 1) {
931 *Control |= EFI_SERIAL_CARRIER_DETECT;
932 }
933 //
934 // Read the Modem Control Register
935 //
936 Mcr.Data = READ_MCR (SerialDevice);
937
938 if (Mcr.Bits.DtrC == 1) {
939 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
940 }
941
942 if (Mcr.Bits.Rts == 1) {
943 *Control |= EFI_SERIAL_REQUEST_TO_SEND;
944 }
945
946 if (Mcr.Bits.Lme == 1) {
947 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
948 }
949
950 if (SerialDevice->HardwareFlowControl) {
951 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
952 }
953 //
954 // Update FIFO status
955 //
956 SerialReceiveTransmit (SerialDevice);
957
958 //
959 // See if the Transmit FIFO is empty
960 //
961 if (SerialFifoEmpty (&SerialDevice->Transmit)) {
962 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
963 }
964
965 //
966 // See if the Receive FIFO is empty.
967 //
968 if (SerialFifoEmpty (&SerialDevice->Receive)) {
969 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
970 }
971
972 if (SerialDevice->SoftwareLoopbackEnable) {
973 *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
974 }
975
976 gBS->RestoreTPL (Tpl);
977
978 return EFI_SUCCESS;
979 }
980
981 /**
982 Write the specified number of bytes to serial device.
983
984 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
985 @param BufferSize On input the size of Buffer, on output the amount of
986 data actually written
987 @param Buffer The buffer of data to write
988
989 @retval EFI_SUCCESS The data were written successfully
990 @retval EFI_DEVICE_ERROR The device reported an error
991 @retval EFI_TIMEOUT The write operation was stopped due to timeout
992
993 **/
994 EFI_STATUS
995 EFIAPI
996 SerialWrite (
997 IN EFI_SERIAL_IO_PROTOCOL *This,
998 IN OUT UINTN *BufferSize,
999 IN VOID *Buffer
1000 )
1001 {
1002 SERIAL_DEV *SerialDevice;
1003 UINT8 *CharBuffer;
1004 UINT32 Index;
1005 UINTN Elapsed;
1006 UINTN ActualWrite;
1007 EFI_TPL Tpl;
1008 UINTN Timeout;
1009 UINTN BitsPerCharacter;
1010
1011 SerialDevice = SERIAL_DEV_FROM_THIS (This);
1012 Elapsed = 0;
1013 ActualWrite = 0;
1014
1015 if (*BufferSize == 0) {
1016 return EFI_SUCCESS;
1017 }
1018
1019 if (Buffer == NULL) {
1020 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1021 EFI_ERROR_CODE,
1022 EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
1023 SerialDevice->DevicePath
1024 );
1025
1026 return EFI_DEVICE_ERROR;
1027 }
1028
1029 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1030
1031 CharBuffer = (UINT8 *) Buffer;
1032
1033 //
1034 // Compute the number of bits in a single character. This is a start bit,
1035 // followed by the number of data bits, followed by the number of stop bits.
1036 // The number of stop bits is specified by an enumeration that includes
1037 // support for 1.5 stop bits. Treat 1.5 stop bits as 2 stop bits.
1038 //
1039 BitsPerCharacter =
1040 1 +
1041 This->Mode->DataBits +
1042 ((This->Mode->StopBits == TwoStopBits) ? 2 : This->Mode->StopBits);
1043
1044 //
1045 // Compute the timeout in microseconds to wait for a single byte to be
1046 // transmitted. The Mode structure contans a Timeout field that is the
1047 // maximum time to transmit or receive a character. However, many UARTs
1048 // have a FIFO for transmits, so the time required to add one new character
1049 // to the transmit FIFO may be the time required to flush a full FIFO. If
1050 // the Timeout in the Mode structure is smaller than the time required to
1051 // flush a full FIFO at the current baud rate, then use a timeout value that
1052 // is required to flush a full transmit FIFO.
1053 //
1054 Timeout = MAX (
1055 This->Mode->Timeout,
1056 (UINTN)DivU64x64Remainder (
1057 BitsPerCharacter * (SerialDevice->TransmitFifoDepth + 1) * 1000000,
1058 This->Mode->BaudRate,
1059 NULL
1060 )
1061 );
1062
1063 for (Index = 0; Index < *BufferSize; Index++) {
1064 SerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);
1065
1066 while (SerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !SerialFifoEmpty (&SerialDevice->Transmit)) {
1067 //
1068 // Unsuccessful write so check if timeout has expired, if not,
1069 // stall for a bit, increment time elapsed, and try again
1070 //
1071 if (Elapsed >= Timeout) {
1072 *BufferSize = ActualWrite;
1073 gBS->RestoreTPL (Tpl);
1074 return EFI_TIMEOUT;
1075 }
1076
1077 gBS->Stall (TIMEOUT_STALL_INTERVAL);
1078
1079 Elapsed += TIMEOUT_STALL_INTERVAL;
1080 }
1081
1082 ActualWrite++;
1083 //
1084 // Successful write so reset timeout
1085 //
1086 Elapsed = 0;
1087 }
1088
1089 gBS->RestoreTPL (Tpl);
1090
1091 return EFI_SUCCESS;
1092 }
1093
1094 /**
1095 Read the specified number of bytes from serial device.
1096
1097 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
1098 @param BufferSize On input the size of Buffer, on output the amount of
1099 data returned in buffer
1100 @param Buffer The buffer to return the data into
1101
1102 @retval EFI_SUCCESS The data were read successfully
1103 @retval EFI_DEVICE_ERROR The device reported an error
1104 @retval EFI_TIMEOUT The read operation was stopped due to timeout
1105
1106 **/
1107 EFI_STATUS
1108 EFIAPI
1109 SerialRead (
1110 IN EFI_SERIAL_IO_PROTOCOL *This,
1111 IN OUT UINTN *BufferSize,
1112 OUT VOID *Buffer
1113 )
1114 {
1115 SERIAL_DEV *SerialDevice;
1116 UINT32 Index;
1117 UINT8 *CharBuffer;
1118 UINTN Elapsed;
1119 EFI_STATUS Status;
1120 EFI_TPL Tpl;
1121
1122 SerialDevice = SERIAL_DEV_FROM_THIS (This);
1123 Elapsed = 0;
1124
1125 if (*BufferSize == 0) {
1126 return EFI_SUCCESS;
1127 }
1128
1129 if (Buffer == NULL) {
1130 return EFI_DEVICE_ERROR;
1131 }
1132
1133 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1134
1135 Status = SerialReceiveTransmit (SerialDevice);
1136
1137 if (EFI_ERROR (Status)) {
1138 *BufferSize = 0;
1139
1140 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1141 EFI_ERROR_CODE,
1142 EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
1143 SerialDevice->DevicePath
1144 );
1145
1146 gBS->RestoreTPL (Tpl);
1147
1148 return EFI_DEVICE_ERROR;
1149 }
1150
1151 CharBuffer = (UINT8 *) Buffer;
1152 for (Index = 0; Index < *BufferSize; Index++) {
1153 while (SerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) {
1154 //
1155 // Unsuccessful read so check if timeout has expired, if not,
1156 // stall for a bit, increment time elapsed, and try again
1157 // Need this time out to get conspliter to work.
1158 //
1159 if (Elapsed >= This->Mode->Timeout) {
1160 *BufferSize = Index;
1161 gBS->RestoreTPL (Tpl);
1162 return EFI_TIMEOUT;
1163 }
1164
1165 gBS->Stall (TIMEOUT_STALL_INTERVAL);
1166 Elapsed += TIMEOUT_STALL_INTERVAL;
1167
1168 Status = SerialReceiveTransmit (SerialDevice);
1169 if (Status == EFI_DEVICE_ERROR) {
1170 *BufferSize = Index;
1171 gBS->RestoreTPL (Tpl);
1172 return EFI_DEVICE_ERROR;
1173 }
1174 }
1175 //
1176 // Successful read so reset timeout
1177 //
1178 Elapsed = 0;
1179 }
1180
1181 SerialReceiveTransmit (SerialDevice);
1182
1183 gBS->RestoreTPL (Tpl);
1184
1185 return EFI_SUCCESS;
1186 }
1187
1188 /**
1189 Use scratchpad register to test if this serial port is present.
1190
1191 @param SerialDevice Pointer to serial device structure
1192
1193 @return if this serial port is present
1194 **/
1195 BOOLEAN
1196 SerialPresent (
1197 IN SERIAL_DEV *SerialDevice
1198 )
1199
1200 {
1201 UINT8 Temp;
1202 BOOLEAN Status;
1203
1204 Status = TRUE;
1205
1206 //
1207 // Save SCR reg
1208 //
1209 Temp = READ_SCR (SerialDevice);
1210 WRITE_SCR (SerialDevice, 0xAA);
1211
1212 if (READ_SCR (SerialDevice) != 0xAA) {
1213 Status = FALSE;
1214 }
1215
1216 WRITE_SCR (SerialDevice, 0x55);
1217
1218 if (READ_SCR (SerialDevice) != 0x55) {
1219 Status = FALSE;
1220 }
1221 //
1222 // Restore SCR
1223 //
1224 WRITE_SCR (SerialDevice, Temp);
1225 return Status;
1226 }
1227
1228 /**
1229 Read serial port.
1230
1231 @param SerialDev Pointer to serial device
1232 @param Offset Offset in register group
1233
1234 @return Data read from serial port
1235
1236 **/
1237 UINT8
1238 SerialReadRegister (
1239 IN SERIAL_DEV *SerialDev,
1240 IN UINT32 Offset
1241 )
1242 {
1243 UINT8 Data;
1244 EFI_STATUS Status;
1245
1246 if (SerialDev->PciDeviceInfo == NULL) {
1247 return IoRead8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride);
1248 } else {
1249 if (SerialDev->MmioAccess) {
1250 Status = SerialDev->PciDeviceInfo->PciIo->Mem.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
1251 SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
1252 } else {
1253 Status = SerialDev->PciDeviceInfo->PciIo->Io.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
1254 SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
1255 }
1256 ASSERT_EFI_ERROR (Status);
1257 return Data;
1258 }
1259 }
1260
1261 /**
1262 Write serial port.
1263
1264 @param SerialDev Pointer to serial device
1265 @param Offset Offset in register group
1266 @param Data data which is to be written to some serial port register
1267 **/
1268 VOID
1269 SerialWriteRegister (
1270 IN SERIAL_DEV *SerialDev,
1271 IN UINT32 Offset,
1272 IN UINT8 Data
1273 )
1274 {
1275 EFI_STATUS Status;
1276
1277 if (SerialDev->PciDeviceInfo == NULL) {
1278 IoWrite8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, Data);
1279 } else {
1280 if (SerialDev->MmioAccess) {
1281 Status = SerialDev->PciDeviceInfo->PciIo->Mem.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
1282 SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
1283 } else {
1284 Status = SerialDev->PciDeviceInfo->PciIo->Io.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
1285 SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
1286 }
1287 ASSERT_EFI_ERROR (Status);
1288 }
1289 }