From 0ecc48e6de7111692f13352696f3f357d1de6b60 Mon Sep 17 00:00:00 2001 From: Tomasz Gajewski Date: Thu, 31 Jan 2019 23:09:54 +0100 Subject: [PATCH] Mini UART driver for Rpi3 Ref #3405 --- .../base/include/drivers/uart/bcm2835_mini.h | 247 ++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 repos/base/include/drivers/uart/bcm2835_mini.h diff --git a/repos/base/include/drivers/uart/bcm2835_mini.h b/repos/base/include/drivers/uart/bcm2835_mini.h new file mode 100644 index 0000000000..0d0041d71b --- /dev/null +++ b/repos/base/include/drivers/uart/bcm2835_mini.h @@ -0,0 +1,247 @@ +/* + * \brief Driver for the MINI UART for Rpi3 + * \author Tomasz Gajewski + * \date 2019-01-30 + */ + +/* + * Copyright (C) 2011-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__DRIVERS__UART__BCM2835_MINI_H_ +#define _INCLUDE__DRIVERS__UART__BCM2835_MINI_H_ + +/* Genode includes */ +#include + +namespace Genode { class Bcm2835_mini_uart; } + + +/** + * Driver base for the PrimeCell UART MINI Revision r1p3 + */ +class Genode::Bcm2835_mini_uart : Mmio +{ + protected: + + enum { MAX_BAUD_RATE = 0xfffffff }; + + /** + * Auxiliary Interrupt status + */ + struct AuxIrq : public Register<0x00, 32> + { + struct MiniUartIrq : Bitfield<0,1> { }; /* read only */ + struct Spi1Irq : Bitfield<1,1> { }; /* read only */ + struct Spi2Irq : Bitfield<2,1> { }; /* read only */ + }; + + /** + * Auxiliary enables + */ + struct AuxEnables : public Register<0x04, 32> + { + struct MiniUartEnable : Bitfield<0,1> { }; + struct Spi1Enable : Bitfield<1,1> { }; + struct Spi2Enable : Bitfield<2,1> { }; + }; + + /** + * Mini Uart I/O Data + */ + struct AuxMuIoReg : public Register<0x40, 32> + { + struct TransmitReceive : Bitfield<0,8> { }; + + struct DLABLS8BitsBaudrate : Bitfield<0,8> { }; + }; + + /** + * Mini Uart Interrupt Enable + */ + struct AuxMuIerReg : public Register<0x44, 32> + { + struct EnableReceiveInterrupt : Bitfield<0,1> { }; + struct EnableTransmitInterrupt : Bitfield<1,1> { }; + + struct DLABMS8BitsBaudrate : Bitfield<0,8> { }; + }; + + /** + * Mini Uart Interrupt Identify + */ + struct AuxMuIirReg : public Register<0x48, 32> + { + struct InterruptPending : Bitfield<0,1> { }; + struct InterruptId : Bitfield<1,2> { /* read only */ + enum { + NO_INTERRUPTS = 0, + TRANSMIT_HOLDING_REGISTER_EMPTY = 1, + RECEIVER_HOLDS_VALID_BYTE = 2, + }; + + }; + struct FifoClear : Bitfield<1,2> { /* write only */ + enum { + CLEAR_RECEIVE_FIFO = 1, + CLEAR_TRANSMIT_FIFO = 2, + CLEAR_BOTH_FIFOS = 3, + }; + }; + }; + + /** + * Mini Uart Line Control + */ + struct AuxMuLcrReg : public Register<0x4C, 32> + { + struct DataSize : Bitfield<0,1> { }; + struct Break : Bitfield<6,1> { }; + struct DLAB : Bitfield<7,1> { }; + }; + + /** + * Mini Uart Modem Control + */ + struct AuxMuMcrReg : public Register<0x50, 32> + { + struct RTS : Bitfield<1,1> { }; + }; + + /** + * Mini Uart Line Status + */ + struct AuxMuLsrReg : public Register<0x54, 32> + { + struct DataReady : Bitfield<0,1> { }; + struct ReceiverOverrun : Bitfield<1,1> { }; /* read/clear only */ + struct TransmitterEmpty : Bitfield<5,1> { }; /* read only */ + struct TransmitterIdle : Bitfield<6,1> { }; /* read only */ + }; + + /** + * Mini Uart Modem Status + */ + struct AuxMuMsrReg : public Register<0x58, 32> + { + struct CtsStatus : Bitfield<5,1> { }; /* read only */ + }; + + /** + * Mini Uart Scratch + */ + struct AuxMuScratch : public Register<0x5C, 32> + { + struct Scratch : Bitfield<0,8> { }; + }; + + /** + * Mini Uart Extra Control + */ + struct AuxMuCntlReg : public Register<0x60, 32> + { + struct ReceiverEnable : Bitfield<0,1> { }; + struct TransmitterEnable : Bitfield<1,1> { }; + struct EnableReceiveAutoFlowRTSControl : Bitfield<2,1> { }; + struct EnableTransmitAutoFlowCTSControl : Bitfield<3,1> { }; + struct RTSAutoFlowLevel : Bitfield<4,2> { + enum { + DE_ASSERT_RTS_RECEIVE_FIFO_3 = 0, + DE_ASSERT_RTS_RECEIVE_FIFO_2 = 1, + DE_ASSERT_RTS_RECEIVE_FIFO_1 = 2, + DE_ASSERT_RTS_RECEIVE_FIFO_4 = 3, + }; + }; + struct RTSAssertLevel : Bitfield<6,1> { }; + struct CTSAssertLevel : Bitfield<7,1> { }; + }; + + /** + * Mini Uart Extra Status + */ + struct AuxMuStatReg : public Register<0x64, 32> + { + struct SymbolAvailable : Bitfield<0, 1> { }; /* read only */ + struct SpaceAvailable : Bitfield<1, 1> { }; /* read only */ + struct ReceiverIsIdle : Bitfield<2, 1> { }; /* read only */ + struct TransmitterIsIdle : Bitfield<3, 1> { }; /* read only */ + struct ReceiverOverrun : Bitfield<4, 1> { }; /* read only */ + struct TransmitFifoIsFull : Bitfield<5, 1> { }; /* read only */ + struct RTSStatus : Bitfield<6, 1> { }; /* read only */ + struct CTSLine : Bitfield<7, 1> { }; /* read only */ + struct TransmitFifoIsEmpty : Bitfield<8, 1> { }; /* read only */ + struct TransmitterDone : Bitfield<9, 1> { }; /* read only */ + struct ReceiveFifoFillLevel : Bitfield<16,4> { }; /* read only */ + struct TransmitFifoFillLevel : Bitfield<24,4> { }; /* read only */ + }; + + /** + * Mini Uart Baudrate + */ + struct AuxMuBaudReg : public Register<0x68, 32> + { + struct Baudrate : Bitfield<0,16> { }; + }; + + /** + * Idle until the device is ready for action + */ + void _wait_until_ready() { + do { + asm volatile("nop"); + } while (!read()) ; + } + + public: + + /** + * Constructor + * \param base device MMIO base + * \param clock device reference clock frequency + * \param baud_rate targeted UART baud rate + */ + inline Bcm2835_mini_uart(addr_t const base, uint32_t const clock, + uint32_t const baud_rate); + + /** + * Send ASCII char 'c' over the UART interface + */ + inline void put_char(char const c); +}; + + +Genode::Bcm2835_mini_uart::Bcm2835_mini_uart(addr_t const base, + uint32_t const clock, + uint32_t const baud_rate) +: Mmio(base) +{ + /* enable UART1, AUX mini uart */ + write(read() | + AuxEnables::MiniUartEnable::bits(1)); + + write(0); + write(3); + write(0); + write(0); + write(0xc6); + uint32_t const adjusted_br = ((clock / baud_rate) / 8) - 1; + write(AuxMuBaudReg::Baudrate::bits(adjusted_br)); + write(3); + _wait_until_ready(); +} + + +void Genode::Bcm2835_mini_uart::put_char(char const c) +{ + _wait_until_ready(); + + /* transmit character */ + write(c); + _wait_until_ready(); +} + + +#endif /* _INCLUDE__DRIVERS__UART__BCM2835_MINI_H_ */