Added various peripherals

This commit is contained in:
Martijn de Vos committed 2024-06-24 17:50:52 +02:00
1 parent 2161b1d851
commit 29e927ab33
14 files changed
+946 -23

No files matched your search

+24
View File
@@ -68,6 +68,7 @@ static void atv4_memory_setup(MachineState *machine, MemoryRegion *sysmem, Addre
// ATV4MachineState *nms = ATV4_MACHINE(machine);
allocate_ram(sysmem, "unknown1", UNKNOWN1_MEM_BASE, 0x200000);
allocate_ram(sysmem, "unknown2", UNKNOWN2_MEM_BASE, 0x1000);
allocate_ram(sysmem, "unknown3", UNKNOWN3_MEM_BASE, 0x20);
// load the bootrom (vrom)
uint8_t *file_data = NULL;
@@ -92,6 +93,15 @@ static void atv4_machine_init(MachineState *machine)
atv4_memory_setup(machine, sysmem, nsas);
// init the interrupt controller
AppleAICState *aic_state = apple_aic_create();
nms->aic_state = aic_state;
SysBusDevice *busdev = SYS_BUS_DEVICE(nms->aic_state);
sysbus_realize(busdev, &error_fatal);
for(int i = 0; i < nms->aic_state->numCPU; i++) {
memory_region_add_subregion(sysmem, AIC_MEM_BASE + i * 0x1000, &aic_state->cpus[i].iomem);
}
// init the chip ID module
DeviceState *dev = qdev_new("atv4.chipid");
ATV4ChipIDState *chipid_state = ATV4_CHIPID(dev);
@@ -110,6 +120,20 @@ static void atv4_machine_init(MachineState *machine)
memory_region_add_subregion(sysmem, PMGR_CLK_MEM_BASE, &pmgr_state->clk_iomem);
memory_region_add_subregion(sysmem, PMGR_CLKCFG_MEM_BASE, &pmgr_state->clkcfg_iomem);
memory_region_add_subregion(sysmem, PMGR_SOC_MEM_BASE, &pmgr_state->soc_iomem);
memory_region_add_subregion(sysmem, PMGR_SCRATCH_MEM_BASE, &pmgr_state->scratch_iomem);
memory_region_add_subregion(sysmem, PMGR_PWRGATE_MEM_BASE, &pmgr_state->pwrgate_iomem);
// init GPIO
dev = qdev_new("atv4.gpio");
ATV4GPIOState *gpio_state = ATV4_GPIO(dev);
nms->gpio_state = gpio_state;
memory_region_add_subregion(sysmem, GPIO_MEM_BASE, &gpio_state->iomem);
// init the Apple USB
dev = qdev_new("atv4.ausb");
ATV4AUSBState *ausb_state = ATV4_AUSB(dev);
nms->ausb_state = ausb_state;
memory_region_add_subregion(sysmem, AUSB_MEM_BASE, &ausb_state->iomem);
qemu_register_reset(atv4_cpu_reset, nms);
}
+58
View File
@@ -0,0 +1,58 @@
#include "hw/arm/atv4_ausb.h"
static uint64_t atv4_ausb_read(void *opaque, hwaddr addr, unsigned size)
{
ATV4AUSBState *s = (ATV4AUSBState *) opaque;
switch(addr)
{
default:
return 0x0;
}
}
static void atv4_ausb_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
ATV4AUSBState *s = (ATV4AUSBState *) opaque;
switch(addr)
{
default:
return;
}
}
static const MemoryRegionOps atv4_ausb_ops = {
.read = atv4_ausb_read,
.write = atv4_ausb_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void atv4_ausb_init(Object *obj)
{
ATV4AUSBState *s = ATV4_AUSB(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
memory_region_init_io(&s->iomem, obj, &atv4_ausb_ops, s, TYPE_ATV4_AUSB, 0x100);
sysbus_init_mmio(sbd, &s->iomem);
}
static void atv4_ausb_class_init(ObjectClass *klass, void *data)
{
}
static const TypeInfo atv4_ausb_type_info = {
.name = TYPE_ATV4_AUSB,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(ATV4AUSBState),
.instance_init = atv4_ausb_init,
.class_init = atv4_ausb_class_init,
};
static void atv4_ausb_register_types(void)
{
type_register_static(&atv4_ausb_type_info);
}
type_init(atv4_ausb_register_types)
+2
View File
@@ -5,6 +5,8 @@ static uint64_t atv4_chipid_read(void *opaque, hwaddr addr, unsigned size)
//fprintf(stderr, "%s: offset = 0x%08x\n", __func__, addr);
switch (addr) {
case rCFG_FUSE0:
return 0;
case CHIPID_REVISION:
return 1;
default:
+60
View File
@@ -0,0 +1,60 @@
#include "hw/arm/atv4_gpio.h"
static void atv4_gpio_write(void *opaque, hwaddr addr, uint64_t value, unsigned size)
{
//fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
ATV4GPIOState *s = (struct ATV4GPIOState *) opaque;
switch(addr) {
default:
break;
}
}
static uint64_t atv4_gpio_read(void *opaque, hwaddr addr, unsigned size)
{
//printf("%s: read from location 0x%08x\n", __func__, addr);
ATV4GPIOState *s = (struct ATV4GPIOState *) opaque;
switch(addr) {
default:
break;
}
return 0;
}
static const MemoryRegionOps gpio_ops = {
.read = atv4_gpio_read,
.write = atv4_gpio_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void atv4_gpio_init(Object *obj)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
DeviceState *dev = DEVICE(sbd);
ATV4GPIOState *s = ATV4_GPIO(dev);
memory_region_init_io(&s->iomem, obj, &gpio_ops, s, "gpio", 0x1000);
}
static void atv4_gpio_class_init(ObjectClass *klass, void *data)
{
}
static const TypeInfo atv4_gpio_info = {
.name = TYPE_ATV4_GPIO,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(ATV4GPIOState),
.instance_init = atv4_gpio_init,
.class_init = atv4_gpio_class_init,
};
static void atv4_gpio_register_types(void)
{
type_register_static(&atv4_gpio_info);
}
type_init(atv4_gpio_register_types)
+72
View File
@@ -221,6 +221,58 @@ static void atv4_pmgr_soc_write(void *opaque, hwaddr addr, uint64_t value, unsig
}
}
static uint64_t atv4_pmgr_scratch_read(void *opaque, hwaddr addr, unsigned size)
{
//fprintf(stderr, "%s: offset = 0x%08x\n", __func__, addr);
switch (addr) {
case 0x0 ... 0x60:
// TODO return the right scratch configuration
break;
default:
hw_error("%s: reading from unknown PMGR SCRATCH register 0x%08x\n", __func__, addr);
}
return 0;
}
static void atv4_pmgr_scratch_write(void *opaque, hwaddr addr, uint64_t value, unsigned size)
{
//fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
ATV4PMGRState *s = (struct ATV4PMGRState *) opaque;
switch(addr) {
default:
break;
}
}
static uint64_t atv4_pmgr_pwrgate_read(void *opaque, hwaddr addr, unsigned size)
{
//fprintf(stderr, "%s: offset = 0x%08x\n", __func__, addr);
switch (addr) {
case 0x0 ... 0x300:
// TODO return the right scratch configuration
break;
default:
hw_error("%s: reading from unknown PMGR PWRGATE register 0x%08x\n", __func__, addr);
}
return 0;
}
static void atv4_pmgr_pwrgate_write(void *opaque, hwaddr addr, uint64_t value, unsigned size)
{
//fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
ATV4PMGRState *s = (struct ATV4PMGRState *) opaque;
switch(addr) {
default:
break;
}
}
static const MemoryRegionOps atv4_pmgr_pll_ops = {
.read = atv4_pmgr_pll_read,
.write = atv4_pmgr_pll_write,
@@ -269,6 +321,18 @@ static const MemoryRegionOps atv4_pmgr_soc_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
static const MemoryRegionOps atv4_pmgr_scratch_ops = {
.read = atv4_pmgr_scratch_read,
.write = atv4_pmgr_scratch_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static const MemoryRegionOps atv4_pmgr_pwrgate_ops = {
.read = atv4_pmgr_pwrgate_read,
.write = atv4_pmgr_pwrgate_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void atv4_pmgr_init(Object *obj)
{
ATV4PMGRState *s = ATV4_PMGR(obj);
@@ -305,6 +369,14 @@ static void atv4_pmgr_init(Object *obj)
// SOC performance
memory_region_init_io(&s->soc_iomem, obj, &atv4_pmgr_soc_ops, s, TYPE_ATV4_PMGR_SOC, 0xFF);
sysbus_init_mmio(sbd, &s->soc_iomem);
// scratch
memory_region_init_io(&s->scratch_iomem, obj, &atv4_pmgr_scratch_ops, s, TYPE_ATV4_PMGR_SCRATCH, 0x60);
sysbus_init_mmio(sbd, &s->scratch_iomem);
// power gate
memory_region_init_io(&s->pwrgate_iomem, obj, &atv4_pmgr_pwrgate_ops, s, TYPE_ATV4_PMGR_PWRGATE, 0x300);
sysbus_init_mmio(sbd, &s->pwrgate_iomem);
}
static void atv4_pmgr_class_init(ObjectClass *klass, void *data)
+1 -1
View File
@@ -65,7 +65,7 @@ arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
arm_ss.add(when: 'CONFIG_XEN', if_true: files('xen_arm.c'))
arm_ss.add(when: 'CONFIG_ATV4', if_true: files('atv4.c', 'atv4_chipid.c', 'atv4_pmgr.c'))
arm_ss.add(when: 'CONFIG_ATV4', if_true: files('atv4.c', 'atv4_chipid.c', 'atv4_pmgr.c', 'atv4_gpio.c', 'atv4_ausb.c'))
system_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c'))
+607
View File
@@ -0,0 +1,607 @@
#include "qemu/osdep.h"
#include "hw/intc/apple_aic.h"
#include "trace.h"
#include "hw/irq.h"
#include "migration/vmstate.h"
#include "qemu/bitops.h"
#include "qemu/lockable.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/timer.h"
#include "hw/pci/msi.h"
/*
* AIC splits IRQs into domains (ipid)
* In T8030 device tree, we have aic->ipid_length = 72
* => IRQ(extInts) max nr = ((len(ipid_mask)>>2)<<5) = 0x240 (interrupts)
* -> num domains = (0x240 + 31)>>5 = 18 (domains)
* 0x240/18 = 32 (bits) of an uint32_t
*
* Commands such as rAIC_EIR_MASK_SET/CLR assign each domain to a 32bit register.
* When masking/unmasking-ing IRQ n,
* write to (aic_base + command_reg_base + (n / 32) * 4)
* a uint32_t which has (n % 32)-th bit set,
* command_reg_base is 0x4100 for rAIC_EIR_MASK_SET, 0x4180 for rAIC_EIR_MASK_CLR.
*
* T8030 uses both fast IPI, and AIC IPIs.
* AIC IPIs' vectors are right after IRQs' vectors.
* num IRQ + (X * 2) -> self_ipi (cpuX->cpuX)
* num IRQ + (Y * 2) + 1 -> other_ipi (cpuX->cpuY)
*/
//TODO: this is hardcoded for T8030
#define AIC_INT_COUNT (256)
#define AIC_CPU_COUNT (2)
#define AIC_VERSION (2)
#define rAIC_REV (0x0000)
#define rAIC_CAP0 (0x0004)
#define rAIC_CAP1 (0x0008)
#define rAIC_RST (0x000C)
#define rAIC_GLB_CFG (0x0010)
#define AIC_GLBCFG_IEN (1 << 0)
#define AIC_GLBCFG_AEWT(_t) ((_t) << 4)
#define AIC_GLBCFG_SEWT(_t) ((_t) << 8)
#define AIC_GLBCFG_AIWT(_t) ((_t) << 12)
#define AIC_GLBCFG_SIWT(_t) ((_t) << 16)
#define AIC_GLBCFG_SYNC_ACG (1 << 29)
#define AIC_GLBCFG_EIR_ACG (1 << 30)
#define AIC_GLBCFG_REG_ACG (1 << 31)
#define AIC_GLBCFG_WT_MASK (15)
#define AIC_GLBCFG_WT_64MICRO (7)
#define rAIC_WHOAMI (0x2000)
#define rAIC_IACK (0x2004)
#define rAIC_IPI_SET (0x2008)
#define rAIC_IPI_CLR (0x200C)
#define AIC_IPI_NORMAL (1 << 0)
#define AIC_IPI_SELF (1 << 31)
#define rAIC_IPI_MASK_SET (0x2024)
#define rAIC_IPI_MASK_CLR (0x2028)
#define rAIC_IPI_DEFER_SET (0x202C)
#define rAIC_IPI_DEFER_CLR (0x2030)
#define rAIC_EIR_DEST(_n) (0x3000 + ((_n) * 4))
#define rAIC_EIR_SW_SET(_n) (0x4000 + ((_n) * 4))
#define rAIC_EIR_SW_CLR(_n) (0x4080 + ((_n) * 4))
#define rAIC_EIR_MASK_SET(_n) (0x4100 + ((_n) * 4))
#define rAIC_EIR_MASK_CLR(_n) (0x4180 + ((_n) * 4))
#define rAIC_EIR_INT_RO(_n) (0x4200 + ((_n) * 4))
#define rAIC_WHOAMI_Pn(_n) (0x5000 + ((_n) * 0x80))
#define rAIC_IACK_Pn(_n) (0x5004 + ((_n) * 0x80))
#define rAIC_IPI_SET_Pn(_n) (0x5008 + ((_n) * 0x80))
#define rAIC_IPI_CLR_Pn(_n) (0x500C + ((_n) * 0x80))
#define rAIC_IPI_MASK_SET_Pn(_n) (0x5024 + ((_n) * 0x80))
#define rAIC_IPI_MASK_CLR_Pn(_n) (0x5028 + ((_n) * 0x80))
#define rAIC_IPI_DEFER_SET_Pn(_n) (0x502C + ((_n) * 0x80))
#define rAIC_IPI_DEFER_CLR_Pn(_n) (0x5030 + ((_n) * 0x80))
#define kAIC_INT_SPURIOUS (0x00000)
#define kAIC_INT_EXT (0x10000)
#define kAIC_INT_IPI (0x40000)
#define kAIC_INT_IPI_NORM (0x40001)
#define kAIC_INT_IPI_SELF (0x40002)
#define AIC_INT_EXT(_v) (((_v) & 0x70000) == kAIC_INT_EXT)
#define AIC_INT_IPI(_v) (((_v) & 0x70000) == kAIC_INT_IPI)
#define AIC_INT_EXTID(_v) ((_v) & 0x3FF)
#define AIC_SRC_TO_EIR(_s) ((_s) >> 5)
#define AIC_SRC_TO_MASK(_s) (1 << ((_s) & 0x1F))
#define AIC_EIR_TO_SRC(_s, _v) (((_s) << 5) + ((_v) & 0x1F))
#define kAIC_MAX_EXTID (AIC_INT_COUNT)
#define kAIC_VEC_IPI (kAIC_MAX_EXTID)
#define kAIC_NUM_INTS (kAIC_VEC_IPI + 1)
#define kAIC_NUM_EIRS AIC_SRC_TO_EIR(kAIC_MAX_EXTID)
#define kAICWT 64000
#define kCNTFRQ (24000000)
static inline uint64_t apple_aic_emulate_timer(void)
{
int period_ns = NANOSECONDS_PER_SECOND > kCNTFRQ ?
NANOSECONDS_PER_SECOND / kCNTFRQ : 1;
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / period_ns;
}
/*
* Check state and interrupt cpus, call with mutex locked
*/
static void apple_aic_update(AppleAICState *s)
{
uint32_t intr = 0;
uint32_t potential = 0;
int i;
for (i = 0; i < s->numCPU; i++) {
s->cpus[i].pendingIPI |= s->cpus[i].deferredIPI;
s->cpus[i].deferredIPI = 0;
}
for (i = 0; i < s->numCPU; i++) {
if ((s->cpus[i].pendingIPI & AIC_IPI_SELF) & (~s->cpus[i].ipi_mask)) {
intr |= (1 << i);
}
if ((~s->cpus[i].ipi_mask & AIC_IPI_NORMAL)
&& (s->cpus[i].pendingIPI & ((1 << s->numCPU) - 1))) {
intr |= (1 << i);
}
}
i = -1;
while ((i = find_next_bit((unsigned long *)s->eir_state, s->numIRQ, i+1))
< s->numIRQ) {
int dest;
if ((test_bit(i, (unsigned long *)s->eir_mask) == 0)
&& (dest = s->eir_dest[i])) {
if (((intr & dest) == 0)) {
/* The interrupt doesn't have a cpu that can process it yet */
uint32_t cpu = find_first_bit((unsigned long *)&s->eir_dest[i],
s->numCPU);
intr |= (1 << cpu);
potential |= dest;
} else {
int k;
for (k = 0; k < s->numCPU; k++) {
if (((intr & (1 << k)) == 0) && (potential & (1 << k))) {
/*
* cpu K isn't in the interrupt list
* and can handle some of the previous interrupts
*/
intr |= (1 << k);
break;
}
}
}
}
}
for (i = 0; i < s->numCPU; i++) {
if (intr & (1 << i)) {
qemu_irq_raise(s->cpus[i].irq);
}
}
}
static void apple_aic_set_irq(void *opaque, int irq, int level)
{
AppleAICState *s = APPLE_AIC(opaque);
WITH_QEMU_LOCK_GUARD(&s->mutex) {
if (level) {
set_bit(irq, (unsigned long *)s->eir_state);
} else {
clear_bit(irq, (unsigned long *)s->eir_state);
}
}
}
static void apple_aic_tick(void *opaque)
{
AppleAICState *s = APPLE_AIC(opaque);
WITH_QEMU_LOCK_GUARD(&s->mutex) {
apple_aic_update(s);
}
timer_mod_ns(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + kAICWT);
}
static void apple_aic_reset(DeviceState *dev)
{
int i;
AppleAICState *s = APPLE_AIC(dev);
/* mask all IRQs */
memset(s->eir_mask, 0xffff, sizeof(uint32_t) * s->numEIR);
#ifdef AIC_DEBUG_NEW_IRQ
memset(s->eir_mask_once, 0xffff, sizeof(uint32_t) * s->numEIR);
#endif
/* dest default to 0 */
memset(s->eir_dest, 0, sizeof(uint32_t) * s->numIRQ);
for (i = 0; i < s->numCPU; i++) {
/* mask all IPI */
s->cpus[i].ipi_mask = AIC_IPI_NORMAL | AIC_IPI_SELF;
s->cpus[i].pendingIPI = 0;
s->cpus[i].deferredIPI = 0;
}
}
static void apple_aic_write(void *opaque, hwaddr addr, uint64_t data,
unsigned size)
{
AppleAICCPU *o = (AppleAICCPU *)opaque;
AppleAICState *s = APPLE_AIC(o->aic);
uint32_t val = (uint32_t)data;
WITH_QEMU_LOCK_GUARD(&s->mutex) {
switch (addr) {
case rAIC_RST:
apple_aic_reset(DEVICE(s));
break;
case rAIC_GLB_CFG:
s->global_cfg = data;
break;
case rAIC_IPI_SET:
{
int i;
for (i = 0; i < s->numCPU; i++) {
if (val & (1 << i)) {
set_bit(o->cpu_id, (unsigned long *)&s->cpus[i].pendingIPI);
if (~s->cpus[i].ipi_mask & AIC_IPI_NORMAL) {
qemu_irq_raise(s->cpus[i].irq);
}
}
}
if (val & AIC_IPI_SELF) {
o->pendingIPI |= AIC_IPI_SELF;
if (~o->ipi_mask & AIC_IPI_SELF) {
qemu_irq_raise(o->irq);
}
}
}
break;
case rAIC_IPI_CLR:
{
int i;
for (i = 0; i < s->numCPU; i++) {
if (val & (1 << i)) {
clear_bit(o->cpu_id, (unsigned long *)&s->cpus[i].pendingIPI);
}
}
if (val & AIC_IPI_SELF) {
o->pendingIPI &= ~AIC_IPI_SELF;
}
}
break;
case rAIC_IPI_MASK_SET:
o->ipi_mask |= (val & (AIC_IPI_NORMAL | AIC_IPI_SELF));
break;
case rAIC_IPI_MASK_CLR:
o->ipi_mask &= ~(val & (AIC_IPI_NORMAL | AIC_IPI_SELF));
break;
case rAIC_IPI_DEFER_SET:
{
int i;
for (i = 0; i < s->numCPU; i++) {
if (val & (1 << i)) {
set_bit(o->cpu_id, (unsigned long *)&s->cpus[i].deferredIPI);
}
}
if (val & AIC_IPI_SELF) {
o->deferredIPI |= AIC_IPI_SELF;
}
}
break;
case rAIC_IPI_DEFER_CLR:
{
int i;
for (i = 0; i < s->numCPU; i++) {
if (val & (1 << i)) {
clear_bit(o->cpu_id, (unsigned long *)&s->cpus[i].deferredIPI);
}
}
if (val & AIC_IPI_SELF) {
o->deferredIPI &= ~AIC_IPI_SELF;
}
}
break;
case rAIC_EIR_DEST(0) ... rAIC_EIR_DEST(AIC_INT_COUNT):
{
uint32_t vector = (addr - rAIC_EIR_DEST(0)) / 4;
if (unlikely(vector >= s->numIRQ)) {
break;
}
s->eir_dest[vector] = val;
}
break;
case rAIC_EIR_SW_SET(0) ... rAIC_EIR_SW_SET(kAIC_NUM_EIRS):
{
uint32_t eir = (addr - rAIC_EIR_SW_SET(0)) / 4;
if (unlikely(eir >= s->numEIR)) {
break;
}
s->eir_state[eir] |= val;
}
break;
case rAIC_EIR_SW_CLR(0) ... rAIC_EIR_SW_CLR(kAIC_NUM_EIRS):
{
uint32_t eir = (addr - rAIC_EIR_SW_CLR(0)) / 4;
if (unlikely(eir >= s->numEIR)) {
break;
}
s->eir_state[eir] &= ~val;
}
break;
case rAIC_EIR_MASK_SET(0) ... rAIC_EIR_MASK_SET(kAIC_NUM_EIRS):
{
uint32_t eir = (addr - rAIC_EIR_MASK_SET(0)) / 4;
if (unlikely(eir >= s->numEIR)) {
break;
}
s->eir_mask[eir] |= val;
}
break;
case rAIC_EIR_MASK_CLR(0) ... rAIC_EIR_MASK_CLR(kAIC_NUM_EIRS):
{
uint32_t eir = (addr - rAIC_EIR_MASK_CLR(0)) / 4;
if (unlikely(eir >= s->numEIR)) {
break;
}
s->eir_mask[eir] &= ~val;
#ifdef AIC_DEBUG_NEW_IRQ
if ((s->eir_mask[eir] | s->eir_mask_once[eir]) != s->eir_mask[eir]) {
for (int i = 0; i < 32; i++) {
if ((s->eir_mask[eir] & (1 << i)) == 0 && (s->eir_mask_once[eir] & (1 << i)) != 0) {
//trace_aic_new_irq(AIC_EIR_TO_SRC(eir, i));
}
}
}
s->eir_mask_once[eir] &= s->eir_mask[eir];
#endif
}
break;
case rAIC_WHOAMI_Pn(0) ... rAIC_WHOAMI_Pn(AIC_CPU_COUNT) - 4:
{
uint32_t cpu = ((addr - 0x5000) / 0x80);
if (unlikely(cpu >= s->numCPU)) {
break;
}
addr = addr - 0x5000 + 0x2000 - 0x80 * cpu;
qemu_mutex_unlock(&s->mutex);
apple_aic_write(&s->cpus[cpu], addr, data, size);
qemu_mutex_lock(&s->mutex);
}
break;
default:
hw_error("AIC: Write to unspported reg 0x%08x cpu %u: 0x%x\n", addr, o->cpu_id, val);
break;
}
}
}
static uint64_t apple_aic_read(void *opaque, hwaddr addr, unsigned size)
{
AppleAICCPU *o = (AppleAICCPU *)opaque;
AppleAICState *s = APPLE_AIC(o->aic);
WITH_QEMU_LOCK_GUARD(&s->mutex) {
switch (addr) {
case rAIC_REV:
return 2;
case rAIC_CAP0:
return (((uint64_t)s->numCPU - 1) << 16) | (s->numIRQ);
case rAIC_GLB_CFG:
return s->global_cfg;
case rAIC_WHOAMI:
return o->cpu_id;
case rAIC_IACK:
{
int i;
qemu_irq_lower(o->irq);
if (o->pendingIPI & AIC_IPI_SELF & ~o->ipi_mask) {
o->ipi_mask |= AIC_IPI_SELF;
return kAIC_INT_IPI | kAIC_INT_IPI_SELF;
}
if (~o->ipi_mask & AIC_IPI_NORMAL) {
if (o->pendingIPI & ((1 << s->numCPU) - 1)) {
o->ipi_mask |= AIC_IPI_NORMAL;
return kAIC_INT_IPI | kAIC_INT_IPI_NORM;
}
}
i = -1;
while ((i = find_next_bit((unsigned long *)s->eir_state,
s->numIRQ, i+1)) < s->numIRQ) {
if (test_bit(i, (unsigned long *)s->eir_mask) == 0) {
if (s->eir_dest[i] & (1 << o->cpu_id)) {
set_bit(i, (unsigned long *)s->eir_mask);
return kAIC_INT_EXT | AIC_INT_EXTID(i);
}
}
}
return kAIC_INT_SPURIOUS;
}
case rAIC_EIR_DEST(0) ... rAIC_EIR_DEST(AIC_INT_COUNT):
{
uint32_t vector = (addr - rAIC_EIR_DEST(0)) / 4;
if (unlikely(vector >= s->numIRQ)) {
break;
}
return s->eir_dest[vector];
}
case rAIC_EIR_MASK_SET(0) ... rAIC_EIR_MASK_SET(kAIC_NUM_EIRS):
{
uint32_t eir = (addr - rAIC_EIR_MASK_SET(0)) / 4;
if (unlikely(eir >= s->numEIR)) {
break;
}
return s->eir_mask[eir];
}
case rAIC_EIR_MASK_CLR(0) ... rAIC_EIR_MASK_CLR(kAIC_NUM_EIRS):
{
uint32_t eir = (addr - rAIC_EIR_MASK_CLR(0)) / 4;
if (unlikely(eir >= s->numEIR)) {
break;
}
return s->eir_mask[eir];
}
case rAIC_EIR_INT_RO(0) ... rAIC_EIR_INT_RO(kAIC_NUM_EIRS):
{
uint32_t eir = (addr - rAIC_EIR_INT_RO(0)) / 4;
if (unlikely(eir >= s->numEIR)) {
break;
}
return s->eir_state[eir];
}
case rAIC_WHOAMI_Pn(0) ... rAIC_WHOAMI_Pn(AIC_CPU_COUNT) - 4:
{
uint32_t cpu = ((addr - 0x5000) / 0x80);
uint64_t val;
if (unlikely(cpu >= s->numCPU)) {
break;
}
addr = addr - 0x5000 + 0x2000 - 0x80 * cpu;
qemu_mutex_unlock(&s->mutex);
val = apple_aic_read(&s->cpus[cpu], addr, size);
qemu_mutex_lock(&s->mutex);
return val;
}
default: {
if (addr == 0x20) {
return apple_aic_emulate_timer() & 0xFFFFFFFF;
} else if (addr == 0x28) {
return (apple_aic_emulate_timer() >> 32) & 0xFFFFFFFF;
} else {
hw_error("AIC: Read from unspported reg 0x%08x cpu: %u\n", addr, o->cpu_id);
}
}
}
}
return -1;
}
static const MemoryRegionOps apple_aic_ops = {
.read = apple_aic_read,
.write = apple_aic_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.impl.min_access_size = 4,
.impl.max_access_size = 4,
.valid.min_access_size = 4,
.valid.max_access_size = 4,
.valid.unaligned = false,
};
static void apple_aic_realize(DeviceState *dev, struct Error **errp)
{
AppleAICState *s = APPLE_AIC(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
int i;
qemu_mutex_init(&s->mutex);
s->cpus = g_new0(AppleAICCPU, s->numCPU);
for (i = 0; i < s->numCPU; i++) {
AppleAICCPU *cpu = &s->cpus[i];
cpu->aic = s;
cpu->cpu_id = i;
memory_region_init_io(&cpu->iomem, OBJECT(dev), &apple_aic_ops, cpu, TYPE_APPLE_AIC, 0x6000);
sysbus_init_mmio(sbd, &cpu->iomem);
sysbus_init_irq(sbd, &cpu->irq);
}
qdev_init_gpio_in(dev, apple_aic_set_irq, s->numIRQ);
assert(s->numCPU > 0);
s->eir_mask = g_new0(uint32_t, s->numEIR);
s->eir_dest = g_new0(uint32_t, s->numIRQ);
s->eir_state = g_new0(uint32_t, s->numEIR);
#ifdef AIC_DEBUG_NEW_IRQ
s->eir_mask_once = g_new0(uint32_t, s->numEIR);
#endif
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apple_aic_tick, dev);
timer_mod_ns(s->timer, kAICWT);
msi_nonbroken = true;
}
static void apple_aic_unrealize(DeviceState *dev)
{
AppleAICState *s = APPLE_AIC(dev);
timer_free(s->timer);
}
AppleAICState *apple_aic_create()
{
DeviceState *dev;
AppleAICState *s;
dev = qdev_new(TYPE_APPLE_AIC);
s = APPLE_AIC(dev);
s->numEIR = 8;
s->numIRQ = s->numEIR * 32;
s->numCPU = 1;
return s;
}
static void apple_aic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = apple_aic_realize;
dc->unrealize = apple_aic_unrealize;
dc->reset = apple_aic_reset;
dc->desc = "Apple Interrupt Controller";
}
static const TypeInfo apple_aic_info = {
.name = TYPE_APPLE_AIC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AppleAICState),
.class_init = apple_aic_class_init,
};
static void apple_aic_register_types(void)
{
type_register_static(&apple_aic_info);
}
type_init(apple_aic_register_types);
+1
View File
@@ -12,6 +12,7 @@ system_ss.add(when: 'CONFIG_ARM_GICV3_TCG', if_true: files(
'arm_gicv3_its.c',
'arm_gicv3_redist.c',
))
system_ss.add(when: 'CONFIG_ATV4', if_true: files('apple_aic.c'))
system_ss.add(when: 'CONFIG_ALLWINNER_A10_PIC', if_true: files('allwinner-a10-pic.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_vic.c'))
system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c'))
+25 -13
View File
@@ -4,9 +4,12 @@
#include "exec/hwaddr.h"
#include "hw/boards.h"
#include "cpu.h"
#include "hw/intc/apple_aic.h"
#include "hw/arm/boot.h"
#include "hw/arm/atv4_chipid.h"
#include "hw/arm/atv4_pmgr.h"
#include "hw/arm/atv4_gpio.h"
#include "hw/arm/atv4_ausb.h"
#define TYPE_ATV4 "ATV4"
@@ -18,19 +21,25 @@
OBJECT_CHECK(ATV4MachineState, (obj), TYPE_ATV4_MACHINE)
// memory addresses
#define VROM_MEM_BASE 0x100000000
#define UNKNOWN1_MEM_BASE 0x180000000
#define UNKNOWN2_MEM_BASE 0x202220000
#define PMGR_MEM_BASE 0x20e000000
#define PMGR_PLL_MEM_BASE (PMGR_MEM_BASE)
#define PMGR_CLKCFG_MEM_BASE (PMGR_MEM_BASE + 0x10000)
#define PMGR_CLK_MEM_BASE (PMGR_MEM_BASE + 0x10308)
#define PMGR_SOC_MEM_BASE (PMGR_MEM_BASE + 0x1a000)
#define PMGR_GFX_MEM_BASE (PMGR_MEM_BASE + 0x1c200)
#define PMGR_PS_MEM_BASE (PMGR_MEM_BASE + 0x20000)
#define PMGR_VOLMAN_MEM_BASE (PMGR_MEM_BASE + 0x23000)
#define PMGR_ACG_MEM_BASE (PMGR_MEM_BASE + 0x32000)
#define CHIPID_MEM_BASE 0x20e02a000
#define VROM_MEM_BASE 0x100000000
#define UNKNOWN1_MEM_BASE 0x180000000
#define UNKNOWN2_MEM_BASE 0x202220000
#define UNKNOWN3_MEM_BASE 0x202240000
#define AUSB_MEM_BASE 0x20c900000
#define PMGR_MEM_BASE 0x20e000000
#define AIC_MEM_BASE 0x20e100000
#define GPIO_MEM_BASE 0x20e300000
#define PMGR_PLL_MEM_BASE (PMGR_MEM_BASE)
#define PMGR_CLKCFG_MEM_BASE (PMGR_MEM_BASE + 0x10000)
#define PMGR_CLK_MEM_BASE (PMGR_MEM_BASE + 0x10308)
#define PMGR_SOC_MEM_BASE (PMGR_MEM_BASE + 0x1a000)
#define PMGR_GFX_MEM_BASE (PMGR_MEM_BASE + 0x1c200)
#define PMGR_PS_MEM_BASE (PMGR_MEM_BASE + 0x20000)
#define PMGR_PWRGATE_MEM_BASE (PMGR_MEM_BASE + 0x22000)
#define PMGR_VOLMAN_MEM_BASE (PMGR_MEM_BASE + 0x23000)
#define PMGR_SCRATCH_MEM_BASE (PMGR_MEM_BASE + 0x29000)
#define PMGR_ACG_MEM_BASE (PMGR_MEM_BASE + 0x32000)
#define CHIPID_MEM_BASE 0x20e02a000
typedef struct {
MachineClass parent;
@@ -41,8 +50,11 @@ typedef struct {
AddressSpace *nsas;
qemu_irq **irq;
ARMCPU *cpu;
AppleAICState *aic_state;
ATV4ChipIDState *chipid_state;
ATV4PMGRState *pmgr_state;
ATV4GPIOState *gpio_state;
ATV4AUSBState *ausb_state;
ATV4_CPREG_VAR_DEF(REG0);
ATV4_CPREG_VAR_DEF(REG1);
ATV4_CPREG_VAR_DEF(REG2);
+16
View File
@@ -0,0 +1,16 @@
#ifndef HW_ARM_ATV4_AUSB_H
#define HW_ARM_ATV4_AUSB_H
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#define TYPE_ATV4_AUSB "atv4.ausb"
OBJECT_DECLARE_SIMPLE_TYPE(ATV4AUSBState, ATV4_AUSB)
typedef struct ATV4AUSBState {
SysBusDevice busdev;
MemoryRegion iomem;
} ATV4AUSBState;
#endif
+1
View File
@@ -8,6 +8,7 @@
#define TYPE_ATV4_CHIPID "atv4.chipid"
OBJECT_DECLARE_SIMPLE_TYPE(ATV4ChipIDState, ATV4_CHIPID)
#define rCFG_FUSE0 0x0
#define CHIPID_REVISION 0x10
typedef struct ATV4ChipIDState {
+21
View File
@@ -0,0 +1,21 @@
#ifndef ATV4_GPIO_H
#define ATV4_GPIO_H
#include <math.h>
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu/timer.h"
#include "hw/sysbus.h"
#define TYPE_ATV4_GPIO "atv4.gpio"
OBJECT_DECLARE_SIMPLE_TYPE(ATV4GPIOState, ATV4_GPIO)
#define GPIO_FORCE_DFU 0xD04
typedef struct ATV4GPIOState
{
SysBusDevice parent_obj;
MemoryRegion iomem;
} ATV4GPIOState;
#endif
+13 -9
View File
@@ -5,15 +5,17 @@
#include "hw/hw.h"
#include "hw/sysbus.h"
#define TYPE_ATV4_PMGR "atv4.pmgr"
#define TYPE_ATV4_PMGR_VOLMAN "atv4.pmgr.volman"
#define TYPE_ATV4_PMGR_PS "atv4.pmgr.ps"
#define TYPE_ATV4_PMGR_GFX "atv4.pmgr.gfx"
#define TYPE_ATV4_PMGR_ACG "atv4.pmgr.acg"
#define TYPE_ATV4_PMGR_CLK "atv4.pmgr.clk"
#define TYPE_ATV4_PMGR_CLKCFG "atv4.pmgr.clkcfg"
#define TYPE_ATV4_PMGR_SOC "atv4.pmgr.soc"
#define TYPE_ATV4_PMGR_PLL "atv4.pmgr.pll"
#define TYPE_ATV4_PMGR "atv4.pmgr"
#define TYPE_ATV4_PMGR_VOLMAN "atv4.pmgr.volman"
#define TYPE_ATV4_PMGR_PS "atv4.pmgr.ps"
#define TYPE_ATV4_PMGR_GFX "atv4.pmgr.gfx"
#define TYPE_ATV4_PMGR_ACG "atv4.pmgr.acg"
#define TYPE_ATV4_PMGR_CLK "atv4.pmgr.clk"
#define TYPE_ATV4_PMGR_CLKCFG "atv4.pmgr.clkcfg"
#define TYPE_ATV4_PMGR_SOC "atv4.pmgr.soc"
#define TYPE_ATV4_PMGR_PLL "atv4.pmgr.pll"
#define TYPE_ATV4_PMGR_SCRATCH "atv4.pmgr.scratch"
#define TYPE_ATV4_PMGR_PWRGATE "atv4.pmgr.pwrgate"
OBJECT_DECLARE_SIMPLE_TYPE(ATV4PMGRState, ATV4_PMGR)
#define NUM_PLLS 0x6
@@ -168,6 +170,8 @@ typedef struct ATV4PMGRState {
MemoryRegion clk_iomem;
MemoryRegion clkcfg_iomem;
MemoryRegion soc_iomem;
MemoryRegion scratch_iomem;
MemoryRegion pwrgate_iomem;
uint64_t pll_bypass_cfg[6];
} ATV4PMGRState;
+45
View File
@@ -0,0 +1,45 @@
#ifndef APPLE_AIC_H
#define APPLE_AIC_H
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "qom/object.h"
#define TYPE_APPLE_AIC "apple.aic"
OBJECT_DECLARE_SIMPLE_TYPE(AppleAICState, APPLE_AIC)
#define AIC_DEBUG_NEW_IRQ
typedef struct AppleAICState AppleAICState;
typedef struct {
AppleAICState *aic;
qemu_irq irq;
MemoryRegion iomem;
uint32_t cpu_id;
uint32_t pendingIPI;
uint32_t deferredIPI;
uint32_t ipi_mask;
} AppleAICCPU;
struct AppleAICState {
SysBusDevice parent_obj;
QEMUTimer *timer;
QemuMutex mutex;
uint32_t numEIR;
uint32_t numIRQ;
uint32_t numCPU;
uint32_t global_cfg;
uint32_t *eir_mask;
uint32_t *eir_dest;
AppleAICCPU *cpus;
uint32_t *eir_state;
#ifdef AIC_DEBUG_NEW_IRQ
uint32_t *eir_mask_once;
#endif
};
AppleAICState *apple_aic_create();
#endif /* APPLE_AIC_H */