|
|
|
@@ -27,6 +27,22 @@
|
|
|
|
|
#define GPIO_ENABLE_W1TS 0x24
|
|
|
|
|
#define GPIO_ENABLE_W1TC 0x28
|
|
|
|
|
#define GPIO_IN 0x3c
|
|
|
|
|
#define GPIO_STATUS 0x44
|
|
|
|
|
#define GPIO_STATUS_W1TS 0x48
|
|
|
|
|
#define GPIO_STATUS_W1TC 0x4c
|
|
|
|
|
#define GPIO_PCPU_INT 0x5c
|
|
|
|
|
|
|
|
|
|
#define GPIO_PIN_INT_TYPE_SHIFT 7
|
|
|
|
|
#define GPIO_PIN_INT_TYPE_MASK 0x7
|
|
|
|
|
#define GPIO_PIN_INT_ENA_SHIFT 13
|
|
|
|
|
#define GPIO_PIN_INT_ENA_CPU0 BIT(0)
|
|
|
|
|
|
|
|
|
|
#define GPIO_INTR_DISABLE 0
|
|
|
|
|
#define GPIO_INTR_POSEDGE 1
|
|
|
|
|
#define GPIO_INTR_NEGEDGE 2
|
|
|
|
|
#define GPIO_INTR_ANYEDGE 3
|
|
|
|
|
#define GPIO_INTR_LOW_LEVEL 4
|
|
|
|
|
#define GPIO_INTR_HIGH_LEVEL 5
|
|
|
|
|
|
|
|
|
|
static void esp32_gpio_drive_outputs(Esp32GpioState *s)
|
|
|
|
|
{
|
|
|
|
@@ -38,6 +54,41 @@ static void esp32_gpio_drive_outputs(Esp32GpioState *s)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint32_t esp32_gpio_enabled_interrupts(Esp32GpioState *s)
|
|
|
|
|
{
|
|
|
|
|
uint32_t enabled = 0;
|
|
|
|
|
|
|
|
|
|
for (int pin = 0; pin < ESP32_GPIO_COUNT; pin++) {
|
|
|
|
|
uint32_t interrupt_enable = s->pin_config[pin] >> GPIO_PIN_INT_ENA_SHIFT;
|
|
|
|
|
if (interrupt_enable & GPIO_PIN_INT_ENA_CPU0) {
|
|
|
|
|
enabled |= BIT(pin);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return enabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void esp32_gpio_update_irq(Esp32GpioState *s)
|
|
|
|
|
{
|
|
|
|
|
qemu_set_irq(s->irq, !!(s->interrupt_status &
|
|
|
|
|
esp32_gpio_enabled_interrupts(s)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void esp32_gpio_latch_level_interrupts(Esp32GpioState *s)
|
|
|
|
|
{
|
|
|
|
|
uint32_t levels = qatomic_read(&s->input_level);
|
|
|
|
|
|
|
|
|
|
for (int pin = 0; pin < ESP32_GPIO_COUNT; pin++) {
|
|
|
|
|
uint32_t type = extract32(s->pin_config[pin],
|
|
|
|
|
GPIO_PIN_INT_TYPE_SHIFT,
|
|
|
|
|
3);
|
|
|
|
|
bool level = !!(levels & BIT(pin));
|
|
|
|
|
if ((type == GPIO_INTR_LOW_LEVEL && !level) ||
|
|
|
|
|
(type == GPIO_INTR_HIGH_LEVEL && level)) {
|
|
|
|
|
s->interrupt_status |= BIT(pin);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void esp32_gpio_set_input_level(Esp32GpioState *s, int pin, bool level)
|
|
|
|
|
{
|
|
|
|
|
uint32_t old_level;
|
|
|
|
@@ -47,6 +98,18 @@ void esp32_gpio_set_input_level(Esp32GpioState *s, int pin, bool level)
|
|
|
|
|
old_level = qatomic_read(&s->input_level);
|
|
|
|
|
new_level = deposit32(old_level, pin, 1, level);
|
|
|
|
|
} while (qatomic_cmpxchg(&s->input_level, old_level, new_level) != old_level);
|
|
|
|
|
|
|
|
|
|
bool old_pin_level = !!(old_level & BIT(pin));
|
|
|
|
|
uint32_t type = extract32(s->pin_config[pin],
|
|
|
|
|
GPIO_PIN_INT_TYPE_SHIFT, 3);
|
|
|
|
|
if ((!old_pin_level && level && type == GPIO_INTR_POSEDGE) ||
|
|
|
|
|
(old_pin_level && !level && type == GPIO_INTR_NEGEDGE) ||
|
|
|
|
|
(old_pin_level != level && type == GPIO_INTR_ANYEDGE) ||
|
|
|
|
|
(!level && type == GPIO_INTR_LOW_LEVEL) ||
|
|
|
|
|
(level && type == GPIO_INTR_HIGH_LEVEL)) {
|
|
|
|
|
s->interrupt_status |= BIT(pin);
|
|
|
|
|
}
|
|
|
|
|
esp32_gpio_update_irq(s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void esp32_gpio_set_input(void *opaque, int pin, int level)
|
|
|
|
@@ -89,7 +152,15 @@ static uint64_t esp32_gpio_read(void *opaque, hwaddr addr, unsigned int size)
|
|
|
|
|
return s->strap_mode;
|
|
|
|
|
case GPIO_IN:
|
|
|
|
|
return qatomic_read(&s->input_level);
|
|
|
|
|
case GPIO_STATUS:
|
|
|
|
|
return s->interrupt_status;
|
|
|
|
|
case GPIO_PCPU_INT:
|
|
|
|
|
return s->interrupt_status & esp32_gpio_enabled_interrupts(s);
|
|
|
|
|
default:
|
|
|
|
|
if (addr >= s->pin_config_base &&
|
|
|
|
|
addr < s->pin_config_base + sizeof(s->pin_config)) {
|
|
|
|
|
return s->pin_config[(addr - s->pin_config_base) / 4];
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -99,6 +170,14 @@ static void esp32_gpio_write(void *opaque, hwaddr addr,
|
|
|
|
|
{
|
|
|
|
|
Esp32GpioState *s = ESP32_GPIO(opaque);
|
|
|
|
|
|
|
|
|
|
if (addr >= s->pin_config_base &&
|
|
|
|
|
addr < s->pin_config_base + sizeof(s->pin_config)) {
|
|
|
|
|
s->pin_config[(addr - s->pin_config_base) / 4] = value;
|
|
|
|
|
esp32_gpio_latch_level_interrupts(s);
|
|
|
|
|
esp32_gpio_update_irq(s);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (addr) {
|
|
|
|
|
case GPIO_OUT:
|
|
|
|
|
s->output_level = value;
|
|
|
|
@@ -118,6 +197,19 @@ static void esp32_gpio_write(void *opaque, hwaddr addr,
|
|
|
|
|
case GPIO_ENABLE_W1TC:
|
|
|
|
|
s->output_enable &= ~value;
|
|
|
|
|
break;
|
|
|
|
|
case GPIO_STATUS:
|
|
|
|
|
s->interrupt_status = value;
|
|
|
|
|
esp32_gpio_update_irq(s);
|
|
|
|
|
return;
|
|
|
|
|
case GPIO_STATUS_W1TS:
|
|
|
|
|
s->interrupt_status |= value;
|
|
|
|
|
esp32_gpio_update_irq(s);
|
|
|
|
|
return;
|
|
|
|
|
case GPIO_STATUS_W1TC:
|
|
|
|
|
s->interrupt_status &= ~value;
|
|
|
|
|
esp32_gpio_latch_level_interrupts(s);
|
|
|
|
|
esp32_gpio_update_irq(s);
|
|
|
|
|
return;
|
|
|
|
|
default:
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
@@ -137,7 +229,10 @@ static void esp32_gpio_reset_hold(Object *obj, ResetType type)
|
|
|
|
|
s->input_level = UINT32_MAX;
|
|
|
|
|
s->output_level = 0;
|
|
|
|
|
s->output_enable = 0;
|
|
|
|
|
s->interrupt_status = 0;
|
|
|
|
|
memset(s->pin_config, 0, sizeof(s->pin_config));
|
|
|
|
|
esp32_gpio_drive_outputs(s);
|
|
|
|
|
esp32_gpio_update_irq(s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void esp32_gpio_realize(DeviceState *dev, Error **errp)
|
|
|
|
@@ -151,6 +246,7 @@ static void esp32_gpio_init(Object *obj)
|
|
|
|
|
|
|
|
|
|
/* Set the default value for the strap_mode property */
|
|
|
|
|
object_property_set_int(obj, "strap_mode", ESP32_STRAP_MODE_FLASH_BOOT, &error_fatal);
|
|
|
|
|
s->pin_config_base = 0x88;
|
|
|
|
|
|
|
|
|
|
memory_region_init_io(&s->iomem, obj, &uart_ops, s,
|
|
|
|
|
TYPE_ESP32_GPIO, 0x1000);
|
|
|
|
|