/* * Copyright 2022 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Oliver Ruiz Dorantes, oliver.ruiz.dorantes@gmail.com */ #include #include #include #include #include using namespace LINFlexRegisters; ArchUARTlinflex::ArchUARTlinflex(addr_t base, int64 clock) : DebugUART(base, clock) { Barrier(); if (LinflexCell()->LINCR1.B.SLEEP == 0) { // This periperal is initialized if ((LinflexCell()->UARTCR.B.TXEN == 1) && (LinflexCell()->UARTCR.B.RXEN == 1) && (LinflexCell()->UARTCR.B.UART == 1)) { // LinFlex already configured as UART mode // TODO: good to go } else { } } } ArchUARTlinflex::~ArchUARTlinflex() { } void ArchUARTlinflex::Barrier() { asm volatile ("" : : : "memory"); } void ArchUARTlinflex::InitPort(uint32 baud) { // Calculate baud divisor uint32 baudDivisor = Clock() / (16 * baud); uint32 remainder = Clock() % (16 * baud); uint32 baudFractional = ((8 * remainder) / baud >> 1) + ((8 * remainder) / baud & 1); // Disable UART Disable(); // Set baud divisor // Set LCR 8n1, enable fifo // Set FIFO levels // Enable UART Enable(); } void ArchUARTlinflex::InitEarly() { // Perform special hardware UART configuration } void ArchUARTlinflex::Enable() { DebugUART::Enable(); } void ArchUARTlinflex::Disable() { DebugUART::Disable(); } int ArchUARTlinflex::PutChar(char c) { if (Enabled() == true) { // Wait until there is room in fifo bool fifo = LinflexCell()->UARTCR.B.TFBM == 1; if (fifo) { // TFF is set by hardware in UART FIFO mode (TFBM = 1) when TX FIFO is full. while (LinflexCell()->UARTSR.B.DTF == 1) { Barrier(); } } Out(&LinflexCell()->BDRL.R, c); if (!fifo) { // DTF is set by hardware in UART buffer mode (TFBM = 0) and // indicates that data transmission is completed. DTF should be cleared by software. while (LinflexCell()->UARTSR.B.DTF == 0) { Barrier(); } auto uartsr = BitfieldRegister(); uartsr.B.DTF = 1; LinflexCell()->UARTSR.R = uartsr.R; } return 0; } return -1; } int ArchUARTlinflex::GetChar(bool wait) { int character; if (Enabled() == true) { bool fifo = LinflexCell()->UARTCR.B.RFBM == 1; if (fifo) { // RFE is set by hardware in UART FIFO mode (RFBM = 1) when the RX FIFO is empty. if (wait) { // Wait until a character is received while (LinflexCell()->UARTSR.B.DRF == 1) { Barrier(); } } else { if (LinflexCell()->UARTSR.B.DRF == 1) return -1; } } else { // DRF is set by hardware in UART buffer mode (RFBM = 0) and // indicates that the number of bytes programmed in RDFL have been received. // DRF should be cleared by software. if (wait) { while (LinflexCell()->UARTSR.B.DRF == 0) { Barrier(); } } else { if (LinflexCell()->UARTSR.B.DRF == 0) return -1; } } character = In(&LinflexCell()->BDRM.R); // Clear status auto uartsr = BitfieldRegister(); uartsr.B.RMB = 1; uartsr.B.DRF = 1; LinflexCell()->UARTSR.R = uartsr.R; return character; } return -1; } void ArchUARTlinflex::FlushTx() { // Wait until transmit fifo empty } void ArchUARTlinflex::FlushRx() { // Wait until receive fifo empty } ArchUARTlinflex* arch_get_uart_linflex(addr_t base, int64 clock) { static char buffer[sizeof(ArchUARTlinflex)]; ArchUARTlinflex *uart = new(buffer) ArchUARTlinflex(base, clock); return uart; }