Skip to content

Commit 4f3c340

Browse files
committed
hw/xtensa: add ESP32 interrupt matrix
1 parent c7e9307 commit 4f3c340

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed

hw/xtensa/esp32_intc.c

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* ESP32 Interrupt Matrix
3+
*
4+
* Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd.
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License version 2 or
8+
* (at your option) any later version.
9+
*/
10+
11+
#include "qemu/osdep.h"
12+
#include "qemu/log.h"
13+
#include "qemu/error-report.h"
14+
#include "qapi/error.h"
15+
#include "hw/hw.h"
16+
#include "hw/sysbus.h"
17+
#include "hw/irq.h"
18+
#include "hw/qdev-properties.h"
19+
#include "hw/xtensa/esp32_intc.h"
20+
21+
#define INTMATRIX_UNINT_VALUE 6
22+
23+
#define IRQ_MAP(cpu, input) s->irq_map[cpu][input]
24+
25+
static void esp32_intmatrix_irq_handler(void *opaque, int n, int level)
26+
{
27+
Esp32IntMatrixState *s = ESP32_INTMATRIX(opaque);
28+
for (int i = 0; i < ESP32_CPU_COUNT; ++i) {
29+
if (s->outputs[i] == NULL) {
30+
continue;
31+
}
32+
int out_index = IRQ_MAP(i, n);
33+
for (int int_index = 0; int_index < s->cpu[i]->env.config->nextint; ++int_index) {
34+
if (s->cpu[i]->env.config->extint[int_index] == out_index) {
35+
qemu_set_irq(s->outputs[i][int_index], level);
36+
break;
37+
}
38+
}
39+
}
40+
}
41+
42+
static inline uint8_t* get_map_entry(Esp32IntMatrixState* s, hwaddr addr)
43+
{
44+
int source_index = addr / sizeof(uint32_t);
45+
if (source_index > ESP32_INT_MATRIX_INPUTS * ESP32_CPU_COUNT) {
46+
error_report("%s: source_index %d out of range", __func__, source_index);
47+
return NULL;
48+
}
49+
int cpu_index = source_index / ESP32_INT_MATRIX_INPUTS;
50+
source_index = source_index % ESP32_INT_MATRIX_INPUTS;
51+
return &IRQ_MAP(cpu_index, source_index);
52+
}
53+
54+
static uint64_t esp32_intmatrix_read(void* opaque, hwaddr addr, unsigned int size)
55+
{
56+
Esp32IntMatrixState *s = ESP32_INTMATRIX(opaque);
57+
uint8_t* map_entry = get_map_entry(s, addr);
58+
return (map_entry != NULL) ? *map_entry : 0;
59+
}
60+
61+
static void esp32_intmatrix_write(void* opaque, hwaddr addr, uint64_t value, unsigned int size)
62+
{
63+
Esp32IntMatrixState *s = ESP32_INTMATRIX(opaque);
64+
uint8_t* map_entry = get_map_entry(s, addr);
65+
if (map_entry != NULL) {
66+
*map_entry = value & 0x1f;
67+
}
68+
}
69+
70+
static const MemoryRegionOps esp_intmatrix_ops = {
71+
.read = esp32_intmatrix_read,
72+
.write = esp32_intmatrix_write,
73+
.endianness = DEVICE_LITTLE_ENDIAN,
74+
};
75+
76+
static void esp32_intmatrix_reset(DeviceState *dev)
77+
{
78+
Esp32IntMatrixState *s = ESP32_INTMATRIX(dev);
79+
memset(s->irq_map, INTMATRIX_UNINT_VALUE, sizeof(s->irq_map));
80+
for (int i = 0; i < ESP32_CPU_COUNT; ++i) {
81+
if (s->outputs[i] == NULL) {
82+
continue;
83+
}
84+
for (int int_index = 0; int_index < s->cpu[i]->env.config->nextint; ++int_index) {
85+
qemu_irq_lower(s->outputs[i][int_index]);
86+
}
87+
}
88+
89+
}
90+
91+
static void esp32_intmatrix_realize(DeviceState *dev, Error **errp)
92+
{
93+
Esp32IntMatrixState *s = ESP32_INTMATRIX(dev);
94+
95+
for (int i = 0; i < ESP32_CPU_COUNT; ++i) {
96+
if (s->cpu[i]) {
97+
s->outputs[i] = xtensa_get_extints(&s->cpu[i]->env);
98+
}
99+
}
100+
esp32_intmatrix_reset(dev);
101+
}
102+
103+
static void esp32_intmatrix_init(Object *obj)
104+
{
105+
Esp32IntMatrixState *s = ESP32_INTMATRIX(obj);
106+
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
107+
108+
memory_region_init_io(&s->iomem, obj, &esp_intmatrix_ops, s,
109+
TYPE_ESP32_INTMATRIX, ESP32_INT_MATRIX_INPUTS * ESP32_CPU_COUNT * sizeof(uint32_t));
110+
sysbus_init_mmio(sbd, &s->iomem);
111+
112+
qdev_init_gpio_in(DEVICE(s), esp32_intmatrix_irq_handler, ESP32_INT_MATRIX_INPUTS);
113+
}
114+
115+
static Property esp32_intmatrix_properties[] = {
116+
DEFINE_PROP_LINK("cpu0", Esp32IntMatrixState, cpu[0], TYPE_XTENSA_CPU, XtensaCPU *),
117+
DEFINE_PROP_LINK("cpu1", Esp32IntMatrixState, cpu[1], TYPE_XTENSA_CPU, XtensaCPU *),
118+
DEFINE_PROP_END_OF_LIST(),
119+
};
120+
121+
static void esp32_intmatrix_class_init(ObjectClass *klass, void *data)
122+
{
123+
DeviceClass *dc = DEVICE_CLASS(klass);
124+
125+
dc->reset = esp32_intmatrix_reset;
126+
dc->realize = esp32_intmatrix_realize;
127+
device_class_set_props(dc, esp32_intmatrix_properties);
128+
}
129+
130+
static const TypeInfo esp32_intmatrix_info = {
131+
.name = TYPE_ESP32_INTMATRIX,
132+
.parent = TYPE_SYS_BUS_DEVICE,
133+
.instance_size = sizeof(Esp32IntMatrixState),
134+
.instance_init = esp32_intmatrix_init,
135+
.class_init = esp32_intmatrix_class_init
136+
};
137+
138+
static void esp32_intmatrix_register_types(void)
139+
{
140+
type_register_static(&esp32_intmatrix_info);
141+
}
142+
143+
type_init(esp32_intmatrix_register_types)

include/hw/xtensa/esp32_intc.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* ESP32 Interrupt Matrix
3+
*
4+
* Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd.
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License version 2 or
8+
* (at your option) any later version.
9+
*/
10+
11+
#pragma once
12+
13+
#include "qemu/osdep.h"
14+
#include "qemu/log.h"
15+
#include "qemu/error-report.h"
16+
#include "qapi/error.h"
17+
#include "hw/hw.h"
18+
#include "hw/sysbus.h"
19+
#include "hw/irq.h"
20+
#include "hw/qdev-properties.h"
21+
#include "target/xtensa/cpu.h"
22+
#include "target/xtensa/cpu-qom.h"
23+
24+
#define ESP32_CPU_COUNT 2
25+
#define ESP32_INT_MATRIX_INPUTS 69
26+
27+
#define TYPE_ESP32_INTMATRIX "misc.esp32.intmatrix"
28+
#define ESP32_INTMATRIX(obj) OBJECT_CHECK(Esp32IntMatrixState, (obj), TYPE_ESP32_INTMATRIX)
29+
30+
31+
typedef struct Esp32IntMatrixState {
32+
SysBusDevice parent_obj;
33+
34+
MemoryRegion iomem;
35+
qemu_irq *outputs[ESP32_CPU_COUNT];
36+
uint8_t irq_map[ESP32_CPU_COUNT][ESP32_INT_MATRIX_INPUTS];
37+
38+
/* properties */
39+
XtensaCPU *cpu[ESP32_CPU_COUNT];
40+
} Esp32IntMatrixState;
41+

0 commit comments

Comments
 (0)