blob: 53268c728e7861221d9aa6f001827a646edda0cd [file] [log] [blame]
// 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;
}