Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_sys_io_baremetal_lm3s6965evb / sys_io_baremetal.cc
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include <cinttypes>
16
17 #include "pw_preprocessor/compiler.h"
18 #include "pw_sys_io/sys_io.h"
19
20 namespace {
21
22 // Default core clock. This is technically not a constant, but since this app
23 // doesn't change the system clock a constant will suffice.
24 constexpr uint32_t kSystemCoreClock = 12000000;
25
26 // UART status flags.
27 constexpr uint32_t kTxFifoEmptyMask = 0b10000000;
28 constexpr uint32_t kRxFifoFullMask = 0b100000;
29
30 // UART line control flags.
31 // Default: 8n1
32 constexpr uint32_t kDefaultLineControl = 0x60;
33
34 // UART control flags.
35 constexpr uint32_t kUartEnableMask = 0x1;
36
37 PW_PACKED(struct) UartBlock {
38   uint32_t data_register;
39   uint32_t receive_error;
40   uint32_t reserved1[4];
41   uint32_t status_flags;
42   uint32_t reserved2;
43   uint32_t low_power;
44   uint32_t integer_baud;
45   uint32_t fractional_baud;
46   uint32_t line_control;
47   uint32_t control;
48   uint32_t interrupt_fifo_level;
49   uint32_t interrupt_mask;
50   uint32_t raw_interrupt;
51   uint32_t masked_interrupt;
52   uint32_t interrupt_clear;
53 };
54
55 // Declare a reference to the memory mapped block for UART0.
56 volatile UartBlock& uart0 = *reinterpret_cast<volatile UartBlock*>(0x4000C000U);
57
58 constexpr uint32_t kRcgcUart0EnableMask = 0x1;
59 volatile uint32_t& rcgc1 = *reinterpret_cast<volatile uint32_t*>(0x400FE104U);
60
61 // Calculate a baud rate multiplier such that we have 16 bits of precision for
62 // the integer portion and 6 bits for the fractional portion.
63 void SetBaudRate(uint32_t clock, uint32_t target_baud) {
64   uint32_t divisor = target_baud * 16;
65   uint32_t remainder = clock % divisor;
66   uart0.integer_baud = (clock % divisor) & 0xffff;
67   uart0.fractional_baud = (((remainder << 7) / divisor + 1) >> 1) & 0x3f;
68 }
69
70 }  // namespace
71
72 extern "C" void pw_sys_io_Init() {
73   rcgc1 |= kRcgcUart0EnableMask;
74   for (volatile int i = 0; i < 3; ++i) {
75     // We must wait after enabling uart.
76   }
77   // Set baud rate.
78   SetBaudRate(kSystemCoreClock, /*target_baud=*/115200);
79   uart0.line_control = kDefaultLineControl;
80   uart0.control |= kUartEnableMask;
81 }
82
83 namespace pw::sys_io {
84
85 // Wait for a byte to read on UART0. This blocks until a byte is read. This is
86 // extremely inefficient as it requires the target to burn CPU cycles polling to
87 // see if a byte is ready yet.
88 Status ReadByte(std::byte* dest) {
89   while (true) {
90     if (TryReadByte(dest).ok()) {
91       return OkStatus();
92     }
93   }
94 }
95
96 Status TryReadByte(std::byte* dest) {
97   if (uart0.receive_error) {
98     // Writing anything to this register clears all errors.
99     uart0.receive_error = 0xff;
100   }
101   if (!(uart0.status_flags & kRxFifoFullMask)) {
102     return Status::Unavailable();
103   }
104   *dest = static_cast<std::byte>(uart0.data_register);
105   return OkStatus();
106 }
107
108 // Send a byte over UART0. Since this blocks on every byte, it's rather
109 // inefficient. At the default baud rate of 115200, one byte blocks the CPU for
110 // ~87 micro seconds. This means it takes only 10 bytes to block the CPU for
111 // 1ms!
112 Status WriteByte(std::byte b) {
113   // Wait for TX buffer to be empty. When the buffer is empty, we can write
114   // a value to be dumped out of UART.
115   while (!(uart0.status_flags & kTxFifoEmptyMask)) {
116   }
117   uart0.data_register = static_cast<uint32_t>(b);
118   return OkStatus();
119 }
120
121 // Writes a string using pw::sys_io, and add newline characters at the end.
122 StatusWithSize WriteLine(const std::string_view& s) {
123   size_t chars_written = 0;
124   StatusWithSize result = WriteBytes(std::as_bytes(std::span(s)));
125   if (!result.ok()) {
126     return result;
127   }
128   chars_written += result.size();
129
130   // Write trailing newline.
131   result = WriteBytes(std::as_bytes(std::span("\r\n", 2)));
132   chars_written += result.size();
133
134   return StatusWithSize(result.status(), chars_written);
135 }
136
137 }  // namespace pw::sys_io