X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/2a576ee6e36924bb3c3e6690e9ca35a9942e0634..b2866c29156afdcad3ced4cc2001bbfe4302d81c:/hw/timer/m48t59.c diff --git a/hw/timer/m48t59.c b/hw/timer/m48t59.c index be0592b53d..f2991762ab 100644 --- a/hw/timer/m48t59.c +++ b/hw/timer/m48t59.c @@ -1,7 +1,8 @@ /* * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms * - * Copyright (c) 2003-2005, 2007 Jocelyn Mayer + * Copyright (c) 2003-2005, 2007, 2017 Jocelyn Mayer + * Copyright (c) 2013 Hervé Poussineau * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,27 +22,24 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/timer/m48t59.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" #include "hw/sysbus.h" -#include "hw/isa/isa.h" #include "exec/address-spaces.h" +#include "qemu/bcd.h" -//#define DEBUG_NVRAM +#include "m48t59-internal.h" -#if defined(DEBUG_NVRAM) -#define NVRAM_PRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0) -#else -#define NVRAM_PRINTF(fmt, ...) do { } while (0) -#endif - -/* - * The M48T02, M48T08 and M48T59 chips are very similar. The newer '59 has - * alarm and a watchdog timer and related control registers. In the - * PPC platform there is also a nvram lock function. - */ +#define TYPE_M48TXX_SYS_BUS "sysbus-m48txx" +#define M48TXX_SYS_BUS_GET_CLASS(obj) \ + OBJECT_GET_CLASS(M48txxSysBusDeviceClass, (obj), TYPE_M48TXX_SYS_BUS) +#define M48TXX_SYS_BUS_CLASS(klass) \ + OBJECT_CLASS_CHECK(M48txxSysBusDeviceClass, (klass), TYPE_M48TXX_SYS_BUS) +#define M48TXX_SYS_BUS(obj) \ + OBJECT_CHECK(M48txxSysBusState, (obj), TYPE_M48TXX_SYS_BUS) /* * Chipset docs: @@ -50,48 +48,33 @@ * http://www.st.com/stonline/products/literature/od/7001/m48t59y.pdf */ -struct M48t59State { - /* Hardware parameters */ - qemu_irq IRQ; - MemoryRegion iomem; - uint32_t io_base; - uint32_t size; - /* RTC management */ - time_t time_offset; - time_t stop_time; - /* Alarm & watchdog */ - struct tm alarm; - QEMUTimer *alrm_timer; - QEMUTimer *wd_timer; - /* NVRAM storage */ - uint8_t *buffer; - /* Model parameters */ - uint32_t model; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */ - /* NVRAM storage */ - uint16_t addr; - uint8_t lock; -}; - -#define TYPE_ISA_M48T59 "m48t59_isa" -#define ISA_M48T59(obj) \ - OBJECT_CHECK(M48t59ISAState, (obj), TYPE_ISA_M48T59) - -typedef struct M48t59ISAState { - ISADevice parent_obj; - - M48t59State state; - MemoryRegion io; -} M48t59ISAState; - -#define SYSBUS_M48T59(obj) \ - OBJECT_CHECK(M48t59SysBusState, (obj), TYPE_SYSBUS_M48T59) - -typedef struct M48t59SysBusState { +typedef struct M48txxSysBusState { SysBusDevice parent_obj; - M48t59State state; MemoryRegion io; -} M48t59SysBusState; +} M48txxSysBusState; + +typedef struct M48txxSysBusDeviceClass { + SysBusDeviceClass parent_class; + M48txxInfo info; +} M48txxSysBusDeviceClass; + +static M48txxInfo m48txx_sysbus_info[] = { + { + .bus_name = "sysbus-m48t02", + .model = 2, + .size = 0x800, + },{ + .bus_name = "sysbus-m48t08", + .model = 8, + .size = 0x2000, + },{ + .bus_name = "sysbus-m48t59", + .model = 59, + .size = 0x2000, + } +}; + /* Fake timer functions */ @@ -175,7 +158,7 @@ static void watchdog_cb (void *opaque) NVRAM->buffer[0x1FF7] = 0x00; NVRAM->buffer[0x1FFC] &= ~0x40; /* May it be a hw CPU Reset instead ? */ - qemu_system_reset_request(); + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); } else { qemu_set_irq(NVRAM->IRQ, 1); qemu_set_irq(NVRAM->IRQ, 0); @@ -198,9 +181,8 @@ static void set_up_watchdog(M48t59State *NVRAM, uint8_t value) } /* Direct access to NVRAM */ -void m48t59_write (void *opaque, uint32_t addr, uint32_t val) +void m48t59_write(M48t59State *NVRAM, uint32_t addr, uint32_t val) { - M48t59State *NVRAM = opaque; struct tm tm; int tmp; @@ -346,11 +328,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) tmp = from_bcd(val); if (tmp >= 0 && tmp <= 99) { get_time(NVRAM, &tm); - if (NVRAM->model == 8) { - tm.tm_year = from_bcd(val) + 68; // Base year is 1968 - } else { - tm.tm_year = from_bcd(val); - } + tm.tm_year = from_bcd(val) + NVRAM->base_year - 1900; set_time(NVRAM, &tm); } break; @@ -368,9 +346,8 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) } } -uint32_t m48t59_read (void *opaque, uint32_t addr) +uint32_t m48t59_read(M48t59State *NVRAM, uint32_t addr) { - M48t59State *NVRAM = opaque; struct tm tm; uint32_t retval = 0xFF; @@ -453,11 +430,7 @@ uint32_t m48t59_read (void *opaque, uint32_t addr) case 0x07FF: /* year */ get_time(NVRAM, &tm); - if (NVRAM->model == 8) { - retval = to_bcd(tm.tm_year - 68); // Base year is 1968 - } else { - retval = to_bcd(tm.tm_year); - } + retval = to_bcd((tm.tm_year + 1900 - NVRAM->base_year) % 100); break; default: /* Check lock registers state */ @@ -477,20 +450,13 @@ uint32_t m48t59_read (void *opaque, uint32_t addr) return retval; } -void m48t59_toggle_lock (void *opaque, int lock) -{ - M48t59State *NVRAM = opaque; - - NVRAM->lock ^= 1 << lock; -} - /* IO access to NVRAM */ static void NVRAM_writeb(void *opaque, hwaddr addr, uint64_t val, unsigned size) { M48t59State *NVRAM = opaque; - NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val); + NVRAM_PRINTF("%s: 0x%"HWADDR_PRIx" => 0x%"PRIx64"\n", __func__, addr, val); switch (addr) { case 0: NVRAM->addr &= ~0x00FF; @@ -522,7 +488,7 @@ static uint64_t NVRAM_readb(void *opaque, hwaddr addr, unsigned size) retval = -1; break; } - NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval); + NVRAM_PRINTF("%s: 0x%"HWADDR_PRIx" <= 0x%08x\n", __func__, addr, retval); return retval; } @@ -555,10 +521,8 @@ static void nvram_writel (void *opaque, hwaddr addr, uint32_t value) static uint32_t nvram_readb (void *opaque, hwaddr addr) { M48t59State *NVRAM = opaque; - uint32_t retval; - retval = m48t59_read(NVRAM, addr); - return retval; + return m48t59_read(NVRAM, addr); } static uint32_t nvram_readw (void *opaque, hwaddr addr) @@ -595,16 +559,15 @@ static const VMStateDescription vmstate_m48t59 = { .name = "m48t59", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT8(lock, M48t59State), VMSTATE_UINT16(addr, M48t59State), - VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, 0, size), + VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, size), VMSTATE_END_OF_LIST() } }; -static void m48t59_reset_common(M48t59State *NVRAM) +void m48t59_reset_common(M48t59State *NVRAM) { NVRAM->addr = 0; NVRAM->lock = 0; @@ -615,23 +578,15 @@ static void m48t59_reset_common(M48t59State *NVRAM) timer_del(NVRAM->wd_timer); } -static void m48t59_reset_isa(DeviceState *d) -{ - M48t59ISAState *isa = ISA_M48T59(d); - M48t59State *NVRAM = &isa->state; - - m48t59_reset_common(NVRAM); -} - static void m48t59_reset_sysbus(DeviceState *d) { - M48t59SysBusState *sys = SYSBUS_M48T59(d); + M48txxSysBusState *sys = M48TXX_SYS_BUS(d); M48t59State *NVRAM = &sys->state; m48t59_reset_common(NVRAM); } -static const MemoryRegionOps m48t59_io_ops = { +const MemoryRegionOps m48t59_io_ops = { .read = NVRAM_readb, .write = NVRAM_writeb, .impl = { @@ -642,61 +597,41 @@ static const MemoryRegionOps m48t59_io_ops = { }; /* Initialisation routine */ -M48t59State *m48t59_init(qemu_irq IRQ, hwaddr mem_base, - uint32_t io_base, uint16_t size, int model) +Nvram *m48t59_init(qemu_irq IRQ, hwaddr mem_base, + uint32_t io_base, uint16_t size, int base_year, + int model) { DeviceState *dev; SysBusDevice *s; - M48t59SysBusState *d; - M48t59State *state; - - dev = qdev_create(NULL, TYPE_SYSBUS_M48T59); - qdev_prop_set_uint32(dev, "model", model); - qdev_prop_set_uint32(dev, "size", size); - qdev_prop_set_uint32(dev, "io_base", io_base); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - d = SYSBUS_M48T59(dev); - state = &d->state; - sysbus_connect_irq(s, 0, IRQ); - memory_region_init_io(&d->io, OBJECT(d), &m48t59_io_ops, state, - "m48t59", 4); - if (io_base != 0) { - memory_region_add_subregion(get_system_io(), io_base, &d->io); - } - if (mem_base != 0) { - sysbus_mmio_map(s, 0, mem_base); - } + int i; - return state; -} + for (i = 0; i < ARRAY_SIZE(m48txx_sysbus_info); i++) { + if (m48txx_sysbus_info[i].size != size || + m48txx_sysbus_info[i].model != model) { + continue; + } -M48t59State *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size, - int model) -{ - M48t59ISAState *d; - ISADevice *isadev; - DeviceState *dev; - M48t59State *s; - - isadev = isa_create(bus, TYPE_ISA_M48T59); - dev = DEVICE(isadev); - qdev_prop_set_uint32(dev, "model", model); - qdev_prop_set_uint32(dev, "size", size); - qdev_prop_set_uint32(dev, "io_base", io_base); - qdev_init_nofail(dev); - d = ISA_M48T59(isadev); - s = &d->state; - - memory_region_init_io(&d->io, OBJECT(d), &m48t59_io_ops, s, "m48t59", 4); - if (io_base != 0) { - isa_register_ioport(isadev, &d->io, io_base); + dev = qdev_create(NULL, m48txx_sysbus_info[i].bus_name); + qdev_prop_set_int32(dev, "base-year", base_year); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(s, 0, IRQ); + if (io_base != 0) { + memory_region_add_subregion(get_system_io(), io_base, + sysbus_mmio_get_region(s, 1)); + } + if (mem_base != 0) { + sysbus_mmio_map(s, 0, mem_base); + } + + return NVRAM(s); } - return s; + assert(false); + return NULL; } -static void m48t59_realize_common(M48t59State *s, Error **errp) +void m48t59_realize_common(M48t59State *s, Error **errp) { s->buffer = g_malloc0(s->size); if (s->model == 59) { @@ -704,92 +639,116 @@ static void m48t59_realize_common(M48t59State *s, Error **errp) s->wd_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &watchdog_cb, s); } qemu_get_timedate(&s->alarm, 0); - - vmstate_register(NULL, -1, &vmstate_m48t59, s); } -static void m48t59_isa_realize(DeviceState *dev, Error **errp) +static void m48t59_init1(Object *obj) { - ISADevice *isadev = ISA_DEVICE(dev); - M48t59ISAState *d = ISA_M48T59(dev); + M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_GET_CLASS(obj); + M48txxSysBusState *d = M48TXX_SYS_BUS(obj); + SysBusDevice *dev = SYS_BUS_DEVICE(obj); M48t59State *s = &d->state; - isa_init_irq(isadev, &s->IRQ, 8); - m48t59_realize_common(s, errp); + s->model = u->info.model; + s->size = u->info.size; + sysbus_init_irq(dev, &s->IRQ); + + memory_region_init_io(&s->iomem, obj, &nvram_ops, s, "m48t59.nvram", + s->size); + memory_region_init_io(&d->io, obj, &m48t59_io_ops, s, "m48t59", 4); } -static int m48t59_init1(SysBusDevice *dev) +static void m48t59_realize(DeviceState *dev, Error **errp) { - M48t59SysBusState *d = SYSBUS_M48T59(dev); + M48txxSysBusState *d = M48TXX_SYS_BUS(dev); M48t59State *s = &d->state; - Error *err = NULL; - - sysbus_init_irq(dev, &s->IRQ); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - memory_region_init_io(&s->iomem, OBJECT(d), &nvram_ops, s, - "m48t59.nvram", s->size); - sysbus_init_mmio(dev, &s->iomem); - m48t59_realize_common(s, &err); - if (err != NULL) { - error_free(err); - return -1; - } - - return 0; + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_mmio(sbd, &d->io); + m48t59_realize_common(s, errp); } -static Property m48t59_isa_properties[] = { - DEFINE_PROP_UINT32("size", M48t59ISAState, state.size, -1), - DEFINE_PROP_UINT32("model", M48t59ISAState, state.model, -1), - DEFINE_PROP_HEX32( "io_base", M48t59ISAState, state.io_base, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void m48t59_isa_class_init(ObjectClass *klass, void *data) +static uint32_t m48txx_sysbus_read(Nvram *obj, uint32_t addr) { - DeviceClass *dc = DEVICE_CLASS(klass); + M48txxSysBusState *d = M48TXX_SYS_BUS(obj); + return m48t59_read(&d->state, addr); +} - dc->realize = m48t59_isa_realize; - dc->no_user = 1; - dc->reset = m48t59_reset_isa; - dc->props = m48t59_isa_properties; +static void m48txx_sysbus_write(Nvram *obj, uint32_t addr, uint32_t val) +{ + M48txxSysBusState *d = M48TXX_SYS_BUS(obj); + m48t59_write(&d->state, addr, val); } -static const TypeInfo m48t59_isa_info = { - .name = TYPE_ISA_M48T59, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(M48t59ISAState), - .class_init = m48t59_isa_class_init, -}; +static void m48txx_sysbus_toggle_lock(Nvram *obj, int lock) +{ + M48txxSysBusState *d = M48TXX_SYS_BUS(obj); + m48t59_toggle_lock(&d->state, lock); +} -static Property m48t59_properties[] = { - DEFINE_PROP_UINT32("size", M48t59SysBusState, state.size, -1), - DEFINE_PROP_UINT32("model", M48t59SysBusState, state.model, -1), - DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base, 0), +static Property m48t59_sysbus_properties[] = { + DEFINE_PROP_INT32("base-year", M48txxSysBusState, state.base_year, 0), DEFINE_PROP_END_OF_LIST(), }; -static void m48t59_class_init(ObjectClass *klass, void *data) +static void m48txx_sysbus_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + NvramClass *nc = NVRAM_CLASS(klass); - k->init = m48t59_init1; + dc->realize = m48t59_realize; dc->reset = m48t59_reset_sysbus; - dc->props = m48t59_properties; + dc->props = m48t59_sysbus_properties; + dc->vmsd = &vmstate_m48t59; + nc->read = m48txx_sysbus_read; + nc->write = m48txx_sysbus_write; + nc->toggle_lock = m48txx_sysbus_toggle_lock; } -static const TypeInfo m48t59_info = { - .name = TYPE_SYSBUS_M48T59, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(M48t59SysBusState), - .class_init = m48t59_class_init, +static void m48txx_sysbus_concrete_class_init(ObjectClass *klass, void *data) +{ + M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_CLASS(klass); + M48txxInfo *info = data; + + u->info = *info; +} + +static const TypeInfo nvram_info = { + .name = TYPE_NVRAM, + .parent = TYPE_INTERFACE, + .class_size = sizeof(NvramClass), +}; + +static const TypeInfo m48txx_sysbus_type_info = { + .name = TYPE_M48TXX_SYS_BUS, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(M48txxSysBusState), + .instance_init = m48t59_init1, + .abstract = true, + .class_init = m48txx_sysbus_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_NVRAM }, + { } + } }; static void m48t59_register_types(void) { - type_register_static(&m48t59_info); - type_register_static(&m48t59_isa_info); + TypeInfo sysbus_type_info = { + .parent = TYPE_M48TXX_SYS_BUS, + .class_size = sizeof(M48txxSysBusDeviceClass), + .class_init = m48txx_sysbus_concrete_class_init, + }; + int i; + + type_register_static(&nvram_info); + type_register_static(&m48txx_sysbus_type_info); + + for (i = 0; i < ARRAY_SIZE(m48txx_sysbus_info); i++) { + sysbus_type_info.name = m48txx_sysbus_info[i].bus_name; + sysbus_type_info.class_data = &m48txx_sysbus_info[i]; + type_register(&sysbus_type_info); + } } type_init(m48t59_register_types)