blob: ac4f6570663265f3c4fb8f697d0e88b9c0770d6a [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/lib/arch/device.h"
#include "sw/device/lib/base/abs_mmio.h"
#include "sw/device/lib/base/bitfield.h"
#include "sw/device/lib/base/csr.h"
#include "sw/device/lib/base/hardened.h"
#include "sw/device/lib/runtime/hart.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/runtime/print.h"
#include "sw/device/silicon_creator/lib/drivers/otp.h"
#include "sw/device/silicon_creator/lib/drivers/pinmux.h"
#include "sw/device/silicon_creator/lib/drivers/uart.h"
#include "sw/device/silicon_creator/lib/error.h"
#include "sw/device/silicon_creator/lib/manifest_def.h"
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
#include "otp_ctrl_regs.h"
#include "pinmux_regs.h"
#include "uart_regs.h"
enum {
/**
* Base address of the pinmux registers.
*/
kPinmuxBase = TOP_EARLGREY_PINMUX_AON_BASE_ADDR,
/**
* Base address of the UART registers.
*/
kUartBase = TOP_EARLGREY_UART0_BASE_ADDR,
};
/**
* Set up peripherals for printing.
*
* This clobbers the existing pinmux/UART configuration and should only be used
* at the very end of the test (e.g. to print a message saying whether the
* tests passed or failed).
*
* Must be called before using `LOG_INFO` or `LOG_ERROR`.
*/
static void setup_stdout(void) {
pinmux_init();
uart_init(kUartNCOValue);
base_set_stdout((buffer_sink_t){
.data = NULL,
.sink = uart_sink,
});
}
/**
* Trigger an instruction access fault.
*/
static void fault(void) {
((void (*)(void))TOP_EARLGREY_SRAM_CTRL_MAIN_RAM_BASE_ADDR)();
}
/**
* Trigger an instruction access fault if the values are not equal.
*/
#define CHECK_EQ(lhs_, rhs_, name_) \
do { \
if (lhs_ != rhs_) { \
setup_stdout(); \
LOG_ERROR("Check failed: %s (0x%08x != 0x%08x)", name_, lhs_, rhs_); \
fault(); \
} \
} while (false)
/**
* Get device-specific mask for MIO pad attributes.
*
* Bits are set if the attribute is legal for the current device. This mask
* should match the result of writing UINT32_MAX to the pad attribute register
* and then reading back, because the pad attribute registers have
* write-any-read-legal behavior.
*/
static uint32_t pad_attr_mask_get() {
CHECK_EQ(kDeviceType, kDeviceFpgaCw310,
"This test is only supported for CW310");
// The only legal attributes on CW310 are `invert` and `virtual_od_en`.
uint32_t mask = 0;
mask = bitfield_bit32_write(mask, PINMUX_MIO_PAD_ATTR_0_INVERT_0_BIT, true);
mask = bitfield_bit32_write(mask, PINMUX_MIO_PAD_ATTR_0_VIRTUAL_OD_EN_0_BIT,
true);
// Save the original attributes for pad 0.
uint32_t attr0_orig =
abs_mmio_read32(kPinmuxBase + PINMUX_MIO_PAD_ATTR_0_REG_OFFSET);
// Check that the mask is correct by writing UINT32_MAX to the attribute
// register for pad 0, and then reading back.
abs_mmio_write32(kPinmuxBase + PINMUX_MIO_PAD_ATTR_0_REG_OFFSET, UINT32_MAX);
uint32_t attr0_legal =
abs_mmio_read32(kPinmuxBase + PINMUX_MIO_PAD_ATTR_0_REG_OFFSET);
CHECK_EQ(attr0_legal, mask, "Pad attribute mask check");
// Restore the original register value.
abs_mmio_write32(kPinmuxBase + PINMUX_MIO_PAD_ATTR_0_REG_OFFSET, attr0_orig);
return mask;
}
/**
* Check that the pinmux has been initialized correctly.
*
* Expected configuration:
* - If the OTP BOOTSTRAP_EN option is set, then pinmux should be configured
* with the following peripheral/pad mapping, with pull-down enabled for all
* pads:
* * GPIO22 -> IOC0
* * GPIO23 -> IOC1
* * GPIO24 -> IOC2
* - Regardless of the OTP values, the pinmux should be configured with the
* following mapping for UART0:
* * UART RX -> IOC3
* * IOC4 -> UART TX (output)
*/
static void pinmux_init_test(void) {
uint32_t bootstrap_en =
otp_read32(OTP_CTRL_PARAM_OWNER_SW_CFG_ROM_BOOTSTRAP_EN_OFFSET);
if (bootstrap_en == kHardenedBoolTrue) {
uint32_t attr_mask = pad_attr_mask_get();
// GPIO 22 (input 22) -> IOC0 (MIO pad 22)
uint32_t insel_gpio22 =
abs_mmio_read32(kPinmuxBase + PINMUX_MIO_PERIPH_INSEL_22_REG_OFFSET);
CHECK_EQ(insel_gpio22, kTopEarlgreyPinmuxInselIoc0,
"GPIO 22 input selector");
// Pad 22 attributes: pull-down selected and enabled (if legal).
uint32_t attr22 =
abs_mmio_read32(kPinmuxBase + PINMUX_MIO_PAD_ATTR_22_REG_OFFSET);
CHECK_EQ(
bitfield_bit32_read(attr22, PINMUX_MIO_PAD_ATTR_22_PULL_EN_22_BIT),
bitfield_bit32_read(attr_mask, PINMUX_MIO_PAD_ATTR_22_PULL_EN_22_BIT),
"GPIO 22 pull enable");
CHECK_EQ(
bitfield_bit32_read(attr22, PINMUX_MIO_PAD_ATTR_22_PULL_SELECT_22_BIT),
false, "GPIO 22 pull select");
// GPIO 23 (input 23) -> IOC1 (MIO pad 23)
uint32_t insel_gpio23 =
abs_mmio_read32(kPinmuxBase + PINMUX_MIO_PERIPH_INSEL_23_REG_OFFSET);
CHECK_EQ(insel_gpio23, kTopEarlgreyPinmuxInselIoc1,
"GPIO 23 input selector");
// Pad 23 attributes: pull-down selected and enabled (if legal).
uint32_t attr23 =
abs_mmio_read32(kPinmuxBase + PINMUX_MIO_PAD_ATTR_23_REG_OFFSET);
CHECK_EQ(
bitfield_bit32_read(attr23, PINMUX_MIO_PAD_ATTR_23_PULL_EN_23_BIT),
bitfield_bit32_read(attr_mask, PINMUX_MIO_PAD_ATTR_23_PULL_EN_23_BIT),
"GPIO 23 pull enable");
CHECK_EQ(
bitfield_bit32_read(attr23, PINMUX_MIO_PAD_ATTR_23_PULL_SELECT_23_BIT),
false, "GPIO 23 pull select");
// GPIO 24 (input 24) -> IOC2 (MIO pad 24)
uint32_t insel_gpio24 =
abs_mmio_read32(kPinmuxBase + PINMUX_MIO_PERIPH_INSEL_24_REG_OFFSET);
CHECK_EQ(insel_gpio24, kTopEarlgreyPinmuxInselIoc2,
"GPIO 24 input selector");
// Pad 24 attributes: pull-down selected and enabled (if legal).
uint32_t attr24 =
abs_mmio_read32(kPinmuxBase + PINMUX_MIO_PAD_ATTR_24_REG_OFFSET);
CHECK_EQ(
bitfield_bit32_read(attr24, PINMUX_MIO_PAD_ATTR_24_PULL_EN_24_BIT),
bitfield_bit32_read(attr_mask, PINMUX_MIO_PAD_ATTR_24_PULL_EN_24_BIT),
"GPIO 24 pull enable");
CHECK_EQ(
bitfield_bit32_read(attr24, PINMUX_MIO_PAD_ATTR_24_PULL_SELECT_24_BIT),
false, "GPIO 24 pull select");
}
// UART RX (input 42) -> IOC3 (MIO pad 25)
uint32_t insel_uartrx =
abs_mmio_read32(kPinmuxBase + PINMUX_MIO_PERIPH_INSEL_42_REG_OFFSET);
CHECK_EQ(insel_uartrx, kTopEarlgreyPinmuxInselIoc3, "UART Rx input selector");
// IOC4 (MIO pad 26) -> UART TX (output 42)
uint32_t outsel_ioc4 =
abs_mmio_read32(kPinmuxBase + PINMUX_MIO_OUTSEL_26_REG_OFFSET);
CHECK_EQ(outsel_ioc4, kTopEarlgreyPinmuxOutselUart0Tx,
"UART Tx output selector");
}
/**
* Check that the UART has been initialized correctly.
*
* Expected configuration:
* - `CTRL.TX` (TX enable) bit is true
* - `CTRL.RX` (RX enable) bit is false
* - `CTRL.SLPBK` (system loopback) bit is false
* - `CTRL.LLPBK` (line loopback) bit is false
* - `CTRL.NCO` is set to the precomputed `kUartNCOValue` for this device
* - `CTRL.PARITY_EN` (parity enable) bit is false
* - All interrupts are disabled
* - All FIFOs have been cleared (both Rx and Tx are empty)
*/
static void uart_init_test(void) {
// Check the control register values.
uint32_t ctrl = abs_mmio_read32(kUartBase + UART_CTRL_REG_OFFSET);
CHECK_EQ(bitfield_bit32_read(ctrl, UART_CTRL_TX_BIT), true,
"UART.CTRL.TX_BIT");
CHECK_EQ(bitfield_bit32_read(ctrl, UART_CTRL_RX_BIT), false,
"UART.CTRL.RX_BIT");
CHECK_EQ(bitfield_bit32_read(ctrl, UART_CTRL_SLPBK_BIT), false,
"UART.CTRL.SLPBK_BIT");
CHECK_EQ(bitfield_bit32_read(ctrl, UART_CTRL_LLPBK_BIT), false,
"UART.CTRL.LLPBK_BIT");
CHECK_EQ(bitfield_field32_read(ctrl, UART_CTRL_NCO_FIELD), kUartNCOValue,
"UART.CTRL.NCO_FIELD");
CHECK_EQ(bitfield_bit32_read(ctrl, UART_CTRL_PARITY_EN_BIT), false,
"UART.CTRL.PARITY_EN_BIT");
// Check that all interrupts are disabled.
uint32_t intr_enable =
abs_mmio_read32(kUartBase + UART_INTR_ENABLE_REG_OFFSET);
CHECK_EQ(intr_enable, 0x0, "UART.INTR_ENABLE");
// Check that both FIFOs are idle and empty.
uint32_t status = abs_mmio_read32(kUartBase + UART_STATUS_REG_OFFSET);
CHECK_EQ(bitfield_bit32_read(status, UART_STATUS_TXIDLE_BIT), true,
"UART.STATUS.TXIDLE_BIT");
CHECK_EQ(bitfield_bit32_read(status, UART_STATUS_RXIDLE_BIT), true,
"UART.STATUS.RXIDLE_BIT");
CHECK_EQ(bitfield_bit32_read(status, UART_STATUS_TXEMPTY_BIT), true,
"UART.STATUS.TXEMPTY_BIT");
CHECK_EQ(bitfield_bit32_read(status, UART_STATUS_RXEMPTY_BIT), true,
"UART.STATUS.RXEMPTY_BIT");
}
/**
* Check that the CPUCTRL CSR has been initialized correctly.
*
* Expected configuration:
* - Bits 0:5 of the CPUCTRL CSR should match the value specified in OTP.
*/
static void cpuctrl_init_test(void) {
uint32_t expected_value =
otp_read32(OTP_CTRL_PARAM_CREATOR_SW_CFG_CPUCTRL_OFFSET);
bitfield_field32_t cpuctrl_mask = {.mask = 0x3f, .index = 0};
uint32_t cpuctrl_csr;
CSR_READ(CSR_REG_CPUCTRL, &cpuctrl_csr);
CHECK_EQ(bitfield_field32_read(cpuctrl_csr, cpuctrl_mask), expected_value,
"CPUCTRL CSR");
}
/**
* Test entrypoint.
*
* Because this function becomes the entrypoint for the manifest, it must be
* word-aligned, otherwise it will trigger a `kManifestBadEntryPoint` boot
* fault.
*/
void __attribute__((aligned(4))) _ottf_start(void) {
pinmux_init_test();
uart_init_test();
cpuctrl_init_test();
setup_stdout();
LOG_INFO("PASS!");
wait_for_interrupt();
}