xref: /aosp_15_r20/external/pigweed/pw_sys_io_emcraft_sf2/sys_io_emcraft_sf2.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 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 "mss_gpio/mss_gpio.h"
18 #include "mss_uart/mss_uart.h"
19 #include "pw_preprocessor/concat.h"
20 #include "pw_status/status.h"
21 #include "pw_sys_io/sys_io.h"
22 #include "pw_sys_io_emcraft_sf2_private/config.h"
23 
24 namespace {
25 
26 // LEDs GPIOs
27 
28 constexpr mss_gpio_id_t kDs3LedGPIO = MSS_GPIO_1;
29 constexpr mss_gpio_id_t kDs4LEDGPIO = MSS_GPIO_2;
30 constexpr uint32_t kDs3LedMask = MSS_GPIO_1_MASK;
31 constexpr uint32_t kDs4LedMask = MSS_GPIO_2_MASK;
32 
33 constexpr uint32_t kReadDataReady = 0x1u;
34 
35 }  // namespace
36 
pw_sys_io_Init()37 extern "C" void pw_sys_io_Init() {
38   // Configure MSS GPIOs.
39 #if SF2_MSS_NO_BOOTLOADER
40   MSS_GPIO_init();
41 #endif
42 
43   MSS_GPIO_config(kDs3LedGPIO, MSS_GPIO_OUTPUT_MODE);
44   MSS_GPIO_config(kDs4LEDGPIO, MSS_GPIO_OUTPUT_MODE);
45   // Set LEDs to initial app state
46   MSS_GPIO_set_outputs(MSS_GPIO_get_outputs() | kDs4LedMask);
47 
48   // Initialize the UART0 controller (57600, 8N1)
49   // Due to a HW eratta in SF2, we need to run at 57600 for
50   // in-system-programming mode. If we are not upgrading FPGA or flash then we
51   // can use a faster BAUD.
52   MSS_UART_init(
53       &g_mss_uart0,
54       MSS_UART_57600_BAUD,
55       MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT);
56 }
57 
58 // This whole implementation is very inefficient because it uses the synchronous
59 // polling UART API and only reads / writes 1 byte at a time.
60 namespace pw::sys_io {
61 
ReadByte(std::byte * dest)62 Status ReadByte(std::byte* dest) {
63   while (true) {
64     if (TryReadByte(dest).ok()) {
65       return OkStatus();
66     }
67   }
68 }
69 
TryReadByte(std::byte * dest)70 Status TryReadByte(std::byte* dest) {
71   if (!(g_mss_uart0.hw_reg->LSR & kReadDataReady)) {
72     return Status::Unavailable();
73   }
74 
75   *dest = static_cast<std::byte>(g_mss_uart0.hw_reg->RBR);
76   return OkStatus();
77 }
78 
WriteByte(std::byte b)79 Status WriteByte(std::byte b) {
80   // Wait for TX buffer to be empty. When the buffer is empty, we can write
81   // a value to be dumped out of UART.
82   const uint8_t pbuff = (uint8_t)b;
83 
84   MSS_UART_polled_tx(&g_mss_uart0, &pbuff, 1);
85   return OkStatus();
86 }
87 
88 // Writes a string using pw::sys_io, and add newline characters at the end.
WriteLine(std::string_view s)89 StatusWithSize WriteLine(std::string_view s) {
90   size_t chars_written = 0;
91   StatusWithSize result = WriteBytes(as_bytes(span(s)));
92   if (!result.ok()) {
93     return result;
94   }
95   chars_written += result.size();
96 
97   // Write trailing newline.
98   result = WriteBytes(as_bytes(span("\r\n", 2)));
99   chars_written += result.size();
100 
101   return StatusWithSize(OkStatus(), chars_written);
102 }
103 
104 }  // namespace pw::sys_io
105