hw/misc: add ESP32 DPORT peripheral, cache, cross-core interrupt

This commit is contained in:
Ivan Grokhotkov
2019-09-27 11:37:31 +02:00
parent d31b34cdfe
commit 959cd7267b
5 changed files with 766 additions and 0 deletions
+91
View File
@@ -0,0 +1,91 @@
/*
* ESP32 Cross-core interrupt
*
* Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 or
* (at your option) any later version.
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
#include "hw/registerfields.h"
#include "hw/qdev-properties.h"
#include "hw/misc/esp32_reg.h"
#include "hw/misc/esp32_crosscore_int.h"
static uint64_t esp32_crosscore_int_read(void *opaque, hwaddr addr, unsigned int size)
{
return 0;
}
static void esp32_crosscore_int_write(void *opaque, hwaddr addr,
uint64_t value, unsigned int size)
{
Esp32CrosscoreInt *s = ESP32_CROSSCORE_INT(opaque);
int index = addr / 4;
assert(index < s->n_irqs);
qemu_set_irq(s->irqs[index], value & 0x1);
}
static const MemoryRegionOps esp32_crosscore_int_ops = {
.read = esp32_crosscore_int_read,
.write = esp32_crosscore_int_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void esp32_crosscore_int_realize(DeviceState *dev, Error **errp)
{
Esp32CrosscoreInt *s = ESP32_CROSSCORE_INT(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
s->irqs = g_malloc0_n(s->n_irqs, sizeof(qemu_irq));
assert(s->irqs);
for (int i = 0; i < s->n_irqs; ++i) {
sysbus_init_irq(sbd, &s->irqs[i]);
}
memory_region_init_io(&s->iomem, OBJECT(dev), &esp32_crosscore_int_ops, s,
TYPE_ESP32_CROSSCORE_INT,
s->n_irqs * sizeof(uint32_t));
sysbus_init_mmio(sbd, &s->iomem);
}
static void esp32_crosscore_int_init(Object *obj)
{
}
static Property esp32_crosscore_int_properties[] = {
DEFINE_PROP_INT32("n_irqs", Esp32CrosscoreInt, n_irqs, 4),
DEFINE_PROP_END_OF_LIST(),
};
static void esp32_crosscore_int_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = esp32_crosscore_int_realize;
device_class_set_props(dc, esp32_crosscore_int_properties);
}
static const TypeInfo esp32_crosscore_int_info = {
.name = TYPE_ESP32_CROSSCORE_INT,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Esp32CrosscoreInt),
.instance_init = esp32_crosscore_int_init,
.class_init = esp32_crosscore_int_class_init
};
static void esp32_crosscore_int_register_types(void)
{
type_register_static(&esp32_crosscore_int_info);
}
type_init(esp32_crosscore_int_register_types)
+476
View File
@@ -0,0 +1,476 @@
/*
* ESP32 "DPORT" device
*
* Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 or
* (at your option) any later version.
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "hw/registerfields.h"
#include "hw/boards.h"
#include "hw/misc/esp32_reg.h"
#include "hw/misc/esp32_dport.h"
#include "hw/misc/esp32_flash_enc.h"
#include "hw/nvram/esp32_efuse.h"
#define ESP32_DPORT_SIZE (DR_REG_DPORT_APB_BASE - DR_REG_DPORT_BASE)
#define MMU_RANGE_SIZE (ESP32_CACHE_PAGES_PER_REGION * sizeof(uint32_t))
#define MMU_RANGE_LAST (MMU_RANGE_SIZE - sizeof(uint32_t))
#define PRO_DROM0_MMU_FIRST (DR_REG_FLASH_MMU_TABLE_PRO - DR_REG_DPORT_BASE)
#define PRO_DROM0_MMU_LAST (PRO_DROM0_MMU_FIRST + MMU_RANGE_LAST)
#define PRO_IRAM0_MMU_FIRST (DR_REG_FLASH_MMU_TABLE_PRO - DR_REG_DPORT_BASE + MMU_RANGE_SIZE)
#define PRO_IRAM0_MMU_LAST (PRO_IRAM0_MMU_FIRST + MMU_RANGE_LAST)
#define APP_DROM0_MMU_FIRST (DR_REG_FLASH_MMU_TABLE_APP - DR_REG_DPORT_BASE)
#define APP_DROM0_MMU_LAST (APP_DROM0_MMU_FIRST + MMU_RANGE_LAST)
#define APP_IRAM0_MMU_FIRST (DR_REG_FLASH_MMU_TABLE_APP - DR_REG_DPORT_BASE + MMU_RANGE_SIZE)
#define APP_IRAM0_MMU_LAST (APP_IRAM0_MMU_FIRST + MMU_RANGE_LAST)
#define MMU_ENTRY_MASK 0x1ff
static void esp32_cache_state_update(Esp32CacheState* cs);
static void esp32_cache_data_sync(Esp32CacheRegionState* crs);
static void esp32_cache_invalidate_all_entries(Esp32CacheRegionState* crs);
static inline uint32_t get_mmu_entry(Esp32CacheRegionState* crs, hwaddr base, hwaddr addr)
{
return crs->mmu_table[(addr - base)/sizeof(uint32_t)] & MMU_ENTRY_MASK;
}
static inline void set_mmu_entry(Esp32CacheRegionState* crs, hwaddr base, hwaddr addr, uint64_t val)
{
uint32_t old_val = crs->mmu_table[(addr - base)/sizeof(uint32_t)];
if (val != old_val) {
crs->mmu_table[(addr - base)/sizeof(uint32_t)] = (val & MMU_ENTRY_MASK) | ESP32_CACHE_MMU_ENTRY_CHANGED;
}
}
static uint64_t esp32_dport_read(void *opaque, hwaddr addr, unsigned int size)
{
Esp32DportState *s = ESP32_DPORT(opaque);
uint64_t r = 0;
switch (addr) {
case A_DPORT_APPCPU_RESET:
r = s->appcpu_reset_state;
break;
case A_DPORT_APPCPU_CLK:
r = s->appcpu_clkgate_state;
break;
case A_DPORT_APPCPU_RUNSTALL:
r = s->appcpu_stall_state;
break;
case A_DPORT_APPCPU_BOOT_ADDR:
r = s->appcpu_boot_addr;
break;
case A_DPORT_CPU_PER_CONF:
r = s->cpuperiod_sel;
break;
case A_DPORT_PRO_CACHE_CTRL:
r = s->cache_state[0].cache_ctrl_reg;
break;
case A_DPORT_PRO_CACHE_CTRL1:
r = s->cache_state[0].cache_ctrl1_reg;
break;
case A_DPORT_APP_CACHE_CTRL:
r = s->cache_state[1].cache_ctrl_reg;
break;
case A_DPORT_APP_CACHE_CTRL1:
r = s->cache_state[1].cache_ctrl1_reg;
break;
case A_DPORT_PRO_DCACHE_DBUG0:
case A_DPORT_APP_DCACHE_DBUG0:
/* in idle state */
r = FIELD_DP32(0, DPORT_PRO_DCACHE_DBUG0, CACHE_STATE, 1);
break;
case A_DPORT_CACHE_IA_INT_EN:
r = s->cache_ill_trap_en_reg;
break;
case A_DPORT_PRO_DCACHE_DBUG3:
r = 0;
r = FIELD_DP32(r, DPORT_PRO_DCACHE_DBUG3, IA_INT_DROM0, s->cache_state[0].drom0.illegal_access_status);
r = FIELD_DP32(r, DPORT_PRO_DCACHE_DBUG3, IA_INT_IRAM0, s->cache_state[0].iram0.illegal_access_status);
break;
case A_DPORT_APP_DCACHE_DBUG3:
r = 0;
r = FIELD_DP32(r, DPORT_APP_DCACHE_DBUG3, IA_INT_DROM0, s->cache_state[1].drom0.illegal_access_status);
r = FIELD_DP32(r, DPORT_APP_DCACHE_DBUG3, IA_INT_IRAM0, s->cache_state[1].iram0.illegal_access_status);
break;
case PRO_DROM0_MMU_FIRST ... PRO_DROM0_MMU_LAST:
r = get_mmu_entry(&s->cache_state[0].drom0, PRO_DROM0_MMU_FIRST, addr);
break;
case PRO_IRAM0_MMU_FIRST ... PRO_IRAM0_MMU_LAST:
r = get_mmu_entry(&s->cache_state[0].iram0, PRO_IRAM0_MMU_FIRST, addr);
break;
case APP_DROM0_MMU_FIRST ... APP_DROM0_MMU_LAST:
r = get_mmu_entry(&s->cache_state[1].drom0, APP_DROM0_MMU_FIRST, addr);
break;
case APP_IRAM0_MMU_FIRST ... APP_IRAM0_MMU_LAST:
r = get_mmu_entry(&s->cache_state[1].iram0, APP_IRAM0_MMU_FIRST, addr);
break;
case A_DPORT_SLAVE_SPI_CONFIG:
r = s->slave_spi_config_reg;
break;
}
return r;
}
static void esp32_dport_write(void *opaque, hwaddr addr,
uint64_t value, unsigned int size)
{
Esp32DportState *s = ESP32_DPORT(opaque);
bool old_state;
uint32_t old_val;
switch (addr) {
case A_DPORT_APPCPU_RESET:
old_state = s->appcpu_reset_state;
s->appcpu_reset_state = value & 1;
if (old_state && !s->appcpu_reset_state) {
qemu_irq_pulse(s->appcpu_reset_req);
}
break;
case A_DPORT_APPCPU_CLK:
s->appcpu_clkgate_state = value & 1;
qemu_set_irq(s->appcpu_stall_req, s->appcpu_stall_state || !s->appcpu_clkgate_state);
break;
case A_DPORT_APPCPU_RUNSTALL:
s->appcpu_stall_state = value & 1;
qemu_set_irq(s->appcpu_stall_req, s->appcpu_stall_state || !s->appcpu_clkgate_state);
break;
case A_DPORT_APPCPU_BOOT_ADDR:
s->appcpu_boot_addr = value;
break;
case A_DPORT_CPU_PER_CONF:
s->cpuperiod_sel = value & R_DPORT_CPU_PER_CONF_CPUPERIOD_SEL_MASK;
qemu_irq_pulse(s->clk_update_req);
break;
case A_DPORT_PRO_CACHE_CTRL:
if (FIELD_EX32(value, DPORT_PRO_CACHE_CTRL, CACHE_FLUSH_ENA)) {
value |= R_DPORT_PRO_CACHE_CTRL_CACHE_FLUSH_DONE_MASK;
value &= ~R_DPORT_PRO_CACHE_CTRL_CACHE_FLUSH_ENA_MASK;
esp32_cache_invalidate_all_entries(&s->cache_state[0].drom0);
esp32_cache_data_sync(&s->cache_state[0].drom0);
esp32_cache_invalidate_all_entries(&s->cache_state[0].iram0);
esp32_cache_data_sync(&s->cache_state[0].iram0);
}
old_val = s->cache_state[0].cache_ctrl_reg;
s->cache_state[0].cache_ctrl_reg = value;
if (value != old_val) {
esp32_cache_state_update(&s->cache_state[0]);
}
break;
case A_DPORT_PRO_CACHE_CTRL1:
old_val = s->cache_state[0].cache_ctrl1_reg;
s->cache_state[0].cache_ctrl1_reg = value;
if (value != old_val) {
esp32_cache_state_update(&s->cache_state[0]);
}
break;
case A_DPORT_APP_CACHE_CTRL:
if (FIELD_EX32(value, DPORT_APP_CACHE_CTRL, CACHE_FLUSH_ENA)) {
value |= R_DPORT_APP_CACHE_CTRL_CACHE_FLUSH_DONE_MASK;
value &= ~R_DPORT_APP_CACHE_CTRL_CACHE_FLUSH_ENA_MASK;
esp32_cache_invalidate_all_entries(&s->cache_state[1].drom0);
esp32_cache_data_sync(&s->cache_state[1].drom0);
esp32_cache_invalidate_all_entries(&s->cache_state[1].iram0);
esp32_cache_data_sync(&s->cache_state[1].iram0);
}
old_val = s->cache_state[1].cache_ctrl_reg;
s->cache_state[1].cache_ctrl_reg = value;
if (value != old_val) {
esp32_cache_state_update(&s->cache_state[1]);
}
break;
case A_DPORT_APP_CACHE_CTRL1:
old_val = s->cache_state[1].cache_ctrl1_reg;
s->cache_state[1].cache_ctrl1_reg = value;
if (value != old_val) {
esp32_cache_state_update(&s->cache_state[1]);
}
break;
case A_DPORT_CACHE_IA_INT_EN:
s->cache_ill_trap_en_reg = value;
s->cache_state[0].drom0.illegal_access_trap_en = (FIELD_EX32(value, DPORT_CACHE_IA_INT_EN, IA_INT_PRO_DROM0));
s->cache_state[0].iram0.illegal_access_trap_en = (FIELD_EX32(value, DPORT_CACHE_IA_INT_EN, IA_INT_PRO_IRAM0));
s->cache_state[1].drom0.illegal_access_trap_en = (FIELD_EX32(value, DPORT_CACHE_IA_INT_EN, IA_INT_APP_DROM0));
s->cache_state[1].iram0.illegal_access_trap_en = (FIELD_EX32(value, DPORT_CACHE_IA_INT_EN, IA_INT_APP_IRAM0));
s->cache_state[0].dram1.illegal_access_trap_en = (FIELD_EX32(value, DPORT_CACHE_IA_INT_EN, IA_INT_PRO_DRAM1));
s->cache_state[1].dram1.illegal_access_trap_en = (FIELD_EX32(value, DPORT_CACHE_IA_INT_EN, IA_INT_APP_DRAM1));
break;
case PRO_DROM0_MMU_FIRST ... PRO_DROM0_MMU_LAST:
set_mmu_entry(&s->cache_state[0].drom0, PRO_DROM0_MMU_FIRST, addr, value);
break;
case PRO_IRAM0_MMU_FIRST ... PRO_IRAM0_MMU_LAST:
set_mmu_entry(&s->cache_state[0].iram0, PRO_IRAM0_MMU_FIRST, addr, value);
break;
case APP_DROM0_MMU_FIRST ... APP_DROM0_MMU_LAST:
set_mmu_entry(&s->cache_state[1].drom0, APP_DROM0_MMU_FIRST, addr, value);
break;
case APP_IRAM0_MMU_FIRST ... APP_IRAM0_MMU_LAST:
set_mmu_entry(&s->cache_state[1].iram0, APP_IRAM0_MMU_FIRST, addr, value);
break;
case A_DPORT_SLAVE_SPI_CONFIG:
s->slave_spi_config_reg = value;
qemu_set_irq(s->flash_enc_en_gpio, FIELD_EX32(value, DPORT_SLAVE_SPI_CONFIG, SLAVE_SPI_ENCRYPT_ENABLE));
qemu_set_irq(s->flash_dec_en_gpio, FIELD_EX32(value, DPORT_SLAVE_SPI_CONFIG, SLAVE_SPI_DECRYPT_ENABLE));
break;
}
}
static const MemoryRegionOps esp32_dport_ops = {
.read = esp32_dport_read,
.write = esp32_dport_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void esp32_cache_data_sync(Esp32CacheRegionState* crs)
{
if (crs->cache->dport->flash_blk == NULL) {
return;
}
Esp32FlashEncryptionState * flash_enc = esp32_flash_encryption_find();
bool decrypt = (flash_enc != NULL && esp32_flash_decryption_enabled(flash_enc));
uint8_t* cache_data = (uint8_t*) memory_region_get_ram_ptr(&crs->mem);
for (int i = 0; i < ESP32_CACHE_PAGES_PER_REGION; ++i) {
uint32_t* cache_page = (uint32_t*) (cache_data + i * ESP32_CACHE_PAGE_SIZE);
uint32_t mmu_entry = crs->mmu_table[i];
if (!(mmu_entry & ESP32_CACHE_MMU_ENTRY_CHANGED)) {
continue;
}
mmu_entry &= MMU_ENTRY_MASK;
if (mmu_entry & ESP32_CACHE_MMU_INVALID_VAL) {
uint32_t fill_val = crs->illegal_access_retval;
for (int word = 0; word < ESP32_CACHE_PAGE_SIZE / sizeof(uint32_t); ++word) {
cache_page[word] = fill_val;
}
} else {
uint32_t phys_addr = mmu_entry * ESP32_CACHE_PAGE_SIZE;
blk_pread(crs->cache->dport->flash_blk, phys_addr, ESP32_CACHE_PAGE_SIZE, cache_page, 0);
if (decrypt) {
esp32_flash_decrypt_inplace(flash_enc, phys_addr, cache_page, ESP32_CACHE_PAGE_SIZE/4);
}
}
crs->mmu_table[i] &= ~ESP32_CACHE_MMU_ENTRY_CHANGED;
}
memory_region_flush_rom_device(&crs->mem, 0, ESP32_CACHE_REGION_SIZE);
}
static void esp32_cache_invalidate_all_entries(Esp32CacheRegionState* crs)
{
for (int i = 0; i < ESP32_CACHE_PAGES_PER_REGION; ++i) {
crs->mmu_table[i] |= ESP32_CACHE_MMU_ENTRY_CHANGED;
}
}
static void esp32_cache_state_update(Esp32CacheState* cs)
{
bool cache_enabled = FIELD_EX32(cs->cache_ctrl_reg, DPORT_PRO_CACHE_CTRL, CACHE_ENA) != 0;
bool drom0_enabled = cache_enabled &&
FIELD_EX32(cs->cache_ctrl1_reg, DPORT_PRO_CACHE_CTRL1, MASK_DROM0) == 0;
if (!cs->drom0.mem.enabled && drom0_enabled) {
esp32_cache_data_sync(&cs->drom0);
}
memory_region_set_enabled(&cs->drom0.mem, drom0_enabled);
bool iram0_enabled = cache_enabled &&
FIELD_EX32(cs->cache_ctrl1_reg, DPORT_PRO_CACHE_CTRL1, MASK_IRAM0) == 0;
if (!cs->iram0.mem.enabled && iram0_enabled) {
esp32_cache_data_sync(&cs->iram0);
}
memory_region_set_enabled(&cs->iram0.mem, iram0_enabled);
if (cs->dport->has_psram) {
bool dram1_enabled = cache_enabled &&
FIELD_EX32(cs->cache_ctrl1_reg, DPORT_PRO_CACHE_CTRL1, MASK_DRAM1) == 0;
memory_region_set_enabled(&cs->dram1.mem, dram1_enabled);
}
}
static void esp32_cache_region_reset(Esp32CacheRegionState *crs)
{
for (int i = 0; i < ESP32_CACHE_PAGES_PER_REGION; ++i) {
crs->mmu_table[i] = ESP32_CACHE_MMU_ENTRY_CHANGED;
}
crs->illegal_access_trap_en = false;
}
static void esp32_cache_reset(Esp32CacheState *cs)
{
esp32_cache_region_reset(&cs->drom0);
esp32_cache_region_reset(&cs->iram0);
}
static uint64_t esp32_cache_ill_read(void *opaque, hwaddr addr, unsigned int size)
{
Esp32CacheRegionState *crs = (Esp32CacheRegionState*) opaque;
uint32_t ill_data[] = { crs->illegal_access_retval, crs->illegal_access_retval };
uint32_t result;
memcpy(&result, ((uint8_t*) ill_data) + (addr % 4), size);
if (crs->illegal_access_trap_en) {
crs->illegal_access_status = true;
qemu_irq_raise(crs->cache->dport->cache_ill_irq);
}
return result;
}
static void esp32_cache_ill_write(void *opaque, hwaddr addr,
uint64_t value, unsigned int size)
{
}
static bool esp32_cache_ill_accepts(void *opaque, hwaddr addr,
unsigned size, bool is_write,
MemTxAttrs attrs)
{
return !is_write;
}
void esp32_dport_clear_ill_trap_state(Esp32DportState* s)
{
s->cache_state[0].drom0.illegal_access_status = false;
s->cache_state[1].drom0.illegal_access_status = false;
s->cache_state[0].iram0.illegal_access_status = false;
s->cache_state[1].iram0.illegal_access_status = false;
s->cache_state[0].dram1.illegal_access_status = false;
s->cache_state[1].dram1.illegal_access_status = false;
qemu_irq_lower(s->cache_ill_irq);
}
static const MemoryRegionOps esp32_cache_ops = {
.write = NULL,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid.accepts = esp32_cache_ill_accepts,
};
static const MemoryRegionOps esp32_cache_ill_trap_ops = {
.read = esp32_cache_ill_read,
.write = esp32_cache_ill_write,
};
static void esp32_dport_reset(DeviceState *dev)
{
Esp32DportState *s = ESP32_DPORT(dev);
s->appcpu_boot_addr = 0;
s->appcpu_clkgate_state = false;
s->appcpu_reset_state = true;
s->appcpu_stall_state = false;
s->cache_ill_trap_en_reg = 0;
esp32_cache_reset(&s->cache_state[0]);
esp32_cache_reset(&s->cache_state[1]);
qemu_irq_lower(s->appcpu_stall_req);
}
static void esp32_dport_realize(DeviceState *dev, Error **errp)
{
Esp32DportState *s = ESP32_DPORT(dev);
MachineState *ms = MACHINE(qdev_get_machine());
s->cpu_count = ms->smp.cpus;
}
static void esp32_cache_init_region(Esp32DportState *ds,
Esp32CacheState *cs,
Esp32CacheRegionState *crs,
Esp32CacheRegionType type,
const char* name, hwaddr base,
uint32_t illegal_access_retval)
{
char desc[16];
crs->cache = cs;
crs->type = type;
crs->base = base;
crs->illegal_access_retval = illegal_access_retval;
snprintf(desc, sizeof(desc), "cpu%d-%s", cs->core_id, name);
if (type == ESP32_DCACHE_PSRAM) {
memory_region_init_alias(&crs->mem, OBJECT(cs->dport), desc,
&ds->psram, 0, ESP32_CACHE_REGION_SIZE);
} else {
memory_region_init_rom_device(&crs->mem, OBJECT(cs->dport),
&esp32_cache_ops, crs,
desc, ESP32_CACHE_REGION_SIZE, &error_abort);
}
snprintf(desc, sizeof(desc), "cpu%d-%s-ill", cs->core_id, name);
memory_region_init_io(&crs->illegal_access_trap_mem, OBJECT(cs->dport),
&esp32_cache_ill_trap_ops, crs,
desc, ESP32_CACHE_REGION_SIZE);
}
static void esp32_dport_init(Object *obj)
{
Esp32DportState *s = ESP32_DPORT(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
memory_region_init_io(&s->iomem, obj, &esp32_dport_ops, s,
TYPE_ESP32_DPORT, ESP32_DPORT_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
memory_region_init_ram(&s->psram, obj, "psram", ESP32_CACHE_REGION_SIZE, &error_fatal);
for (int i = 0; i < ESP32_CPU_COUNT; ++i) {
Esp32CacheState* cs = &s->cache_state[i];
cs->core_id = i;
cs->dport = s;
esp32_cache_init_region(s, cs, &cs->drom0, ESP32_DCACHE_FLASH, "drom0",
0x3F400000, 0xbaadbaad);
esp32_cache_init_region(s, cs, &cs->iram0, ESP32_ICACHE_FLASH, "iram0",
0x40000000, 0x00000000);
esp32_cache_init_region(s, cs, &cs->dram1, ESP32_DCACHE_PSRAM, "dram1",
0x3F800000, 0xbaadbaad);
}
qdev_init_gpio_out_named(DEVICE(sbd), &s->appcpu_stall_req, ESP32_DPORT_APPCPU_STALL_GPIO, 1);
qdev_init_gpio_out_named(DEVICE(sbd), &s->appcpu_reset_req, ESP32_DPORT_APPCPU_RESET_GPIO, 1);
qdev_init_gpio_out_named(DEVICE(sbd), &s->clk_update_req, ESP32_DPORT_CLK_UPDATE_GPIO, 1);
qdev_init_gpio_out_named(DEVICE(sbd), &s->cache_ill_irq, ESP32_DPORT_CACHE_ILL_IRQ_GPIO, 1);
qdev_init_gpio_out_named(DEVICE(sbd), &s->flash_enc_en_gpio, ESP32_DPORT_FLASH_ENC_EN_GPIO, 1);
qdev_init_gpio_out_named(DEVICE(sbd), &s->flash_dec_en_gpio, ESP32_DPORT_FLASH_DEC_EN_GPIO, 1);
}
static Property esp32_dport_properties[] = {
DEFINE_PROP_DRIVE("flash", Esp32DportState, flash_blk),
DEFINE_PROP_BOOL("has_psram", Esp32DportState, has_psram, false),
DEFINE_PROP_END_OF_LIST(),
};
static void esp32_dport_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->legacy_reset = esp32_dport_reset;
dc->realize = esp32_dport_realize;
device_class_set_props(dc, esp32_dport_properties);
}
static const TypeInfo esp32_dport_info = {
.name = TYPE_ESP32_DPORT,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Esp32DportState),
.instance_init = esp32_dport_init,
.class_init = esp32_dport_class_init
};
static void esp32_dport_register_types(void)
{
type_register_static(&esp32_dport_info);
}
type_init(esp32_dport_register_types)
+4
View File
@@ -136,6 +136,10 @@ system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
system_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c'))
system_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c'))
system_ss.add(when: 'CONFIG_XTENSA_ESP32', if_true: files(
'esp32_crosscore_int.c',
'esp32_dport.c',
))
system_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_ahb_apb_pnp.c'))
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include "hw/hw.h"
#include "hw/registerfields.h"
#include "hw/sysbus.h"
#include "sysemu/block-backend.h"
#define TYPE_ESP32_CROSSCORE_INT "misc.esp32.crosscoreint"
#define ESP32_CROSSCORE_INT(obj) OBJECT_CHECK(Esp32CrosscoreInt, (obj), TYPE_ESP32_CROSSCORE_INT)
typedef struct Esp32CrosscoreInt {
SysBusDevice parent_obj;
MemoryRegion iomem;
int n_irqs;
qemu_irq *irqs;
} Esp32CrosscoreInt;
+178
View File
@@ -0,0 +1,178 @@
#pragma once
#include "hw/hw.h"
#include "hw/registerfields.h"
#include "hw/sysbus.h"
#include "sysemu/block-backend.h"
#include "hw/misc/esp32_flash_enc.h"
typedef struct Esp32DportState Esp32DportState;
typedef struct Esp32CacheState Esp32CacheState;
#define TYPE_ESP32_DPORT "misc.esp32.dport"
#define ESP32_DPORT(obj) OBJECT_CHECK(Esp32DportState, (obj), TYPE_ESP32_DPORT)
#define ESP32_CACHE_PAGE_SIZE 0x10000
#define ESP32_CACHE_PAGES_PER_REGION 64
#define ESP32_CACHE_REGION_SIZE (ESP32_CACHE_PAGE_SIZE * ESP32_CACHE_PAGES_PER_REGION)
#define ESP32_CACHE_MMU_INVALID_VAL 0x100
#define ESP32_CACHE_MMU_ENTRY_CHANGED 0x200 /* not a hardware flag; used here to check if the page data needs to be updated */
#define ESP32_CACHE_MAX_PHYS_PAGES 0x100
typedef enum Esp32CacheRegionType {
ESP32_DCACHE_FLASH,
ESP32_ICACHE_FLASH,
ESP32_DCACHE_PSRAM,
} Esp32CacheRegionType;
typedef struct Esp32CacheRegionState {
Esp32CacheState* cache;
MemoryRegion mem;
MemoryRegion illegal_access_trap_mem;
Esp32CacheRegionType type;
hwaddr base;
uint32_t illegal_access_retval;
bool illegal_access_trap_en;
bool illegal_access_status;
uint16_t mmu_table[ESP32_CACHE_PAGES_PER_REGION];
} Esp32CacheRegionState;
typedef struct Esp32CacheState {
Esp32DportState* dport;
int core_id;
uint32_t cache_ctrl_reg;
uint32_t cache_ctrl1_reg;
/* Using only the first 4MB range.
* TODO: add memory regions for other ports: iram1, irom0
*/
Esp32CacheRegionState iram0;
Esp32CacheRegionState drom0;
Esp32CacheRegionState dram1; /* PSRAM */
} Esp32CacheState;
typedef struct Esp32DportState {
SysBusDevice parent_obj;
MemoryRegion iomem;
bool has_psram;
int cpu_count;
Esp32CacheState cache_state[ESP32_CPU_COUNT];
MemoryRegion psram; /* Shared between the CPUs: the actual memory region for PSRAM */
BlockBackend *flash_blk;
qemu_irq appcpu_stall_req;
qemu_irq appcpu_reset_req;
qemu_irq clk_update_req;
qemu_irq cache_ill_irq;
qemu_irq flash_enc_en_gpio;
qemu_irq flash_dec_en_gpio;
bool appcpu_reset_state;
bool appcpu_stall_state;
bool appcpu_clkgate_state;
uint32_t appcpu_boot_addr;
uint32_t cpuperiod_sel;
uint32_t cache_ill_trap_en_reg;
uint32_t slave_spi_config_reg;
} Esp32DportState;
void esp32_dport_clear_ill_trap_state(Esp32DportState* s);
#define ESP32_DPORT_APPCPU_STALL_GPIO "appcpu-stall"
#define ESP32_DPORT_APPCPU_RESET_GPIO "appcpu-reset"
#define ESP32_DPORT_CLK_UPDATE_GPIO "clk-update"
#define ESP32_DPORT_CACHE_ILL_IRQ_GPIO "cache-ill-irq"
#define ESP32_DPORT_FLASH_ENC_EN_GPIO "flash-enc-en"
#define ESP32_DPORT_FLASH_DEC_EN_GPIO "flash-dec-en"
REG32(DPORT_APPCPU_RESET, 0x2c)
REG32(DPORT_APPCPU_CLK, 0x30)
REG32(DPORT_APPCPU_RUNSTALL, 0x34)
REG32(DPORT_APPCPU_BOOT_ADDR, 0x38)
REG32(DPORT_CPU_PER_CONF, 0x3c)
FIELD(DPORT_CPU_PER_CONF, CPUPERIOD_SEL, 0, 2)
REG32(DPORT_PRO_CACHE_CTRL, 0x40)
FIELD(DPORT_PRO_CACHE_CTRL, CACHE_FLUSH_DONE, 5, 1)
FIELD(DPORT_PRO_CACHE_CTRL, CACHE_FLUSH_ENA, 4, 1)
FIELD(DPORT_PRO_CACHE_CTRL, CACHE_ENA, 3, 1)
REG32(DPORT_PRO_CACHE_CTRL1, 0x44)
FIELD(DPORT_PRO_CACHE_CTRL1, MMU_IA_CLR, 13, 1)
FIELD(DPORT_PRO_CACHE_CTRL1, MASK_OPSDRAM, 5, 1)
FIELD(DPORT_PRO_CACHE_CTRL1, MASK_DROM0, 4, 1)
FIELD(DPORT_PRO_CACHE_CTRL1, MASK_DRAM1, 3, 1)
FIELD(DPORT_PRO_CACHE_CTRL1, MASK_IROM0, 2, 1)
FIELD(DPORT_PRO_CACHE_CTRL1, MASK_IRAM1, 1, 1)
FIELD(DPORT_PRO_CACHE_CTRL1, MASK_IRAM0, 0, 1)
REG32(DPORT_APP_CACHE_CTRL, 0x58)
FIELD(DPORT_APP_CACHE_CTRL, CACHE_FLUSH_DONE, 5, 1)
FIELD(DPORT_APP_CACHE_CTRL, CACHE_FLUSH_ENA, 4, 1)
FIELD(DPORT_APP_CACHE_CTRL, CACHE_ENA, 3, 1)
REG32(DPORT_APP_CACHE_CTRL1, 0x5C)
FIELD(DPORT_APP_CACHE_CTRL1, MMU_IA_CLR, 13, 1)
FIELD(DPORT_APP_CACHE_CTRL1, MASK_OPSDRAM, 5, 1)
FIELD(DPORT_APP_CACHE_CTRL1, MASK_DROM0, 4, 1)
FIELD(DPORT_APP_CACHE_CTRL1, MASK_DRAM1, 3, 1)
FIELD(DPORT_APP_CACHE_CTRL1, MASK_IROM0, 2, 1)
FIELD(DPORT_APP_CACHE_CTRL1, MASK_IRAM1, 1, 1)
FIELD(DPORT_APP_CACHE_CTRL1, MASK_IRAM0, 0, 1)
REG32(DPORT_SLAVE_SPI_CONFIG, 0xC8)
FIELD(DPORT_SLAVE_SPI_CONFIG, SLAVE_SPI_ENCRYPT_ENABLE, 8, 1)
FIELD(DPORT_SLAVE_SPI_CONFIG, SLAVE_SPI_DECRYPT_ENABLE, 12, 1)
REG32(DPORT_CPU_INTR_FROM_CPU_0, 0xdc)
REG32(DPORT_CPU_INTR_FROM_CPU_1, 0xe0)
REG32(DPORT_CPU_INTR_FROM_CPU_2, 0xe4)
REG32(DPORT_CPU_INTR_FROM_CPU_3, 0xe8)
REG32(DPORT_PRO_MAC_INTR_MAP, 0x104)
REG32(DPORT_APP_MAC_INTR_MAP, 0x218)
REG32(DPORT_PRO_DCACHE_DBUG0, 0x3f0)
FIELD(DPORT_PRO_DCACHE_DBUG0, CACHE_STATE, 7, 12)
REG32(DPORT_PRO_DCACHE_DBUG3, 0x3FC)
FIELD(DPORT_PRO_DCACHE_DBUG3, IA_INT_OPPOSITE, 9, 1)
FIELD(DPORT_PRO_DCACHE_DBUG3, IA_INT_DRAM1, 10, 1)
FIELD(DPORT_PRO_DCACHE_DBUG3, IA_INT_IROM0, 11, 1)
FIELD(DPORT_PRO_DCACHE_DBUG3, IA_INT_IRAM1, 12, 1)
FIELD(DPORT_PRO_DCACHE_DBUG3, IA_INT_IRAM0, 13, 1)
FIELD(DPORT_PRO_DCACHE_DBUG3, IA_INT_DROM0, 14, 1)
REG32(DPORT_APP_DCACHE_DBUG0, 0x418)
FIELD(DPORT_APP_DCACHE_DBUG0, CACHE_STATE, 7, 12)
REG32(DPORT_APP_DCACHE_DBUG3, 0x424)
FIELD(DPORT_APP_DCACHE_DBUG3, IA_INT_OPPOSITE, 9, 1)
FIELD(DPORT_APP_DCACHE_DBUG3, IA_INT_DRAM1, 10, 1)
FIELD(DPORT_APP_DCACHE_DBUG3, IA_INT_IROM0, 11, 1)
FIELD(DPORT_APP_DCACHE_DBUG3, IA_INT_IRAM1, 12, 1)
FIELD(DPORT_APP_DCACHE_DBUG3, IA_INT_IRAM0, 13, 1)
FIELD(DPORT_APP_DCACHE_DBUG3, IA_INT_DROM0, 14, 1)
REG32(DPORT_CACHE_IA_INT_EN, 0x5A0)
FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_PRO_OPPOSITE, 19, 1)
FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_PRO_DRAM1, 18, 1)
FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_PRO_IROM0, 17, 1)
FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_PRO_IRAM1, 16, 1)
FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_PRO_IRAM0, 15, 1)
FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_PRO_DROM0, 14, 1)
FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_APP_OPPOSITE, 5, 1)
FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_APP_DRAM1, 4, 1)
FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_APP_IROM0, 3, 1)
FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_APP_IRAM1, 2, 1)
FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_APP_IRAM0, 1, 1)
FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_APP_DROM0, 0, 1)
#define ESP32_DPORT_PRO_INTMATRIX_BASE A_DPORT_PRO_MAC_INTR_MAP
#define ESP32_DPORT_APP_INTMATRIX_BASE A_DPORT_APP_MAC_INTR_MAP
#define ESP32_DPORT_CROSSCORE_INT_BASE A_DPORT_CPU_INTR_FROM_CPU_0