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
16 using namespace LINFlexRegisters;
17
18
ArchUARTlinflex(addr_t base,int64 clock)19 ArchUARTlinflex::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
~ArchUARTlinflex()39 ArchUARTlinflex::~ArchUARTlinflex()
40 {
41 }
42
43
44 void
Barrier()45 ArchUARTlinflex::Barrier()
46 {
47 asm volatile ("" : : : "memory");
48 }
49
50
51 void
InitPort(uint32 baud)52 ArchUARTlinflex::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
74 void
InitEarly()75 ArchUARTlinflex::InitEarly()
76 {
77 // Perform special hardware UART configuration
78 }
79
80
81 void
Enable()82 ArchUARTlinflex::Enable()
83 {
84
85 DebugUART::Enable();
86 }
87
88
89 void
Disable()90 ArchUARTlinflex::Disable()
91 {
92
93 DebugUART::Disable();
94 }
95
96
97 int
PutChar(char c)98 ArchUARTlinflex::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
132 int
GetChar(bool wait)133 ArchUARTlinflex::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
180 void
FlushTx()181 ArchUARTlinflex::FlushTx()
182 {
183 // Wait until transmit fifo empty
184 }
185
186
187 void
FlushRx()188 ArchUARTlinflex::FlushRx()
189 {
190 // Wait until receive fifo empty
191 }
192
193
194 ArchUARTlinflex*
arch_get_uart_linflex(addr_t base,int64 clock)195 arch_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