/* * QEMU IOSB emulation * * Copyright (c) 2019 Laurent Vivier * Copyright (c) 2022 Mark Cave-Ayland * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "qemu/osdep.h" #include "qemu/log.h" #include "migration/vmstate.h" #include "hw/sysbus.h" #include "hw/misc/iosb.h" #include "trace.h" #define IOSB_SIZE 0x2000 #define IOSB_CONFIG 0x0 #define IOSB_CONFIG2 0x100 #define IOSB_SONIC_SCSI 0x200 #define IOSB_REVISION 0x300 #define IOSB_SCSI_RESID 0x400 #define IOSB_BRIGHTNESS 0x500 #define IOSB_TIMEOUT 0x600 static uint64_t iosb_read(void *opaque, hwaddr addr, unsigned size) { IOSBState *s = IOSB(opaque); uint64_t val = 0; switch (addr) { case IOSB_CONFIG: case IOSB_CONFIG2: case IOSB_SONIC_SCSI: case IOSB_REVISION: case IOSB_SCSI_RESID: case IOSB_BRIGHTNESS: case IOSB_TIMEOUT: val = s->regs[addr >> 8]; break; default: qemu_log_mask(LOG_UNIMP, "IOSB: unimplemented read addr=0x%"PRIx64 " val=0x%"PRIx64 " size=%d\n", addr, val, size); } trace_iosb_read(addr, val, size); return val; } static void iosb_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { IOSBState *s = IOSB(opaque); switch (addr) { case IOSB_CONFIG: case IOSB_CONFIG2: case IOSB_SONIC_SCSI: case IOSB_REVISION: case IOSB_SCSI_RESID: case IOSB_BRIGHTNESS: case IOSB_TIMEOUT: s->regs[addr >> 8] = val; break; default: qemu_log_mask(LOG_UNIMP, "IOSB: unimplemented write addr=0x%"PRIx64 " val=0x%"PRIx64 " size=%d\n", addr, val, size); } trace_iosb_write(addr, val, size); } static const MemoryRegionOps iosb_mmio_ops = { .read = iosb_read, .write = iosb_write, .endianness = DEVICE_BIG_ENDIAN, }; static void iosb_reset_hold(Object *obj, ResetType type) { IOSBState *s = IOSB(obj); memset(s->regs, 0, sizeof(s->regs)); /* BCLK 33 MHz */ s->regs[IOSB_CONFIG >> 8] = 1; } static void iosb_init(Object *obj) { IOSBState *s = IOSB(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); memory_region_init_io(&s->mem_regs, obj, &iosb_mmio_ops, s, "IOSB", IOSB_SIZE); sysbus_init_mmio(sbd, &s->mem_regs); } static const VMStateDescription vmstate_iosb = { .name = "IOSB", .version_id = 1, .minimum_version_id = 1, .fields = (const VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, IOSBState, IOSB_REGS), VMSTATE_END_OF_LIST() } }; static void iosb_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); ResettableClass *rc = RESETTABLE_CLASS(oc); dc->vmsd = &vmstate_iosb; rc->phases.hold = iosb_reset_hold; } static const TypeInfo iosb_info_types[] = { { .name = TYPE_IOSB, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IOSBState), .instance_init = iosb_init, .class_init = iosb_class_init, }, }; DEFINE_TYPES(iosb_info_types)