TianoCore EDK2 master
Loading...
Searching...
No Matches
SerialPortParser.c
Go to the documentation of this file.
1
15#include <Library/BaseLib.h>
17
18#include "CmObjectDescUtility.h"
19#include "FdtHwInfoParser.h"
21
27 { "ns16550a" },
28 { "arm,sbsa-uart" },
29 { "arm,pl011" }
30};
31
37};
38
44 { "ns16550a" }
45};
46
52};
53
61 { "arm,sbsa-uart" },
62 { "arm,pl011" }
63};
64
70};
71
85EFIAPI
87 IN CONST VOID *Fdt,
88 IN INT32 SerialPortNode,
90 )
91{
92 EFI_STATUS Status;
93 INT32 IntcNode;
94 CONST UINT8 *SizeValue;
95
96 INT32 AddressCells;
97 INT32 SizeCells;
98 INT32 IntCells;
99
100 CONST UINT8 *Data;
101 INT32 DataSize;
102 UINT8 AccessSize;
103
104 if ((Fdt == NULL) ||
105 (SerialPortInfo == NULL))
106 {
107 ASSERT (0);
108 return EFI_INVALID_PARAMETER;
109 }
110
111 Status = FdtGetParentAddressInfo (
112 Fdt,
113 SerialPortNode,
114 &AddressCells,
115 &SizeCells
116 );
117 if (EFI_ERROR (Status)) {
118 ASSERT (0);
119 return Status;
120 }
121
122 // Don't support more than 64 bits and less than 32 bits addresses.
123 if ((AddressCells < 1) ||
124 (AddressCells > 2) ||
125 (SizeCells < 1) ||
126 (SizeCells > 2))
127 {
128 ASSERT (0);
129 return EFI_ABORTED;
130 }
131
132 Data = fdt_getprop (Fdt, SerialPortNode, "reg", &DataSize);
133 if ((Data == NULL) ||
134 (DataSize < (INT32)(sizeof (UINT32) *
135 GET_DT_REG_ADDRESS_OFFSET (1, AddressCells, SizeCells)) - 1))
136 {
137 // If error or not enough space.
138 ASSERT (0);
139 return EFI_ABORTED;
140 }
141
142 if (AddressCells == 2) {
143 SerialPortInfo->BaseAddress = fdt64_to_cpu (*(UINT64 *)Data);
144 } else {
145 SerialPortInfo->BaseAddress = fdt32_to_cpu (*(UINT32 *)Data);
146 }
147
148 SizeValue = Data + (sizeof (UINT32) *
149 GET_DT_REG_SIZE_OFFSET (0, AddressCells, SizeCells));
150 if (SizeCells == 2) {
151 SerialPortInfo->BaseAddressLength = fdt64_to_cpu (*(UINT64 *)SizeValue);
152 } else {
153 SerialPortInfo->BaseAddressLength = fdt32_to_cpu (*(UINT32 *)SizeValue);
154 }
155
156 // Get the associated interrupt-controller.
157 Status = FdtGetIntcParentNode (Fdt, SerialPortNode, &IntcNode);
158 if (EFI_ERROR (Status)) {
159 ASSERT (0);
160 if (Status == EFI_NOT_FOUND) {
161 // Should have found the node.
162 Status = EFI_ABORTED;
163 }
164
165 return Status;
166 }
167
168 // Get the number of cells used to encode an interrupt.
169 Status = FdtGetInterruptCellsInfo (Fdt, IntcNode, &IntCells);
170 if (EFI_ERROR (Status)) {
171 ASSERT (0);
172 return Status;
173 }
174
175 Data = fdt_getprop (Fdt, SerialPortNode, "interrupts", &DataSize);
176 if ((Data == NULL) || (DataSize != (IntCells * sizeof (UINT32)))) {
177 // If error or not 1 interrupt.
178 ASSERT (0);
179 return EFI_ABORTED;
180 }
181
182 SerialPortInfo->Interrupt = FdtGetInterruptId ((CONST UINT32 *)Data);
183
184 // Note: clock-frequency is optional for SBSA UART.
185 Data = fdt_getprop (Fdt, SerialPortNode, "clock-frequency", &DataSize);
186 if (Data != NULL) {
187 if (DataSize < sizeof (UINT32)) {
188 // If error or not enough space.
189 ASSERT (0);
190 return EFI_ABORTED;
191 } else if (fdt_node_offset_by_phandle (Fdt, fdt32_to_cpu (*Data)) >= 0) {
192 // "clock-frequency" can be a "clocks phandle to refer to the clk used".
193 // This is not supported.
194 ASSERT (0);
195 return EFI_UNSUPPORTED;
196 }
197
198 SerialPortInfo->Clock = fdt32_to_cpu (*(UINT32 *)Data);
199 }
200
201 if (FdtNodeIsCompatible (Fdt, SerialPortNode, &Serial16550CompatibleInfo)) {
202 SerialPortInfo->PortSubtype =
203 EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_16550_WITH_GAS;
204
205 /* reg-io-width:
206 description: |
207 The size (in bytes) of the IO accesses that should be performed on the
208 device. There are some systems that require 32-bit accesses to the
209 UART.
210 */
211 Data = fdt_getprop (Fdt, SerialPortNode, "reg-io-width", &DataSize);
212 if (Data != NULL) {
213 if (DataSize < sizeof (UINT32)) {
214 // If error or not enough space.
215 ASSERT (0);
216 return EFI_ABORTED;
217 }
218
219 AccessSize = fdt32_to_cpu (*(UINT32 *)Data);
220 if (AccessSize > EFI_ACPI_6_3_QWORD) {
221 ASSERT (0);
222 return EFI_INVALID_PARAMETER;
223 }
224
225 SerialPortInfo->AccessSize = AccessSize;
226 } else {
227 // 8250/16550 defaults to byte access.
228 SerialPortInfo->AccessSize = EFI_ACPI_6_3_BYTE;
229 }
230 } else if (FdtNodeIsCompatible (
231 Fdt,
232 SerialPortNode,
234 ))
235 {
236 SerialPortInfo->PortSubtype =
237 EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART;
238 } else {
239 ASSERT (0);
240 return EFI_UNSUPPORTED;
241 }
242
243 // Set Baudrate to 115200 by default
244 SerialPortInfo->BaudRate = 115200;
245 return EFI_SUCCESS;
246}
247
262STATIC
264EFIAPI
266 IN CONST VOID *Fdt,
267 OUT INT32 *SerialConsoleNode
268 )
269{
270 CONST CHAR8 *Prop;
271 INT32 PropSize;
272 CONST CHAR8 *Path;
273 INT32 PathLen;
274 INT32 ChosenNode;
275
276 if ((Fdt == NULL) ||
277 (SerialConsoleNode == NULL))
278 {
279 ASSERT (0);
280 return EFI_INVALID_PARAMETER;
281 }
282
283 // The "chosen" node resides at the root of the DT. Fetch it.
284 ChosenNode = fdt_path_offset (Fdt, "/chosen");
285 if (ChosenNode < 0) {
286 return EFI_NOT_FOUND;
287 }
288
289 Prop = fdt_getprop (Fdt, ChosenNode, "stdout-path", &PropSize);
290 if ((Prop == NULL) || (PropSize < 0)) {
291 return EFI_NOT_FOUND;
292 }
293
294 // Determine the actual path length, as a colon terminates the path.
295 Path = ScanMem8 (Prop, PropSize, ':');
296 if (Path == NULL) {
297 PathLen = (UINT32)AsciiStrLen (Prop);
298 } else {
299 PathLen = (INT32)(Path - Prop);
300 }
301
302 // Aliases cannot start with a '/', so it must be the actual path.
303 if (Prop[0] == '/') {
304 *SerialConsoleNode = fdt_path_offset_namelen (Fdt, Prop, PathLen);
305 return EFI_SUCCESS;
306 }
307
308 // Lookup the alias, as this contains the actual path.
309 Path = fdt_get_alias_namelen (Fdt, Prop, PathLen);
310 if (Path == NULL) {
311 return EFI_NOT_FOUND;
312 }
313
314 *SerialConsoleNode = fdt_path_offset (Fdt, Path);
315 return EFI_SUCCESS;
316}
317
331STATIC
333EFIAPI
335 IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
336 IN CM_ARCH_COMMON_SERIAL_PORT_INFO *GenericSerialInfo,
337 IN INT32 NodeCount,
338 IN EARCH_COMMON_OBJECT_ID SerialObjectId
339 )
340{
341 EFI_STATUS Status;
342 CM_OBJ_DESCRIPTOR *NewCmObjDesc;
343
344 if ((GenericSerialInfo == NULL) || (NodeCount == 0)) {
345 ASSERT (0);
346 return EFI_INVALID_PARAMETER;
347 }
348
349 if ((SerialObjectId != EArchCommonObjSerialPortInfo) &&
350 (SerialObjectId != EArchCommonObjSerialDebugPortInfo) &&
351 (SerialObjectId != EArchCommonObjConsolePortInfo))
352 {
353 ASSERT (0);
354 return EFI_INVALID_PARAMETER;
355 }
356
357 // Dispatch the Generic Serial ports
358 Status = CreateCmObjDesc (
359 CREATE_CM_ARCH_COMMON_OBJECT_ID (SerialObjectId),
360 NodeCount,
361 GenericSerialInfo,
362 sizeof (CM_ARCH_COMMON_SERIAL_PORT_INFO) * NodeCount,
363 &NewCmObjDesc
364 );
365 if (EFI_ERROR (Status)) {
366 ASSERT (0);
367 return Status;
368 }
369
370 // Add all the CmObjs to the Configuration Manager.
371 Status = AddMultipleCmObj (FdtParserHandle, NewCmObjDesc, 0, NULL);
372 ASSERT_EFI_ERROR (Status);
373 FreeCmObjDesc (NewCmObjDesc);
374 return Status;
375}
376
410STATIC
412EFIAPI
414 IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
415 IN INT32 FdtBranch,
416 IN EARCH_COMMON_OBJECT_ID SerialObjectId
417 )
418{
419 EFI_STATUS Status;
421
422 if ((SerialObjectId != EArchCommonObjSerialDebugPortInfo) &&
423 (SerialObjectId != EArchCommonObjConsolePortInfo))
424 {
425 ASSERT (0);
426 return EFI_INVALID_PARAMETER;
427 }
428
429 ZeroMem (&SerialInfo, sizeof (SerialInfo));
430
431 Status = SerialPortNodeParser (
432 FdtParserHandle->Fdt,
433 FdtBranch,
434 &SerialInfo
435 );
436 if (EFI_ERROR (Status)) {
437 ASSERT (0);
438 return Status;
439 }
440
441 Status = SerialPortInfoDispatch (
442 FdtParserHandle,
443 &SerialInfo,
444 1,
445 SerialObjectId
446 );
447 ASSERT_EFI_ERROR (Status);
448 return Status;
449}
450
477EFIAPI
479 IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
480 IN INT32 FdtBranch
481 )
482{
483 EFI_STATUS Status;
484 INT32 SerialConsoleNode;
485 INT32 SerialDebugNode;
486 INT32 SerialNode;
487 UINT32 Index;
488 UINT32 SerialNodeCount;
489 UINT32 SerialNodesRemaining;
490 CM_ARCH_COMMON_SERIAL_PORT_INFO *GenericSerialInfo;
491 UINT32 GenericSerialIndex;
492 VOID *Fdt;
493
494 if (FdtParserHandle == NULL) {
495 ASSERT (0);
496 return EFI_INVALID_PARAMETER;
497 }
498
499 Fdt = FdtParserHandle->Fdt;
500
501 // Count the number of serial-ports.
503 Fdt,
504 FdtBranch,
506 &SerialNodeCount
507 );
508 if (EFI_ERROR (Status)) {
509 ASSERT (0);
510 return Status;
511 }
512
513 if (SerialNodeCount == 0) {
514 return EFI_NOT_FOUND;
515 }
516
517 // Track remaining nodes separately as SerialNodeCount
518 // is used in for loop below and reducing SerialNodeCount
519 // would result in the Generic Serial port nodes not
520 // being found if the serial console port node is among
521 // the first few serial nodes.
522 SerialNodesRemaining = SerialNodeCount;
523
524 // Identify the serial console port.
525 Status = GetSerialConsoleNode (Fdt, &SerialConsoleNode);
526 if (Status == EFI_NOT_FOUND) {
527 // No serial console.
528 SerialConsoleNode = -1;
529 } else if (EFI_ERROR (Status)) {
530 ASSERT (0);
531 return Status;
532 } else {
533 // Parse the console serial-port.
534 Status = SerialPortInfoParser (
535 FdtParserHandle,
536 SerialConsoleNode,
538 );
539 if (EFI_ERROR (Status)) {
540 ASSERT (0);
541 return Status;
542 }
543
544 SerialNodesRemaining--;
545 }
546
547 GenericSerialInfo = NULL;
548 if (SerialNodesRemaining > 1) {
549 // We have more than one serial port remaining.
550 // This means that the first serial port will
551 // be reserved as a debug port, and the remaining
552 // will be for general purpose use.
553 SerialNodesRemaining--;
554 GenericSerialInfo = AllocateZeroPool (
555 SerialNodesRemaining *
557 );
558 if (GenericSerialInfo == NULL) {
559 ASSERT (0);
560 return EFI_OUT_OF_RESOURCES;
561 }
562 }
563
564 SerialNode = FdtBranch;
565 SerialDebugNode = -1;
566 GenericSerialIndex = 0;
567 for (Index = 0; Index < SerialNodeCount; Index++) {
568 // Search the next serial-port node in the branch.
570 Fdt,
571 FdtBranch,
573 &SerialNode
574 );
575 if (EFI_ERROR (Status)) {
576 ASSERT (0);
577 if (Status == EFI_NOT_FOUND) {
578 // Should have found the node.
579 Status = EFI_ABORTED;
580 }
581
582 goto exit_handler;
583 }
584
585 // Ignore the serial console node.
586 if (SerialNode == SerialConsoleNode) {
587 continue;
588 } else if (SerialDebugNode == -1) {
589 // The first serial-port node, not being the console serial-port,
590 // will be the debug serial-port.
591 SerialDebugNode = SerialNode;
592 Status = SerialPortInfoParser (
593 FdtParserHandle,
594 SerialDebugNode,
596 );
597 if (EFI_ERROR (Status)) {
598 ASSERT (0);
599 goto exit_handler;
600 }
601 } else {
602 if (GenericSerialInfo == NULL) {
603 // Should not be possible.
604 ASSERT (0);
605 Status = EFI_ABORTED;
606 goto exit_handler;
607 }
608
609 Status = SerialPortNodeParser (
610 Fdt,
611 SerialNode,
612 &GenericSerialInfo[GenericSerialIndex++]
613 );
614 if (EFI_ERROR (Status)) {
615 ASSERT (0);
616 goto exit_handler;
617 }
618 }
619 } // for
620
621 if (GenericSerialIndex > 0) {
622 Status = SerialPortInfoDispatch (
623 FdtParserHandle,
624 GenericSerialInfo,
625 GenericSerialIndex,
627 );
628 }
629
630exit_handler:
631 if (GenericSerialInfo != NULL) {
632 FreePool (GenericSerialInfo);
633 }
634
635 return Status;
636}
enum ArchCommonObjectID EARCH_COMMON_OBJECT_ID
@ EArchCommonObjSerialPortInfo
2 - Generic Serial Port Info
@ EArchCommonObjSerialDebugPortInfo
4 - Serial Debug Port Info
@ EArchCommonObjConsolePortInfo
3 - Serial Console Port Info
UINT32 EFIAPI FdtGetInterruptId(UINT32 CONST *Data)
UINTN EFIAPI AsciiStrLen(IN CONST CHAR8 *String)
Definition: String.c:641
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID *EFIAPI ScanMem8(IN CONST VOID *Buffer, IN UINTN Length, IN UINT8 Value)
EFI_STATUS EFIAPI FreeCmObjDesc(IN CM_OBJ_DESCRIPTOR *CmObjDesc)
EFI_STATUS EFIAPI AddMultipleCmObj(IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle, IN CONST CM_OBJ_DESCRIPTOR *CmObjDesc, IN UINT32 TokenCount, OPTIONAL OUT CM_OBJECT_TOKEN *TokenTable OPTIONAL)
EFI_STATUS EFIAPI CreateCmObjDesc(IN CM_OBJECT_ID ObjectId, IN UINT32 Count, IN VOID *Data, IN UINT32 Size, OUT CM_OBJ_DESCRIPTOR **NewCmObjDesc)
#define CREATE_CM_ARCH_COMMON_OBJECT_ID(ObjectId)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
EFI_STATUS EFIAPI FdtGetNextCompatNodeInBranch(IN CONST VOID *Fdt, IN INT32 FdtBranch, IN CONST COMPATIBILITY_INFO *CompatNamesInfo, IN OUT INT32 *Node)
Definition: FdtUtility.c:398
BOOLEAN EFIAPI FdtNodeIsCompatible(IN CONST VOID *Fdt, IN INT32 Node, IN CONST VOID *CompatInfo)
Definition: FdtUtility.c:90
EFI_STATUS EFIAPI FdtGetParentAddressInfo(IN CONST VOID *Fdt, IN INT32 Node, OUT INT32 *AddressCells, OPTIONAL OUT INT32 *SizeCells OPTIONAL)
Definition: FdtUtility.c:833
EFI_STATUS EFIAPI FdtCountCompatNodeInBranch(IN CONST VOID *Fdt, IN INT32 FdtBranch, IN CONST COMPATIBILITY_INFO *CompatNamesInfo, OUT UINT32 *NodeCount)
Definition: FdtUtility.c:573
EFI_STATUS EFIAPI FdtGetIntcParentNode(IN CONST VOID *Fdt, IN INT32 Node, OUT INT32 *IntcNode)
Definition: FdtUtility.c:650
EFI_STATUS EFIAPI FdtGetInterruptCellsInfo(IN CONST VOID *Fdt, IN INT32 IntcNode, OUT INT32 *IntCells)
Definition: FdtUtility.c:726
#define GET_DT_REG_SIZE_OFFSET(Index, AddrCells, SizeCells)
Definition: FdtUtility.h:50
#define GET_DT_REG_ADDRESS_OFFSET(Index, AddrCells, SizeCells)
Definition: FdtUtility.h:31
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define ARRAY_SIZE(Array)
Definition: Base.h:1393
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
STATIC CONST COMPATIBILITY_STR SerialSbsaCompatibleStr[]
EFI_STATUS EFIAPI SerialPortDispatcher(IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle, IN INT32 FdtBranch)
CONST COMPATIBILITY_INFO Serial16550CompatibleInfo
CONST COMPATIBILITY_INFO SerialCompatibleInfo
STATIC CONST COMPATIBILITY_STR Serial16550CompatibleStr[]
STATIC EFI_STATUS EFIAPI SerialPortInfoDispatch(IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle, IN CM_ARCH_COMMON_SERIAL_PORT_INFO *GenericSerialInfo, IN INT32 NodeCount, IN EARCH_COMMON_OBJECT_ID SerialObjectId)
STATIC CONST COMPATIBILITY_STR SerialCompatibleStr[]
STATIC EFI_STATUS EFIAPI SerialPortInfoParser(IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle, IN INT32 FdtBranch, IN EARCH_COMMON_OBJECT_ID SerialObjectId)
CONST COMPATIBILITY_INFO SerialSbsaCompatibleInfo
STATIC EFI_STATUS EFIAPI SerialPortNodeParser(IN CONST VOID *Fdt, IN INT32 SerialPortNode, IN CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo)
STATIC EFI_STATUS EFIAPI GetSerialConsoleNode(IN CONST VOID *Fdt, OUT INT32 *SerialConsoleNode)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112