diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2012-10-12 11:20:14 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2012-10-12 11:20:14 -0500 |
commit | ae72f3f5391cc761665824eeea542d3c5ad7ca67 (patch) | |
tree | b466a4171aac3b6aa9ee91a4f20635b166e26638 /hw | |
parent | 5d9619aa1fc348fe8894553c15c1ec886fa33939 (diff) | |
parent | fae15286751d8a8209724b14b62d065f1111e621 (diff) | |
download | hqemu-ae72f3f5391cc761665824eeea542d3c5ad7ca67.zip hqemu-ae72f3f5391cc761665824eeea542d3c5ad7ca67.tar.gz |
Merge remote-tracking branch 'pmaydell/arm-devs.for-upstream' into staging
* pmaydell/arm-devs.for-upstream:
arm_gic: Rename gic_state to GICState
zynq_slcr: Fixed ResetValues enum
versatilepb: add gpio pl061 support
hw/ds1338: Implement state save/restore
hw/ds1338: Remove 'now' field from state struct
hw/ds1338: Recapture current time when register pointer wraps around
hw/ds1338: Fix mishandling of register pointer
hw/arm_gic.c: Fix improper DPRINTF output.
cadence_ttc: Fix 'clear on read' behavior
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm_gic.c | 46 | ||||
-rw-r--r-- | hw/arm_gic_common.c | 16 | ||||
-rw-r--r-- | hw/arm_gic_internal.h | 20 | ||||
-rw-r--r-- | hw/armv7m_nvic.c | 6 | ||||
-rw-r--r-- | hw/cadence_ttc.c | 2 | ||||
-rw-r--r-- | hw/ds1338.c | 123 | ||||
-rw-r--r-- | hw/versatilepb.c | 5 | ||||
-rw-r--r-- | hw/zynq_slcr.c | 2 |
8 files changed, 137 insertions, 83 deletions
diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 55871fa..56376c0 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -36,7 +36,7 @@ static const uint8_t gic_id[] = { #define NUM_CPU(s) ((s)->num_cpu) -static inline int gic_get_current_cpu(gic_state *s) +static inline int gic_get_current_cpu(GICState *s) { if (s->num_cpu > 1) { return cpu_single_env->cpu_index; @@ -46,7 +46,7 @@ static inline int gic_get_current_cpu(gic_state *s) /* TODO: Many places that call this routine could be optimized. */ /* Update interrupt status after enabled or pending bits have been changed. */ -void gic_update(gic_state *s) +void gic_update(GICState *s) { int best_irq; int best_prio; @@ -84,7 +84,7 @@ void gic_update(gic_state *s) } } -void gic_set_pending_private(gic_state *s, int cpu, int irq) +void gic_set_pending_private(GICState *s, int cpu, int irq) { int cm = 1 << cpu; @@ -105,7 +105,7 @@ static void gic_set_irq(void *opaque, int irq, int level) * [N+32..N+63] : PPI (internal interrupts for CPU 1 * ... */ - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; int cm, target; if (irq < (s->num_irq - GIC_INTERNAL)) { /* The first external input line is internal interrupt 32. */ @@ -137,7 +137,7 @@ static void gic_set_irq(void *opaque, int irq, int level) gic_update(s); } -static void gic_set_running_irq(gic_state *s, int cpu, int irq) +static void gic_set_running_irq(GICState *s, int cpu, int irq) { s->running_irq[cpu] = irq; if (irq == 1023) { @@ -148,7 +148,7 @@ static void gic_set_running_irq(gic_state *s, int cpu, int irq) gic_update(s); } -uint32_t gic_acknowledge_irq(gic_state *s, int cpu) +uint32_t gic_acknowledge_irq(GICState *s, int cpu) { int new_irq; int cm = 1 << cpu; @@ -167,7 +167,7 @@ uint32_t gic_acknowledge_irq(gic_state *s, int cpu) return new_irq; } -void gic_complete_irq(gic_state *s, int cpu, int irq) +void gic_complete_irq(GICState *s, int cpu, int irq) { int update = 0; int cm = 1 << cpu; @@ -214,7 +214,7 @@ void gic_complete_irq(gic_state *s, int cpu, int irq) static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; uint32_t res; int irq; int i; @@ -347,7 +347,7 @@ static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset) static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, uint32_t value) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; int irq; int i; int cpu; @@ -500,7 +500,7 @@ static void gic_dist_writew(void *opaque, target_phys_addr_t offset, static void gic_dist_writel(void *opaque, target_phys_addr_t offset, uint32_t value) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; if (offset == 0xf00) { int cpu; int irq; @@ -539,7 +539,7 @@ static const MemoryRegionOps gic_dist_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset) +static uint32_t gic_cpu_read(GICState *s, int cpu, int offset) { switch (offset) { case 0x00: /* Control */ @@ -561,12 +561,12 @@ static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset) } } -static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value) +static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value) { switch (offset) { case 0x00: /* Control */ s->cpu_enabled[cpu] = (value & 1); - DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled ? "En" : "Dis"); + DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis"); break; case 0x04: /* Priority mask */ s->priority_mask[cpu] = (value & 0xff); @@ -587,25 +587,25 @@ static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value) static uint64_t gic_thiscpu_read(void *opaque, target_phys_addr_t addr, unsigned size) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; return gic_cpu_read(s, gic_get_current_cpu(s), addr); } static void gic_thiscpu_write(void *opaque, target_phys_addr_t addr, uint64_t value, unsigned size) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; gic_cpu_write(s, gic_get_current_cpu(s), addr, value); } /* Wrappers to read/write the GIC CPU interface for a specific CPU. - * These just decode the opaque pointer into gic_state* + cpu id. + * These just decode the opaque pointer into GICState* + cpu id. */ static uint64_t gic_do_cpu_read(void *opaque, target_phys_addr_t addr, unsigned size) { - gic_state **backref = (gic_state **)opaque; - gic_state *s = *backref; + GICState **backref = (GICState **)opaque; + GICState *s = *backref; int id = (backref - s->backref); return gic_cpu_read(s, id, addr); } @@ -613,8 +613,8 @@ static uint64_t gic_do_cpu_read(void *opaque, target_phys_addr_t addr, static void gic_do_cpu_write(void *opaque, target_phys_addr_t addr, uint64_t value, unsigned size) { - gic_state **backref = (gic_state **)opaque; - gic_state *s = *backref; + GICState **backref = (GICState **)opaque; + GICState *s = *backref; int id = (backref - s->backref); gic_cpu_write(s, id, addr, value); } @@ -631,7 +631,7 @@ static const MemoryRegionOps gic_cpu_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -void gic_init_irqs_and_distributor(gic_state *s, int num_irq) +void gic_init_irqs_and_distributor(GICState *s, int num_irq) { int i; @@ -657,7 +657,7 @@ static int arm_gic_init(SysBusDevice *dev) { /* Device instance init function for the GIC sysbus device */ int i; - gic_state *s = FROM_SYSBUS(gic_state, dev); + GICState *s = FROM_SYSBUS(GICState, dev); ARMGICClass *agc = ARM_GIC_GET_CLASS(s); agc->parent_init(dev); @@ -701,7 +701,7 @@ static void arm_gic_class_init(ObjectClass *klass, void *data) static TypeInfo arm_gic_info = { .name = TYPE_ARM_GIC, .parent = TYPE_ARM_GIC_COMMON, - .instance_size = sizeof(gic_state), + .instance_size = sizeof(GICState), .class_init = arm_gic_class_init, .class_size = sizeof(ARMGICClass), }; diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c index 360e782..8369309 100644 --- a/hw/arm_gic_common.c +++ b/hw/arm_gic_common.c @@ -22,7 +22,7 @@ static void gic_save(QEMUFile *f, void *opaque) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; int i; int j; @@ -56,7 +56,7 @@ static void gic_save(QEMUFile *f, void *opaque) static int gic_load(QEMUFile *f, void *opaque, int version_id) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; int i; int j; @@ -96,7 +96,7 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) static int arm_gic_common_init(SysBusDevice *dev) { - gic_state *s = FROM_SYSBUS(gic_state, dev); + GICState *s = FROM_SYSBUS(GICState, dev); int num_irq = s->num_irq; if (s->num_cpu > NCPU) { @@ -123,7 +123,7 @@ static int arm_gic_common_init(SysBusDevice *dev) static void arm_gic_common_reset(DeviceState *dev) { - gic_state *s = FROM_SYSBUS(gic_state, sysbus_from_qdev(dev)); + GICState *s = FROM_SYSBUS(GICState, sysbus_from_qdev(dev)); int i; memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state)); for (i = 0 ; i < s->num_cpu; i++) { @@ -147,13 +147,13 @@ static void arm_gic_common_reset(DeviceState *dev) } static Property arm_gic_common_properties[] = { - DEFINE_PROP_UINT32("num-cpu", gic_state, num_cpu, 1), - DEFINE_PROP_UINT32("num-irq", gic_state, num_irq, 32), + DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 1), + DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 32), /* Revision can be 1 or 2 for GIC architecture specification * versions 1 or 2, or 0 to indicate the legacy 11MPCore GIC. * (Internally, 0xffffffff also indicates "not a GIC but an NVIC".) */ - DEFINE_PROP_UINT32("revision", gic_state, revision, 1), + DEFINE_PROP_UINT32("revision", GICState, revision, 1), DEFINE_PROP_END_OF_LIST(), }; @@ -170,7 +170,7 @@ static void arm_gic_common_class_init(ObjectClass *klass, void *data) static TypeInfo arm_gic_common_type = { .name = TYPE_ARM_GIC_COMMON, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(gic_state), + .instance_size = sizeof(GICState), .class_size = sizeof(ARMGICCommonClass), .class_init = arm_gic_common_class_init, .abstract = true, diff --git a/hw/arm_gic_internal.h b/hw/arm_gic_internal.h index db4fad5..699352c 100644 --- a/hw/arm_gic_internal.h +++ b/hw/arm_gic_internal.h @@ -69,7 +69,7 @@ typedef struct gic_irq_state { unsigned trigger:1; /* nonzero = edge triggered. */ } gic_irq_state; -typedef struct gic_state { +typedef struct GICState { SysBusDevice busdev; qemu_irq parent_irq[NCPU]; int enabled; @@ -92,25 +92,25 @@ typedef struct gic_state { /* This is just so we can have an opaque pointer which identifies * both this GIC and which CPU interface we should be accessing. */ - struct gic_state *backref[NCPU]; + struct GICState *backref[NCPU]; MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */ uint32_t num_irq; uint32_t revision; -} gic_state; +} GICState; /* The special cases for the revision property: */ #define REV_11MPCORE 0 #define REV_NVIC 0xffffffff -void gic_set_pending_private(gic_state *s, int cpu, int irq); -uint32_t gic_acknowledge_irq(gic_state *s, int cpu); -void gic_complete_irq(gic_state *s, int cpu, int irq); -void gic_update(gic_state *s); -void gic_init_irqs_and_distributor(gic_state *s, int num_irq); +void gic_set_pending_private(GICState *s, int cpu, int irq); +uint32_t gic_acknowledge_irq(GICState *s, int cpu); +void gic_complete_irq(GICState *s, int cpu, int irq); +void gic_update(GICState *s); +void gic_init_irqs_and_distributor(GICState *s, int num_irq); #define TYPE_ARM_GIC_COMMON "arm_gic_common" #define ARM_GIC_COMMON(obj) \ - OBJECT_CHECK(gic_state, (obj), TYPE_ARM_GIC_COMMON) + OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC_COMMON) #define ARM_GIC_COMMON_CLASS(klass) \ OBJECT_CLASS_CHECK(ARMGICCommonClass, (klass), TYPE_ARM_GIC_COMMON) #define ARM_GIC_COMMON_GET_CLASS(obj) \ @@ -122,7 +122,7 @@ typedef struct ARMGICCommonClass { #define TYPE_ARM_GIC "arm_gic" #define ARM_GIC(obj) \ - OBJECT_CHECK(gic_state, (obj), TYPE_ARM_GIC) + OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC) #define ARM_GIC_CLASS(klass) \ OBJECT_CLASS_CHECK(ARMGICClass, (klass), TYPE_ARM_GIC) #define ARM_GIC_GET_CLASS(obj) \ diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index 5c09116..c449e08 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -17,7 +17,7 @@ #include "arm_gic_internal.h" typedef struct { - gic_state gic; + GICState gic; struct { uint32_t control; uint32_t reload; @@ -505,9 +505,9 @@ static void armv7m_nvic_instance_init(Object *obj) * than our superclass. This function runs after qdev init * has set the defaults from the Property array and before * any user-specified property setting, so just modify the - * value in the gic_state struct. + * value in the GICState struct. */ - gic_state *s = ARM_GIC_COMMON(obj); + GICState *s = ARM_GIC_COMMON(obj); /* The ARM v7m may have anything from 0 to 496 external interrupt * IRQ lines. We default to 64. Other boards may differ and should * set the num-irq property appropriately. diff --git a/hw/cadence_ttc.c b/hw/cadence_ttc.c index dd02f86..77b6976 100644 --- a/hw/cadence_ttc.c +++ b/hw/cadence_ttc.c @@ -274,6 +274,7 @@ static uint32_t cadence_ttc_read_imp(void *opaque, target_phys_addr_t offset) /* cleared after read */ value = s->reg_intr; s->reg_intr = 0; + cadence_timer_update(s); return value; case 0x60: /* interrupt enable */ @@ -355,7 +356,6 @@ static void cadence_ttc_write(void *opaque, target_phys_addr_t offset, case 0x54: /* interrupt register */ case 0x58: case 0x5c: - s->reg_intr &= (~value & 0xfff); break; case 0x60: /* interrupt enable */ diff --git a/hw/ds1338.c b/hw/ds1338.c index d590d9c..b576d56 100644 --- a/hw/ds1338.c +++ b/hw/ds1338.c @@ -12,39 +12,84 @@ #include "i2c.h" +/* Size of NVRAM including both the user-accessible area and the + * secondary register area. + */ +#define NVRAM_SIZE 64 + typedef struct { I2CSlave i2c; - time_t offset; - struct tm now; - uint8_t nvram[56]; - int ptr; - int addr_byte; + int64_t offset; + uint8_t nvram[NVRAM_SIZE]; + int32_t ptr; + bool addr_byte; } DS1338State; +static const VMStateDescription vmstate_ds1338 = { + .name = "ds1338", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_I2C_SLAVE(i2c, DS1338State), + VMSTATE_INT64(offset, DS1338State), + VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE), + VMSTATE_INT32(ptr, DS1338State), + VMSTATE_BOOL(addr_byte, DS1338State), + VMSTATE_END_OF_LIST() + } +}; + +static void capture_current_time(DS1338State *s) +{ + /* Capture the current time into the secondary registers + * which will be actually read by the data transfer operation. + */ + struct tm now; + qemu_get_timedate(&now, s->offset); + s->nvram[0] = to_bcd(now.tm_sec); + s->nvram[1] = to_bcd(now.tm_min); + if (s->nvram[2] & 0x40) { + s->nvram[2] = (to_bcd((now.tm_hour % 12)) + 1) | 0x40; + if (now.tm_hour >= 12) { + s->nvram[2] |= 0x20; + } + } else { + s->nvram[2] = to_bcd(now.tm_hour); + } + s->nvram[3] = to_bcd(now.tm_wday) + 1; + s->nvram[4] = to_bcd(now.tm_mday); + s->nvram[5] = to_bcd(now.tm_mon) + 1; + s->nvram[6] = to_bcd(now.tm_year - 100); +} + +static void inc_regptr(DS1338State *s) +{ + /* The register pointer wraps around after 0x3F; wraparound + * causes the current time/date to be retransferred into + * the secondary registers. + */ + s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1); + if (!s->ptr) { + capture_current_time(s); + } +} + static void ds1338_event(I2CSlave *i2c, enum i2c_event event) { DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); switch (event) { case I2C_START_RECV: - qemu_get_timedate(&s->now, s->offset); - s->nvram[0] = to_bcd(s->now.tm_sec); - s->nvram[1] = to_bcd(s->now.tm_min); - if (s->nvram[2] & 0x40) { - s->nvram[2] = (to_bcd((s->now.tm_hour % 12)) + 1) | 0x40; - if (s->now.tm_hour >= 12) { - s->nvram[2] |= 0x20; - } - } else { - s->nvram[2] = to_bcd(s->now.tm_hour); - } - s->nvram[3] = to_bcd(s->now.tm_wday) + 1; - s->nvram[4] = to_bcd(s->now.tm_mday); - s->nvram[5] = to_bcd(s->now.tm_mon) + 1; - s->nvram[6] = to_bcd(s->now.tm_year - 100); + /* In h/w, capture happens on any START condition, not just a + * START_RECV, but there is no need to actually capture on + * START_SEND, because the guest can't get at that data + * without going through a START_RECV which would overwrite it. + */ + capture_current_time(s); break; case I2C_START_SEND: - s->addr_byte = 1; + s->addr_byte = true; break; default: break; @@ -57,7 +102,7 @@ static int ds1338_recv(I2CSlave *i2c) uint8_t res; res = s->nvram[s->ptr]; - s->ptr = (s->ptr + 1) & 0xff; + inc_regptr(s); return res; } @@ -65,20 +110,20 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data) { DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); if (s->addr_byte) { - s->ptr = data; - s->addr_byte = 0; + s->ptr = data & (NVRAM_SIZE - 1); + s->addr_byte = false; return 0; } - s->nvram[s->ptr - 8] = data; - if (data < 8) { - qemu_get_timedate(&s->now, s->offset); - switch(data) { + if (s->ptr < 8) { + struct tm now; + qemu_get_timedate(&now, s->offset); + switch(s->ptr) { case 0: /* TODO: Implement CH (stop) bit. */ - s->now.tm_sec = from_bcd(data & 0x7f); + now.tm_sec = from_bcd(data & 0x7f); break; case 1: - s->now.tm_min = from_bcd(data & 0x7f); + now.tm_min = from_bcd(data & 0x7f); break; case 2: if (data & 0x40) { @@ -90,27 +135,29 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data) } else { data = from_bcd(data); } - s->now.tm_hour = data; + now.tm_hour = data; break; case 3: - s->now.tm_wday = from_bcd(data & 7) - 1; + now.tm_wday = from_bcd(data & 7) - 1; break; case 4: - s->now.tm_mday = from_bcd(data & 0x3f); + now.tm_mday = from_bcd(data & 0x3f); break; case 5: - s->now.tm_mon = from_bcd(data & 0x1f) - 1; + now.tm_mon = from_bcd(data & 0x1f) - 1; break; case 6: - s->now.tm_year = from_bcd(data) + 100; + now.tm_year = from_bcd(data) + 100; break; case 7: /* Control register. Currently ignored. */ break; } - s->offset = qemu_timedate_diff(&s->now); + s->offset = qemu_timedate_diff(&now); + } else { + s->nvram[s->ptr] = data; } - s->ptr = (s->ptr + 1) & 0xff; + inc_regptr(s); return 0; } @@ -121,12 +168,14 @@ static int ds1338_init(I2CSlave *i2c) static void ds1338_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); k->init = ds1338_init; k->event = ds1338_event; k->recv = ds1338_recv; k->send = ds1338_send; + dc->vmsd = &vmstate_ds1338; } static TypeInfo ds1338_info = { diff --git a/hw/versatilepb.c b/hw/versatilepb.c index b3f8077..7b1b025 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -266,6 +266,11 @@ static void versatile_init(ram_addr_t ram_size, sysbus_create_simple("sp804", 0x101e2000, pic[4]); sysbus_create_simple("sp804", 0x101e3000, pic[5]); + sysbus_create_simple("pl061", 0x101e4000, pic[6]); + sysbus_create_simple("pl061", 0x101e5000, pic[7]); + sysbus_create_simple("pl061", 0x101e6000, pic[8]); + sysbus_create_simple("pl061", 0x101e7000, pic[9]); + /* The versatile/PB actually has a modified Color LCD controller that includes hardware cursor support from the PL111. */ dev = sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]); diff --git a/hw/zynq_slcr.c b/hw/zynq_slcr.c index 4f97575..8acba01 100644 --- a/hw/zynq_slcr.c +++ b/hw/zynq_slcr.c @@ -91,7 +91,7 @@ typedef enum { typedef enum { PSS, DDDR, - DMAC, + DMAC = 3, USB, GEM, SDIO, |