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 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 39 ArchUARTlinflex::~ArchUARTlinflex() 40 { 41 } 42 43 44 void 45 ArchUARTlinflex::Barrier() 46 { 47 asm volatile ("" : : : "memory"); 48 } 49 50 51 void 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 75 ArchUARTlinflex::InitEarly() 76 { 77 // Perform special hardware UART configuration 78 } 79 80 81 void 82 ArchUARTlinflex::Enable() 83 { 84 85 DebugUART::Enable(); 86 } 87 88 89 void 90 ArchUARTlinflex::Disable() 91 { 92 93 DebugUART::Disable(); 94 } 95 96 97 int 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 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 181 ArchUARTlinflex::FlushTx() 182 { 183 // Wait until transmit fifo empty 184 } 185 186 187 void 188 ArchUARTlinflex::FlushRx() 189 { 190 // Wait until receive fifo empty 191 } 192 193 194 ArchUARTlinflex* 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