xref: /haiku/src/system/boot/platform/u-boot/serial.cpp (revision f7c507c3a6fbf3a44c59500543926a9088724968)
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 <boot/platform.h>
23 #include <arch/cpu.h>
24 #include <boot/stage2.h>
25 #include <new>
26 #include <string.h>
27 
28 extern "C" {
29 #include <fdt.h>
30 #include <libfdt.h>
31 #include <libfdt_env.h>
32 };
33 
34 #include "fdt_serial.h"
35 
36 
37 DebugUART* gUART;
38 
39 static int32 sSerialEnabled = 0;
40 static char sBuffer[16384];
41 static uint32 sBufferPosition;
42 
43 
44 static void
45 serial_putc(char c)
46 {
47 	if (gUART == NULL || sSerialEnabled <= 0)
48 		return;
49 
50 	gUART->PutChar(c);
51 }
52 
53 
54 extern "C" int
55 serial_getc(bool wait)
56 {
57 	if (gUART == NULL || sSerialEnabled <= 0)
58 		return 0;
59 
60 	return gUART->GetChar(wait);
61 }
62 
63 
64 extern "C" void
65 serial_puts(const char* string, size_t size)
66 {
67 	if (sSerialEnabled <= 0)
68 		return;
69 
70 	if (sBufferPosition + size < sizeof(sBuffer)) {
71 		memcpy(sBuffer + sBufferPosition, string, size);
72 		sBufferPosition += size;
73 	}
74 
75 	while (size-- != 0) {
76 		char c = string[0];
77 
78 		if (c == '\n') {
79 			serial_putc('\r');
80 			serial_putc('\n');
81 		} else if (c != '\r')
82 			serial_putc(c);
83 
84 		string++;
85 	}
86 }
87 
88 
89 extern "C" void
90 serial_disable(void)
91 {
92 	sSerialEnabled = 0;
93 }
94 
95 
96 extern "C" void
97 serial_enable(void)
98 {
99 	/* should already be initialized by U-Boot */
100 	gUART->InitEarly();
101 	gUART->InitPort(115200);
102 	sSerialEnabled++;
103 }
104 
105 
106 extern "C" void
107 serial_cleanup(void)
108 {
109 	if (sSerialEnabled <= 0)
110 		return;
111 
112 	gKernelArgs.debug_output = kernel_args_malloc(sBufferPosition);
113 	if (gKernelArgs.debug_output != NULL) {
114 		memcpy(gKernelArgs.debug_output, sBuffer, sBufferPosition);
115 		gKernelArgs.debug_size = sBufferPosition;
116 	}
117 }
118 
119 
120 extern "C" void
121 serial_init(const void *fdt)
122 {
123 	// first try with hints from the FDT
124 	gUART = debug_uart_from_fdt(fdt);
125 
126 	// Do we can some kind of direct fallback here
127 	// (aka, guess arch_get_uart_pl011 or arch_get_uart_8250?)
128 	if (gUART == NULL)
129 		return;
130 
131 	serial_enable();
132 }
133