summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-07-03 14:59:27 +0100
committerPeter Maydell <peter.maydell@linaro.org>2018-07-03 14:59:27 +0100
commitb07cd3e748b3f27a17c27afeee578dc4eedb8dd5 (patch)
treec7a6d5ea8459801bcc120b30958397824b8453f3 /hw
parenta395717cbd26e7593d3c3fe81faca121ec6d13e8 (diff)
parent29f9cef39eb1ae55e82c6763eb22d7a1bdff7276 (diff)
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-3.0-20180703' into staging
ppc patch queue 2018-07-03 Here's a last minue pull request before today's soft freeze. Ideally I would have sent this earlier, but I was waiting for a couple of extra fixes I knew were close. And the freeze crept up on me, like always. Most of the changes here are bugfixes in any case. There are some cleanups as well, which have been in my staging tree for a little while. There are a couple of truly new features (some extensions to the sam460ex platform), but these are low risk, since they only affect a new and not really stabilized machine type anyway. Higlights are: * Mac platform improvements from Mark Cave-Ayland * Sam460ex improvements from BALATON Zoltan et al. * XICS interrupt handler cleanups from Cédric Le Goater * TCG improvements for atomic loads and stores from Richard Henderson * Assorted other bugfixes # gpg: Signature made Tue 03 Jul 2018 06:55:22 BST # gpg: using RSA key 6C38CACA20D9B392 # gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" # gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" # gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" # gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" # Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392 * remotes/dgibson/tags/ppc-for-3.0-20180703: (35 commits) ppc: Include vga cirrus card into the compiling process target/ppc: Relax reserved bitmask of indexed store instructions target/ppc: set is_jmp on ppc_tr_breakpoint_check spapr: compute default value of "hpt-max-page-size" later target/ppc/kvm: don't pass cpu to kvm_get_smmu_info() target/ppc/kvm: get rid of kvm_get_fallback_smmu_info() ppc440_uc: Basic emulation of PPC440 DMA controller sam460ex: Add RTC device hw/timer: Add basic M41T80 emulation ppc4xx_i2c: Rewrite to model hardware more closely hw/ppc: Give sam46ex its own config option fpu_helper.c: fix setting FPSCR[FI] bit target/ppc: Implement the rest of gen_st_atomic target/ppc: Implement the rest of gen_ld_atomic target/ppc: Use atomic min/max helpers target/ppc: Use MO_ALIGN for EXIWX and ECOWX target/ppc: Split out gen_st_atomic target/ppc: Split out gen_ld_atomic target/ppc: Split out gen_load_locked target/ppc: Tidy gen_conditional_store ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org> # Conflicts: # hw/ppc/spapr.c
Diffstat (limited to 'hw')
-rw-r--r--hw/i2c/ppc4xx_i2c.c299
-rw-r--r--hw/intc/xics.c174
-rw-r--r--hw/intc/xics_kvm.c80
-rw-r--r--hw/intc/xics_pnv.c15
-rw-r--r--hw/misc/macio/mac_dbdma.c21
-rw-r--r--hw/ppc/Makefile.objs3
-rw-r--r--hw/ppc/mac_newworld.c4
-rw-r--r--hw/ppc/pnv_core.c1
-rw-r--r--hw/ppc/ppc440.h1
-rw-r--r--hw/ppc/ppc440_uc.c222
-rw-r--r--hw/ppc/sam460ex.c32
-rw-r--r--hw/ppc/spapr.c16
-rw-r--r--hw/ppc/spapr_caps.c13
-rw-r--r--hw/timer/Makefile.objs1
-rw-r--r--hw/timer/m41t80.c117
15 files changed, 724 insertions, 275 deletions
diff --git a/hw/i2c/ppc4xx_i2c.c b/hw/i2c/ppc4xx_i2c.c
index fca80d695a..d6dfafab31 100644
--- a/hw/i2c/ppc4xx_i2c.c
+++ b/hw/i2c/ppc4xx_i2c.c
@@ -34,16 +34,50 @@
#define PPC4xx_I2C_MEM_SIZE 18
+enum {
+ IIC_MDBUF = 0,
+ /* IIC_SDBUF = 2, */
+ IIC_LMADR = 4,
+ IIC_HMADR,
+ IIC_CNTL,
+ IIC_MDCNTL,
+ IIC_STS,
+ IIC_EXTSTS,
+ IIC_LSADR,
+ IIC_HSADR,
+ IIC_CLKDIV,
+ IIC_INTRMSK,
+ IIC_XFRCNT,
+ IIC_XTCNTLSS,
+ IIC_DIRECTCNTL
+ /* IIC_INTR */
+};
+
#define IIC_CNTL_PT (1 << 0)
#define IIC_CNTL_READ (1 << 1)
#define IIC_CNTL_CHT (1 << 2)
#define IIC_CNTL_RPST (1 << 3)
+#define IIC_CNTL_AMD (1 << 6)
+#define IIC_CNTL_HMT (1 << 7)
+
+#define IIC_MDCNTL_EINT (1 << 2)
+#define IIC_MDCNTL_ESM (1 << 3)
+#define IIC_MDCNTL_FMDB (1 << 6)
#define IIC_STS_PT (1 << 0)
+#define IIC_STS_IRQA (1 << 1)
#define IIC_STS_ERR (1 << 2)
+#define IIC_STS_MDBF (1 << 4)
#define IIC_STS_MDBS (1 << 5)
#define IIC_EXTSTS_XFRA (1 << 0)
+#define IIC_EXTSTS_BCS_FREE (4 << 4)
+#define IIC_EXTSTS_BCS_BUSY (5 << 4)
+
+#define IIC_INTRMSK_EIMTC (1 << 0)
+#define IIC_INTRMSK_EITA (1 << 1)
+#define IIC_INTRMSK_EIIC (1 << 2)
+#define IIC_INTRMSK_EIHE (1 << 3)
#define IIC_XTCNTLSS_SRST (1 << 0)
@@ -56,130 +90,83 @@ static void ppc4xx_i2c_reset(DeviceState *s)
{
PPC4xxI2CState *i2c = PPC4xx_I2C(s);
- /* FIXME: Should also reset bus?
- *if (s->address != ADDR_RESET) {
- * i2c_end_transfer(s->bus);
- *}
- */
-
- i2c->mdata = 0;
- i2c->lmadr = 0;
- i2c->hmadr = 0;
+ i2c->mdidx = -1;
+ memset(i2c->mdata, 0, ARRAY_SIZE(i2c->mdata));
+ /* [hl][ms]addr are not affected by reset */
i2c->cntl = 0;
i2c->mdcntl = 0;
i2c->sts = 0;
- i2c->extsts = 0x8f;
- i2c->lsadr = 0;
- i2c->hsadr = 0;
+ i2c->extsts = IIC_EXTSTS_BCS_FREE;
i2c->clkdiv = 0;
i2c->intrmsk = 0;
i2c->xfrcnt = 0;
i2c->xtcntlss = 0;
- i2c->directcntl = 0xf;
-}
-
-static inline bool ppc4xx_i2c_is_master(PPC4xxI2CState *i2c)
-{
- return true;
+ i2c->directcntl = 0xf; /* all non-reserved bits set */
}
static uint64_t ppc4xx_i2c_readb(void *opaque, hwaddr addr, unsigned int size)
{
PPC4xxI2CState *i2c = PPC4xx_I2C(opaque);
uint64_t ret;
+ int i;
switch (addr) {
- case 0:
- ret = i2c->mdata;
- if (ppc4xx_i2c_is_master(i2c)) {
+ case IIC_MDBUF:
+ if (i2c->mdidx < 0) {
ret = 0xff;
-
- if (!(i2c->sts & IIC_STS_MDBS)) {
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read "
- "without starting transfer\n",
- TYPE_PPC4xx_I2C, __func__);
- } else {
- int pending = (i2c->cntl >> 4) & 3;
-
- /* get the next byte */
- int byte = i2c_recv(i2c->bus);
-
- if (byte < 0) {
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: read failed "
- "for device 0x%02x\n", TYPE_PPC4xx_I2C,
- __func__, i2c->lmadr);
- ret = 0xff;
- } else {
- ret = byte;
- /* Raise interrupt if enabled */
- /*ppc4xx_i2c_raise_interrupt(i2c)*/;
- }
-
- if (!pending) {
- i2c->sts &= ~IIC_STS_MDBS;
- /*i2c_end_transfer(i2c->bus);*/
- /*} else if (i2c->cntl & (IIC_CNTL_RPST | IIC_CNTL_CHT)) {*/
- } else if (pending) {
- /* current smbus implementation doesn't like
- multibyte xfer repeated start */
- i2c_end_transfer(i2c->bus);
- if (i2c_start_transfer(i2c->bus, i2c->lmadr >> 1, 1)) {
- /* if non zero is returned, the adress is not valid */
- i2c->sts &= ~IIC_STS_PT;
- i2c->sts |= IIC_STS_ERR;
- i2c->extsts |= IIC_EXTSTS_XFRA;
- } else {
- /*i2c->sts |= IIC_STS_PT;*/
- i2c->sts |= IIC_STS_MDBS;
- i2c->sts &= ~IIC_STS_ERR;
- i2c->extsts = 0;
- }
- }
- pending--;
- i2c->cntl = (i2c->cntl & 0xcf) | (pending << 4);
- }
- } else {
- qemu_log_mask(LOG_UNIMP, "[%s]%s: slave mode not implemented\n",
- TYPE_PPC4xx_I2C, __func__);
+ break;
+ }
+ ret = i2c->mdata[0];
+ if (i2c->mdidx == 3) {
+ i2c->sts &= ~IIC_STS_MDBF;
+ } else if (i2c->mdidx == 0) {
+ i2c->sts &= ~IIC_STS_MDBS;
+ }
+ for (i = 0; i < i2c->mdidx; i++) {
+ i2c->mdata[i] = i2c->mdata[i + 1];
+ }
+ if (i2c->mdidx >= 0) {
+ i2c->mdidx--;
}
break;
- case 4:
+ case IIC_LMADR:
ret = i2c->lmadr;
break;
- case 5:
+ case IIC_HMADR:
ret = i2c->hmadr;
break;
- case 6:
+ case IIC_CNTL:
ret = i2c->cntl;
break;
- case 7:
+ case IIC_MDCNTL:
ret = i2c->mdcntl;
break;
- case 8:
+ case IIC_STS:
ret = i2c->sts;
break;
- case 9:
- ret = i2c->extsts;
+ case IIC_EXTSTS:
+ ret = i2c_bus_busy(i2c->bus) ?
+ IIC_EXTSTS_BCS_BUSY : IIC_EXTSTS_BCS_FREE;
break;
- case 10:
+ case IIC_LSADR:
ret = i2c->lsadr;
break;
- case 11:
+ case IIC_HSADR:
ret = i2c->hsadr;
break;
- case 12:
+ case IIC_CLKDIV:
ret = i2c->clkdiv;
break;
- case 13:
+ case IIC_INTRMSK:
ret = i2c->intrmsk;
break;
- case 14:
+ case IIC_XFRCNT:
ret = i2c->xfrcnt;
break;
- case 15:
+ case IIC_XTCNTLSS:
ret = i2c->xtcntlss;
break;
- case 16:
+ case IIC_DIRECTCNTL:
ret = i2c->directcntl;
break;
default:
@@ -202,99 +189,127 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, uint64_t value,
PPC4xxI2CState *i2c = opaque;
switch (addr) {
- case 0:
- i2c->mdata = value;
- if (!i2c_bus_busy(i2c->bus)) {
- /* assume we start a write transfer */
- if (i2c_start_transfer(i2c->bus, i2c->lmadr >> 1, 0)) {
- /* if non zero is returned, the adress is not valid */
- i2c->sts &= ~IIC_STS_PT;
- i2c->sts |= IIC_STS_ERR;
- i2c->extsts |= IIC_EXTSTS_XFRA;
- } else {
- i2c->sts |= IIC_STS_PT;
- i2c->sts &= ~IIC_STS_ERR;
- i2c->extsts = 0;
- }
+ case IIC_MDBUF:
+ if (i2c->mdidx >= 3) {
+ break;
}
- if (i2c_bus_busy(i2c->bus)) {
- if (i2c_send(i2c->bus, i2c->mdata)) {
- /* if the target return non zero then end the transfer */
- i2c->sts &= ~IIC_STS_PT;
- i2c->sts |= IIC_STS_ERR;
- i2c->extsts |= IIC_EXTSTS_XFRA;
- i2c_end_transfer(i2c->bus);
- }
+ i2c->mdata[++i2c->mdidx] = value;
+ if (i2c->mdidx == 3) {
+ i2c->sts |= IIC_STS_MDBF;
+ } else if (i2c->mdidx == 0) {
+ i2c->sts |= IIC_STS_MDBS;
}
break;
- case 4:
+ case IIC_LMADR:
i2c->lmadr = value;
- if (i2c_bus_busy(i2c->bus)) {
- i2c_end_transfer(i2c->bus);
- }
break;
- case 5:
+ case IIC_HMADR:
i2c->hmadr = value;
break;
- case 6:
- i2c->cntl = value;
- if (i2c->cntl & IIC_CNTL_PT) {
- if (i2c->cntl & IIC_CNTL_READ) {
- if (i2c_bus_busy(i2c->bus)) {
- /* end previous transfer */
- i2c->sts &= ~IIC_STS_PT;
- i2c_end_transfer(i2c->bus);
+ case IIC_CNTL:
+ i2c->cntl = value & ~IIC_CNTL_PT;
+ if (value & IIC_CNTL_AMD) {
+ qemu_log_mask(LOG_UNIMP, "%s: only 7 bit addresses supported\n",
+ __func__);
+ }
+ if (value & IIC_CNTL_HMT && i2c_bus_busy(i2c->bus)) {
+ i2c_end_transfer(i2c->bus);
+ if (i2c->mdcntl & IIC_MDCNTL_EINT &&
+ i2c->intrmsk & IIC_INTRMSK_EIHE) {
+ i2c->sts |= IIC_STS_IRQA;
+ qemu_irq_raise(i2c->irq);
+ }
+ } else if (value & IIC_CNTL_PT) {
+ int recv = (value & IIC_CNTL_READ) >> 1;
+ int tct = value >> 4 & 3;
+ int i;
+
+ if (recv && (i2c->lmadr >> 1) >= 0x50 && (i2c->lmadr >> 1) < 0x58) {
+ /* smbus emulation does not like multi byte reads w/o restart */
+ value |= IIC_CNTL_RPST;
+ }
+
+ for (i = 0; i <= tct; i++) {
+ if (!i2c_bus_busy(i2c->bus)) {
+ i2c->extsts = IIC_EXTSTS_BCS_FREE;
+ if (i2c_start_transfer(i2c->bus, i2c->lmadr >> 1, recv)) {
+ i2c->sts |= IIC_STS_ERR;
+ i2c->extsts |= IIC_EXTSTS_XFRA;
+ break;
+ } else {
+ i2c->sts &= ~IIC_STS_ERR;
+ }
}
- if (i2c_start_transfer(i2c->bus, i2c->lmadr >> 1, 1)) {
- /* if non zero is returned, the adress is not valid */
- i2c->sts &= ~IIC_STS_PT;
+ if (!(i2c->sts & IIC_STS_ERR) &&
+ i2c_send_recv(i2c->bus, &i2c->mdata[i], !recv)) {
i2c->sts |= IIC_STS_ERR;
i2c->extsts |= IIC_EXTSTS_XFRA;
- } else {
- /*i2c->sts |= IIC_STS_PT;*/
- i2c->sts |= IIC_STS_MDBS;
- i2c->sts &= ~IIC_STS_ERR;
- i2c->extsts = 0;
+ break;
+ }
+ if (value & IIC_CNTL_RPST || !(value & IIC_CNTL_CHT)) {
+ i2c_end_transfer(i2c->bus);
}
- } else {
- /* we actually already did the write transfer... */
- i2c->sts &= ~IIC_STS_PT;
+ }
+ i2c->xfrcnt = i;
+ i2c->mdidx = i - 1;
+ if (recv && i2c->mdidx >= 0) {
+ i2c->sts |= IIC_STS_MDBS;
+ }
+ if (recv && i2c->mdidx == 3) {
+ i2c->sts |= IIC_STS_MDBF;
+ }
+ if (i && i2c->mdcntl & IIC_MDCNTL_EINT &&
+ i2c->intrmsk & IIC_INTRMSK_EIMTC) {
+ i2c->sts |= IIC_STS_IRQA;
+ qemu_irq_raise(i2c->irq);
}
}
break;
- case 7:
- i2c->mdcntl = value & 0xdf;
+ case IIC_MDCNTL:
+ i2c->mdcntl = value & 0x3d;
+ if (value & IIC_MDCNTL_ESM) {
+ qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
+ __func__);
+ }
+ if (value & IIC_MDCNTL_FMDB) {
+ i2c->mdidx = -1;
+ memset(i2c->mdata, 0, ARRAY_SIZE(i2c->mdata));
+ i2c->sts &= ~(IIC_STS_MDBF | IIC_STS_MDBS);
+ }
break;
- case 8:
- i2c->sts &= ~(value & 0xa);
+ case IIC_STS:
+ i2c->sts &= ~(value & 0x0a);
+ if (value & IIC_STS_IRQA && i2c->mdcntl & IIC_MDCNTL_EINT) {
+ qemu_irq_lower(i2c->irq);
+ }
break;
- case 9:
+ case IIC_EXTSTS:
i2c->extsts &= ~(value & 0x8f);
break;
- case 10:
+ case IIC_LSADR:
i2c->lsadr = value;
break;
- case 11:
+ case IIC_HSADR:
i2c->hsadr = value;
break;
- case 12:
+ case IIC_CLKDIV:
i2c->clkdiv = value;
break;
- case 13:
+ case IIC_INTRMSK:
i2c->intrmsk = value;
break;
- case 14:
+ case IIC_XFRCNT:
i2c->xfrcnt = value & 0x77;
break;
- case 15:
+ case IIC_XTCNTLSS:
+ i2c->xtcntlss &= ~(value & 0xf0);
if (value & IIC_XTCNTLSS_SRST) {
/* Is it actually a full reset? U-Boot sets some regs before */
ppc4xx_i2c_reset(DEVICE(i2c));
break;
}
- i2c->xtcntlss = value;
break;
- case 16:
+ case IIC_DIRECTCNTL:
i2c->directcntl = value & (IIC_DIRECTCNTL_SDAC & IIC_DIRECTCNTL_SCLC);
i2c->directcntl |= (value & IIC_DIRECTCNTL_SCLC ? 1 : 0);
bitbang_i2c_set(i2c->bitbang, BITBANG_I2C_SCL,
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index e73e623e3b..b9f1a3c972 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -294,7 +294,6 @@ static const VMStateDescription vmstate_icp_server = {
static void icp_reset(void *dev)
{
ICPState *icp = ICP(dev);
- ICPStateClass *icpc = ICP_GET_CLASS(icp);
icp->xirr = 0;
icp->pending_priority = 0xff;
@@ -302,16 +301,11 @@ static void icp_reset(void *dev)
/* Make all outputs are deasserted */
qemu_set_irq(icp->output, 0);
-
- if (icpc->reset) {
- icpc->reset(icp);
- }
}
static void icp_realize(DeviceState *dev, Error **errp)
{
ICPState *icp = ICP(dev);
- ICPStateClass *icpc = ICP_GET_CLASS(dev);
PowerPCCPU *cpu;
CPUPPCState *env;
Object *obj;
@@ -351,10 +345,6 @@ static void icp_realize(DeviceState *dev, Error **errp)
return;
}
- if (icpc->realize) {
- icpc->realize(icp, errp);
- }
-
qemu_register_reset(icp_reset, dev);
vmstate_register(NULL, icp->cs->cpu_index, &vmstate_icp_server, icp);
}
@@ -547,9 +537,61 @@ static void ics_simple_eoi(ICSState *ics, uint32_t nr)
}
}
-static void ics_simple_reset(void *dev)
+static void ics_simple_reset(DeviceState *dev)
+{
+ ICSStateClass *icsc = ICS_BASE_GET_CLASS(dev);
+
+ icsc->parent_reset(dev);
+}
+
+static void ics_simple_reset_handler(void *dev)
+{
+ ics_simple_reset(dev);
+}
+
+static void ics_simple_realize(DeviceState *dev, Error **errp)
{
ICSState *ics = ICS_SIMPLE(dev);
+ ICSStateClass *icsc = ICS_BASE_GET_CLASS(ics);
+ Error *local_err = NULL;
+
+ icsc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ ics->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs);
+
+ qemu_register_reset(ics_simple_reset_handler, ics);
+}
+
+static void ics_simple_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ICSStateClass *isc = ICS_BASE_CLASS(klass);
+
+ device_class_set_parent_realize(dc, ics_simple_realize,
+ &isc->parent_realize);
+ device_class_set_parent_reset(dc, ics_simple_reset,
+ &isc->parent_reset);
+
+ isc->reject = ics_simple_reject;
+ isc->resend = ics_simple_resend;
+ isc->eoi = ics_simple_eoi;
+}
+
+static const TypeInfo ics_simple_info = {
+ .name = TYPE_ICS_SIMPLE,
+ .parent = TYPE_ICS_BASE,
+ .instance_size = sizeof(ICSState),
+ .class_init = ics_simple_class_init,
+ .class_size = sizeof(ICSStateClass),
+};
+
+static void ics_base_reset(DeviceState *dev)
+{
+ ICSState *ics = ICS_BASE(dev);
int i;
uint8_t flags[ics->nr_irqs];
@@ -566,7 +608,35 @@ static void ics_simple_reset(void *dev)
}
}
-static int ics_simple_dispatch_pre_save(void *opaque)
+static void ics_base_realize(DeviceState *dev, Error **errp)
+{
+ ICSState *ics = ICS_BASE(dev);
+ Object *obj;
+ Error *err = NULL;
+
+ obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &err);
+ if (!obj) {
+ error_propagate(errp, err);
+ error_prepend(errp, "required link '" ICS_PROP_XICS "' not found: ");
+ return;
+ }
+ ics->xics = XICS_FABRIC(obj);
+
+ if (!ics->nr_irqs) {
+ error_setg(errp, "Number of interrupts needs to be greater 0");
+ return;
+ }
+ ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
+}
+
+static void ics_base_instance_init(Object *obj)
+{
+ ICSState *ics = ICS_BASE(obj);
+
+ ics->offset = XICS_IRQ_BASE;
+}
+
+static int ics_base_dispatch_pre_save(void *opaque)
{
ICSState *ics = opaque;
ICSStateClass *info = ICS_BASE_GET_CLASS(ics);
@@ -578,7 +648,7 @@ static int ics_simple_dispatch_pre_save(void *opaque)
return 0;
}
-static int ics_simple_dispatch_post_load(void *opaque, int version_id)
+static int ics_base_dispatch_post_load(void *opaque, int version_id)
{
ICSState *ics = opaque;
ICSStateClass *info = ICS_BASE_GET_CLASS(ics);
@@ -590,7 +660,7 @@ static int ics_simple_dispatch_post_load(void *opaque, int version_id)
return 0;
}
-static const VMStateDescription vmstate_ics_simple_irq = {
+static const VMStateDescription vmstate_ics_base_irq = {
.name = "ics/irq",
.version_id = 2,
.minimum_version_id = 1,
@@ -604,95 +674,36 @@ static const VMStateDescription vmstate_ics_simple_irq = {
},
};
-static const VMStateDescription vmstate_ics_simple = {
+static const VMStateDescription vmstate_ics_base = {
.name = "ics",
.version_id = 1,
.minimum_version_id = 1,
- .pre_save = ics_simple_dispatch_pre_save,
- .post_load = ics_simple_dispatch_post_load,
+ .pre_save = ics_base_dispatch_pre_save,
+ .post_load = ics_base_dispatch_post_load,
.fields = (VMStateField[]) {
/* Sanity check */
VMSTATE_UINT32_EQUAL(nr_irqs, ICSState, NULL),
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
- vmstate_ics_simple_irq,
+ vmstate_ics_base_irq,
ICSIRQState),
VMSTATE_END_OF_LIST()
},
};
-static void ics_simple_initfn(Object *obj)
-{
- ICSState *ics = ICS_SIMPLE(obj);
-
- ics->offset = XICS_IRQ_BASE;
-}
-
-static void ics_simple_realize(ICSState *ics, Error **errp)
-{
- if (!ics->nr_irqs) {
- error_setg(errp, "Number of interrupts needs to be greater 0");
- return;
- }
- ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
- ics->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs);
-
- qemu_register_reset(ics_simple_reset, ics);
-}
-
-static Property ics_simple_properties[] = {
+static Property ics_base_properties[] = {
DEFINE_PROP_UINT32("nr-irqs", ICSState, nr_irqs, 0),
DEFINE_PROP_END_OF_LIST(),
};
-static void ics_simple_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- ICSStateClass *isc = ICS_BASE_CLASS(klass);
-
- isc->realize = ics_simple_realize;
- dc->props = ics_simple_properties;
- dc->vmsd = &vmstate_ics_simple;
- isc->reject = ics_simple_reject;
- isc->resend = ics_simple_resend;
- isc->eoi = ics_simple_eoi;
-}
-
-static const TypeInfo ics_simple_info = {
- .name = TYPE_ICS_SIMPLE,
- .parent = TYPE_ICS_BASE,
- .instance_size = sizeof(ICSState),
- .class_init = ics_simple_class_init,
- .class_size = sizeof(ICSStateClass),
- .instance_init = ics_simple_initfn,
-};
-
-static void ics_base_realize(DeviceState *dev, Error **errp)
-{
- ICSStateClass *icsc = ICS_BASE_GET_CLASS(dev);
- ICSState *ics = ICS_BASE(dev);
- Object *obj;
- Error *err = NULL;
-
- obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &err);
- if (!obj) {
- error_propagate(errp, err);
- error_prepend(errp, "required link '" ICS_PROP_XICS "' not found: ");
- return;
- }
- ics->xics = XICS_FABRIC(obj);
-
-
- if (icsc->realize) {
- icsc->realize(ics, errp);
- }
-}
-
static void ics_base_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = ics_base_realize;
+ dc->props = ics_base_properties;
+ dc->reset = ics_base_reset;
+ dc->vmsd = &vmstate_ics_base;
}
static const TypeInfo ics_base_info = {
@@ -700,6 +711,7 @@ static const TypeInfo ics_base_info = {
.parent = TYPE_DEVICE,
.abstract = true,
.instance_size = sizeof(ICSState),
+ .instance_init = ics_base_instance_init,
.class_init = ics_base_class_init,
.class_size = sizeof(ICSStateClass),
};
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index 8dba2f84e7..30c3769a20 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -114,22 +114,38 @@ static int icp_set_kvm_state(ICPState *icp, int version_id)
return 0;
}
-static void icp_kvm_reset(ICPState *icp)
+static void icp_kvm_reset(DeviceState *dev)
{
- icp_set_kvm_state(icp, 1);
+ ICPStateClass *icpc = ICP_GET_CLASS(dev);
+
+ icpc->parent_reset(dev);
+
+ icp_set_kvm_state(ICP(dev), 1);
}
-static void icp_kvm_realize(ICPState *icp, Error **errp)
+static void icp_kvm_realize(DeviceState *dev, Error **errp)
{
- CPUState *cs = icp->cs;
+ ICPState *icp = ICP(dev);
+ ICPStateClass *icpc = ICP_GET_CLASS(icp);
+ Error *local_err = NULL;
+ CPUState *cs;
KVMEnabledICP *enabled_icp;
- unsigned long vcpu_id = kvm_arch_vcpu_id(cs);
+ unsigned long vcpu_id;
int ret;
if (kernel_xics_fd == -1) {
abort();
}
+ icpc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ cs = icp->cs;
+ vcpu_id = kvm_arch_vcpu_id(cs);
+
/*
* If we are reusing a parked vCPU fd corresponding to the CPU
* which was hot-removed earlier we don't have to renable
@@ -154,12 +170,16 @@ static void icp_kvm_realize(ICPState *icp, Error **errp)
static void icp_kvm_class_init(ObjectClass *klass, void *data)
{
+ DeviceClass *dc = DEVICE_CLASS(klass);
ICPStateClass *icpc = ICP_CLASS(klass);
+ device_class_set_parent_realize(dc, icp_kvm_realize,
+ &icpc->parent_realize);
+ device_class_set_parent_reset(dc, icp_kvm_reset,
+ &icpc->parent_reset);
+
icpc->pre_save = icp_get_kvm_state;
icpc->post_load = icp_set_kvm_state;
- icpc->realize = icp_kvm_realize;
- icpc->reset = icp_kvm_reset;
icpc->synchronize_state = icp_synchronize_state;
}
@@ -304,44 +324,46 @@ static void ics_kvm_set_irq(void *opaque, int srcno, int val)
}
}
-static void ics_kvm_reset(void *dev)
+static void ics_kvm_reset(DeviceState *dev)
{
- ICSState *ics = ICS_SIMPLE(dev);
- int i;
- uint8_t flags[ics->nr_irqs];
+ ICSStateClass *icsc = ICS_BASE_GET_CLASS(dev);
- for (i = 0; i < ics->nr_irqs; i++) {
- flags[i] = ics->irqs[i].flags;
- }
-
- memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
+ icsc->parent_reset(dev);
- for (i = 0; i < ics->nr_irqs; i++) {
- ics->irqs[i].priority = 0xff;
- ics->irqs[i].saved_priority = 0xff;
- ics->irqs[i].flags = flags[i];
- }
+ ics_set_kvm_state(ICS_KVM(dev), 1);
+}
- ics_set_kvm_state(ics, 1);
+static void ics_kvm_reset_handler(void *dev)
+{
+ ics_kvm_reset(dev);
}
-static void ics_kvm_realize(ICSState *ics, Error **errp)
+static void ics_kvm_realize(DeviceState *dev, Error **errp)
{
- if (!ics->nr_irqs) {
- error_setg(errp, "Number of interrupts needs to be greater 0");
+ ICSState *ics = ICS_KVM(dev);
+ ICSStateClass *icsc = ICS_BASE_GET_CLASS(ics);
+ Error *local_err = NULL;
+
+ icsc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
- ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
ics->qirqs = qemu_allocate_irqs(ics_kvm_set_irq, ics, ics->nr_irqs);
- qemu_register_reset(ics_kvm_reset, ics);
+ qemu_register_reset(ics_kvm_reset_handler, ics);
}
static void ics_kvm_class_init(ObjectClass *klass, void *data)
{
ICSStateClass *icsc = ICS_BASE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ device_class_set_parent_realize(dc, ics_kvm_realize,
+ &icsc->parent_realize);
+ device_class_set_parent_reset(dc, ics_kvm_reset,
+ &icsc->parent_reset);
- icsc->realize = ics_kvm_realize;
icsc->pre_save = ics_get_kvm_state;
icsc->post_load = ics_set_kvm_state;
icsc->synchronize_state = ics_synchronize_state;
@@ -349,7 +371,7 @@ static void ics_kvm_class_init(ObjectClass *klass, void *data)
static const TypeInfo ics_kvm_info = {
.name = TYPE_ICS_KVM,
- .parent = TYPE_ICS_SIMPLE,
+ .parent = TYPE_ICS_BASE,
.instance_size = sizeof(ICSState),
.class_init = ics_kvm_class_init,
};
diff --git a/hw/intc/xics_pnv.c b/hw/intc/xics_pnv.c
index c87de2189c..fa48505f36 100644
--- a/hw/intc/xics_pnv.c
+++ b/hw/intc/xics_pnv.c
@@ -18,6 +18,7 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "sysemu/sysemu.h"
#include "qemu/log.h"
#include "hw/ppc/xics.h"
@@ -158,9 +159,18 @@ static const MemoryRegionOps pnv_icp_ops = {
},
};
-static void pnv_icp_realize(ICPState *icp, Error **errp)
+static void pnv_icp_realize(DeviceState *dev, Error **errp)
{
+ ICPState *icp = ICP(dev);
PnvICPState *pnv_icp = PNV_ICP(icp);
+ ICPStateClass *icpc = ICP_GET_CLASS(icp);
+ Error *local_err = NULL;
+
+ icpc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
memory_region_init_io(&pnv_icp->mmio, OBJECT(icp), &pnv_icp_ops,
icp, "icp-thread", 0x1000);
@@ -171,7 +181,8 @@ static void pnv_icp_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
ICPStateClass *icpc = ICP_CLASS(klass);
- icpc->realize = pnv_icp_realize;
+ device_class_set_parent_realize(dc, pnv_icp_realize,
+ &icpc->parent_realize);
dc->desc = "PowerNV ICP";
}
diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c
index 1b2a69b3ef..87ae246d37 100644
--- a/hw/misc/macio/mac_dbdma.c
+++ b/hw/misc/macio/mac_dbdma.c
@@ -71,18 +71,19 @@ static DBDMAState *dbdma_from_ch(DBDMA_channel *ch)
}
#if DEBUG_DBDMA
-static void dump_dbdma_cmd(dbdma_cmd *cmd)
+static void dump_dbdma_cmd(DBDMA_channel *ch, dbdma_cmd *cmd)
{
- printf("dbdma_cmd %p\n", cmd);
- printf(" req_count 0x%04x\n", le16_to_cpu(cmd->req_count));
- printf(" command 0x%04x\n", le16_to_cpu(cmd->command));
- printf(" phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr));
- printf(" cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep));
- printf(" res_count 0x%04x\n", le16_to_cpu(cmd->res_count));
- printf(" xfer_status 0x%04x\n", le16_to_cpu(cmd->xfer_status));
+ DBDMA_DPRINTFCH(ch, "dbdma_cmd %p\n", cmd);
+ DBDMA_DPRINTFCH(ch, " req_count 0x%04x\n", le16_to_cpu(cmd->req_count));
+ DBDMA_DPRINTFCH(ch, " command 0x%04x\n", le16_to_cpu(cmd->command));
+ DBDMA_DPRINTFCH(ch, " phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr));
+ DBDMA_DPRINTFCH(ch, " cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep));
+ DBDMA_DPRINTFCH(ch, " res_count 0x%04x\n", le16_to_cpu(cmd->res_count));
+ DBDMA_DPRINTFCH(ch, " xfer_status 0x%04x\n",
+ le16_to_cpu(cmd->xfer_status));
}
#else
-static void dump_dbdma_cmd(dbdma_cmd *cmd)
+static void dump_dbdma_cmd(DBDMA_channel *ch, dbdma_cmd *cmd)
{
}
#endif
@@ -448,7 +449,7 @@ static void channel_run(DBDMA_channel *ch)
uint32_t phy_addr;
DBDMA_DPRINTFCH(ch, "channel_run\n");
- dump_dbdma_cmd(current);
+ dump_dbdma_cmd(ch, current);
/* clear WAKE flag at command fetch */
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index 86d82a6ec3..bcab6323b7 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -14,7 +14,8 @@ obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o
# PowerPC 4xx boards
obj-y += ppc4xx_devs.o ppc405_uc.o
obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o
-obj-$(CONFIG_PPC4XX) += ppc440_bamboo.o ppc440_pcix.o ppc440_uc.o sam460ex.o
+obj-$(CONFIG_PPC4XX) += ppc440_bamboo.o ppc440_pcix.o ppc440_uc.o
+obj-$(CONFIG_SAM460EX) += sam460ex.o
# PReP
obj-$(CONFIG_PREP) += prep.o
obj-$(CONFIG_PREP) += prep_systemio.o
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 84355b2672..d11980166f 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -406,11 +406,11 @@ static void ppc_core99_init(MachineState *machine)
adb_bus = qdev_get_child_bus(dev, "adb.0");
dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD);
- qdev_prop_set_bit(dev, "disable-direct-reg3-writes", has_pmu);
+ qdev_prop_set_bit(dev, "disable-direct-reg3-writes", true);
qdev_init_nofail(dev);
dev = qdev_create(adb_bus, TYPE_ADB_MOUSE);
- qdev_prop_set_bit(dev, "disable-direct-reg3-writes", has_pmu);
+ qdev_prop_set_bit(dev, "disable-direct-reg3-writes", true);
qdev_init_nofail(dev);
}
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index a9f129fc2c..9750464bf4 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -150,6 +150,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
if (!chip) {
error_propagate(errp, local_err);
error_prepend(errp, "required link 'chip' not found: ");
+ return;
}
pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
diff --git a/hw/ppc/ppc440.h b/hw/ppc/ppc440.h
index ad27db12e4..7cef936125 100644
--- a/hw/ppc/ppc440.h
+++ b/hw/ppc/ppc440.h
@@ -21,6 +21,7 @@ void ppc440_sdram_init(CPUPPCState *env, int nbanks,
hwaddr *ram_bases, hwaddr *ram_sizes,
int do_init);
void ppc4xx_ahb_init(CPUPPCState *env);
+void ppc4xx_dma_init(CPUPPCState *env, int dcr_base);
void ppc460ex_pcie_init(CPUPPCState *env);
#endif /* PPC440_H */
diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c
index 1ab2235f20..0bbaa6844a 100644
--- a/hw/ppc/ppc440_uc.c
+++ b/hw/ppc/ppc440_uc.c
@@ -13,6 +13,7 @@
#include "qemu-common.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
+#include "qemu/log.h"
#include "cpu.h"
#include "hw/hw.h"
#include "exec/address-spaces.h"
@@ -803,6 +804,227 @@ void ppc4xx_ahb_init(CPUPPCState *env)
}
/*****************************************************************************/
+/* DMA controller */
+
+#define DMA0_CR_CE (1 << 31)
+#define DMA0_CR_PW (1 << 26 | 1 << 25)
+#define DMA0_CR_DAI (1 << 24)
+#define DMA0_CR_SAI (1 << 23)
+#define DMA0_CR_DEC (1 << 2)
+
+enum {
+ DMA0_CR = 0x00,
+ DMA0_CT,
+ DMA0_SAH,
+ DMA0_SAL,
+ DMA0_DAH,
+ DMA0_DAL,
+ DMA0_SGH,
+ DMA0_SGL,
+
+ DMA0_SR = 0x20,
+ DMA0_SGC = 0x23,
+ DMA0_SLP = 0x25,
+ DMA0_POL = 0x26,
+};
+
+typedef struct {
+ uint32_t cr;
+ uint32_t ct;
+ uint64_t sa;
+ uint64_t da;
+ uint64_t sg;
+} PPC4xxDmaChnl;
+
+typedef struct {
+ int base;
+ PPC4xxDmaChnl ch[4];
+ uint32_t sr;
+} PPC4xxDmaState;
+
+static uint32_t dcr_read_dma(void *opaque, int dcrn)
+{
+ PPC4xxDmaState *dma = opaque;
+ uint32_t val = 0;
+ int addr = dcrn - dma->base;
+ int chnl = addr / 8;
+
+ switch (addr) {
+ case 0x00 ... 0x1f:
+ switch (addr % 8) {
+ case DMA0_CR:
+ val = dma->ch[chnl].cr;
+ break;
+ case DMA0_CT:
+ val = dma->ch[chnl].ct;
+ break;
+ case DMA0_SAH:
+ val = dma->ch[chnl].sa >> 32;
+ break;
+ case DMA0_SAL:
+ val = dma->ch[chnl].sa;
+ break;
+ case DMA0_DAH:
+ val = dma->ch[chnl].da >> 32;
+ break;
+ case DMA0_DAL:
+ val = dma->ch[chnl].da;
+ break;
+ case DMA0_SGH:
+ val = dma->ch[chnl].sg >> 32;
+ break;
+ case DMA0_SGL:
+ val = dma->ch[chnl].sg;
+ break;
+ }
+ break;
+ case DMA0_SR:
+ val = dma->sr;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented register %x (%d, %x)\n",
+ __func__, dcrn, chnl, addr);
+ }
+
+ return val;
+}
+
+static void dcr_write_dma(void *opaque, int dcrn, uint32_t val)
+{
+ PPC4xxDmaState *dma = opaque;
+ int addr = dcrn - dma->base;
+ int chnl = addr / 8;
+
+ switch (addr) {
+ case 0x00 ... 0x1f:
+ switch (addr % 8) {
+ case DMA0_CR:
+ dma->ch[chnl].cr = val;
+ if (val & DMA0_CR_CE) {
+ int count = dma->ch[chnl].ct & 0xffff;
+
+ if (count) {
+ int width, i, sidx, didx;
+ uint8_t *rptr, *wptr;
+ hwaddr rlen, wlen;
+
+ sidx = didx = 0;
+ width = 1 << ((val & DMA0_CR_PW) >> 25);
+ rptr = cpu_physical_memory_map(dma->ch[chnl].sa, &rlen, 0);
+ wptr = cpu_physical_memory_map(dma->ch[chnl].da, &wlen, 1);
+ if (rptr && wptr) {
+ if (!(val & DMA0_CR_DEC) &&
+ val & DMA0_CR_SAI && val & DMA0_CR_DAI) {
+ /* optimise common case */
+ memmove(wptr, rptr, count * width);
+ sidx = didx = count * width;
+ } else {
+ /* do it the slow way */
+ for (sidx = didx = i = 0; i < count; i++) {
+ uint64_t v = ldn_le_p(rptr + sidx, width);
+ stn_le_p(wptr + didx, width, v);
+ if (val & DMA0_CR_SAI) {
+ sidx += width;
+ }
+ if (val & DMA0_CR_DAI) {
+ didx += width;
+ }
+ }
+ }
+ }
+ if (wptr) {
+ cpu_physical_memory_unmap(wptr, wlen, 1, didx);
+ }
+ if (wptr) {
+ cpu_physical_memory_unmap(rptr, rlen, 0, sidx);
+ }
+ }
+ }
+ break;
+ case DMA0_CT:
+ dma->ch[chnl].ct = val;
+ break;
+ case DMA0_SAH:
+ dma->ch[chnl].sa &= 0xffffffffULL;
+ dma->ch[chnl].sa |= (uint64_t)val << 32;
+ break;
+ case DMA0_SAL:
+ dma->ch[chnl].sa &= 0xffffffff00000000ULL;
+ dma->ch[chnl].sa |= val;
+ break;
+ case DMA0_DAH:
+ dma->ch[chnl].da &= 0xffffffffULL;
+ dma->ch[chnl].da |= (uint64_t)val << 32;
+ break;
+ case DMA0_DAL:
+ dma->ch[chnl].da &= 0xffffffff00000000ULL;
+ dma->ch[chnl].da |= val;
+ break;
+ case DMA0_SGH:
+ dma->ch[chnl].sg &= 0xffffffffULL;
+ dma->ch[chnl].sg |= (uint64_t)val << 32;
+ break;
+ case DMA0_SGL:
+ dma->ch[chnl].sg &= 0xffffffff00000000ULL;
+ dma->ch[chnl].sg |= val;
+ break;
+ }
+ break;
+ case DMA0_SR:
+ dma->sr &= ~val;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented register %x (%d, %x)\n",
+ __func__, dcrn, chnl, addr);
+ }
+}
+
+static void ppc4xx_dma_reset(void *opaque)
+{
+ PPC4xxDmaState *dma = opaque;
+ int dma_base = dma->base;
+
+ memset(dma, 0, sizeof(*dma));
+ dma->base = dma_base;
+}
+
+void ppc4xx_dma_init(CPUPPCState *env, int dcr_base)
+{
+ PPC4xxDmaState *dma;
+ int i;
+
+ dma = g_malloc0(sizeof(*dma));
+ dma->base = dcr_base;
+ qemu_register_reset(&ppc4xx_dma_reset, dma);
+ for (i = 0; i < 4; i++) {
+ ppc_dcr_register(env, dcr_base + i * 8 + DMA0_CR,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, dcr_base + i * 8 + DMA0_CT,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SAH,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SAL,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, dcr_base + i * 8 + DMA0_DAH,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, dcr_base + i * 8 + DMA0_DAL,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SGH,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SGL,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ }
+ ppc_dcr_register(env, dcr_base + DMA0_SR,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, dcr_base + DMA0_SGC,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, dcr_base + DMA0_SLP,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, dcr_base + DMA0_POL,
+ dma, &dcr_read_dma, &dcr_write_dma);
+}
+
+/*****************************************************************************/
/* PCI Express controller */
/* FIXME: This is not complete and does not work, only implemented partially
* to allow firmware and guests to find an empty bus. Cards should use PCI.
diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
index c7c799b843..7eed2ec601 100644
--- a/hw/ppc/sam460ex.c
+++ b/hw/ppc/sam460ex.c
@@ -37,6 +37,8 @@
#include "hw/i2c/smbus.h"
#include "hw/usb/hcd-ehci.h"
+#include <libfdt.h>
+
#define BINARY_DEVICE_TREE_FILE "canyonlands.dtb"
#define UBOOT_FILENAME "u-boot-sam460-20100605.bin"
/* to extract the official U-Boot bin from the updater: */
@@ -67,6 +69,10 @@
*/
#define CPU_FREQ 1150000000
+#define PLB_FREQ 230000000
+#define OPB_FREQ 115000000
+#define EBC_FREQ 115000000
+#define UART_FREQ 11059200
#define SDRAM_NR_BANKS 4
/* FIXME: See u-boot.git 8ac41e, also fix in ppc440_uc.c */
@@ -255,6 +261,7 @@ static int sam460ex_load_device_tree(hwaddr addr,
void *fdt;
uint32_t tb_freq = CPU_FREQ;
uint32_t clock_freq = CPU_FREQ;
+ int offset;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
if (!filename) {
@@ -308,6 +315,27 @@ static int sam460ex_load_device_tree(hwaddr addr,
qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
tb_freq);
+ /* Remove cpm node if it exists (it is not emulated) */
+ offset = fdt_path_offset(fdt, "/cpm");
+ if (offset >= 0) {
+ fdt_nop_node(fdt, offset);
+ }
+
+ /* set serial port clocks */
+ offset = fdt_node_offset_by_compatible(fdt, -1, "ns16550");
+ while (offset >= 0) {
+ fdt_setprop_cell(fdt, offset, "clock-frequency", UART_FREQ);
+ offset = fdt_node_offset_by_compatible(fdt, offset, "ns16550");
+ }
+
+ /* some more clocks */
+ qemu_fdt_setprop_cell(fdt, "/plb", "clock-frequency",
+ PLB_FREQ);
+ qemu_fdt_setprop_cell(fdt, "/plb/opb", "clock-frequency",
+ OPB_FREQ);
+ qemu_fdt_setprop_cell(fdt, "/plb/opb/ebc", "clock-frequency",
+ EBC_FREQ);
+
rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
g_free(fdt);
ret = fdt_size;
@@ -457,6 +485,7 @@ static void sam460ex_init(MachineState *machine)
object_property_set_bool(OBJECT(dev), true, "realized", NULL);
smbus_eeprom_init(i2c[0]->bus, 8, smbus_eeprom_buf, smbus_eeprom_size);
g_free(smbus_eeprom_buf);
+ i2c_create_slave(i2c[0]->bus, "m41t80", 0x68);
dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800, uic[0][3]);
i2c[1] = PPC4xx_I2C(dev);
@@ -476,6 +505,9 @@ static void sam460ex_init(MachineState *machine)
/* MAL */
ppc4xx_mal_init(env, 4, 16, &uic[2][3]);
+ /* DMA */
+ ppc4xx_dma_init(env, 0x200);
+
/* 256K of L2 cache as memory */
ppc4xx_l2sram_init(env);
/* FIXME: remove this after fixing l2sram mapping in ppc440_uc.c? */
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 1602472165..3f5e1d3ec2 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -137,7 +137,7 @@ static ICSState *spapr_ics_create(sPAPRMachineState *spapr,
goto error;
}
- return ICS_SIMPLE(obj);
+ return ICS_BASE(obj);
error:
error_propagate(errp, local_err);
@@ -3962,6 +3962,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
mc->no_parallel = 1;
mc->default_boot_order = "";
mc->default_ram_size = 512 * MiB;
+ mc->default_display = "std";
mc->kvm_type = spapr_kvm_type;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_SPAPR_PCI_HOST_BRIDGE);
mc->pci_allow_0_address = true;
@@ -4095,17 +4096,16 @@ static void spapr_machine_2_12_instance_options(MachineState *machine)
static void spapr_machine_2_12_class_options(MachineClass *mc)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
- uint8_t mps;
spapr_machine_3_0_class_options(mc);
SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_12);
- if (kvmppc_hpt_needs_host_contiguous_pages()) {
- mps = ctz64(qemu_getrampagesize());
- } else {
- mps = 34; /* allow everything up to 16GiB, i.e. everything */
- }
- smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = mps;
+ /* We depend on kvm_enabled() to choose a default value for the
+ * hpt-max-page-size capability. Of course we can't do it here
+ * because this is too early and the HW accelerator isn't initialzed
+ * yet. Postpone this to machine init (see default_caps_with_cpu()).
+ */
+ smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0;
}
DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 62663ebdf5..aa605cea91 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -465,6 +465,19 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
}
+ /* This is for pseries-2.12 and older */
+ if (smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] == 0) {
+ uint8_t mps;
+
+ if (kvmppc_hpt_needs_host_contiguous_pages()) {
+ mps = ctz64(qemu_getrampagesize());
+ } else {
+ mps = 34; /* allow everything up to 16GiB, i.e. everything */
+ }
+
+ caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = mps;
+ }
+
return caps;
}
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 8b27a4b7ef..e16b2b913c 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -6,6 +6,7 @@ common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
common-obj-$(CONFIG_DS1338) += ds1338.o
common-obj-$(CONFIG_HPET) += hpet.o
common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
+common-obj-$(CONFIG_M41T80) += m41t80.o
common-obj-$(CONFIG_M48T59) += m48t59.o
ifeq ($(CONFIG_ISA_BUS),y)
common-obj-$(CONFIG_M48T59) += m48t59-isa.o
diff --git a/hw/timer/m41t80.c b/hw/timer/m41t80.c
new file mode 100644
index 0000000000..734d7d95fc
--- /dev/null
+++ b/hw/timer/m41t80.c
@@ -0,0 +1,117 @@
+/*
+ * M41T80 serial rtc emulation
+ *
+ * Copyright (c) 2018 BALATON Zoltan
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/timer.h"
+#include "qemu/bcd.h"
+#include "hw/i2c/i2c.h"
+
+#define TYPE_M41T80 "m41t80"
+#define M41T80(obj) OBJECT_CHECK(M41t80State, (obj), TYPE_M41T80)
+
+typedef struct M41t80State {
+ I2CSlave parent_obj;
+ int8_t addr;
+} M41t80State;
+
+static void m41t80_realize(DeviceState *dev, Error **errp)
+{
+ M41t80State *s = M41T80(dev);
+
+ s->addr = -1;
+}
+
+static int m41t80_send(I2CSlave *i2c, uint8_t data)
+{
+ M41t80State *s = M41T80(i2c);
+
+ if (s->addr < 0) {
+ s->addr = data;
+ } else {
+ s->addr++;
+ }
+ return 0;
+}
+
+static int m41t80_recv(I2CSlave *i2c)
+{
+ M41t80State *s = M41T80(i2c);
+ struct tm now;
+ qemu_timeval tv;
+
+ if (s->addr < 0) {
+ s->addr = 0;
+ }
+ if (s->addr >= 1 && s->addr <= 7) {
+ qemu_get_timedate(&now, -1);
+ }
+ switch (s->addr++) {
+ case 0:
+ qemu_gettimeofday(&tv);
+ return to_bcd(tv.tv_usec / 10000);
+ case 1:
+ return to_bcd(now.tm_sec);
+ case 2:
+ return to_bcd(now.tm_min);
+ case 3:
+ return to_bcd(now.tm_hour);
+ case 4:
+ return to_bcd(now.tm_wday);
+ case 5:
+ return to_bcd(now.tm_mday);
+ case 6:
+ return to_bcd(now.tm_mon + 1);
+ case 7:
+ return to_bcd(now.tm_year % 100);
+ case 8 ... 19:
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented register: %d\n",
+ __func__, s->addr - 1);
+ return 0;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid register: %d\n",
+ __func__, s->addr - 1);
+ return 0;
+ }
+}
+
+static int m41t80_event(I2CSlave *i2c, enum i2c_event event)
+{
+ M41t80State *s = M41T80(i2c);
+
+ if (event == I2C_START_SEND) {
+ s->addr = -1;
+ }
+ return 0;
+}
+
+static void m41t80_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+ dc->realize = m41t80_realize;
+ sc->send = m41t80_send;
+ sc->recv = m41t80_recv;
+ sc->event = m41t80_event;
+}
+
+static const TypeInfo m41t80_info = {
+ .name = TYPE_M41T80,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(M41t80State),
+ .class_init = m41t80_class_init,
+};
+
+static void m41t80_register_types(void)
+{
+ type_register_static(&m41t80_info);
+}
+
+type_init(m41t80_register_types)