hw/timer: fix reset/default value for register SYSTIMER_CONF on ESP targets

* Fixes https://github.com/espressif/qemu/issues/120
This commit is contained in:
Omar Chebib
2025-03-10 18:05:42 +08:00
parent 7591824ec4
commit ccdda32084
3 changed files with 29 additions and 5 deletions
+8 -1
View File
@@ -20,13 +20,20 @@ static uint64_t esp32c3_systimer_read(void *opaque, hwaddr addr, unsigned int si
uint64_t r = 0; uint64_t r = 0;
switch (addr) { switch (addr) {
case A_SYSTIMER_CONF:
/* On the C3, bit 27 is always 0, bit 25 is always high */
r = class->parent_systimer_read(opaque, addr, size);
r &= ~BIT(27);
r |= BIT(25);
break;
case A_SYSTIMER_REAL_TARGET0_LO: case A_SYSTIMER_REAL_TARGET0_LO:
case A_SYSTIMER_REAL_TARGET0_HI: case A_SYSTIMER_REAL_TARGET0_HI:
case A_SYSTIMER_REAL_TARGET1_LO: case A_SYSTIMER_REAL_TARGET1_LO:
case A_SYSTIMER_REAL_TARGET1_HI: case A_SYSTIMER_REAL_TARGET1_HI:
case A_SYSTIMER_REAL_TARGET2_LO: case A_SYSTIMER_REAL_TARGET2_LO:
case A_SYSTIMER_REAL_TARGET2_HI: case A_SYSTIMER_REAL_TARGET2_HI:
/* These registers are not supported on the C3 hardware, so nothing! */ /* These registers are not supported on the C3 hardware, do nothing! */
break; break;
default: default:
+19 -3
View File
@@ -381,8 +381,10 @@ static void esp_systimer_conf_set(ESPSysTimerState *s, uint64_t value)
} }
s->counter[0].enabled = (value & R_SYSTIMER_CONF_TIMER_UNIT0_WORK_EN_MASK) ? 1 : 0; s->counter[0].enabled = (value & R_SYSTIMER_CONF_TIMER_UNIT0_WORK_EN_MASK) ? 1 : 0;
s->counter[1].enabled = (value & R_SYSTIMER_CONF_TIMER_UNIT1_WORK_EN_MASK) ? 1 : 0; s->counter[1].enabled = (value & R_SYSTIMER_CONF_TIMER_UNIT1_WORK_EN_MASK) ? 1 : 0;
s->counter[0].enabled_on_stall = (value & R_SYSTIMER_CONF_TIMER_UNIT0_CORE0_STALL_EN_MASK) ? 1 : 0; s->counter[0].core0_stall_en = (value & R_SYSTIMER_CONF_TIMER_UNIT0_CORE0_STALL_EN_MASK) ? 1 : 0;
s->counter[1].enabled_on_stall = (value & R_SYSTIMER_CONF_TIMER_UNIT1_CORE0_STALL_EN_MASK) ? 1 : 0; s->counter[1].core0_stall_en = (value & R_SYSTIMER_CONF_TIMER_UNIT1_CORE0_STALL_EN_MASK) ? 1 : 0;
s->counter[0].core1_stall_en = (value & R_SYSTIMER_CONF_TIMER_UNIT0_CORE1_STALL_EN_MASK) ? 1 : 0;
s->counter[1].core1_stall_en = (value & R_SYSTIMER_CONF_TIMER_UNIT1_CORE1_STALL_EN_MASK) ? 1 : 0;
/* If the state of the counter changed while one of the comparator depends on it, reload it */ /* If the state of the counter changed while one of the comparator depends on it, reload it */
for (int i = 0; i < ESP_SYSTIMER_COMP_COUNT; i++) { for (int i = 0; i < ESP_SYSTIMER_COMP_COUNT; i++) {
@@ -558,10 +560,22 @@ static void esp_systimer_cb(void* opaque)
} }
static void esp_systimer_default_conf(ESPSysTimerState *s)
{
/* According to the TRM, on dual-core targets, counter 1 stalls with core 1 */
s->counter[1].core0_stall_en = true;
s->counter[1].core1_stall_en = true;
/* Counter 0 is marked as enabled (no comparator enabled though) */
s->counter[0].enabled = true;
s->conf = R_SYSTIMER_CONF_TIMER_UNIT0_WORK_EN_MASK |
R_SYSTIMER_CONF_TIMER_UNIT1_CORE0_STALL_EN_MASK |
R_SYSTIMER_CONF_TIMER_UNIT1_CORE1_STALL_EN_MASK;
}
static void esp_systimer_reset(DeviceState* ts) static void esp_systimer_reset(DeviceState* ts)
{ {
ESPSysTimerState *s = ESP_SYSTIMER(ts); ESPSysTimerState *s = ESP_SYSTIMER(ts);
s->conf = 0;
for (int i = 0; i < ESP_SYSTIMER_COMP_COUNT; i++) { for (int i = 0; i < ESP_SYSTIMER_COMP_COUNT; i++) {
ESPSysTimerComp* comp = &s->comparators[i]; ESPSysTimerComp* comp = &s->comparators[i];
QEMUTimer qtimer = comp->qtimer; QEMUTimer qtimer = comp->qtimer;
@@ -579,6 +593,7 @@ static void esp_systimer_reset(DeviceState* ts)
comp->irq = irq; comp->irq = irq;
comp->systimer = s; comp->systimer = s;
} }
esp_systimer_default_conf(s);
} }
@@ -602,6 +617,7 @@ static void esp_systimer_init(Object *obj)
sysbus_init_irq(sbd, &s->comparators[i].irq); sysbus_init_irq(sbd, &s->comparators[i].irq);
timer_init_ns(&s->comparators[i].qtimer, QEMU_CLOCK_VIRTUAL, esp_systimer_cb, &s->comparators[i]); timer_init_ns(&s->comparators[i].qtimer, QEMU_CLOCK_VIRTUAL, esp_systimer_cb, &s->comparators[i]);
} }
esp_systimer_default_conf(s);
} }
+2 -1
View File
@@ -69,7 +69,8 @@ static inline void systimer_set_reg(uint64_t* reg, uint64_t value, uint64_t mask
typedef struct { typedef struct {
bool enabled; bool enabled;
/* Enabled on CPU stall */ /* Enabled on CPU stall */
bool enabled_on_stall; bool core0_stall_en;
bool core1_stall_en;
uint64_t value; // Internal counter that should be updated as often as possible uint64_t value; // Internal counter that should be updated as often as possible
uint64_t toload; // Counter that can be loaded by the guest program uint64_t toload; // Counter that can be loaded by the guest program
uint64_t flushed; // Mirror of the internal counter that can be seen by the guest program uint64_t flushed; // Mirror of the internal counter that can be seen by the guest program