xref: /haiku/src/system/boot/platform/u-boot/serial.cpp (revision 6d2f2ec177bf615a117a7428d71be4330545b320)
1 /*
2  * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  *
5  * Copyright 2012-2015, Haiku, Inc. All rights reserved.
6  * Distributed under the terms of the MIT License.
7  *
8  * Authors:
9  *		Axel Dörfler, axeld@pinc-software.de
10  *		Alexander von Gluck IV, kallisti5@unixzen.com
11  */
12 
13 
14 #include "serial.h"
15 
16 #include <arch/generic/debug_uart_8250.h>
17 
18 #if defined(__ARM__)
19 #include <arch/arm/arch_uart_pl011.h>
20 #endif
21 
22 #include <board_config.h>
23 #include <boot/platform.h>
24 #include <arch/cpu.h>
25 #include <boot/stage2.h>
26 #include <new>
27 #include <string.h>
28 
29 extern "C" {
30 #include <fdt.h>
31 #include <libfdt.h>
32 #include <libfdt_env.h>
33 };
34 
35 #include "fdt_serial.h"
36 
37 
38 DebugUART* gUART;
39 
40 static int32 sSerialEnabled = 0;
41 static char sBuffer[16384];
42 static uint32 sBufferPosition;
43 
44 
45 static void
46 serial_putc(char c)
47 {
48 	if (gUART == NULL || sSerialEnabled <= 0)
49 		return;
50 
51 	gUART->PutChar(c);
52 }
53 
54 
55 extern "C" int
56 serial_getc(bool wait)
57 {
58 	if (gUART == NULL || sSerialEnabled <= 0)
59 		return 0;
60 
61 	return gUART->GetChar(wait);
62 }
63 
64 
65 extern "C" void
66 serial_puts(const char* string, size_t size)
67 {
68 	if (sSerialEnabled <= 0)
69 		return;
70 
71 	if (sBufferPosition + size < sizeof(sBuffer)) {
72 		memcpy(sBuffer + sBufferPosition, string, size);
73 		sBufferPosition += size;
74 	}
75 
76 	while (size-- != 0) {
77 		char c = string[0];
78 
79 		if (c == '\n') {
80 			serial_putc('\r');
81 			serial_putc('\n');
82 		} else if (c != '\r')
83 			serial_putc(c);
84 
85 		string++;
86 	}
87 }
88 
89 
90 extern "C" void
91 serial_disable(void)
92 {
93 	sSerialEnabled = 0;
94 }
95 
96 
97 extern "C" void
98 serial_enable(void)
99 {
100 	/* should already be initialized by U-Boot */
101 	gUART->InitEarly();
102 	gUART->InitPort(115200);
103 	sSerialEnabled++;
104 }
105 
106 
107 extern "C" void
108 serial_cleanup(void)
109 {
110 	if (sSerialEnabled <= 0)
111 		return;
112 
113 	gKernelArgs.debug_output = kernel_args_malloc(sBufferPosition);
114 	if (gKernelArgs.debug_output != NULL) {
115 		memcpy(gKernelArgs.debug_output, sBuffer, sBufferPosition);
116 		gKernelArgs.debug_size = sBufferPosition;
117 	}
118 }
119 
120 
121 extern "C" void
122 serial_init(const void *fdt)
123 {
124 	// first try with hints from the FDT
125 	gUART = debug_uart_from_fdt(fdt);
126 
127 	// fallback to known board UARTs
128 	#if defined(BOARD_UART_DEBUG) && defined(BOARD_UART_CLOCK)
129 	if (gUART == NULL) {
130 		#ifdef BOARD_UART_PL011
131 		gUART = arch_get_uart_pl011(BOARD_UART_DEBUG, BOARD_UART_CLOCK);
132 		#else
133 		gUART = arch_get_uart_8250(BOARD_UART_DEBUG, BOARD_UART_CLOCK);
134 		#endif
135 	}
136 	#endif
137 
138 	if (gUART == NULL)
139 		return;
140 
141 	serial_enable();
142 }
143