hw/xtensa: implement ESP32-S3 machine
This also includes the ESP32-S3 BIOS (ROM bootloader)
This commit is contained in:
committed by
Ivan Grokhotkov
parent
c0cce1fc74
commit
7591824ec4
@@ -9,3 +9,4 @@
|
||||
# CONFIG_XTENSA_VIRT=n
|
||||
# CONFIG_XTENSA_XTFPGA=n
|
||||
# CONFIG_XTENSA_ESP32=n
|
||||
# CONFIG_XTENSA_ESP32S3=n
|
||||
|
||||
@@ -33,3 +33,16 @@ config XTENSA_ESP32
|
||||
select LED
|
||||
select ESP_RGB
|
||||
|
||||
config XTENSA_ESP32S3
|
||||
bool
|
||||
default y
|
||||
depends on XTENSA
|
||||
select SSI
|
||||
select SSI_M25P80
|
||||
select UNIMP
|
||||
select OPENCORES_ETH
|
||||
select DWC_SDMMC
|
||||
select TMP105
|
||||
select ESP_RGB
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,954 @@
|
||||
/*
|
||||
* ESP32S3 SoC and Machine
|
||||
*
|
||||
* Copyright (c) 2023-2024 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 "qemu/units.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/memalign.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/xtensa/xtensa_memory.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "target/xtensa/cpu.h"
|
||||
|
||||
#include "hw/misc/esp32s3_rtc_cntl.h"
|
||||
#include "hw/xtensa/esp32s3_intc.h"
|
||||
|
||||
#include "hw/misc/ssi_psram.h"
|
||||
#include "core-esp32s3/core-isa.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "net/net.h"
|
||||
#include "elf.h"
|
||||
|
||||
#include "hw/ssi/esp32s3_spi.h"
|
||||
#include "hw/misc/esp32s3_cache.h"
|
||||
#include "hw/char/esp32s3_uart.h"
|
||||
#include "hw/misc/esp32s3_rng.h"
|
||||
|
||||
#include "hw/nvram/esp32s3_efuse.h"
|
||||
#include "hw/xtensa/esp32s3_clk.h"
|
||||
#include "hw/dma/esp32s3_gdma.h"
|
||||
#include "hw/misc/esp32s3_sha.h"
|
||||
#include "hw/misc/esp32s3_aes.h"
|
||||
#include "hw/misc/esp32s3_rsa.h"
|
||||
#include "hw/misc/esp32s3_hmac.h"
|
||||
#include "hw/misc/esp32s3_ds.h"
|
||||
#include "hw/timer/esp32c3_timg.h"
|
||||
#include "hw/timer/esp32s3_systimer.h"
|
||||
#include "hw/gpio/esp32s3_gpio.h"
|
||||
#include "hw/misc/esp32s3_xts_aes.h"
|
||||
#include "hw/misc/esp32s3_pms.h"
|
||||
|
||||
#include "cpu_esp32s3.h"
|
||||
|
||||
#include "hw/misc/esp32c3_jtag.h"
|
||||
#include "hw/display/esp_rgb.h"
|
||||
|
||||
#define TYPE_ESP32S3_SOC "xtensa.esp32s3"
|
||||
#define ESP32S3_SOC(obj) OBJECT_CHECK(Esp32s3SocState, (obj), TYPE_ESP32S3_SOC)
|
||||
|
||||
#define TYPE_ESP32S3_CPU XTENSA_CPU_TYPE_NAME("esp32s3")
|
||||
|
||||
|
||||
enum {
|
||||
ESP32S3_MEMREGION_IROM,
|
||||
ESP32S3_MEMREGION_DROM,
|
||||
ESP32S3_MEMREGION_DRAM,
|
||||
ESP32S3_MEMREGION_IRAM,
|
||||
ESP32S3_MEMREGION_ICACHE,
|
||||
ESP32S3_MEMREGION_DCACHE,
|
||||
ESP32S3_MEMREGION_RTCSLOW,
|
||||
ESP32S3_MEMREGION_RTCFAST,
|
||||
ESP32S3_MEMREGION_FRAMEBUF,
|
||||
};
|
||||
|
||||
static const struct MemmapEntry {
|
||||
hwaddr base;
|
||||
hwaddr size;
|
||||
} esp32s3_memmap[] = {
|
||||
[ESP32S3_MEMREGION_DROM] = { 0x3ff00000, 0x20000 },
|
||||
[ESP32S3_MEMREGION_IROM] = { 0x40000000, 0x60000 },
|
||||
[ESP32S3_MEMREGION_DRAM] = { 0x3FC80000, 0x170000 },
|
||||
[ESP32S3_MEMREGION_IRAM] = { 0x40370000, 0x80000 },
|
||||
[ESP32S3_MEMREGION_DCACHE] = { 0x3c000000, ESP32S3_EXTMEM_REGION_SIZE },
|
||||
[ESP32S3_MEMREGION_ICACHE] = { 0x42000000, ESP32S3_EXTMEM_REGION_SIZE },
|
||||
[ESP32S3_MEMREGION_RTCSLOW] = { 0x50000000, 0x2000 },
|
||||
[ESP32S3_MEMREGION_RTCFAST] = { 0x600fe000, 0x2000 },
|
||||
/* Virtual Framebuffer, used for the graphical interface */
|
||||
[ESP32S3_MEMREGION_FRAMEBUF] = { 0x20000000, ESP_RGB_MAX_VRAM_SIZE },
|
||||
};
|
||||
|
||||
|
||||
#define ESP32S3_SOC_RESET_PROCPU 0x1
|
||||
#define ESP32S3_SOC_RESET_APPCPU 0x2
|
||||
#define ESP32S3_SOC_RESET_PERIPH 0x4
|
||||
#define ESP32S3_SOC_RESET_DIG (ESP32S3_SOC_RESET_PROCPU | ESP32S3_SOC_RESET_APPCPU | ESP32S3_SOC_RESET_PERIPH)
|
||||
#define ESP32S3_SOC_RESET_RTC 0x8
|
||||
#define ESP32S3_SOC_RESET_ALL (ESP32S3_SOC_RESET_RTC | ESP32S3_SOC_RESET_DIG)
|
||||
|
||||
#define ESP32S3_IO_WARNING 0
|
||||
|
||||
typedef struct Esp32s3SocState {
|
||||
/*< private >*/
|
||||
DeviceState parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
XtensaCPU cpu[ESP32S3_CPU_COUNT];
|
||||
Esp32s3IntMatrixState intmatrix;
|
||||
ESP32S3UARTState uart[ESP32S3_UART_COUNT];
|
||||
ESP32S3GPIOState gpio;
|
||||
Esp32s3RngState rng;
|
||||
|
||||
Esp32s3RtcCntlState rtc_cntl;
|
||||
|
||||
BusState rtc_bus;
|
||||
BusState periph_bus;
|
||||
|
||||
MemoryRegion cpu_specific_mem[ESP32S3_CPU_COUNT];
|
||||
ESP32S3SpiState spi1;
|
||||
ESP32S3CacheState cache;
|
||||
ESP32S3EfuseState efuse;
|
||||
ESP32S3ClockState clock;
|
||||
ESP32S3GdmaState gdma;
|
||||
ESP32S3ShaState sha;
|
||||
ESP32S3AesState aes;
|
||||
ESP32S3RsaState rsa;
|
||||
ESP32S3HmacState hmac;
|
||||
ESP32S3DsState ds;
|
||||
ESP32S3PmsState pms;
|
||||
|
||||
ESP32S3XtsAesState xts_aes;
|
||||
ESP32C3TimgState timg[2];
|
||||
ESP32S3SysTimerState systimer;
|
||||
|
||||
ESP32C3UsbJtagState jtag;
|
||||
ESPRgbState rgb;
|
||||
|
||||
MemoryRegion iomem;
|
||||
DeviceState *eth;
|
||||
SsiPsramState *psram;
|
||||
|
||||
uint32_t requested_reset;
|
||||
} Esp32s3SocState;
|
||||
|
||||
|
||||
/* Temporary macro to mark the CPU as in non-debugging mode */
|
||||
#define A_ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG 0x098
|
||||
|
||||
/* "QEMU" as a 32-bit value, can be used by the application to to check whether it is running in
|
||||
* QEMU or on real hardware */
|
||||
#define RGB_QEMU_ORIGIN 0x51454d55
|
||||
#define RGB_QEMU_ORIGIN_REG 0x3F8
|
||||
|
||||
static void remove_cpu_watchpoints(XtensaCPU* xcs)
|
||||
{
|
||||
for (int i = 0; i < MAX_NDBREAK; ++i) {
|
||||
if (xcs->env.cpu_watchpoint[i]) {
|
||||
cpu_watchpoint_remove_by_ref(CPU(xcs), xcs->env.cpu_watchpoint[i]);
|
||||
xcs->env.cpu_watchpoint[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void esp32s3_dig_reset(void *opaque, int n, int level)
|
||||
{
|
||||
Esp32s3SocState *s = ESP32S3_SOC(opaque);
|
||||
if (level) {
|
||||
s->requested_reset = ESP32S3_SOC_RESET_DIG;
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
static void esp32s3_cpu_reset(void* opaque, int n, int level)
|
||||
{
|
||||
Esp32s3SocState *s = ESP32S3_SOC(opaque);
|
||||
if (level) {
|
||||
s->requested_reset = (n == 0) ? ESP32S3_SOC_RESET_PROCPU : ESP32S3_SOC_RESET_APPCPU;
|
||||
/* Use different cause for APP CPU so that its reset doesn't cause QEMU to exit,
|
||||
* when -no-reboot option is given.
|
||||
*/
|
||||
ShutdownCause cause = (n == 0) ? SHUTDOWN_CAUSE_GUEST_RESET : SHUTDOWN_CAUSE_SUBSYSTEM_RESET;
|
||||
qemu_system_reset_request(cause);
|
||||
}
|
||||
}
|
||||
|
||||
static void esp32s3_soc_reset(DeviceState *dev)
|
||||
{
|
||||
Esp32s3SocState *s = ESP32S3_SOC(dev);
|
||||
if (s->requested_reset == 0) {
|
||||
s->requested_reset = ESP32S3_SOC_RESET_ALL;
|
||||
}
|
||||
if (s->requested_reset & ESP32S3_SOC_RESET_PERIPH) {
|
||||
device_cold_reset(DEVICE(&s->intmatrix));
|
||||
for (int i = 0; i < ESP32S3_UART_COUNT; ++i) {
|
||||
device_cold_reset(DEVICE(&s->uart[i]));
|
||||
}
|
||||
}
|
||||
if (s->requested_reset & ESP32S3_SOC_RESET_PROCPU) {
|
||||
xtensa_select_static_vectors(&s->cpu[0].env, s->rtc_cntl.stat_vector_sel[0]);
|
||||
remove_cpu_watchpoints(&s->cpu[0]);
|
||||
cpu_reset(CPU(&s->cpu[0]));
|
||||
}
|
||||
if (s->requested_reset & ESP32S3_SOC_RESET_APPCPU && (ESP32S3_CPU_COUNT > 1)) {
|
||||
xtensa_select_static_vectors(&s->cpu[1].env, s->rtc_cntl.stat_vector_sel[1]);
|
||||
remove_cpu_watchpoints(&s->cpu[1]);
|
||||
cpu_reset(CPU(&s->cpu[1]));
|
||||
}
|
||||
s->requested_reset = 0;
|
||||
}
|
||||
|
||||
static void esp32s3_cpu_stall(void* opaque, int n, int level)
|
||||
{
|
||||
}
|
||||
|
||||
static void esp32s3_clk_update(void* opaque, int n, int level)
|
||||
{
|
||||
if (!level) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void esp32s3_soc_add_periph_device(MemoryRegion *dest, void* dev, hwaddr dport_base_addr)
|
||||
{
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
|
||||
memory_region_add_subregion_overlap(dest, dport_base_addr, mr, 0);
|
||||
MemoryRegion *mr_apb = g_new(MemoryRegion, 1);
|
||||
char *name = g_strdup_printf("mr-apb-0x%08x", (uint32_t) dport_base_addr);
|
||||
memory_region_init_alias(mr_apb, OBJECT(dev), name, mr, 0, memory_region_size(mr));
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
#define MB (1024*1024)
|
||||
|
||||
static void esp32s3_init_spi_flash(Esp32s3SocState *ms, BlockBackend* blk)
|
||||
{
|
||||
DeviceState *spi_master = DEVICE(&ms->spi1);
|
||||
BusState* spi_bus = qdev_get_child_bus(spi_master, "spi");
|
||||
const char* flash_model = NULL;
|
||||
int64_t image_size = blk_getlength(blk);
|
||||
|
||||
switch (image_size) {
|
||||
case 2 * MB:
|
||||
flash_model = "w25x16";
|
||||
break;
|
||||
case 4 * MB:
|
||||
flash_model = "gd25q32";
|
||||
break;
|
||||
case 8 * MB:
|
||||
flash_model = "gd25q64";
|
||||
break;
|
||||
case 16 * MB:
|
||||
flash_model = "is25lp128";
|
||||
break;
|
||||
default:
|
||||
error_report("Drive size error: only 2, 4, 8, and 16MB images are supported");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create the SPI flash model */
|
||||
DeviceState *flash_dev = qdev_new(flash_model);
|
||||
qdev_prop_set_drive(flash_dev, "drive", blk);
|
||||
|
||||
/* Realize the SPI flash, its "drive" (blk) property must already be set! */
|
||||
qdev_realize(flash_dev, spi_bus, &error_fatal);
|
||||
qdev_connect_gpio_out_named(spi_master, SSI_GPIO_CS, 0,
|
||||
qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0));
|
||||
}
|
||||
|
||||
static void esp32s3_machine_init_psram(Esp32s3SocState *ms, uint32_t size_mbytes)
|
||||
{
|
||||
/* PSRAM attached to SPI1, CS1 */
|
||||
DeviceState *spi_master = DEVICE(&ms->spi1);
|
||||
BusState* spi_bus = qdev_get_child_bus(spi_master, "spi");
|
||||
DeviceState *psram = qdev_new(TYPE_SSI_PSRAM);
|
||||
qdev_prop_set_uint32(psram, "size_mbytes", size_mbytes);
|
||||
qdev_prop_set_uint8(psram, "cs", 1);
|
||||
qdev_prop_set_uint32(psram, "dummy", 0);
|
||||
qdev_realize(psram, spi_bus, &error_fatal);
|
||||
ms->psram = SSI_PSRAM(psram);
|
||||
qdev_connect_gpio_out_named(spi_master, SSI_GPIO_CS, 1,
|
||||
qdev_get_gpio_in_named(psram, SSI_GPIO_CS, 0));
|
||||
}
|
||||
|
||||
struct Esp32s3MachineState {
|
||||
MachineState parent;
|
||||
|
||||
Esp32s3SocState esp32s3;
|
||||
DeviceState *flash_dev;
|
||||
};
|
||||
#define TYPE_ESP32S3_MACHINE MACHINE_TYPE_NAME("esp32s3")
|
||||
|
||||
static void esp32s3_init_openeth(Esp32s3SocState *ms)
|
||||
{
|
||||
MemoryRegion* mr = NULL;
|
||||
SysBusDevice* sbd = NULL;
|
||||
|
||||
MemoryRegion* sys_mem = get_system_memory();
|
||||
|
||||
/* Create a new OpenCores Ethernet component */
|
||||
DeviceState* open_eth_dev = qemu_create_nic_device("open_eth", true, NULL);
|
||||
if (!open_eth_dev) {
|
||||
return;
|
||||
}
|
||||
ms->eth = open_eth_dev;
|
||||
sbd = SYS_BUS_DEVICE(open_eth_dev);
|
||||
sysbus_realize(sbd, &error_fatal);
|
||||
|
||||
/* OpenCores Ethernet has two memory regions: one for registers and one for descriptors,
|
||||
* we need to provide one I/O range for each of them */
|
||||
mr = sysbus_mmio_get_region(sbd, 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_EMAC_BASE, mr, 0);
|
||||
mr = sysbus_mmio_get_region(sbd, 1);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_EMAC_BASE + 0x400, mr, 0);
|
||||
|
||||
sysbus_connect_irq(sbd, 0,
|
||||
qdev_get_gpio_in(DEVICE(&ms->intmatrix), ETS_ETH_MAC_INTR_SOURCE));
|
||||
}
|
||||
|
||||
|
||||
static void esp32s3_soc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
Esp32s3SocState *s = ESP32S3_SOC(dev);
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
|
||||
const struct MemmapEntry *memmap = esp32s3_memmap;
|
||||
MemoryRegion *sys_mem = get_system_memory();
|
||||
|
||||
MemoryRegion *iram = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *rtcslow = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *rtcfast = g_new(MemoryRegion, 1);
|
||||
|
||||
for (int i = 0; i < ms->smp.cpus; ++i) {
|
||||
MemoryRegion *drom = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *irom = g_new(MemoryRegion, 1);
|
||||
|
||||
char name[20];
|
||||
snprintf(name, sizeof(name), "esp32s3.irom.cpu%d", i);
|
||||
memory_region_init_rom(irom, NULL, name, memmap[ESP32S3_MEMREGION_IROM].size, &error_fatal);
|
||||
memory_region_add_subregion(&s->cpu_specific_mem[i], memmap[ESP32S3_MEMREGION_IROM].base, irom);
|
||||
|
||||
const hwaddr offset_in_orig = 0x40000;
|
||||
snprintf(name, sizeof(name), "esp32s3.drom.cpu%d", i);
|
||||
memory_region_init_alias(drom, NULL, name, irom, offset_in_orig, memmap[ESP32S3_MEMREGION_DROM].size);
|
||||
memory_region_add_subregion(sys_mem, memmap[ESP32S3_MEMREGION_DROM].base, drom);
|
||||
}
|
||||
|
||||
|
||||
memory_region_init_ram(iram, NULL, "esp32s3.iram",
|
||||
memmap[ESP32S3_MEMREGION_IRAM].size, &error_fatal);
|
||||
memory_region_add_subregion(sys_mem, memmap[ESP32S3_MEMREGION_IRAM].base, iram);
|
||||
|
||||
memory_region_init_ram(rtcslow, NULL, "esp32s3.rtcslow",
|
||||
memmap[ESP32S3_MEMREGION_RTCSLOW].size, &error_fatal);
|
||||
memory_region_add_subregion(sys_mem, memmap[ESP32S3_MEMREGION_RTCSLOW].base, rtcslow);
|
||||
|
||||
memory_region_init_ram(rtcfast, NULL, "esp32s3.rtcfast",
|
||||
memmap[ESP32S3_MEMREGION_RTCFAST].size, &error_fatal);
|
||||
memory_region_add_subregion(sys_mem, memmap[ESP32S3_MEMREGION_RTCFAST].base, rtcfast);
|
||||
|
||||
for (int i = 0; i < ms->smp.cpus; ++i) {
|
||||
qdev_realize(DEVICE(&s->cpu[i]), NULL, &error_fatal);
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < ESP32S3_CPU_COUNT; ++i) {
|
||||
char name[16];
|
||||
snprintf(name, sizeof(name), "cpu%d", i);
|
||||
object_property_set_link(OBJECT(&s->intmatrix), name, OBJECT(qemu_get_cpu(i)), &error_abort);
|
||||
}
|
||||
qdev_realize(DEVICE(&s->intmatrix), &s->periph_bus, &error_fatal);
|
||||
DeviceState* intmatrix_dev = DEVICE(&s->intmatrix);
|
||||
|
||||
|
||||
qdev_realize(DEVICE(&s->rtc_cntl), &s->rtc_bus, &error_fatal);
|
||||
esp32s3_soc_add_periph_device(sys_mem, &s->rtc_cntl, DR_REG_RTCCNTL_BASE);
|
||||
|
||||
qdev_connect_gpio_out_named(DEVICE(&s->rtc_cntl), ESP32S3_RTC_DIG_RESET_GPIO, 0,
|
||||
qdev_get_gpio_in_named(dev, ESP32S3_RTC_DIG_RESET_GPIO, 0));
|
||||
qdev_connect_gpio_out_named(DEVICE(&s->rtc_cntl), ESP32S3_RTC_CLK_UPDATE_GPIO, 0,
|
||||
qdev_get_gpio_in_named(dev, ESP32S3_RTC_CLK_UPDATE_GPIO, 0));
|
||||
for (int i = 0; i < ms->smp.cpus; ++i) {
|
||||
qdev_connect_gpio_out_named(DEVICE(&s->rtc_cntl), ESP32S3_RTC_CPU_RESET_GPIO, i,
|
||||
qdev_get_gpio_in_named(dev, ESP32S3_RTC_CPU_RESET_GPIO, i));
|
||||
qdev_connect_gpio_out_named(DEVICE(&s->rtc_cntl), ESP32S3_RTC_CPU_STALL_GPIO, i,
|
||||
qdev_get_gpio_in_named(dev, ESP32S3_RTC_CPU_STALL_GPIO, i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < ESP32S3_UART_COUNT; ++i) {
|
||||
const hwaddr uart_base[] = {DR_REG_UART_BASE, DR_REG_UART1_BASE, DR_REG_UART2_BASE};
|
||||
qdev_realize(DEVICE(&s->uart[i]), &s->periph_bus, &error_fatal);
|
||||
esp32s3_soc_add_periph_device(sys_mem, &s->uart[i], uart_base[i]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
|
||||
qdev_get_gpio_in(intmatrix_dev, ETS_UART0_INTR_SOURCE + i));
|
||||
}
|
||||
|
||||
|
||||
/* Emulation of APB_CTRL_DATE_REG, needed for ECO3 revision detection.
|
||||
* This is a small hack to avoid creating a whole new device just to emulate one
|
||||
* register.
|
||||
*/
|
||||
const hwaddr apb_ctrl_regs = DR_REG_APB_CTRL_BASE;
|
||||
MemoryRegion *apbctrl_mem = g_new(MemoryRegion, 1);
|
||||
memory_region_init_ram(apbctrl_mem, NULL, "esp32s3.apbctrl", 0x400 /* bytes */, &error_fatal);
|
||||
memory_region_add_subregion(sys_mem, apb_ctrl_regs, apbctrl_mem);
|
||||
uint32_t apb_ctrl_date_reg_val = 0x16042000 | 0x80000000; /* MSB indicates ECO3 silicon revision */
|
||||
uint32_t qemu_sig = RGB_QEMU_ORIGIN;
|
||||
cpu_physical_memory_write(apb_ctrl_regs + 0x7c, &apb_ctrl_date_reg_val, 4);
|
||||
cpu_physical_memory_write(apb_ctrl_regs + RGB_QEMU_ORIGIN_REG, &qemu_sig, 4);
|
||||
|
||||
qemu_register_reset((QEMUResetHandler*) esp32s3_soc_reset, dev);
|
||||
}
|
||||
|
||||
|
||||
static uint64_t esp32s3_io_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
#if ESP32S3_IO_WARNING
|
||||
warn_report("[ESP32-S3] Unsupported read to $%08lx, size = %i\n", ESP32S3_IO_START_ADDR + addr, size);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void esp32s3_io_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size)
|
||||
{
|
||||
#if ESP32S3_IO_WARNING
|
||||
warn_report("[ESP32-S3] Unsupported write $%08lx = %08lx\n", ESP32S3_IO_START_ADDR + addr, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Define operations for I/OS */
|
||||
static const MemoryRegionOps esp32s3_io_ops = {
|
||||
.read = esp32s3_io_read,
|
||||
.write = esp32s3_io_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void esp32s3_soc_init(Object *obj)
|
||||
{
|
||||
Esp32s3SocState *s = ESP32S3_SOC(obj);
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
char name[16];
|
||||
MemoryRegion *system_memory = get_system_memory();
|
||||
|
||||
|
||||
qbus_init(&s->periph_bus, sizeof(s->periph_bus),
|
||||
TYPE_SYSTEM_BUS, DEVICE(s), "esp32-periph-bus");
|
||||
qbus_init(&s->rtc_bus, sizeof(s->rtc_bus),
|
||||
TYPE_SYSTEM_BUS, DEVICE(s), "esp32-rtc-bus");
|
||||
|
||||
for (int i = 0; i < ms->smp.cpus; ++i) {
|
||||
snprintf(name, sizeof(name), "cpu%d", i);
|
||||
|
||||
object_initialize_child(obj, name, &s->cpu[i], TYPE_ESP32S3_CPU);
|
||||
// Allocate memory for TIE registers
|
||||
s->cpu[i].env.ext = qemu_memalign(16, sizeof(CPUXtensaEsp32s3State));
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
s->cpu[i].env.sregs[PRID] = 0xcdcd;
|
||||
}
|
||||
if (i == 1)
|
||||
{
|
||||
s->cpu[i].env.sregs[PRID] = 0xabab;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "cpu%d-mem", i);
|
||||
memory_region_init(&s->cpu_specific_mem[i], NULL, name, UINT32_MAX);
|
||||
|
||||
CPUState* cs = CPU(&s->cpu[i]);
|
||||
cs->num_ases = 1;
|
||||
cpu_address_space_init(cs, 0, "cpu-memory", &s->cpu_specific_mem[i]);
|
||||
|
||||
MemoryRegion *cpu_view_sysmem = g_new(MemoryRegion, 1);
|
||||
snprintf(name, sizeof(name), "cpu%d-sysmem", i);
|
||||
memory_region_init_alias(cpu_view_sysmem, NULL, name, system_memory, 0, UINT32_MAX);
|
||||
memory_region_add_subregion_overlap(&s->cpu_specific_mem[i], 0, cpu_view_sysmem, 0);
|
||||
cs->memory = &s->cpu_specific_mem[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < ESP32S3_UART_COUNT; ++i) {
|
||||
snprintf(name, sizeof(name), "uart%d", i);
|
||||
object_initialize_child(obj, name, &s->uart[i], TYPE_ESP32S3_UART);
|
||||
}
|
||||
|
||||
object_property_add_alias(obj, "serial0", OBJECT(&s->uart[0]), "chardev");
|
||||
object_property_add_alias(obj, "serial1", OBJECT(&s->uart[1]), "chardev");
|
||||
// object_property_add_alias(obj, "serial2", OBJECT(&s->uart[2]), "chardev");
|
||||
qdev_prop_set_chr(DEVICE(&s->uart[0]), "chardev", serial_hd(0));
|
||||
qdev_prop_set_chr(DEVICE(&s->uart[1]), "chardev", serial_hd(1));
|
||||
// qdev_prop_set_chr(DEVICE(&s->uart[2]), "chardev", serial_hd(2));
|
||||
|
||||
object_initialize_child(obj, "intmatrix", &s->intmatrix, TYPE_ESP32S3_INTMATRIX);
|
||||
|
||||
object_initialize_child(obj, "rtc_cntl", &s->rtc_cntl, TYPE_ESP32S3_RTC_CNTL);
|
||||
|
||||
qdev_init_gpio_in_named(DEVICE(s), esp32s3_dig_reset, ESP32S3_RTC_DIG_RESET_GPIO, 1);
|
||||
qdev_init_gpio_in_named(DEVICE(s), esp32s3_cpu_reset, ESP32S3_RTC_CPU_RESET_GPIO, ESP32S3_CPU_COUNT);
|
||||
qdev_init_gpio_in_named(DEVICE(s), esp32s3_cpu_stall, ESP32S3_RTC_CPU_STALL_GPIO, ESP32S3_CPU_COUNT);
|
||||
qdev_init_gpio_in_named(DEVICE(s), esp32s3_clk_update, ESP32S3_RTC_CLK_UPDATE_GPIO, 1);
|
||||
}
|
||||
|
||||
static Property esp32s3_soc_properties[] = {
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void esp32s3_soc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = esp32s3_soc_realize;
|
||||
device_class_set_props(dc, esp32s3_soc_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo esp32s3_soc_info = {
|
||||
.name = TYPE_ESP32S3_SOC,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(Esp32s3SocState),
|
||||
.instance_init = esp32s3_soc_init,
|
||||
.class_init = esp32s3_soc_class_init
|
||||
};
|
||||
|
||||
static void esp32s3_soc_register_types(void)
|
||||
{
|
||||
type_register_static(&esp32s3_soc_info);
|
||||
}
|
||||
|
||||
type_init(esp32s3_soc_register_types)
|
||||
|
||||
|
||||
static uint64_t translate_phys_addr(void *opaque, uint64_t addr)
|
||||
{
|
||||
XtensaCPU *cpu = opaque;
|
||||
|
||||
return cpu_get_phys_page_debug(CPU(cpu), addr);
|
||||
}
|
||||
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(Esp32s3MachineState, ESP32S3_MACHINE)
|
||||
|
||||
// -----------------------------------------------
|
||||
|
||||
static void esp32s3_soc_add_unimp_device(MemoryRegion *dest, const char* name, hwaddr dport_base_addr, size_t size)
|
||||
{
|
||||
create_unimplemented_device(name, dport_base_addr, size);
|
||||
char * name_apb = g_strdup_printf("%s-apb", name);
|
||||
create_unimplemented_device(name_apb, dport_base_addr + APB_REG_BASE, size);
|
||||
g_free(name_apb);
|
||||
}
|
||||
|
||||
static void esp32s3_machine_init(MachineState *machine)
|
||||
{
|
||||
DriveInfo *dinfo = drive_get(IF_MTD, 0, 0);
|
||||
BlockBackend* blk = NULL;
|
||||
if (dinfo) {
|
||||
/* MTD was given! We need to initialize and emulate SPI flash */
|
||||
qemu_log("Adding SPI flash device\n");
|
||||
blk = blk_by_legacy_dinfo(dinfo);
|
||||
} else {
|
||||
qemu_log("Not initializing SPI Flash\n");
|
||||
}
|
||||
|
||||
MemoryRegion *sys_mem = get_system_memory();
|
||||
Esp32s3MachineState *ms = ESP32S3_MACHINE(machine);
|
||||
object_initialize_child(OBJECT(ms), "soc", &ms->esp32s3, TYPE_ESP32S3_SOC);
|
||||
Esp32s3SocState *ss = ESP32S3_SOC(&ms->esp32s3);
|
||||
|
||||
MemoryRegion *dram = g_new(MemoryRegion, 1);
|
||||
const struct MemmapEntry *memmap = esp32s3_memmap;
|
||||
|
||||
memory_region_init_ram(dram, NULL, "esp32s3.dram",
|
||||
memmap[ESP32S3_MEMREGION_DRAM].size, &error_fatal);
|
||||
memory_region_add_subregion(sys_mem, memmap[ESP32S3_MEMREGION_DRAM].base, dram);
|
||||
|
||||
|
||||
memory_region_init_io(&ss->iomem, OBJECT(&ss->cpu[0]), &esp32s3_io_ops,
|
||||
NULL, "esp32s3.iomem", 0xd1000);
|
||||
memory_region_add_subregion(sys_mem, ESP32S3_IO_START_ADDR, &ss->iomem);
|
||||
|
||||
// qdev_prop_set_chr(DEVICE(ss), "serial0", serial_hd(0));
|
||||
// qdev_prop_set_chr(DEVICE(ss), "serial1", serial_hd(1));
|
||||
// qdev_prop_set_chr(DEVICE(ss), "serial2", serial_hd(2));
|
||||
|
||||
qdev_realize(DEVICE(ss), NULL, &error_fatal);
|
||||
|
||||
object_initialize_child(OBJECT(ss), "extmem", &ss->cache, TYPE_ESP32S3_CACHE);
|
||||
object_initialize_child(OBJECT(ss), "spi1", &ss->spi1, TYPE_ESP32S3_SPI);
|
||||
object_initialize_child(OBJECT(ss), "efuse", &ss->efuse, TYPE_ESP32S3_EFUSE);
|
||||
object_initialize_child(OBJECT(ss), "jtag", &ss->jtag, TYPE_ESP32C3_JTAG);
|
||||
object_initialize_child(OBJECT(ss), "gpio", &ss->gpio, TYPE_ESP32S3_GPIO);
|
||||
object_initialize_child(OBJECT(ss), "rng", &ss->rng, TYPE_ESP32S3_RNG);
|
||||
|
||||
object_initialize_child(OBJECT(ss), "clock", &ss->clock, TYPE_ESP32S3_CLOCK);
|
||||
|
||||
object_initialize_child(OBJECT(ss), "gdma", &ss->gdma, TYPE_ESP32S3_GDMA);
|
||||
object_initialize_child(OBJECT(ss), "sha", &ss->sha, TYPE_ESP32S3_SHA);
|
||||
object_initialize_child(OBJECT(ss), "aes", &ss->aes, TYPE_ESP32S3_AES);
|
||||
object_initialize_child(OBJECT(ss), "rsa", &ss->rsa, TYPE_ESP32S3_RSA);
|
||||
object_initialize_child(OBJECT(ss), "hmac", &ss->hmac, TYPE_ESP32S3_HMAC);
|
||||
object_initialize_child(OBJECT(ss), "ds", &ss->ds, TYPE_ESP32S3_DS);
|
||||
object_initialize_child(OBJECT(ss), "pms", &ss->pms, TYPE_ESP32S3_PMS);
|
||||
|
||||
object_initialize_child(OBJECT(ss), "xts_aes", &ss->xts_aes, TYPE_ESP32S3_XTS_AES);
|
||||
object_initialize_child(OBJECT(ss), "timg0", &ss->timg[0], TYPE_ESP32C3_TIMG);
|
||||
object_initialize_child(OBJECT(ss), "timg1", &ss->timg[1], TYPE_ESP32C3_TIMG);
|
||||
object_initialize_child(OBJECT(ss), "systimer", &ss->systimer, TYPE_ESP32S3_SYSTIMER);
|
||||
object_initialize_child(OBJECT(ss), "rgb", &ss->rgb, TYPE_ESP_RGB);
|
||||
|
||||
DeviceState* intmatrix_dev = DEVICE(&ss->intmatrix);
|
||||
{
|
||||
/* Store the current Machine CPU in the interrupt matrix */
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->intmatrix), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_INTERRUPT_BASE, mr, 0);
|
||||
}
|
||||
|
||||
/* Initialize OpenCores Ethernet controller now sicne it requires the interrupt matrix */
|
||||
esp32s3_init_openeth(ss);
|
||||
|
||||
/* USB Serial JTAG realization */
|
||||
{
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->jtag), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->jtag), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_USB_SERIAL_JTAG_BASE, mr, 0);
|
||||
}
|
||||
|
||||
/* SPI1 controller (SPI Flash) */
|
||||
{
|
||||
ss->spi1.xts_aes = &ss->xts_aes;
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->spi1), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->spi1), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_SPI1_BASE, mr, 0);
|
||||
if (blk) {
|
||||
esp32s3_init_spi_flash(ss, blk);
|
||||
}
|
||||
if (machine->ram_size > 0) {
|
||||
esp32s3_machine_init_psram(ss, (uint32_t) (machine->ram_size / MiB));
|
||||
}
|
||||
}
|
||||
|
||||
/* (Extmem) Cache realization */
|
||||
{
|
||||
if (blk) {
|
||||
ss->cache.flash_blk = blk;
|
||||
}
|
||||
if (ss->psram) {
|
||||
ss->cache.psram = ss->psram;
|
||||
}
|
||||
ss->cache.xts_aes = &ss->xts_aes;
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->cache), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->cache), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_EXTMEM_BASE, mr, 0);
|
||||
|
||||
memory_region_add_subregion(sys_mem, memmap[ESP32S3_MEMREGION_DCACHE].base, &ss->cache.dcache);
|
||||
memory_region_add_subregion(sys_mem, memmap[ESP32S3_MEMREGION_ICACHE].base, &ss->cache.icache);
|
||||
}
|
||||
|
||||
/* eFuses realization */
|
||||
{
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->efuse), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->efuse), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_EFUSE_BASE, mr, 0);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&ss->efuse), 0,
|
||||
qdev_get_gpio_in(intmatrix_dev, ETS_EFUSE_INTR_SOURCE));
|
||||
}
|
||||
|
||||
/* System clock realization */
|
||||
{
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->clock), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->clock), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_SYSTEM_BASE, mr, 0);
|
||||
/* Connect the IRQ lines to the interrupt matrix */
|
||||
for (int i = 0; i < ESP32S3_SYSTEM_CPU_INTR_COUNT; i++) {
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&ss->clock), i,
|
||||
qdev_get_gpio_in(intmatrix_dev, ETS_FROM_CPU_INTR0_SOURCE + i));
|
||||
}
|
||||
}
|
||||
/* Timer Groups realization */
|
||||
{
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->timg[0]), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->timg[0]), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_TIMERGROUP0_BASE, mr, 0);
|
||||
/* Connect the T0 interrupt line to the interrupt matrix */
|
||||
qdev_connect_gpio_out_named(DEVICE(&ss->timg[0]), ESP32C3_T0_IRQ_INTERRUPT, 0,
|
||||
qdev_get_gpio_in(intmatrix_dev, ETS_TG0_T0_LEVEL_INTR_SOURCE));
|
||||
/* Connect the Watchdog interrupt line to the interrupt matrix */
|
||||
qdev_connect_gpio_out_named(DEVICE(&ss->timg[0]), ESP32C3_WDT_IRQ_INTERRUPT, 0,
|
||||
qdev_get_gpio_in(intmatrix_dev, ETS_TG0_WDT_LEVEL_INTR_SOURCE));
|
||||
}
|
||||
{
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->timg[1]), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->timg[1]), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_TIMERGROUP1_BASE, mr, 0);
|
||||
/* Connect the T0 interrupt line to the interrupt matrix */
|
||||
qdev_connect_gpio_out_named(DEVICE(&ss->timg[1]), ESP32C3_T0_IRQ_INTERRUPT, 0,
|
||||
qdev_get_gpio_in(intmatrix_dev, ETS_TG1_T0_LEVEL_INTR_SOURCE));
|
||||
qdev_connect_gpio_out_named(DEVICE(&ss->timg[1]), ESP32C3_WDT_IRQ_INTERRUPT, 0,
|
||||
qdev_get_gpio_in(intmatrix_dev, ETS_TG1_WDT_LEVEL_INTR_SOURCE));
|
||||
}
|
||||
|
||||
/* System timer */
|
||||
{
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->systimer), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->systimer), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_SYSTIMER_BASE, mr, 0);
|
||||
for (int i = 0; i < ESP_SYSTIMER_IRQ_COUNT; i++) {
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&ss->systimer), i,
|
||||
qdev_get_gpio_in(intmatrix_dev, ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE + i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* GPIO realization */
|
||||
{
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->gpio), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->gpio), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_GPIO_BASE, mr, 0);
|
||||
}
|
||||
|
||||
{
|
||||
qdev_realize(DEVICE(&ss->rng), &ss->periph_bus, &error_fatal);
|
||||
esp32s3_soc_add_periph_device(sys_mem, &ss->rng, ESP32S3_RNG_BASE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* GDMA Realization */
|
||||
{
|
||||
object_property_set_link(OBJECT(&ss->gdma), "soc_mr", OBJECT(dram), &error_abort);
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->gdma), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->gdma), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_GDMA_BASE, mr, 0);
|
||||
/* Connect the IRQs to the Interrupt Matrix */
|
||||
for (int i = 0; i < ESP32S3_GDMA_CHANNEL_COUNT; i++) {
|
||||
qdev_connect_gpio_out_named(DEVICE(&ss->gdma), ESP_GDMA_IRQ_IN_NAME, i,
|
||||
qdev_get_gpio_in(intmatrix_dev, ETS_DMA_IN_CH0_INTR_SOURCE + i));
|
||||
qdev_connect_gpio_out_named(DEVICE(&ss->gdma), ESP_GDMA_IRQ_OUT_NAME, i,
|
||||
qdev_get_gpio_in(intmatrix_dev, ETS_DMA_OUT_CH0_INTR_SOURCE + i));
|
||||
}
|
||||
}
|
||||
|
||||
/* SHA realization */
|
||||
{
|
||||
ss->sha.parent.gdma = ESP_GDMA(&ss->gdma);
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->sha), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->sha), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_SHA_BASE, mr, 0);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&ss->sha), 0,
|
||||
qdev_get_gpio_in(intmatrix_dev, ETS_SHA_INTR_SOURCE));
|
||||
}
|
||||
|
||||
/* AES realization */
|
||||
{
|
||||
ss->aes.parent.gdma = ESP_GDMA(&ss->gdma);
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->aes), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->aes), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_AES_BASE, mr, 0);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&ss->aes), 0,
|
||||
qdev_get_gpio_in(intmatrix_dev, ETS_AES_INTR_SOURCE));
|
||||
}
|
||||
/* RSA realization */
|
||||
{
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->rsa), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->rsa), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_RSA_BASE, mr, 0);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&ss->rsa), 0,
|
||||
qdev_get_gpio_in(intmatrix_dev, ETS_RSA_INTR_SOURCE));
|
||||
}
|
||||
/* PMS realization */
|
||||
{
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->pms), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->pms), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_SENSITIVE_BASE, mr, 0);
|
||||
}
|
||||
|
||||
/* HMAC realization */
|
||||
{
|
||||
ss->hmac.parent.efuse = ESP_EFUSE(&ss->efuse);
|
||||
qdev_realize(DEVICE(&ss->hmac), &ss->periph_bus, &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->hmac), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_HMAC_BASE, mr, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Digital Signature realization */
|
||||
{
|
||||
ss->ds.parent.hmac = ESP_HMAC(&ss->hmac);
|
||||
ss->ds.parent.aes = ESP_AES(&ss->aes);
|
||||
ss->ds.parent.rsa = ESP_RSA(&ss->rsa);
|
||||
ss->ds.parent.sha = ESP_SHA(&ss->sha);
|
||||
qdev_realize(DEVICE(&ss->ds), &ss->periph_bus, &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->ds), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_DIGITAL_SIGNATURE_BASE, mr, 0);
|
||||
}
|
||||
/* XTS-AES realization */
|
||||
{
|
||||
ss->xts_aes.efuse = ESP_EFUSE(&ss->efuse);
|
||||
ss->xts_aes.clock = &ss->clock;
|
||||
qdev_realize(DEVICE(&ss->xts_aes), &ss->periph_bus, &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->xts_aes), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_AES_XTS_BASE, mr, 0);
|
||||
}
|
||||
|
||||
/* RGB display realization */
|
||||
{
|
||||
/* Give the internal RAM memory region to the display */
|
||||
ss->rgb.intram = dram;
|
||||
sysbus_realize(SYS_BUS_DEVICE(&ss->rgb), &error_fatal);
|
||||
MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ss->rgb), 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_FRAMEBUF_BASE, mr, 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, esp32s3_memmap[ESP32S3_MEMREGION_FRAMEBUF].base, &ss->rgb.vram, 0);
|
||||
}
|
||||
|
||||
esp32s3_soc_add_unimp_device(sys_mem, "esp32s3.rmt", DR_REG_RMT_BASE, 0x1000);
|
||||
esp32s3_soc_add_unimp_device(sys_mem, "esp32s3.iomux", DR_REG_IO_MUX_BASE, 0x2000);
|
||||
|
||||
/* Need MMU initialized prior to ELF loading,
|
||||
* so that ELF gets loaded into virtual addresses
|
||||
*/
|
||||
cpu_reset(CPU(&ss->cpu[0]));
|
||||
|
||||
const char *load_elf_filename = NULL;
|
||||
if (machine->firmware) {
|
||||
load_elf_filename = machine->firmware;
|
||||
}
|
||||
if (machine->kernel_filename) {
|
||||
qemu_log("Warning: both -bios and -kernel arguments specified. Only loading the the -kernel file.\n");
|
||||
load_elf_filename = machine->kernel_filename;
|
||||
}
|
||||
|
||||
if (load_elf_filename) {
|
||||
uint64_t elf_entry;
|
||||
uint64_t elf_lowaddr;
|
||||
int size = load_elf(load_elf_filename, NULL,
|
||||
translate_phys_addr, &ss->cpu[0],
|
||||
&elf_entry, &elf_lowaddr,
|
||||
NULL, NULL, 0, EM_XTENSA, 0, 0);
|
||||
if (size < 0) {
|
||||
error_report("Error: could not load ELF file '%s'", load_elf_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (elf_entry != XCHAL_RESET_VECTOR_PADDR) {
|
||||
// Since ROM is empty when loading elf file AND
|
||||
// PC value is 0x40000400 after reset
|
||||
// need to jump to elf entry point to run a programm
|
||||
uint8_t p[4];
|
||||
memcpy(p, &elf_entry, 4);
|
||||
uint8_t boot[] = {
|
||||
0x06, 0x01, 0x00, /* j 1 */
|
||||
0x00, /* .literal_position */
|
||||
p[0], p[1], p[2], p[3], /* .literal elf_entry */
|
||||
/* 1: */
|
||||
0x01, 0xff, 0xff, /* l32r a0, elf_entry */
|
||||
0xa0, 0x00, 0x00, /* jx a0 */
|
||||
};
|
||||
// Write boot function to reset-vector address (0x40000400) of the CPU 0
|
||||
rom_add_blob_fixed_as("boot", boot, sizeof(boot), XCHAL_RESET_VECTOR_PADDR, CPU(&ss->cpu[0])->as);
|
||||
ss->cpu[0].env.pc = XCHAL_RESET_VECTOR_PADDR;
|
||||
}
|
||||
} else {
|
||||
char *rom_binary = qemu_find_file(QEMU_FILE_TYPE_BIOS, "esp32s3_rev0_rom.bin");
|
||||
if (rom_binary == NULL) {
|
||||
error_report("Error: -bios argument not set, and ROM code binary not found (1)");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int size = load_image_targphys_as(rom_binary, esp32s3_memmap[ESP32S3_MEMREGION_IROM].base, esp32s3_memmap[ESP32S3_MEMREGION_IROM].size, CPU(&ss->cpu[0])->as);
|
||||
if (size < 0) {
|
||||
error_report("Error: could not load ROM binary '%s'", rom_binary);
|
||||
exit(1);
|
||||
}
|
||||
g_free(rom_binary);
|
||||
|
||||
if (ESP32S3_CPU_COUNT > 1)
|
||||
{
|
||||
rom_binary = qemu_find_file(QEMU_FILE_TYPE_BIOS, "esp32s3_rev0_rom.bin");
|
||||
if (rom_binary == NULL) {
|
||||
error_report("Error: -bios argument not set, and ROM code binary not found (2)");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
size = load_image_targphys_as(rom_binary, esp32s3_memmap[ESP32S3_MEMREGION_IROM].base, esp32s3_memmap[ESP32S3_MEMREGION_IROM].size, CPU(&ss->cpu[1])->as);
|
||||
if (size < 0) {
|
||||
error_report("Error: could not load ROM binary '%s'", rom_binary);
|
||||
exit(1);
|
||||
}
|
||||
g_free(rom_binary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ram_addr_t esp32s3_fixup_ram_size(ram_addr_t requested_size)
|
||||
{
|
||||
ram_addr_t size;
|
||||
if (requested_size == 0) {
|
||||
size = 0;
|
||||
} else if (requested_size <= 2 * MiB) {
|
||||
size = 2 * MiB;
|
||||
} else if (requested_size <= 4 * MiB ) {
|
||||
size = 4 * MiB;
|
||||
} else if (requested_size <= 8 * MiB ) {
|
||||
size = 8 * MiB;
|
||||
} else if (requested_size <= 16 * MiB ) {
|
||||
size = 16 * MiB;
|
||||
} else if (requested_size <= 32 * MiB ) {
|
||||
size = 32 * MiB;
|
||||
} else {
|
||||
qemu_log("RAM size larger than 32 MB not supported\n");
|
||||
size = 32 * MiB;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Initialize machine type */
|
||||
static void esp32s3_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
mc->desc = "Espressif ESP32S3 machine";
|
||||
mc->init = esp32s3_machine_init;
|
||||
mc->max_cpus = 2;
|
||||
mc->default_cpus = 2;
|
||||
mc->default_ram_size = 0;
|
||||
mc->fixup_ram_size = esp32s3_fixup_ram_size;
|
||||
}
|
||||
|
||||
static const TypeInfo esp32s3_info = {
|
||||
.name = TYPE_ESP32S3_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_size = sizeof(Esp32s3MachineState),
|
||||
.class_init = esp32s3_machine_class_init,
|
||||
};
|
||||
|
||||
static void esp32s3_machine_type_init(void)
|
||||
{
|
||||
type_register_static(&esp32s3_info);
|
||||
}
|
||||
|
||||
type_init(esp32s3_machine_type_init);
|
||||
|
||||
@@ -11,6 +11,7 @@ xtensa_ss.add(when: 'CONFIG_XTENSA_ESP32', if_true: files('esp32.c', 'esp32_intc
|
||||
xtensa_ss.add(when: 'CONFIG_XTENSA_ESP32S3', if_true: files(
|
||||
'esp32s3_clk.c',
|
||||
'esp32s3_intc.c',
|
||||
'esp32s3.c',
|
||||
))
|
||||
|
||||
hw_arch += {'xtensa': xtensa_ss}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* ESP32-S3 registers
|
||||
*
|
||||
* Copyright (c) 2024 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define DR_REG_FRAMEBUF_BASE 0x21000000
|
||||
|
||||
#define DR_REG_UART_BASE 0x60000000
|
||||
#define DR_REG_SPI1_BASE 0x60002000
|
||||
#define DR_REG_SPI0_BASE 0x60003000
|
||||
#define DR_REG_GPIO_BASE 0x60004000
|
||||
#define DR_REG_GPIO_SD_BASE 0x60004f00
|
||||
#define DR_REG_FE2_BASE 0x60005000
|
||||
#define DR_REG_FE_BASE 0x60006000
|
||||
#define DR_REG_EFUSE_BASE 0x60007000
|
||||
#define DR_REG_RTCCNTL_BASE 0x60008000
|
||||
#define DR_REG_RTCIO_BASE 0x60008400
|
||||
#define DR_REG_SENS_BASE 0x60008800
|
||||
#define DR_REG_RTC_I2C_BASE 0x60008C00
|
||||
#define DR_REG_IO_MUX_BASE 0x60009000
|
||||
#define DR_REG_HINF_BASE 0x6000B000
|
||||
#define DR_REG_UHCI1_BASE 0x6000C000
|
||||
#define DR_REG_I2S_BASE 0x6000F000
|
||||
#define DR_REG_UART1_BASE 0x60010000
|
||||
#define DR_REG_BT_BASE 0x60011000
|
||||
#define DR_REG_I2C_EXT_BASE 0x60013000
|
||||
#define DR_REG_UHCI0_BASE 0x60014000
|
||||
#define DR_REG_SLCHOST_BASE 0x60015000
|
||||
#define DR_REG_RMT_BASE 0x60016000
|
||||
#define DR_REG_PCNT_BASE 0x60017000
|
||||
#define DR_REG_SLC_BASE 0x60018000
|
||||
#define DR_REG_LEDC_BASE 0x60019000
|
||||
#define DR_REG_NRX_BASE 0x6001CC00
|
||||
#define DR_REG_BB_BASE 0x6001D000
|
||||
#define DR_REG_PWM0_BASE 0x6001E000
|
||||
#define DR_REG_TIMERGROUP0_BASE 0x6001F000
|
||||
#define DR_REG_TIMERGROUP1_BASE 0x60020000
|
||||
#define DR_REG_RTC_SLOWMEM_BASE 0x60021000
|
||||
#define DR_REG_SYSTIMER_BASE 0x60023000
|
||||
#define DR_REG_SPI2_BASE 0x60024000
|
||||
#define DR_REG_SPI3_BASE 0x60025000
|
||||
#define DR_REG_SYSCON_BASE 0x60026000
|
||||
#define DR_REG_APB_CTRL_BASE 0x60026000 /* Old name for SYSCON, to be removed */
|
||||
#define DR_REG_I2C1_EXT_BASE 0x60027000
|
||||
#define DR_REG_SDMMC_BASE 0x60028000
|
||||
#define DR_REG_PERI_BACKUP_BASE 0x6002A000
|
||||
#define DR_REG_TWAI_BASE 0x6002B000
|
||||
#define DR_REG_PWM1_BASE 0x6002C000
|
||||
#define DR_REG_I2S1_BASE 0x6002D000
|
||||
#define DR_REG_UART2_BASE 0x6002E000
|
||||
#define DR_REG_USB_SERIAL_JTAG_BASE 0x60038000
|
||||
#define DR_REG_USB_WRAP_BASE 0x60039000
|
||||
#define DR_REG_AES_BASE 0x6003A000
|
||||
#define DR_REG_SHA_BASE 0x6003B000
|
||||
#define DR_REG_RSA_BASE 0x6003C000
|
||||
#define DR_REG_HMAC_BASE 0x6003E000
|
||||
#define DR_REG_DIGITAL_SIGNATURE_BASE 0x6003D000
|
||||
#define DR_REG_GDMA_BASE 0x6003F000
|
||||
#define DR_REG_APB_SARADC_BASE 0x60040000
|
||||
#define DR_REG_LCD_CAM_BASE 0x60041000
|
||||
#define DR_REG_SYSTEM_BASE 0x600C0000
|
||||
#define DR_REG_SENSITIVE_BASE 0x600C1000
|
||||
#define DR_REG_INTERRUPT_BASE 0x600C2000
|
||||
#define DR_REG_AES_XTS_BASE 0x600CC000
|
||||
#define DR_REG_EXTMEM_BASE 0x600C4000
|
||||
#define DR_REG_MMU_TABLE 0x600C5000
|
||||
#define DR_REG_ASSIST_DEBUG_BASE 0x600CE000
|
||||
#define DR_REG_WCL_BASE 0x600D0000
|
||||
#define ESP_CACHE_TEMP_ADDR 0x3C800000
|
||||
#define DR_REG_EMAC_BASE 0x600CD000
|
||||
#define DR_REG_WDEV_BASE 0x3ff75000
|
||||
|
||||
|
||||
#define ESP32S3_IO_START_ADDR (DR_REG_UART_BASE)
|
||||
|
||||
|
||||
#define APB_REG_BASE 0x60000000
|
||||
|
||||
|
||||
#define ESP32S3_DPORT_CROSSCORE_INT_COUNT 4
|
||||
#define ESP32S3_INT_MATRIX_OUTPUTS 32
|
||||
#define ESP32S3_CPU_COUNT 2
|
||||
#define ESP32S3_UART_COUNT 3
|
||||
#define ESP32S3_FRC_COUNT 2
|
||||
#define ESP32S3_TIMG_COUNT 2
|
||||
#define ESP32S3_SPI_COUNT 4
|
||||
#define ESP32S3_I2C_COUNT 2
|
||||
#define ESP32S3_RTC_CNTL_SCRATCH_REG_COUNT 8
|
||||
Binary file not shown.
@@ -63,6 +63,7 @@ blobs = [
|
||||
'esp32-v3-rom.bin',
|
||||
'esp32-v3-rom-app.bin',
|
||||
'esp32c3-rom.bin',
|
||||
'esp32s3_rev0_rom.bin',
|
||||
'qemu-nsis.bmp',
|
||||
'multiboot.bin',
|
||||
'multiboot_dma.bin',
|
||||
|
||||
Reference in New Issue
Block a user