Blob


1 // uart_a64.cc
2 // Allwinner A64 UART (16550)
5 #include <hw.h>
6 #include <uart.h>
7 #include <uart16550.h>
10 namespace Board {
11 namespace Uart {
14 namespace {
16 constexpr uintptr_t UART0_BASE = 0x01c28000;
18 constexpr auto SERIAL_CLOCK = 24000000;
19 constexpr auto BAUDRATE = 115200;
20 constexpr auto BAUDRATE_DIVISOR = (BAUDRATE * 16);
21 constexpr auto CLOCK_DIVISOR = (SERIAL_CLOCK + (BAUDRATE_DIVISOR / 2)) / BAUDRATE_DIVISOR;
23 static_assert(CLOCK_DIVISOR == 13, "Should be 13");
25 template <typename T>
26 uint8_t read8()
27 {
28 return Hw::read8(UART0_BASE + T::OFFSET);
29 }
31 template <typename T>
32 T read()
33 {
34 return T{read8<T>()};
35 }
38 template <typename T>
39 void write8(uint8_t nValue)
40 {
41 Hw::write8(UART0_BASE + T::OFFSET, nValue);
42 }
44 template <typename T>
45 void write(T Register)
46 {
47 write8<T>(Register.m_u.m_nValue);
48 }
51 } // anonymous namespace
54 void initialize()
55 {
56 for (; ; )
57 {
58 const auto LineStatusRegister{read<Uart16550::LineStatusRegister>()};
59 if (LineStatusRegister.m_u.m_Bits.m_TransmitterEmpty)
60 break;
61 }
63 write(Uart16550::InterruptEnableRegister{});
65 Uart16550::ModemControlRegister ModemControlRegister;
66 ModemControlRegister.m_u.m_Bits.m_DataTerminalReady = 1;
67 ModemControlRegister.m_u.m_Bits.m_RequestToSend = 1;
68 write(ModemControlRegister);
70 Uart16550::FifoControlRegister FifoControlRegister;
71 FifoControlRegister.m_u.m_Bits.m_EnableFifos = 1;
72 FifoControlRegister.m_u.m_Bits.m_RcvrFifoReset = 1;
73 FifoControlRegister.m_u.m_Bits.m_XmitFifoReset = 1;
74 write(FifoControlRegister);
76 Uart16550::LineControlRegister LineControlRegister;
77 LineControlRegister.m_u.m_Bits.m_DataLengthSelect = Uart16550::LineControlRegister::BITS_8;
78 write(LineControlRegister);
80 LineControlRegister.m_u.m_Bits.m_DivisorLatchAccess = 1;
81 write(LineControlRegister);
83 write8<Uart16550::DivisorLatchLowRegister>(CLOCK_DIVISOR & 0xff);
84 write8<Uart16550::DivisorLatchHighRegister>((CLOCK_DIVISOR >> 8) & 0xff);
86 LineControlRegister.m_u.m_Bits.m_DivisorLatchAccess = 0;
87 write(LineControlRegister);
88 }
91 void send(uint8_t nValue)
92 {
93 for (; ; )
94 {
95 const auto LineStatusRegister{read<Uart16550::LineStatusRegister>()};
96 if (LineStatusRegister.m_u.m_Bits.m_TxHoldingRegisterEmpty)
97 break;
98 }
99 write8<Uart16550::TransmitHoldingRegister>(nValue);
103 uint8_t recv()
105 for (; ; )
107 const auto LineStatusRegister{read<Uart16550::LineStatusRegister>()};
108 if (LineStatusRegister.m_u.m_Bits.m_DataReady)
109 break;
111 return read8<Uart16550::ReceiveBufferRegister>();
115 } // namespace Uart
116 } // namespace Board