diff --git a/hw/opentitan/Kconfig b/hw/opentitan/Kconfig index d3e0231c2fd4..68eee3523220 100644 --- a/hw/opentitan/Kconfig +++ b/hw/opentitan/Kconfig @@ -164,4 +164,7 @@ config OT_TIMER config OT_UART bool +config OT_UNIMP + bool + source otbn/Kconfig diff --git a/hw/opentitan/meson.build b/hw/opentitan/meson.build index d368ade36a46..7fffd4db4144 100644 --- a/hw/opentitan/meson.build +++ b/hw/opentitan/meson.build @@ -53,5 +53,6 @@ system_ss.add(when: 'CONFIG_OT_SPI_HOST', if_true: files('ot_spi_host.c')) system_ss.add(when: 'CONFIG_OT_SRAM_CTRL', if_true: files('ot_sram_ctrl.c')) system_ss.add(when: 'CONFIG_OT_TIMER', if_true: files('ot_timer.c')) system_ss.add(when: 'CONFIG_OT_UART', if_true: files('ot_uart.c')) +system_ss.add(when: 'CONFIG_OT_UNIMP', if_true: files('ot_unimp.c')) subdir('otbn') diff --git a/hw/opentitan/ot_aes.c b/hw/opentitan/ot_aes.c index 3ecf202e46f5..43c0cd51f886 100644 --- a/hw/opentitan/ot_aes.c +++ b/hw/opentitan/ot_aes.c @@ -56,8 +56,8 @@ /* clang-format off */ REG32(ALERT_TEST, 0x0u) - FIELD(ALERT_TEST, RECOV_CTRL_UPDATE_ERR, 0, 1u) - FIELD(ALERT_TEST, FATAL_FAULT, 1, 1u) + SHARED_FIELD(ALERT_RECOV_CTRL_UPDATE_ERR, 0u, 1u) + SHARED_FIELD(ALERT_FATAL_FAULT, 1u, 1u) REG32(KEY_SHARE0_0, 0x4u) REG32(KEY_SHARE0_1, 0x8u) REG32(KEY_SHARE0_2, 0xcu) @@ -120,6 +120,10 @@ REG32(STATUS, 0x84u) #define OT_AES_IV_BM_MASK ((1u << (PARAM_NUM_REGS_IV)) - 1u) #define OT_AES_DATA_BM_MASK ((1u << (PARAM_NUM_REGS_DATA)) - 1u) +#define OT_AES_ALERT_STATUS_OFFSET \ + (R_STATUS_ALERT_RECOV_CTRL_UPDATE_ERR_SHIFT - \ + ALERT_RECOV_CTRL_UPDATE_ERR_SHIFT) + #define OT_AES_DATA_SIZE (PARAM_NUM_REGS_DATA * sizeof(uint32_t)) #define OT_AES_KEY_SIZE (PARAM_NUM_REGS_KEY * sizeof(uint32_t)) #define OT_AES_IV_SIZE (PARAM_NUM_REGS_IV * sizeof(uint32_t)) @@ -327,7 +331,8 @@ static inline uint32_t ot_aes_get_key_mask(OtAESRegisters *r) static void ot_aes_update_alert(OtAESState *s) { for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - bool level = (bool)(s->regs->status & (1u << ix)); + bool level = + (bool)(s->regs->status & (1u << (ix + OT_AES_ALERT_STATUS_OFFSET))); ibex_irq_set(&s->alerts[ix], (int)level); } } @@ -1095,10 +1100,10 @@ static void ot_aes_write(void *opaque, hwaddr addr, uint64_t val64, switch (reg) { case R_ALERT_TEST: - if (val32 & R_ALERT_TEST_RECOV_CTRL_UPDATE_ERR_MASK) { + if (val32 & ALERT_RECOV_CTRL_UPDATE_ERR_MASK) { r->status |= R_STATUS_ALERT_RECOV_CTRL_UPDATE_ERR_MASK; } - if (val32 & R_ALERT_TEST_FATAL_FAULT_MASK) { + if (val32 & ALERT_FATAL_FAULT_MASK) { r->status |= R_STATUS_ALERT_FATAL_FAULT_MASK; } ot_aes_update_alert(s); diff --git a/hw/opentitan/ot_alert.c b/hw/opentitan/ot_alert.c index 61cbf76c4fa1..68de0eae932b 100644 --- a/hw/opentitan/ot_alert.c +++ b/hw/opentitan/ot_alert.c @@ -1008,15 +1008,11 @@ static void ot_alert_realize(DeviceState *dev, Error **errp) OtAlertState *s = OT_ALERT(dev); + g_assert(s->ot_id); g_assert(s->n_alerts != 0); g_assert(s->pclk != 0); g_assert(s->n_classes > 0 && s->n_classes <= 32); - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } - size_t size = sizeof(OtAlertIntr) + sizeof(OtAlertPing) + sizeof(OtAlertTemplate) * s->n_alerts + sizeof(OtAlertTemplate) * LOCAL_ALERT_COUNT + diff --git a/hw/opentitan/ot_aon_timer.c b/hw/opentitan/ot_aon_timer.c index d709abf2d7a6..70b54c89a793 100644 --- a/hw/opentitan/ot_aon_timer.c +++ b/hw/opentitan/ot_aon_timer.c @@ -532,10 +532,8 @@ static void ot_aon_timer_realize(DeviceState *dev, Error **errp) (void)errp; OtAonTimerState *s = OT_AON_TIMER(dev); - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } + + g_assert(s->ot_id); } static void ot_aon_timer_init(Object *obj) diff --git a/hw/opentitan/ot_edn.c b/hw/opentitan/ot_edn.c index b505bdeb149d..99fece34c026 100644 --- a/hw/opentitan/ot_edn.c +++ b/hw/opentitan/ot_edn.c @@ -1085,8 +1085,8 @@ static uint64_t ot_edn_regs_read(void *opaque, hwaddr addr, unsigned size) val32 = s->regs[reg]; break; case R_SW_CMD_STS: { - uint32_t rdy = (uint32_t) ot_edn_is_cmd_rdy(s, false); - uint32_t reg_rdy = (uint32_t) ot_edn_is_cmd_rdy(s, true); + uint32_t rdy = (uint32_t)ot_edn_is_cmd_rdy(s, false); + uint32_t reg_rdy = (uint32_t)ot_edn_is_cmd_rdy(s, true); val32 = s->regs[R_SW_CMD_STS]; val32 = FIELD_DP32(val32, SW_CMD_STS, CMD_STS, s->rng.last_cmd_status); val32 = FIELD_DP32(val32, SW_CMD_STS, CMD_RDY, rdy); @@ -1163,6 +1163,7 @@ static void ot_edn_regs_write(void *opaque, hwaddr addr, uint64_t val64, case R_ALERT_TEST: val32 &= ALERT_TEST_MASK; s->regs[R_ALERT_TEST] = val32; + ot_edn_update_alerts(s); break; case R_REGWEN: val32 &= R_REGWEN_EN_MASK; diff --git a/hw/opentitan/ot_gpio_dj.c b/hw/opentitan/ot_gpio_dj.c index 8b632174c918..2e10d8b9beb9 100644 --- a/hw/opentitan/ot_gpio_dj.c +++ b/hw/opentitan/ot_gpio_dj.c @@ -815,11 +815,6 @@ static void ot_gpio_dj_reset_enter(Object *obj, ResetType type) OtGpioDjClass *c = OT_GPIO_DJ_GET_CLASS(obj); OtGpioDjState *s = OT_GPIO_DJ(obj); - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } - s->log_en = s->log_id ? !strcmp(s->ot_id, s->log_id) : true; if (s->log_en) { @@ -896,6 +891,8 @@ static void ot_gpio_dj_realize(DeviceState *dev, Error **errp) OtGpioDjState *s = OT_GPIO_DJ(dev); (void)errp; + g_assert(s->ot_id); + qemu_chr_fe_set_handlers(&s->chr, &ot_gpio_dj_chr_can_receive, &ot_gpio_dj_chr_receive, &ot_gpio_dj_chr_event_hander, diff --git a/hw/opentitan/ot_hmac.c b/hw/opentitan/ot_hmac.c index f77025e0c44b..3bfdb578da31 100644 --- a/hw/opentitan/ot_hmac.c +++ b/hw/opentitan/ot_hmac.c @@ -1229,10 +1229,8 @@ static void ot_hmac_realize(DeviceState *dev, Error **errp) (void)errp; OtHMACState *s = OT_HMAC(dev); - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } + + g_assert(s->ot_id); } static void ot_hmac_reset(DeviceState *dev) diff --git a/hw/opentitan/ot_i2c_dj.c b/hw/opentitan/ot_i2c_dj.c index e51874062256..060688c67c8d 100644 --- a/hw/opentitan/ot_i2c_dj.c +++ b/hw/opentitan/ot_i2c_dj.c @@ -959,11 +959,6 @@ static void ot_i2c_dj_reset(DeviceState *dev) { OtI2CDjState *s = OT_I2C_DJ(dev); - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(dev)->parent)); - } - i2c_end_transfer(s->bus); for (unsigned index = 0; index < ARRAY_SIZE(s->irqs); index++) { @@ -984,6 +979,8 @@ static void ot_i2c_dj_realize(DeviceState *dev, Error **errp) OtI2CDjState *s = OT_I2C_DJ(dev); (void)errp; + g_assert(s->ot_id); + /* TODO: check if the following can be moved to ot_i2c_dj_init */ s->bus = i2c_init_bus(dev, TYPE_OT_I2C_DJ); s->target = i2c_slave_create_simple(s->bus, TYPE_OT_I2C_DJ_TARGET, 0xff); diff --git a/hw/opentitan/ot_lc_ctrl.c b/hw/opentitan/ot_lc_ctrl.c index 199d0a7e8196..910286ac9344 100644 --- a/hw/opentitan/ot_lc_ctrl.c +++ b/hw/opentitan/ot_lc_ctrl.c @@ -2178,10 +2178,7 @@ static void ot_lc_ctrl_realize(DeviceState *dev, Error **errp) (void)errp; OtLcCtrlState *s = OT_LC_CTRL(dev); - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } + g_assert(s->ot_id); ot_lc_ctrl_configure_lc_states(s); ot_lc_ctrl_configure_transitions(s, LC_CTRL_TRANS_LC_TCOUNT, diff --git a/hw/opentitan/ot_otp_eg.c b/hw/opentitan/ot_otp_eg.c index e1ea79ec3583..09cc68eea019 100644 --- a/hw/opentitan/ot_otp_eg.c +++ b/hw/opentitan/ot_otp_eg.c @@ -308,8 +308,10 @@ REG32(LC_STATE, 2008u) #define INTR_MASK (INTR_OTP_OPERATION_DONE_MASK | INTR_OTP_ERROR_MASK) #define ALERT_TEST_MASK \ - (R_ALERT_TEST_FATAL_MACRO_ERROR_MASK | R_ALERT_TEST_FATAL_CHECK_ERROR_MASK | \ - R_ALERT_TEST_FATAL_BUS_INTEG_ERROR_MASK | R_ALERT_TEST_FATAL_PRIM_OTP_ALERT_MASK | \ + (R_ALERT_TEST_FATAL_MACRO_ERROR_MASK | \ + R_ALERT_TEST_FATAL_CHECK_ERROR_MASK | \ + R_ALERT_TEST_FATAL_BUS_INTEG_ERROR_MASK | \ + R_ALERT_TEST_FATAL_PRIM_OTP_ALERT_MASK | \ R_ALERT_TEST_RECOV_PRIM_OTP_ALERT_MASK) #define SW_CFG_WINDOW 0x800u @@ -667,14 +669,13 @@ static bool ot_otp_eg_is_readable(OtOTPEgState *s, int partition, unsigned addr) READ_LOCK); break; case OTP_PART_ROT_CREATOR_AUTH_CODESIGN: - rdaccess = - (bool)SHARED_FIELD_EX32(s->regs[R_ROT_CREATOR_AUTH_CODESIGN_READ_LOCK], - READ_LOCK); + rdaccess = (bool)SHARED_FIELD_EX32( + s->regs[R_ROT_CREATOR_AUTH_CODESIGN_READ_LOCK], READ_LOCK); break; case OTP_PART_ROT_CREATOR_AUTH_STATE: - rdaccess = - (bool)SHARED_FIELD_EX32(s->regs[R_ROT_CREATOR_AUTH_STATE_READ_LOCK], - READ_LOCK); + rdaccess = (bool) + SHARED_FIELD_EX32(s->regs[R_ROT_CREATOR_AUTH_STATE_READ_LOCK], + READ_LOCK); break; case OTP_PART_SECRET0: case OTP_PART_SECRET1: @@ -852,16 +853,23 @@ static uint64_t ot_otp_eg_reg_read(void *opaque, hwaddr addr, unsigned size) 32u); break; case R_ROT_CREATOR_AUTH_CODESIGN_DIGEST_0: - val32 = (uint32_t)ot_otp_eg_swcfg_get_part_digest(s, OTP_PART_ROT_CREATOR_AUTH_CODESIGN); + val32 = (uint32_t) + ot_otp_eg_swcfg_get_part_digest(s, + OTP_PART_ROT_CREATOR_AUTH_CODESIGN); break; case R_ROT_CREATOR_AUTH_CODESIGN_DIGEST_1: - val32 = (uint32_t)(ot_otp_eg_swcfg_get_part_digest(s, OTP_PART_ROT_CREATOR_AUTH_CODESIGN) >> 32u); + val32 = (uint32_t)(ot_otp_eg_swcfg_get_part_digest( + s, OTP_PART_ROT_CREATOR_AUTH_CODESIGN) >> + 32u); break; case R_ROT_CREATOR_AUTH_STATE_DIGEST_0: - val32 = (uint32_t)ot_otp_eg_swcfg_get_part_digest(s, OTP_PART_ROT_CREATOR_AUTH_STATE); + val32 = (uint32_t) + ot_otp_eg_swcfg_get_part_digest(s, OTP_PART_ROT_CREATOR_AUTH_STATE); break; case R_ROT_CREATOR_AUTH_STATE_DIGEST_1: - val32 = (uint32_t)(ot_otp_eg_swcfg_get_part_digest(s, OTP_PART_ROT_CREATOR_AUTH_STATE) >> 32u); + val32 = (uint32_t)(ot_otp_eg_swcfg_get_part_digest( + s, OTP_PART_ROT_CREATOR_AUTH_STATE) >> + 32u); break; case R_HW_CFG0_DIGEST_0: val32 = (uint32_t)ot_otp_eg_swcfg_get_part_digest(s, OTP_PART_HW_CFG0); @@ -1168,7 +1176,8 @@ static void ot_otp_eg_load_hw_cfg(OtOTPEgState *s) memset(hw_cfg->soc_dbg_state, 0, sizeof(hw_cfg->soc_dbg_state)); hw_cfg->en_sram_ifetch = (uint8_t)otp->data[R_EN_SRAM_IFETCH]; - entropy_cfg->en_csrng_sw_app_read = (uint8_t)otp->data[R_EN_CSRNG_SW_APP_READ]; + entropy_cfg->en_csrng_sw_app_read = + (uint8_t)otp->data[R_EN_CSRNG_SW_APP_READ]; } static void ot_otp_eg_ctrl_get_lc_info( @@ -1374,10 +1383,7 @@ static void ot_otp_eg_realize(DeviceState *dev, Error **errp) OtOTPEgState *s = OT_OTP_EG(dev); (void)errp; - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } + g_assert(s->ot_id); ot_otp_eg_load(s, &error_fatal); } diff --git a/hw/opentitan/ot_plic_ext.c b/hw/opentitan/ot_plic_ext.c index d2c145c7f9ef..bf38aec6b615 100644 --- a/hw/opentitan/ot_plic_ext.c +++ b/hw/opentitan/ot_plic_ext.c @@ -2,6 +2,7 @@ * QEMU OpenTitan PLIC extension * * Copyright (c) 2024 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Emmanuel Blot @@ -41,38 +42,59 @@ /* clang-format off */ REG32(MSIP0, 0x0u) FIELD(MSIP0, EN, 0u, 1u) -REG32(ALERT_TEST, 0x4u) + +REG32(ALERT_TEST, 0x0u) FIELD(ALERT_TEST, FATAL_FAULT, 0u, 1u) /* clang-format on */ +#define OT_PLIC_EXT_MSIP_BASE 0x0u +#define OT_PLIC_EXT_ALERT_BASE 0x4000u +#define OT_PLIC_EXT_APERTURE 0x8000u + #define R32_OFF(_r_) ((_r_) / sizeof(uint32_t)) -#define R_LAST_REG (R_ALERT_TEST) -#define REGS_COUNT (R_LAST_REG + 1u) -#define REGS_SIZE (REGS_COUNT * sizeof(uint32_t)) -#define REG_NAME(_reg_) \ - ((((_reg_) <= REGS_COUNT) && REG_NAMES[_reg_]) ? REG_NAMES[_reg_] : "?") +#define R_LAST_MSIP_REG (R_MSIP0) +#define MSIP_REGS_COUNT (R_LAST_MSIP_REG + 1u) +#define MSIP_REGS_SIZE (MSIP_REGS_COUNT * sizeof(uint32_t)) +#define MSIP_REG_NAME(_reg_) \ + ((((_reg_) <= MSIP_REGS_COUNT) && MSIP_REG_NAMES[_reg_]) ? \ + MSIP_REG_NAMES[_reg_] : \ + "?") + +#define R_LAST_ALERT_REG (R_ALERT_TEST) +#define ALERT_REGS_COUNT (R_LAST_ALERT_REG + 1u) +#define ALERT_REGS_SIZE (ALERT_REGS_COUNT * sizeof(uint32_t)) +#define ALERT_REG_NAME(_reg_) \ + ((((_reg_) <= ALERT_REGS_COUNT) && ALERT_REG_NAMES[_reg_]) ? \ + ALERT_REG_NAMES[_reg_] : \ + "?") struct OtPlicExtState { SysBusDevice parent_obj; - MemoryRegion mmio; + MemoryRegion mem; + MemoryRegion mmio_msip; + MemoryRegion mmio_alert; + IbexIRQ irq; IbexIRQ alert; - uint32_t regs[REGS_COUNT]; + uint32_t msip_regs[MSIP_REGS_COUNT]; char *ot_id; }; #define REG_NAME_ENTRY(_reg_) [R_##_reg_] = stringify(_reg_) -static const char *REG_NAMES[REGS_COUNT] = { +static const char *MSIP_REG_NAMES[MSIP_REGS_COUNT] = { REG_NAME_ENTRY(MSIP0), +}; + +static const char *ALERT_REG_NAMES[ALERT_REGS_COUNT] = { REG_NAME_ENTRY(ALERT_TEST), }; #undef REG_NAME_ENTRY -static uint64_t ot_plic_ext_regs_read(void *opaque, hwaddr addr, unsigned size) +static uint64_t ot_plic_ext_msip_read(void *opaque, hwaddr addr, unsigned size) { OtPlicExtState *s = opaque; (void)size; @@ -80,15 +102,10 @@ static uint64_t ot_plic_ext_regs_read(void *opaque, hwaddr addr, unsigned size) hwaddr reg = R32_OFF(addr); + /* NOLINTNEXTLINE(hicpp-multiway-paths-covered) */ switch (reg) { case R_MSIP0: - val32 = s->regs[reg]; - break; - case R_ALERT_TEST: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: %s: W/O register 0x%02" HWADDR_PRIx " (%s)\n", - __func__, s->ot_id, addr, REG_NAME(reg)); - val32 = 0; + val32 = s->msip_regs[reg]; break; default: qemu_log_mask(LOG_GUEST_ERROR, @@ -99,13 +116,13 @@ static uint64_t ot_plic_ext_regs_read(void *opaque, hwaddr addr, unsigned size) } uint32_t pc = ibex_get_current_pc(); - trace_ot_plic_ext_io_read_out(s->ot_id, (uint32_t)addr, REG_NAME(reg), - val32, pc); + trace_ot_plic_ext_io_msip_read_out(s->ot_id, (uint32_t)addr, + MSIP_REG_NAME(reg), val32, pc); return (uint64_t)val32; } -static void ot_plic_ext_regs_write(void *opaque, hwaddr addr, uint64_t val64, +static void ot_plic_ext_msip_write(void *opaque, hwaddr addr, uint64_t val64, unsigned size) { OtPlicExtState *s = opaque; @@ -115,18 +132,72 @@ static void ot_plic_ext_regs_write(void *opaque, hwaddr addr, uint64_t val64, hwaddr reg = R32_OFF(addr); uint32_t pc = ibex_get_current_pc(); - trace_ot_plic_ext_io_write(s->ot_id, (uint32_t)addr, REG_NAME(reg), val32, - pc); + trace_ot_plic_ext_io_msip_write(s->ot_id, (uint32_t)addr, + MSIP_REG_NAME(reg), val32, pc); + /* NOLINTNEXTLINE(hicpp-multiway-paths-covered) */ switch (reg) { case R_MSIP0: val32 &= R_MSIP0_EN_MASK; - s->regs[reg] = val32; + s->msip_regs[reg] = val32; ibex_irq_set(&s->irq, (int)(bool)val32); break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, + s->ot_id, addr); + break; + } +} + +static uint64_t ot_plic_ext_alert_read(void *opaque, hwaddr addr, unsigned size) +{ + OtPlicExtState *s = opaque; + (void)size; + uint32_t val32; + + hwaddr reg = R32_OFF(addr); + + /* NOLINTNEXTLINE(hicpp-multiway-paths-covered) */ + switch (reg) { + case R_ALERT_TEST: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: W/O register 0x%02" HWADDR_PRIx " (%s)\n", + __func__, s->ot_id, addr, ALERT_REG_NAME(reg)); + val32 = 0; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, + s->ot_id, addr); + val32 = 0; + break; + } + + uint32_t pc = ibex_get_current_pc(); + trace_ot_plic_ext_io_alert_read_out(s->ot_id, (uint32_t)addr, + ALERT_REG_NAME(reg), val32, pc); + + return (uint64_t)val32; +} + +static void ot_plic_ext_alert_write(void *opaque, hwaddr addr, uint64_t val64, + unsigned size) +{ + OtPlicExtState *s = opaque; + uint32_t val32 = (uint32_t)val64; + (void)size; + + hwaddr reg = R32_OFF(addr); + + uint32_t pc = ibex_get_current_pc(); + trace_ot_plic_ext_io_alert_write(s->ot_id, (uint32_t)addr, + ALERT_REG_NAME(reg), val32, pc); + + /* NOLINTNEXTLINE(hicpp-multiway-paths-covered) */ + switch (reg) { case R_ALERT_TEST: val32 &= R_ALERT_TEST_FATAL_FAULT_MASK; - s->regs[reg] = val32; ibex_irq_set(&s->alert, (int)(bool)val32); break; default: @@ -142,9 +213,17 @@ static Property ot_plic_ext_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static const MemoryRegionOps ot_plic_ext_regs_ops = { - .read = &ot_plic_ext_regs_read, - .write = &ot_plic_ext_regs_write, +static const MemoryRegionOps ot_plic_ext_msip_ops = { + .read = &ot_plic_ext_msip_read, + .write = &ot_plic_ext_msip_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl.min_access_size = 4u, + .impl.max_access_size = 4u, +}; + +static const MemoryRegionOps ot_plic_ext_alert_ops = { + .read = &ot_plic_ext_alert_read, + .write = &ot_plic_ext_alert_write, .endianness = DEVICE_NATIVE_ENDIAN, .impl.min_access_size = 4u, .impl.max_access_size = 4u, @@ -158,25 +237,22 @@ static void ot_plic_ext_reset(DeviceState *dev) ibex_irq_set(&s->alert, 0); } -static void ot_plic_ext_realize(DeviceState *dev, Error **errp) -{ - (void)errp; - - OtPlicExtState *s = OT_PLIC_EXT(dev); - - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } -} - static void ot_plic_ext_init(Object *obj) { OtPlicExtState *s = OT_PLIC_EXT(obj); - memory_region_init_io(&s->mmio, obj, &ot_plic_ext_regs_ops, s, - TYPE_OT_PLIC_EXT, REGS_SIZE); - sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); + /* Top-level container */ + memory_region_init(&s->mem, obj, TYPE_OT_PLIC_EXT, OT_PLIC_EXT_APERTURE); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mem); + + memory_region_init_io(&s->mmio_msip, obj, &ot_plic_ext_msip_ops, s, + TYPE_OT_PLIC_EXT ".msip", MSIP_REGS_SIZE); + memory_region_add_subregion(&s->mem, OT_PLIC_EXT_MSIP_BASE, &s->mmio_msip); + + memory_region_init_io(&s->mmio_alert, obj, &ot_plic_ext_alert_ops, s, + TYPE_OT_PLIC_EXT ".alert", ALERT_REGS_SIZE); + memory_region_add_subregion(&s->mem, OT_PLIC_EXT_ALERT_BASE, + &s->mmio_alert); ibex_qdev_init_irq(obj, &s->irq, NULL); ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT); @@ -188,7 +264,6 @@ static void ot_plic_ext_class_init(ObjectClass *klass, void *data) (void)data; device_class_set_legacy_reset(dc, &ot_plic_ext_reset); - dc->realize = &ot_plic_ext_realize; device_class_set_props(dc, ot_plic_ext_properties); set_bit(DEVICE_CATEGORY_MISC, dc->categories); } diff --git a/hw/opentitan/ot_pwrmgr.c b/hw/opentitan/ot_pwrmgr.c index 9adc7967c6ee..3a2d15636c47 100644 --- a/hw/opentitan/ot_pwrmgr.c +++ b/hw/opentitan/ot_pwrmgr.c @@ -928,11 +928,6 @@ static void ot_pwrmgr_reset_enter(Object *obj, ResetType type) g_assert(PWRMGR_CONFIG[s->version].reset_mask < (1u << PWRMGR_CONFIG[s->version].reset_count)); - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } - trace_ot_pwrmgr_reset(s->ot_id, "enter"); if (c->parent_phases.enter) { @@ -982,6 +977,8 @@ static void ot_pwrmgr_realize(DeviceState *dev, Error **errp) OtPwrMgrState *s = OT_PWRMGR(dev); (void)errp; + g_assert(s->ot_id); + if (s->num_rom) { if (s->num_rom > 8u * sizeof(uint8_t)) { error_setg(&error_fatal, "too many ROMs\n"); diff --git a/hw/opentitan/ot_socdbg_ctrl.c b/hw/opentitan/ot_socdbg_ctrl.c index 35ca380a2201..5729dcadc8b0 100644 --- a/hw/opentitan/ot_socdbg_ctrl.c +++ b/hw/opentitan/ot_socdbg_ctrl.c @@ -776,10 +776,7 @@ static void ot_socdbg_ctrl_realize(DeviceState *dev, Error **errp) OtSoCDbgCtrlState *s = OT_SOCDBG_CTRL(dev); (void)errp; - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } + g_assert(s->ot_id); s->dbg_locked &= POLICY_CAT_MASK | POLICY_RELOCK_MASK; s->dbg_unlocked &= POLICY_CAT_MASK | POLICY_RELOCK_MASK; diff --git a/hw/opentitan/ot_spi_device.c b/hw/opentitan/ot_spi_device.c index 9311120e7278..d14ddc5dd1d0 100644 --- a/hw/opentitan/ot_spi_device.c +++ b/hw/opentitan/ot_spi_device.c @@ -2133,10 +2133,7 @@ static void ot_spi_device_realize(DeviceState *dev, Error **errp) OtSPIDeviceState *s = OT_SPI_DEVICE(dev); (void)errp; - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } + g_assert(s->ot_id); qemu_chr_fe_set_handlers(&s->chr, &ot_spi_device_chr_can_receive, &ot_spi_device_chr_receive, diff --git a/hw/opentitan/ot_spi_host.c b/hw/opentitan/ot_spi_host.c index 85c325a3ce67..cc01a8ffcf8e 100644 --- a/hw/opentitan/ot_spi_host.c +++ b/hw/opentitan/ot_spi_host.c @@ -1320,11 +1320,6 @@ static void ot_spi_host_realize(DeviceState *dev, Error **errp) g_assert(s->pclk); - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } - s->cs_lines = g_new0(qemu_irq, (size_t)s->num_cs); qdev_init_gpio_out_named(DEVICE(s), s->cs_lines, SSI_GPIO_CS, diff --git a/hw/opentitan/ot_sram_ctrl.c b/hw/opentitan/ot_sram_ctrl.c index 28672ded2be6..6e50de332db6 100644 --- a/hw/opentitan/ot_sram_ctrl.c +++ b/hw/opentitan/ot_sram_ctrl.c @@ -709,13 +709,9 @@ static void ot_sram_ctrl_realize(DeviceState *dev, Error **errp) { OtSramCtrlState *s = OT_SRAM_CTRL(dev); + g_assert(s->ot_id); g_assert(s->size); - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } - s->wsize = DIV_ROUND_UP(s->size, sizeof(uint32_t)); unsigned size = s->wsize * sizeof(uint32_t); diff --git a/hw/opentitan/ot_timer.c b/hw/opentitan/ot_timer.c index 67435c7946b5..d1e951540e8a 100644 --- a/hw/opentitan/ot_timer.c +++ b/hw/opentitan/ot_timer.c @@ -375,13 +375,10 @@ static void ot_timer_reset(DeviceState *dev) static void ot_timer_realize(DeviceState *dev, Error **errp) { + OtTimerState *s = OT_TIMER(dev); (void)errp; - OtTimerState *s = OT_TIMER(dev); - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } + g_assert(s->ot_id); } static void ot_timer_init(Object *obj) diff --git a/hw/opentitan/ot_uart.c b/hw/opentitan/ot_uart.c index c97c2fb44e14..61999bf8f551 100644 --- a/hw/opentitan/ot_uart.c +++ b/hw/opentitan/ot_uart.c @@ -453,7 +453,8 @@ static uint64_t ot_uart_read(void *opaque, hwaddr addr, unsigned size) } uint32_t pc = ibex_get_current_pc(); - trace_ot_uart_io_read_out(s->ot_id, (uint32_t)addr, REG_NAME(reg), val32, pc); + trace_ot_uart_io_read_out(s->ot_id, (uint32_t)addr, REG_NAME(reg), val32, + pc); return (uint64_t)val32; } @@ -604,10 +605,7 @@ static void ot_uart_realize(DeviceState *dev, Error **errp) OtUARTState *s = OT_UART(dev); (void)errp; - if (!s->ot_id) { - s->ot_id = - g_strdup(object_get_canonical_path_component(OBJECT(s)->parent)); - } + g_assert(s->ot_id); fifo8_create(&s->tx_fifo, OT_UART_TX_FIFO_SIZE); fifo8_create(&s->rx_fifo, OT_UART_RX_FIFO_SIZE); diff --git a/hw/opentitan/ot_unimp.c b/hw/opentitan/ot_unimp.c new file mode 100644 index 000000000000..038e0f616549 --- /dev/null +++ b/hw/opentitan/ot_unimp.c @@ -0,0 +1,323 @@ +/* + * QEMU OpenTitan unimplemented device + * + * Copyright (c) 2025 lowRISC contributors. + * + * Author(s): + * Emmanuel Blot + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "exec/hwaddr.h" +#include "hw/opentitan/ot_alert.h" +#include "hw/opentitan/ot_common.h" +#include "hw/opentitan/ot_unimp.h" +#include "hw/qdev-properties.h" +#include "hw/registerfields.h" +#include "hw/riscv/ibex_irq.h" +#include "hw/sysbus.h" +#include "trace.h" + +/* Comportable special registers */ + +REG32(INTR_STATE, 0x00u) +REG32(INTR_ENABLE, 0x04u) +REG32(INTR_TEST, 0x08u) +REG32(ALERT_TEST, 0x0cu) + +REG32(ALERT_TEST_NO_IRQ, 0x00u) + + +struct OtUnimpClass { + SysBusDeviceClass parent_class; + ResettablePhases parent_phases; +}; + +struct OtUnimpState { + SysBusDevice parent_obj; + + MemoryRegion mmio; + IbexIRQ *irqs; + IbexIRQ *alerts; + + uint32_t *regs; + bool r_warned; + bool w_warned; + + char *ot_id; + uint32_t size; /* mapped size, in bytes */ + uint32_t irq_ro_mask; /* INTR_STATE R/o bits (vs, RW1C) */ + uint8_t irq_count; /* output IRQ lines, maybe 0 */ + uint8_t alert_count; /* output alert lines, maybe 0 */ + bool warn_once; /* whether to emit a warning once or on each access */ + bool no_store; /* whether to store written values */ +}; + +#define R32_OFF(_r_) ((_r_) / sizeof(uint32_t)) + +static inline hwaddr ot_unimp_alert_test_reg(const OtUnimpState *s) +{ + return s->alert_count ? + (s->irq_count ? R_ALERT_TEST : R_ALERT_TEST_NO_IRQ) : + HWADDR_MAX; +} + +static void ot_unimp_update_irqs(OtUnimpState *s) +{ + uint32_t level = s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE]; + + for (unsigned ix = 0; ix < s->irq_count; ix++) { + int lvl = (int)((level >> ix) & 0x1u); + if (ibex_irq_get_level(&s->irqs[ix]) != lvl) { + trace_ot_unimp_irq(s->ot_id, ix, (bool)lvl); + } + ibex_irq_set(&s->irqs[ix], lvl); + } +} + +static void ot_unimp_update_alerts(OtUnimpState *s, uint32_t val32) +{ + for (unsigned ix = 0; ix < s->alert_count; ix++) { + if ((val32 >> ix) & 0x1u) { + /* alert test signals are transient */ + trace_ot_unimp_alert(s->ot_id, ix); + ibex_irq_raise(&s->alerts[ix]); + ibex_irq_lower(&s->alerts[ix]); + } + } +} + +static uint64_t ot_unimp_io_read(void *opaque, hwaddr addr, unsigned size) +{ + OtUnimpState *s = OT_UNIMP(opaque); + (void)size; + + hwaddr reg = R32_OFF(addr); + uint32_t val32; + + if (s->irq_count) { + switch (reg) { + case R_INTR_STATE: + case R_INTR_ENABLE: + return s->regs[reg]; + case R_INTR_TEST: + qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: W/O register 0x%08x\n", + __func__, s->ot_id, (uint32_t)addr); + return 0; + default: + break; + } + } + + if (reg == ot_unimp_alert_test_reg(s)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: W/O register 0x%08x\n", + __func__, s->ot_id, (uint32_t)addr); + return 0u; + } + + if (!s->no_store) { + val32 = s->regs[reg]; + } else { + val32 = 0u; + } + + if (s->warn_once && s->r_warned) { + return val32; + } + + qemu_log_mask(LOG_UNIMP, + "%s: unimplemented device read @ 0x%08x = 0x%08x\n", s->ot_id, + (uint32_t)addr, val32); + + s->r_warned = true; + + return val32; +} + +static void ot_unimp_io_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + OtUnimpState *s = OT_UNIMP(opaque); + (void)size; + + hwaddr reg = R32_OFF(addr); + uint32_t val32 = (uint32_t)value; + + if (s->irq_count) { + switch (reg) { + case R_INTR_STATE: + val32 &= (1u << s->irq_count) - 1u; + val32 &= ~s->irq_ro_mask; + s->regs[R_INTR_STATE] &= ~val32; + ot_unimp_update_irqs(s); + return; + case R_INTR_ENABLE: + val32 &= (1u << s->irq_count) - 1u; + s->regs[R_INTR_ENABLE] = val32; + ot_unimp_update_irqs(s); + return; + case R_INTR_TEST: + val32 &= (1u << s->irq_count) - 1u; + s->regs[R_INTR_STATE] |= val32; + ot_unimp_update_irqs(s); + return; + default: + break; + } + } + + if (reg == ot_unimp_alert_test_reg(s)) { + val32 &= (1u << s->alert_count) - 1u; + ot_unimp_update_alerts(s, val32); + return; + } + + if (!s->no_store) { + s->regs[reg] = val32; + } + + if (s->warn_once && s->w_warned) { + return; + } + + qemu_log_mask(LOG_UNIMP, + "%s: unimplemented device write @ 0x%08x = 0x%08x\n", + s->ot_id, (uint32_t)addr, (uint32_t)value); + + s->w_warned = true; +} + +/* clang-format off */ +static const MemoryRegionOps ot_unimp_ops = { + .read = ot_unimp_io_read, + .write = ot_unimp_io_write, + /* OpenTitan default LE */ + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4u, + .max_access_size = 4u, + } +}; +/* clang-format on */ + +static Property ot_unimp_properties[] = { + DEFINE_PROP_STRING("ot_id", OtUnimpState, ot_id), + DEFINE_PROP_UINT32("size", OtUnimpState, size, 0), + DEFINE_PROP_UINT32("irq-ro-mask", OtUnimpState, irq_ro_mask, 0), + DEFINE_PROP_UINT8("irq-count", OtUnimpState, irq_count, 0), + DEFINE_PROP_UINT8("alert-count", OtUnimpState, alert_count, 0), + DEFINE_PROP_BOOL("warn-once", OtUnimpState, warn_once, false), + DEFINE_PROP_BOOL("no-store", OtUnimpState, no_store, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ot_unimp_reset_enter(Object *obj, ResetType type) +{ + OtUnimpClass *c = OT_UNIMP_GET_CLASS(obj); + OtUnimpState *s = OT_UNIMP(obj); + + if (c->parent_phases.enter) { + c->parent_phases.enter(obj, type); + } + + memset(s->regs, 0, s->size); + + for (unsigned ix = 0; ix < (unsigned)s->irq_count; ix++) { + ibex_irq_lower(&s->irqs[ix]); + } + + for (unsigned ix = 0; ix < (unsigned)s->alert_count; ix++) { + ibex_irq_lower(&s->alerts[ix]); + } + + /* note: warn-once booleans are not reset */ +} + +static void ot_unimp_realize(DeviceState *dev, Error **errp) +{ + OtUnimpState *s = OT_UNIMP(dev); + + if (!s->ot_id) { + error_setg(errp, "ot_id property required for " TYPE_OT_UNIMP); + return; + } + + if (!s->size || (s->size & 3u)) { + error_setg(errp, "%s: invalid size", s->ot_id); + return; + } + + if (s->irq_ro_mask & ~((1u << s->irq_count) - 1u)) { + error_setg(errp, "%s: invalid irq mask/count", s->ot_id); + return; + } + + s->regs = !s->no_store ? g_new(uint32_t, s->size / sizeof(uint32_t)) : + (s->irq_count ? g_new(uint32_t, 2u) : NULL); + s->irqs = s->irq_count ? g_new(IbexIRQ, s->irq_count) : NULL; + s->alerts = s->alert_count ? g_new(IbexIRQ, s->alert_count) : NULL; + + if (s->irq_count) { + ibex_qdev_init_irqs(OBJECT(dev), s->irqs, SYSBUS_DEVICE_GPIO_IRQ, + s->irq_count); + } + if (s->alert_count) { + ibex_qdev_init_irqs(OBJECT(dev), s->alerts, OT_DEVICE_ALERT, + s->alert_count); + } + + memory_region_init_io(&s->mmio, OBJECT(s), &ot_unimp_ops, s, s->ot_id, + s->size); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); +} + +static void ot_unimp_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + (void)data; + + dc->realize = ot_unimp_realize; + device_class_set_props(dc, ot_unimp_properties); + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + + ResettableClass *rc = RESETTABLE_CLASS(klass); + OtUnimpClass *uc = OT_UNIMP_CLASS(klass); + resettable_class_set_parent_phases(rc, &ot_unimp_reset_enter, NULL, NULL, + &uc->parent_phases); +} + +static const TypeInfo ot_unimp_info = { + .name = TYPE_OT_UNIMP, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(OtUnimpState), + .class_init = ot_unimp_class_init, + .class_size = sizeof(OtUnimpClass), +}; + +static void ot_unimp_register_types(void) +{ + type_register_static(&ot_unimp_info); +} + +type_init(ot_unimp_register_types) diff --git a/hw/opentitan/trace-events b/hw/opentitan/trace-events index 88cde6958e83..db083211d5ff 100644 --- a/hw/opentitan/trace-events +++ b/hw/opentitan/trace-events @@ -362,8 +362,10 @@ ot_pinmux_io_write(uint32_t addr, uint32_t val, uint32_t pc) "addr=0x%02x, val=0 # ot_plic_ext.c -ot_plic_ext_io_read_out(const char *id, uint32_t addr, const char *regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" -ot_plic_ext_io_write(const char *id, uint32_t addr, const char *regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" +ot_plic_ext_io_msip_read_out(const char *id, uint32_t addr, const char *regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" +ot_plic_ext_io_msip_write(const char *id, uint32_t addr, const char *regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" +ot_plic_ext_io_alert_read_out(const char *id, uint32_t addr, const char *regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" +ot_plic_ext_io_alert_write(const char *id, uint32_t addr, const char *regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" # ot_pwrmgr.c @@ -527,3 +529,8 @@ ot_uart_debug(const char *id, const char *msg) "%s: %s" ot_uart_io_read_out(const char *id, uint32_t addr, const char *regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" ot_uart_io_write(const char *id, uint32_t addr, const char *regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" ot_uart_irqs(const char *id, uint32_t active, uint32_t mask, uint32_t eff) "%s: act:0x%08x msk:0x%08x eff:0x%08x" + +# ot_unimp.c + +ot_unimp_irq(const char *id, unsigned ix, bool lvl) "%s: #%u = %u" +ot_unimp_alert(const char *id, unsigned ix) "%s: #%u" diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 6ee6ba33fce1..dc815d82f664 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -59,6 +59,7 @@ config OT_DARJEELING select SIFIVE_PLIC select SPLIT_IRQ select TAP_CTRL_RBB + select UNIMP config OT_EARLGREY bool @@ -92,6 +93,7 @@ config OT_EARLGREY select OT_SRAM_CTRL select OT_TIMER select OT_UART + select OT_UNIMP select PULP_RV_DM select RISCV_DM select RISCV_DTM diff --git a/hw/riscv/ot_darjeeling.c b/hw/riscv/ot_darjeeling.c index 95034605a374..db373bc7b010 100644 --- a/hw/riscv/ot_darjeeling.c +++ b/hw/riscv/ot_darjeeling.c @@ -1602,8 +1602,8 @@ static void ot_dj_soc_realize(DeviceState *dev, Error **errp) cpu->cpu_index = 0; /* Link, define properties and realize devices, then connect GPIOs */ - ot_common_configure_devices_with_id(s->devices, dev->parent_bus, "", false, - ot_dj_soc_devices, + ot_common_configure_devices_with_id(s->devices, dev->parent_bus, "soc", + false, ot_dj_soc_devices, ARRAY_SIZE(ot_dj_soc_devices)); Object *oas; diff --git a/hw/riscv/ot_earlgrey.c b/hw/riscv/ot_earlgrey.c index 87d0f211a458..a9035944bda5 100644 --- a/hw/riscv/ot_earlgrey.c +++ b/hw/riscv/ot_earlgrey.c @@ -65,6 +65,7 @@ #include "hw/opentitan/ot_sram_ctrl.h" #include "hw/opentitan/ot_timer.h" #include "hw/opentitan/ot_uart.h" +#include "hw/opentitan/ot_unimp.h" #include "hw/qdev-properties.h" #include "hw/riscv/dm.h" #include "hw/riscv/dtm.h" @@ -514,47 +515,67 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ), }, [OT_EG_SOC_DEV_I2C0] = { - .type = TYPE_UNIMPLEMENTED_DEVICE, - .name = "ot-i2c", + .type = TYPE_OT_UNIMP, .cfg = &ibex_unimp_configure, .memmap = MEMMAPENTRIES( { .base = 0x40080000u } ), .prop = IBEXDEVICEPROPDEFS( - IBEX_DEV_UINT_PROP("size", 0x80u) + IBEX_DEV_STRING_PROP("ot_id", "i2c0"), + IBEX_DEV_UINT_PROP("size", 0x80u), + IBEX_DEV_UINT_PROP("irq-count", 15u), + IBEX_DEV_UINT_PROP("alert-count", 1u) + ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 6) ) }, [OT_EG_SOC_DEV_I2C1] = { - .type = TYPE_UNIMPLEMENTED_DEVICE, - .name = "ot-i2c", + .type = TYPE_OT_UNIMP, .cfg = &ibex_unimp_configure, .memmap = MEMMAPENTRIES( { .base = 0x40090000u } ), .prop = IBEXDEVICEPROPDEFS( - IBEX_DEV_UINT_PROP("size", 0x80u) + IBEX_DEV_STRING_PROP("ot_id", "i2c1"), + IBEX_DEV_UINT_PROP("size", 0x80u), + IBEX_DEV_UINT_PROP("irq-count", 15u), + IBEX_DEV_UINT_PROP("alert-count", 1u) + ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 7) ) }, [OT_EG_SOC_DEV_I2C2] = { - .type = TYPE_UNIMPLEMENTED_DEVICE, - .name = "ot-i2c", + .type = TYPE_OT_UNIMP, .cfg = &ibex_unimp_configure, .memmap = MEMMAPENTRIES( { .base = 0x400a0000u } ), .prop = IBEXDEVICEPROPDEFS( - IBEX_DEV_UINT_PROP("size", 0x80u) + IBEX_DEV_STRING_PROP("ot_id", "i2c2"), + IBEX_DEV_UINT_PROP("size", 0x80u), + IBEX_DEV_UINT_PROP("irq-count", 15u), + IBEX_DEV_UINT_PROP("alert-count", 1u) + ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 8) ) }, [OT_EG_SOC_DEV_PATTGEN] = { - .type = TYPE_UNIMPLEMENTED_DEVICE, - .name = "ot-pattgen", + .type = TYPE_OT_UNIMP, .cfg = &ibex_unimp_configure, .memmap = MEMMAPENTRIES( { .base = 0x400e0000u } ), .prop = IBEXDEVICEPROPDEFS( - IBEX_DEV_UINT_PROP("size", 0x80u) + IBEX_DEV_STRING_PROP("ot_id", "pattgen"), + IBEX_DEV_UINT_PROP("size", 0x40u), + IBEX_DEV_UINT_PROP("irq-count", 2u), + IBEX_DEV_UINT_PROP("alert-count", 1u) + ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 9) ) }, [OT_EG_SOC_DEV_TIMER] = { @@ -702,14 +723,19 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ), }, [OT_EG_SOC_DEV_USBDEV] = { - .type = TYPE_UNIMPLEMENTED_DEVICE, - .name = "ot-usbdev", + .type = TYPE_OT_UNIMP, .cfg = &ibex_unimp_configure, .memmap = MEMMAPENTRIES( { .base = 0x40320000u } ), .prop = IBEXDEVICEPROPDEFS( - IBEX_DEV_UINT_PROP("size", 0x1000u) + IBEX_DEV_STRING_PROP("ot_id", "usbdev"), + IBEX_DEV_UINT_PROP("size", 0x1000u), + IBEX_DEV_UINT_PROP("irq-count", 18u), + IBEX_DEV_UINT_PROP("alert-count", 1u) + ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 21) ) }, [OT_EG_SOC_DEV_PWRMGR] = { @@ -758,36 +784,50 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ) }, [OT_EG_SOC_DEV_SYSRST_CTRL] = { - .type = TYPE_UNIMPLEMENTED_DEVICE, - .name = "ot-sysrst_ctrl", + .type = TYPE_OT_UNIMP, .cfg = &ibex_unimp_configure, .memmap = MEMMAPENTRIES( { .base = 0x40430000u } ), .prop = IBEXDEVICEPROPDEFS( - IBEX_DEV_UINT_PROP("size", 0x100u) + IBEX_DEV_STRING_PROP("ot_id", "sysrst_ctrl"), + IBEX_DEV_UINT_PROP("size", 0x100u), + IBEX_DEV_UINT_PROP("irq-count", 1u), + IBEX_DEV_UINT_PROP("alert-count", 1u) + ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 27) ) }, [OT_EG_SOC_DEV_ADC_CTRL] = { - .type = TYPE_UNIMPLEMENTED_DEVICE, - .name = "ot-adc_ctrl", + .type = TYPE_OT_UNIMP, .cfg = &ibex_unimp_configure, .memmap = MEMMAPENTRIES( { .base = 0x40440000u } ), .prop = IBEXDEVICEPROPDEFS( - IBEX_DEV_UINT_PROP("size", 0x80u) + IBEX_DEV_STRING_PROP("ot_id", "adc_ctrl"), + IBEX_DEV_UINT_PROP("size", 0x80u), + IBEX_DEV_UINT_PROP("irq-count", 1u), + IBEX_DEV_UINT_PROP("alert-count", 1u) + ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 28) ) }, [OT_EG_SOC_DEV_PWM] = { - .type = TYPE_UNIMPLEMENTED_DEVICE, - .name = "ot-pwm", + .type = TYPE_OT_UNIMP, .cfg = &ibex_unimp_configure, .memmap = MEMMAPENTRIES( { .base = 0x40450000u } ), .prop = IBEXDEVICEPROPDEFS( - IBEX_DEV_UINT_PROP("size", 0x80u) + IBEX_DEV_STRING_PROP("ot_id", "pwm"), + IBEX_DEV_UINT_PROP("size", 0x80u), + IBEX_DEV_UINT_PROP("alert-count", 1u) + ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 29) ) }, [OT_EG_SOC_DEV_PINMUX] = { @@ -943,15 +983,21 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ), }, [OT_EG_SOC_DEV_KEYMGR] = { - .type = TYPE_UNIMPLEMENTED_DEVICE, - .name = "ot-keymgr", + .type = TYPE_OT_UNIMP, .cfg = &ibex_unimp_configure, .memmap = MEMMAPENTRIES( { .base = 0x41140000u } ), .prop = IBEXDEVICEPROPDEFS( + IBEX_DEV_STRING_PROP("ot_id", "keymgr"), IBEX_DEV_UINT_PROP("size", 0x100u), + IBEX_DEV_UINT_PROP("irq-count", 1u), + IBEX_DEV_UINT_PROP("alert-count", 2u), IBEX_DEV_BOOL_PROP("warn-once", true) + ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 49), + OT_EG_SOC_GPIO_ALERT(1, 50) ) }, [OT_EG_SOC_DEV_CSRNG] = { @@ -1045,7 +1091,6 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { }, [OT_EG_SOC_DEV_ROM_CTRL] = { .type = TYPE_OT_ROM_CTRL, - .name = "ot-rom_ctrl", .memmap = MEMMAPENTRIES( { .base = 0x411e0000u }, { .base = 0x00008000u } @@ -1127,7 +1172,7 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { [OT_EG_SOC_DEV_PLIC_EXT] = { .type = TYPE_OT_PLIC_EXT, .memmap = MEMMAPENTRIES( - { .base = 0x2c000000u } + { .base = 0x4c000000u } ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO(0, HART, IRQ_M_SOFT), @@ -1354,7 +1399,7 @@ static void ot_eg_soc_realize(DeviceState *dev, Error **errp) /* Link, define properties and realize devices, then connect GPIOs */ BusState *bus = sysbus_get_default(); - ot_common_configure_devices_with_id(s->devices, bus, "", false, + ot_common_configure_devices_with_id(s->devices, bus, "soc", false, ot_eg_soc_devices, ARRAY_SIZE(ot_eg_soc_devices)); diff --git a/include/hw/opentitan/ot_unimp.h b/include/hw/opentitan/ot_unimp.h new file mode 100644 index 000000000000..64012d4c32cb --- /dev/null +++ b/include/hw/opentitan/ot_unimp.h @@ -0,0 +1,36 @@ +/* + * QEMU OpenTitan unimplemented device + * + * Copyright (c) 2025 lowRISC contributors. + * + * Author(s): + * Emmanuel Blot + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_OPENTITAN_OT_UNIMP_H +#define HW_OPENTITAN_OT_UNIMP_H + +#include "qom/object.h" + +#define TYPE_OT_UNIMP "ot-unimp" +OBJECT_DECLARE_TYPE(OtUnimpState, OtUnimpClass, OT_UNIMP) + +#endif /* HW_OPENTITAN_OT_UNIMP_H */