blob: f4ddc41f89f42886ba2b9fb9731bc538c0d37bff [file] [log] [blame]
/*
* Copyright 2023 Google LLC
* Copyright lowRISC contributors
*
* 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/arch/device.h"
#include "sw/device/lib/base/memory.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_i2c.h"
#include "sw/device/lib/dif/dif_rstmgr.h"
#include "sw/device/lib/dif/dif_spi_device.h"
#include "sw/device/lib/dif/dif_spi_host.h"
#include "sw/device/lib/dif/dif_usbdev.h"
#include "sw/device/lib/dif/dif_ml_top.h"
#include "sw/device/lib/runtime/hart.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_main.h"
#include "hw/top_matcha/sw/autogen/top_matcha.h"
#include "i2c_regs.h"
#include "spi_device_regs.h"
#include "spi_host_regs.h"
#include "usbdev_regs.h"
#include "ml_top_regs.h"
OTTF_DEFINE_TEST_CONFIG();
/**
* RSTMGR SW_RST_CTRL Test
*
* This test checks RSTMGR.SW_RST_CTRL_N[index] with peripheral devices.
* There are 7 RSTMGR.SW_RST_CTRL_N registers and each register
* controls peripheral reset as follows:
*
* // index | device | test register | reset value | prgm value |
* // ------------------------------------------------------------------
* // 0 | SPI_DEVICE | CFG | 0x7f00 | 0x3f0c
* // 1 | SPI_HOST0 | CONFIGOPTS | 0x0 | 0x3210000
* // 2 | SPI_HOST1 | CONFIGOPTS | 0x0 | 0x6540000
* // 3 | SPI_HOST2 | CONFIGOPTS | 0x0 | 0x4320000
* // 4 | USB | EP_OUT_ENABLE | 0x0 | 0xc3
* // 5 | USBAON | Not used
* // 6 | I2C0 | TIMING0 | 0x0 | 0x8b00cfe
* // 7 | I2C1 | TIMING1 | 0x0 | 0x114010d8
* // 8 | I2C2 | TIMING2 | 0x0 | 0x19ec1595
* // 9 | SMC | TODO(kunb)
* // 10 | ML_TOP | INIT_START | 0x0 | 0x1c1595
* // 11 | CAM_I2C | TIMING3 | 0x0 | 0x12345678
* // 12 | VIDEO | TODO(kunb)
* // 13 | AUDIO | TODO(kunb)
*
* 'test register' is a rw type register under each peripheral device.
* During the test, these registers are programmed with arbitrary values. ('prgm
* value') when sw resets are asserted, those values are updated to reset value.
* In each round, the rstmgr asserts reset to each peripheral device and
* each test register value is compared with the expected reset value.
*/
#define MAKE_INIT_FUNC(dif_) \
void dif_##_init(void *dif, uintptr_t base) { \
CHECK_DIF_OK(dif##_##dif_##_init(mmio_region_from_addr(base), dif)); \
}
MAKE_INIT_FUNC(spi_device);
MAKE_INIT_FUNC(spi_host);
MAKE_INIT_FUNC(usbdev);
MAKE_INIT_FUNC(i2c);
MAKE_INIT_FUNC(ml_top);
static void spi_device_config(void *dif) {
uintptr_t handle_address =
((uintptr_t)dif - offsetof(dif_spi_device_handle_t, dev));
dif_spi_device_handle_t *handle = (dif_spi_device_handle_t *)handle_address;
dif_spi_device_config_t cfg = {
.clock_polarity = kDifSpiDeviceEdgePositive,
.data_phase = kDifSpiDeviceEdgeNegative,
.tx_order = kDifSpiDeviceBitOrderLsbToMsb,
.rx_order = kDifSpiDeviceBitOrderLsbToMsb,
.device_mode = kDifSpiDeviceModeGeneric,
.mode_cfg =
{
.generic =
{
.rx_fifo_commit_wait = 63,
.rx_fifo_len = 0x800,
.tx_fifo_len = 0x800,
},
},
};
CHECK_DIF_OK(dif_spi_device_configure(handle, cfg));
}
static void spi_host0_config(void *dif) {
dif_spi_host_config_t cfg = {
.spi_clock = 1000000,
.peripheral_clock_freq_hz = 10000000,
.chip_select =
{
.idle = 1,
.trail = 2,
.lead = 3,
},
.full_cycle = false,
.cpha = false,
.cpol = false,
};
CHECK_DIF_OK(dif_spi_host_configure(dif, cfg));
}
static void spi_host1_config(void *dif) {
dif_spi_host_config_t cfg = {
.spi_clock = 1000000,
.peripheral_clock_freq_hz = 10000000,
.chip_select =
{
.idle = 4,
.trail = 5,
.lead = 6,
},
.full_cycle = false,
.cpha = false,
.cpol = false,
};
CHECK_DIF_OK(dif_spi_host_configure(dif, cfg));
}
static void spi_host2_config(void *dif) {
dif_spi_host_config_t cfg = {
.spi_clock = 1000000,
.peripheral_clock_freq_hz = 10000000,
.chip_select =
{
.idle = 7,
.trail = 8,
.lead = 9,
},
.full_cycle = false,
.cpha = false,
.cpol = false,
};
CHECK_DIF_OK(dif_spi_host_configure(dif, cfg));
}
static void i2c0_config(void *dif) {
dif_i2c_config_t cfg = {
.scl_time_high_cycles = 3326,
.scl_time_low_cycles = 2224,
};
CHECK_DIF_OK(dif_i2c_configure(dif, cfg));
}
static void i2c1_config(void *dif) {
dif_i2c_config_t cfg = {
.rise_cycles = 4312,
.fall_cycles = 4416,
};
CHECK_DIF_OK(dif_i2c_configure(dif, cfg));
}
static void i2c2_config(void *dif) {
dif_i2c_config_t cfg = {
.start_signal_setup_cycles = 5525,
.start_signal_hold_cycles = 6636,
};
CHECK_DIF_OK(dif_i2c_configure(dif, cfg));
}
static void ml_top_config(void *dif) {
}
static void cam_i2c_config(void *dif) {
dif_i2c_config_t cfg = {
.start_signal_setup_cycles = 5525,
.start_signal_hold_cycles = 6636,
};
CHECK_DIF_OK(dif_i2c_configure(dif, cfg));
}
static dif_spi_device_handle_t spi_dev;
static dif_spi_host_t spi_host0;
static dif_spi_host_t spi_host1;
static dif_spi_host_t spi_host2;
static dif_usbdev_t usbdev;
static dif_i2c_t i2c0;
static dif_i2c_t i2c1;
static dif_i2c_t i2c2;
static dif_ml_top_t ml_top;
static dif_i2c_t cam_i2c;
typedef struct test {
/**
* Name of the peripheral.
*/
const char *name;
/**
* Base address for the peripheral.
*/
uintptr_t base;
/**
* Offset to the peripheral's test register.
*/
ptrdiff_t offset;
/**
* Handle to the DIF object for this peripheral.
*/
void *dif;
/**
* Initialization for the DIF based on an address location.
*
* May be `NULL`.
*/
void (*init)(void *dif, uintptr_t base);
/**
* Configuration and initialization actions for the device. This
* will be passed the value of `dif` above.
*
* If `NULL`, the test register will be set to 'reset_vals[]'.
*/
void (*config)(void *dif);
/**
* Arbitrary test register value before reset.
*/
uint32_t program_val;
/**
* The index in the reset manager for this device.
*/
uint32_t reset_index;
} test_t;
static const test_t kPeripherals[] = {
{
.name = "SPI_DEVICE",
.base = TOP_MATCHA_SPI_DEVICE_BASE_ADDR,
.offset = SPI_DEVICE_CFG_REG_OFFSET,
.dif = &spi_dev.dev,
.init = spi_device_init,
.config = spi_device_config,
.program_val = 0x3f0c,
.reset_index = kTopMatchaResetManagerSwResetsSpiDevice,
},
{
.name = "SPI_HOST0",
.base = TOP_MATCHA_SPI_HOST0_BASE_ADDR,
.offset = SPI_HOST_CONFIGOPTS_REG_OFFSET,
.dif = &spi_host0,
.init = spi_host_init,
.config = spi_host0_config,
.program_val = 0x3210000,
.reset_index = kTopMatchaResetManagerSwResetsSpiHost0,
},
{
.name = "SPI_HOST1",
.base = TOP_MATCHA_SPI_HOST1_BASE_ADDR,
.offset = SPI_HOST_CONFIGOPTS_REG_OFFSET,
.dif = &spi_host1,
.init = spi_host_init,
.config = spi_host1_config,
.program_val = 0x6540000,
.reset_index = kTopMatchaResetManagerSwResetsSpiHost1,
},
{
.name = "SPI_HOST2",
.base = TOP_MATCHA_SPI_HOST2_BASE_ADDR,
.offset = SPI_HOST_CONFIGOPTS_REG_OFFSET,
.dif = &spi_host2,
.init = spi_host_init,
.config = spi_host2_config,
.program_val = 0x4320000,
.reset_index = kTopMatchaResetManagerSwResetsSpiHost2,
},
{
.name = "USB",
.base = TOP_MATCHA_USBDEV_BASE_ADDR,
.offset = USBDEV_EP_OUT_ENABLE_REG_OFFSET,
.dif = &usbdev,
.init = usbdev_init,
.program_val = 0xc3,
.reset_index = kTopMatchaResetManagerSwResetsUsb,
},
{
.name = "I2C0",
.base = TOP_MATCHA_I2C0_BASE_ADDR,
.offset = I2C_TIMING0_REG_OFFSET,
.dif = &i2c0,
.init = i2c_init,
.config = i2c0_config,
.program_val = 0x8b00cfe,
.reset_index = kTopMatchaResetManagerSwResetsI2c0,
},
{
.name = "I2C1",
.base = TOP_MATCHA_I2C1_BASE_ADDR,
.offset = I2C_TIMING1_REG_OFFSET,
.dif = &i2c1,
.init = i2c_init,
.config = i2c1_config,
.program_val = 0x114010d8,
.reset_index = kTopMatchaResetManagerSwResetsI2c1,
},
{
.name = "I2C2",
.base = TOP_MATCHA_I2C2_BASE_ADDR,
.offset = I2C_TIMING2_REG_OFFSET,
.dif = &i2c2,
.init = i2c_init,
.config = i2c2_config,
.program_val = 0x19ec1595,
.reset_index = kTopMatchaResetManagerSwResetsI2c2,
},
{
.name = "ML_TOP",
.base = TOP_MATCHA_ML_TOP_CORE_BASE_ADDR,
.offset = ML_TOP_INIT_START_REG_OFFSET,
.dif = &ml_top,
.init = ml_top_init,
.config = ml_top_config,
.program_val = 0x1c1595,
.reset_index = kTopMatchaResetManagerSwResetsMl,
},
{
.name = "CAM_I2C",
.base = TOP_MATCHA_CAM_I2C_BASE_ADDR,
.offset = I2C_TIMING3_REG_OFFSET,
.dif = &cam_i2c,
.init = i2c_init,
.config = cam_i2c_config,
.program_val = 0x12345678,
.reset_index = kTopMatchaResetManagerSwResetsCamI2c,
}
};
/**
* Reads the value of the test register in a particular device.
*/
static uint32_t read_test_reg(const test_t *test) {
return mmio_region_read32(mmio_region_from_addr(test->base), test->offset);
}
bool test_main(void) {
dif_rstmgr_t rstmgr;
CHECK_DIF_OK(dif_rstmgr_init(
mmio_region_from_addr(TOP_MATCHA_RSTMGR_AON_BASE_ADDR), &rstmgr));
uint32_t reset_vals[ARRAYSIZE(kPeripherals)];
for (size_t i = 0; i < ARRAYSIZE(kPeripherals); ++i) {
if (kPeripherals[i].init != NULL) {
kPeripherals[i].init(kPeripherals[i].dif, kPeripherals[i].base);
}
reset_vals[i] = read_test_reg(&kPeripherals[i]);
LOG_INFO("reset_val for %s is 0x%08x", kPeripherals[i].name, reset_vals[i]);
}
for (size_t i = 0; i < ARRAYSIZE(kPeripherals); ++i) {
if (kPeripherals[i].config != NULL) {
kPeripherals[i].config(kPeripherals[i].dif);
} else {
mmio_region_write32(mmio_region_from_addr(kPeripherals[i].base),
kPeripherals[i].offset, kPeripherals[i].program_val);
}
// add read back to make sure
// all register access complete
uint32_t got = read_test_reg(&kPeripherals[i]);
LOG_INFO("programmed value : 0x%x", got);
}
for (size_t i = 0; i < ARRAYSIZE(kPeripherals); ++i) {
CHECK_DIF_OK(dif_rstmgr_software_reset(&rstmgr, kPeripherals[i].reset_index,
kDifRstmgrSoftwareReset));
uint32_t got = read_test_reg(&kPeripherals[i]);
CHECK(got == reset_vals[i],
"after configure: reset_val for %s mismatch: want 0x%x, got 0x%x",
kPeripherals[i].name, reset_vals[i], got);
}
return true;
}