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
28extern "C" {
29#include <fdt.h>
30#include <libfdt.h>
31#include <libfdt_env.h>
32};
33
34#include "fdt_serial.h"
35
36
37DebugUART* gUART;
38
39static int32 sSerialEnabled = 0;
40static char sBuffer[16384];
41static uint32 sBufferPosition;
42
43
44static void
45serial_putc(char c)
46{
47	if (gUART == NULL || sSerialEnabled <= 0)
48		return;
49
50	gUART->PutChar(c);
51}
52
53
54extern "C" int
55serial_getc(bool wait)
56{
57	if (gUART == NULL || sSerialEnabled <= 0)
58		return 0;
59
60	return gUART->GetChar(wait);
61}
62
63
64extern "C" void
65serial_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
89extern "C" void
90serial_disable(void)
91{
92	sSerialEnabled = 0;
93}
94
95
96extern "C" void
97serial_enable(void)
98{
99	/* should already be initialized by U-Boot */
100	gUART->InitEarly();
101	gUART->InitPort(115200);
102	sSerialEnabled++;
103}
104
105
106extern "C" void
107serial_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
120extern "C" void
121serial_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