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