| // 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; | |
| } |