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