| // Copyright 2023 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| |
| #include "sw/device/lib/testing/test_rom/puppeteer_utils/uart.h" |
| |
| #include "hw/top_matcha/sw/autogen/top_matcha.h" // Generated. |
| #include "pinmux_regs.h" // NOLINT(build/include_subdir) Generated. |
| #include "sw/device/lib/testing/test_rom/puppeteer_utils/opentitan_uart.h" |
| #include "uart_regs.h" // NOLINT(build/include_subdir) Generated. |
| |
| // Opentitan toolchain doesn't invoke -lgcc, so the clk divider needs to be |
| // computed in preprocessor instead of in runtime to bypass the uint64 division. |
| #ifndef TINY_IO_PERIPHERAL_CLOCK |
| #define TINY_IO_PERIPHERAL_CLOCK 2500000ull |
| #endif |
| #ifndef TINY_IO_BUAD_RATE |
| #define TINY_IO_BUAD_RATE 115200ull |
| #endif |
| |
| // The UART's clock scaler is a 16-bit accumulator that needs to overflow 16 |
| // times per bit period to account for oversampling. We do this bit of math |
| // using 64-bit ints so we don't overflow, even though the resulting divider |
| // setting is only 16 bits. |
| #define TINY_IO_CLK_DIV \ |
| (16ull * 65536ull * TINY_IO_BUAD_RATE) / TINY_IO_PERIPHERAL_CLOCK |
| |
| // Simple helper method to initialize a TinyIO interface to point to Ibex's |
| // UART0 peripheral. |
| TinyIO init_uart0() { |
| // To use UART0, we need to set up the pinmux to connect uart 0 to some MIO |
| // pads and set the pin drive modes. |
| |
| volatile uint32_t* insel_base = reinterpret_cast<uint32_t*>( |
| TOP_MATCHA_PINMUX_AON_BASE_ADDR + PINMUX_MIO_PERIPH_INSEL_0_REG_OFFSET); |
| volatile uint32_t* outsel_base = reinterpret_cast<uint32_t*>( |
| TOP_MATCHA_PINMUX_AON_BASE_ADDR + PINMUX_MIO_OUTSEL_0_REG_OFFSET); |
| |
| // Uart0Rx input is tied to MIO pad 25 (GPIO C3). |
| insel_base[kTopMatchaPinmuxPeripheralInUart0Rx] = kTopMatchaPinmuxInselIoc3; |
| |
| // MIO pad 25 output (GPIO C3) is set to High-Z. |
| outsel_base[kTopMatchaPinmuxMioOutIoc3] = kTopMatchaPinmuxOutselConstantHighZ; |
| |
| // MIO pad 26 output (GPIO C4) is set to Uart0Tx. |
| outsel_base[kTopMatchaPinmuxMioOutIoc4] = kTopMatchaPinmuxOutselUart0Tx; |
| |
| // Turn on the UART peripheral. |
| uint64_t clk_div = TINY_IO_CLK_DIV; |
| |
| volatile OpenTitanUart* uart = |
| reinterpret_cast<OpenTitanUart*>(TOP_MATCHA_UART0_BASE_ADDR); |
| uart->CTRL = 0; |
| uart->FIFO_CTRL = |
| (1 << UART_FIFO_CTRL_RXRST_BIT) | (1 << UART_FIFO_CTRL_TXRST_BIT); |
| uart->OVRD = 0; |
| uart->VAL = 0; |
| uart->INTR_ENABLE = 0; |
| uart->INTR_STATE = ~0; |
| uart->CTRL = |
| (clk_div << 16) | (1 << UART_CTRL_TX_BIT) | (1 << UART_CTRL_RX_BIT); |
| |
| // The "get byte" and "put byte" methods for the bootrom just busy-wait while |
| // the queue is empty/full. |
| |
| auto getter = [](void* user) -> uint8_t { |
| volatile OpenTitanUart* uart = reinterpret_cast<OpenTitanUart*>(user); |
| while (uart->STATUS & (1 << UART_STATUS_RXEMPTY_BIT)) { |
| } |
| return uart->RDATA; |
| }; |
| |
| auto setter = [](void* user, uint8_t b) { |
| volatile OpenTitanUart* uart = reinterpret_cast<OpenTitanUart*>(user); |
| while (uart->STATUS & (1 << UART_STATUS_TXFULL_BIT)) { |
| } |
| uart->WDATA = b; |
| }; |
| |
| return {getter, setter, reinterpret_cast<void*>(TOP_MATCHA_UART0_BASE_ADDR)}; |
| } |
| |
| void init_smc_uart() { |
| volatile uint32_t* insel_base = reinterpret_cast<uint32_t*>( |
| TOP_MATCHA_PINMUX_AON_BASE_ADDR + PINMUX_MIO_PERIPH_INSEL_0_REG_OFFSET); |
| volatile uint32_t* outsel_base = reinterpret_cast<uint32_t*>( |
| TOP_MATCHA_PINMUX_AON_BASE_ADDR + PINMUX_MIO_OUTSEL_0_REG_OFFSET); |
| |
| // SmcUartRx input is tied to MIO pad 32 (GPIO C10). |
| insel_base[kTopMatchaPinmuxPeripheralInSmcUartRx] = |
| kTopMatchaPinmuxInselIoc10; |
| // MIO pad 32 output (GPIO C10) is set to High-Z. |
| outsel_base[kTopMatchaPinmuxMioOutIoc10] = |
| kTopMatchaPinmuxOutselConstantHighZ; |
| // MIO pad 33 output (GPIO C11) is set to SmcTx. |
| outsel_base[kTopMatchaPinmuxMioOutIoc11] = kTopMatchaPinmuxOutselSmcUartTx; |
| } |