hw/misc/aspeed_xdma: New device

The XDMA engine embedded in the Aspeed SOCs performs PCI DMA operations
between the SOC (acting as a BMC) and a host processor in a server.

The XDMA engine exists on the AST2400, AST2500, and AST2600 SOCs, so
enable it for all of those. Add trace events on the important register
writes in the XDMA engine.

Signed-off-by: Eddie James <eajames@linux.ibm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-id: 20190618165311.27066-21-clg@kaod.org
[clg: - changed title ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Eddie James 2019-07-01 17:26:18 +01:00 committed by Peter Maydell
parent aae7a18d47
commit 118c82e7ff
6 changed files with 219 additions and 0 deletions

View File

@ -32,6 +32,7 @@ static const hwaddr aspeed_soc_ast2400_memmap[] = {
[ASPEED_VIC] = 0x1E6C0000,
[ASPEED_SDMC] = 0x1E6E0000,
[ASPEED_SCU] = 0x1E6E2000,
[ASPEED_XDMA] = 0x1E6E7000,
[ASPEED_ADC] = 0x1E6E9000,
[ASPEED_SRAM] = 0x1E720000,
[ASPEED_GPIO] = 0x1E780000,
@ -58,6 +59,7 @@ static const hwaddr aspeed_soc_ast2500_memmap[] = {
[ASPEED_VIC] = 0x1E6C0000,
[ASPEED_SDMC] = 0x1E6E0000,
[ASPEED_SCU] = 0x1E6E2000,
[ASPEED_XDMA] = 0x1E6E7000,
[ASPEED_ADC] = 0x1E6E9000,
[ASPEED_SRAM] = 0x1E720000,
[ASPEED_GPIO] = 0x1E780000,
@ -104,6 +106,7 @@ static const int aspeed_soc_ast2400_irqmap[] = {
[ASPEED_I2C] = 12,
[ASPEED_ETH1] = 2,
[ASPEED_ETH2] = 3,
[ASPEED_XDMA] = 6,
};
#define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap
@ -238,6 +241,9 @@ static void aspeed_soc_init(Object *obj)
sysbus_init_child_obj(obj, "ftgmac100[*]", OBJECT(&s->ftgmac100[i]),
sizeof(s->ftgmac100[i]), TYPE_FTGMAC100);
}
sysbus_init_child_obj(obj, "xdma", OBJECT(&s->xdma), sizeof(s->xdma),
TYPE_ASPEED_XDMA);
}
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
@ -406,6 +412,17 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
aspeed_soc_get_irq(s, ASPEED_ETH1 + i));
}
/* XDMA */
object_property_set_bool(OBJECT(&s->xdma), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->xdma), 0,
sc->info->memmap[ASPEED_XDMA]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->xdma), 0,
aspeed_soc_get_irq(s, ASPEED_XDMA));
}
static Property aspeed_soc_properties[] = {
DEFINE_PROP_UINT32("num-cpus", AspeedSoCState, num_cpus, 0),

View File

@ -74,6 +74,7 @@ obj-$(CONFIG_ARMSSE_MHU) += armsse-mhu.o
obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_AUX) += auxbus.o
obj-$(CONFIG_ASPEED_SOC) += aspeed_xdma.o
obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
obj-$(CONFIG_MSF2) += msf2-sysreg.o
obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o

165
hw/misc/aspeed_xdma.c Normal file
View File

@ -0,0 +1,165 @@
/*
* ASPEED XDMA Controller
* Eddie James <eajames@linux.ibm.com>
*
* Copyright (C) 2019 IBM Corp
* SPDX-License-Identifer: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "hw/misc/aspeed_xdma.h"
#include "qapi/error.h"
#include "trace.h"
#define XDMA_BMC_CMDQ_ADDR 0x10
#define XDMA_BMC_CMDQ_ENDP 0x14
#define XDMA_BMC_CMDQ_WRP 0x18
#define XDMA_BMC_CMDQ_W_MASK 0x0003FFFF
#define XDMA_BMC_CMDQ_RDP 0x1C
#define XDMA_BMC_CMDQ_RDP_MAGIC 0xEE882266
#define XDMA_IRQ_ENG_CTRL 0x20
#define XDMA_IRQ_ENG_CTRL_US_COMP BIT(4)
#define XDMA_IRQ_ENG_CTRL_DS_COMP BIT(5)
#define XDMA_IRQ_ENG_CTRL_W_MASK 0xBFEFF07F
#define XDMA_IRQ_ENG_STAT 0x24
#define XDMA_IRQ_ENG_STAT_US_COMP BIT(4)
#define XDMA_IRQ_ENG_STAT_DS_COMP BIT(5)
#define XDMA_IRQ_ENG_STAT_RESET 0xF8000000
#define XDMA_MEM_SIZE 0x1000
#define TO_REG(addr) ((addr) / sizeof(uint32_t))
static uint64_t aspeed_xdma_read(void *opaque, hwaddr addr, unsigned int size)
{
uint32_t val = 0;
AspeedXDMAState *xdma = opaque;
if (addr < ASPEED_XDMA_REG_SIZE) {
val = xdma->regs[TO_REG(addr)];
}
return (uint64_t)val;
}
static void aspeed_xdma_write(void *opaque, hwaddr addr, uint64_t val,
unsigned int size)
{
unsigned int idx;
uint32_t val32 = (uint32_t)val;
AspeedXDMAState *xdma = opaque;
if (addr >= ASPEED_XDMA_REG_SIZE) {
return;
}
switch (addr) {
case XDMA_BMC_CMDQ_ENDP:
xdma->regs[TO_REG(addr)] = val32 & XDMA_BMC_CMDQ_W_MASK;
break;
case XDMA_BMC_CMDQ_WRP:
idx = TO_REG(addr);
xdma->regs[idx] = val32 & XDMA_BMC_CMDQ_W_MASK;
xdma->regs[TO_REG(XDMA_BMC_CMDQ_RDP)] = xdma->regs[idx];
trace_aspeed_xdma_write(addr, val);
if (xdma->bmc_cmdq_readp_set) {
xdma->bmc_cmdq_readp_set = 0;
} else {
xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] |=
XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP;
if (xdma->regs[TO_REG(XDMA_IRQ_ENG_CTRL)] &
(XDMA_IRQ_ENG_CTRL_US_COMP | XDMA_IRQ_ENG_CTRL_DS_COMP))
qemu_irq_raise(xdma->irq);
}
break;
case XDMA_BMC_CMDQ_RDP:
trace_aspeed_xdma_write(addr, val);
if (val32 == XDMA_BMC_CMDQ_RDP_MAGIC) {
xdma->bmc_cmdq_readp_set = 1;
}
break;
case XDMA_IRQ_ENG_CTRL:
xdma->regs[TO_REG(addr)] = val32 & XDMA_IRQ_ENG_CTRL_W_MASK;
break;
case XDMA_IRQ_ENG_STAT:
trace_aspeed_xdma_write(addr, val);
idx = TO_REG(addr);
if (val32 & (XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP)) {
xdma->regs[idx] &=
~(XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP);
qemu_irq_lower(xdma->irq);
}
break;
default:
xdma->regs[TO_REG(addr)] = val32;
break;
}
}
static const MemoryRegionOps aspeed_xdma_ops = {
.read = aspeed_xdma_read,
.write = aspeed_xdma_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid.min_access_size = 4,
.valid.max_access_size = 4,
};
static void aspeed_xdma_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedXDMAState *xdma = ASPEED_XDMA(dev);
sysbus_init_irq(sbd, &xdma->irq);
memory_region_init_io(&xdma->iomem, OBJECT(xdma), &aspeed_xdma_ops, xdma,
TYPE_ASPEED_XDMA, XDMA_MEM_SIZE);
sysbus_init_mmio(sbd, &xdma->iomem);
}
static void aspeed_xdma_reset(DeviceState *dev)
{
AspeedXDMAState *xdma = ASPEED_XDMA(dev);
xdma->bmc_cmdq_readp_set = 0;
memset(xdma->regs, 0, ASPEED_XDMA_REG_SIZE);
xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] = XDMA_IRQ_ENG_STAT_RESET;
qemu_irq_lower(xdma->irq);
}
static const VMStateDescription aspeed_xdma_vmstate = {
.name = TYPE_ASPEED_XDMA,
.version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, AspeedXDMAState, ASPEED_XDMA_NUM_REGS),
VMSTATE_END_OF_LIST(),
},
};
static void aspeed_xdma_class_init(ObjectClass *classp, void *data)
{
DeviceClass *dc = DEVICE_CLASS(classp);
dc->realize = aspeed_xdma_realize;
dc->reset = aspeed_xdma_reset;
dc->vmsd = &aspeed_xdma_vmstate;
}
static const TypeInfo aspeed_xdma_info = {
.name = TYPE_ASPEED_XDMA,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedXDMAState),
.class_init = aspeed_xdma_class_init,
};
static void aspeed_xdma_register_type(void)
{
type_register_static(&aspeed_xdma_info);
}
type_init(aspeed_xdma_register_type);

View File

@ -140,3 +140,6 @@ armsse_cpuid_write(uint64_t offset, uint64_t data, unsigned size) "SSE-200 CPU_I
# armsse-mhu.c
armsse_mhu_read(uint64_t offset, uint64_t data, unsigned size) "SSE-200 MHU read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
armsse_mhu_write(uint64_t offset, uint64_t data, unsigned size) "SSE-200 MHU write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
# aspeed_xdma.c
aspeed_xdma_write(uint64_t offset, uint64_t data) "XDMA write: offset 0x%" PRIx64 " data 0x%" PRIx64

View File

@ -15,6 +15,7 @@
#include "hw/intc/aspeed_vic.h"
#include "hw/misc/aspeed_scu.h"
#include "hw/misc/aspeed_sdmc.h"
#include "hw/misc/aspeed_xdma.h"
#include "hw/timer/aspeed_timer.h"
#include "hw/timer/aspeed_rtc.h"
#include "hw/i2c/aspeed_i2c.h"
@ -40,6 +41,7 @@ typedef struct AspeedSoCState {
AspeedTimerCtrlState timerctrl;
AspeedI2CState i2c;
AspeedSCUState scu;
AspeedXDMAState xdma;
AspeedSMCState fmc;
AspeedSMCState spi[ASPEED_SPIS_NUM];
AspeedSDMCState sdmc;
@ -108,6 +110,7 @@ enum {
ASPEED_ETH1,
ASPEED_ETH2,
ASPEED_SDRAM,
ASPEED_XDMA,
};
#endif /* ASPEED_SOC_H */

View File

@ -0,0 +1,30 @@
/*
* ASPEED XDMA Controller
* Eddie James <eajames@linux.ibm.com>
*
* Copyright (C) 2019 IBM Corp.
* SPDX-License-Identifer: GPL-2.0-or-later
*/
#ifndef ASPEED_XDMA_H
#define ASPEED_XDMA_H
#include "hw/sysbus.h"
#define TYPE_ASPEED_XDMA "aspeed.xdma"
#define ASPEED_XDMA(obj) OBJECT_CHECK(AspeedXDMAState, (obj), TYPE_ASPEED_XDMA)
#define ASPEED_XDMA_NUM_REGS (ASPEED_XDMA_REG_SIZE / sizeof(uint32_t))
#define ASPEED_XDMA_REG_SIZE 0x7C
typedef struct AspeedXDMAState {
SysBusDevice parent;
MemoryRegion iomem;
qemu_irq irq;
char bmc_cmdq_readp_set;
uint32_t regs[ASPEED_XDMA_NUM_REGS];
} AspeedXDMAState;
#endif /* ASPEED_XDMA_H */