1/*
2 * Copyright 2022 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Oliver Ruiz Dorantes, oliver.ruiz.dorantes@gmail.com
7 */
8
9#include <debug.h>
10#include <arch/arm/reg.h>
11#include <arch/generic/debug_uart.h>
12#include <arch/arm64/arch_uart_linflex.h>
13#include <new>
14
15
16using namespace LINFlexRegisters;
17
18
19ArchUARTlinflex::ArchUARTlinflex(addr_t base, int64 clock)
20	:
21	DebugUART(base, clock)
22{
23	Barrier();
24
25	if (LinflexCell()->LINCR1.B.SLEEP == 0) {
26		// This periperal is initialized
27		if ((LinflexCell()->UARTCR.B.TXEN == 1)
28			&& (LinflexCell()->UARTCR.B.RXEN == 1)
29			&& (LinflexCell()->UARTCR.B.UART == 1)) {
30			// LinFlex already configured as UART mode
31			// TODO: good to go
32		} else {
33
34		}
35	}
36}
37
38
39ArchUARTlinflex::~ArchUARTlinflex()
40{
41}
42
43
44void
45ArchUARTlinflex::Barrier()
46{
47	asm volatile ("" : : : "memory");
48}
49
50
51void
52ArchUARTlinflex::InitPort(uint32 baud)
53{
54	// Calculate baud divisor
55	uint32 baudDivisor = Clock() / (16 * baud);
56	uint32 remainder = Clock() % (16 * baud);
57	uint32 baudFractional = ((8 * remainder) / baud >> 1)
58		+ ((8 * remainder) / baud & 1);
59
60	// Disable UART
61	Disable();
62
63	// Set baud divisor
64
65	// Set LCR 8n1, enable fifo
66
67	// Set FIFO levels
68
69	// Enable UART
70	Enable();
71}
72
73
74void
75ArchUARTlinflex::InitEarly()
76{
77	// Perform special hardware UART configuration
78}
79
80
81void
82ArchUARTlinflex::Enable()
83{
84
85	DebugUART::Enable();
86}
87
88
89void
90ArchUARTlinflex::Disable()
91{
92
93	DebugUART::Disable();
94}
95
96
97int
98ArchUARTlinflex::PutChar(char c)
99{
100	if (Enabled() == true) {
101		// Wait until there is room in fifo
102		bool fifo = LinflexCell()->UARTCR.B.TFBM == 1;
103
104		if (fifo) {
105			// TFF is set by hardware in UART FIFO mode (TFBM = 1) when TX FIFO is full.
106			while (LinflexCell()->UARTSR.B.DTF == 1) {
107				Barrier();
108			}
109		}
110
111		Out<uint8, vuint32>(&LinflexCell()->BDRL.R, c);
112
113		if (!fifo) {
114			// DTF is set by hardware in UART buffer mode (TFBM = 0) and
115			// indicates that data transmission is completed. DTF should be cleared by software.
116			while (LinflexCell()->UARTSR.B.DTF == 0) {
117				Barrier();
118			}
119
120			auto uartsr = BitfieldRegister<UARTSR_register>();
121			uartsr.B.DTF = 1;
122			LinflexCell()->UARTSR.R = uartsr.R;
123		}
124
125		return 0;
126	}
127
128	return -1;
129}
130
131
132int
133ArchUARTlinflex::GetChar(bool wait)
134{
135	int character;
136
137	if (Enabled() == true) {
138		bool fifo = LinflexCell()->UARTCR.B.RFBM == 1;
139
140		if (fifo) {
141			// RFE is set by hardware in UART FIFO mode (RFBM = 1) when the RX FIFO is empty.
142			if (wait) {
143				// Wait until a character is received
144				while (LinflexCell()->UARTSR.B.DRF == 1) {
145					Barrier();
146				}
147			} else {
148				if (LinflexCell()->UARTSR.B.DRF == 1)
149					return -1;
150			}
151		} else {
152			// DRF is set by hardware in UART buffer mode (RFBM = 0) and
153			// indicates that the number of bytes programmed in RDFL have been received.
154			// DRF should be cleared by software.
155			if (wait) {
156				while (LinflexCell()->UARTSR.B.DRF == 0) {
157					Barrier();
158				}
159			} else {
160				if (LinflexCell()->UARTSR.B.DRF == 0)
161					return -1;
162			}
163		}
164
165		character = In<uint8, vuint32>(&LinflexCell()->BDRM.R);
166
167		// Clear status
168		auto uartsr = BitfieldRegister<UARTSR_register>();
169		uartsr.B.RMB = 1;
170		uartsr.B.DRF = 1;
171		LinflexCell()->UARTSR.R = uartsr.R;
172
173		return character;
174	}
175
176	return -1;
177}
178
179
180void
181ArchUARTlinflex::FlushTx()
182{
183	// Wait until transmit fifo empty
184}
185
186
187void
188ArchUARTlinflex::FlushRx()
189{
190	// Wait until receive fifo empty
191}
192
193
194ArchUARTlinflex*
195arch_get_uart_linflex(addr_t base, int64 clock)
196{
197	static char buffer[sizeof(ArchUARTlinflex)];
198	ArchUARTlinflex *uart = new(buffer) ArchUARTlinflex(base, clock);
199	return uart;
200}
201