| 
									
										
										
										
											2023-10-04 09:37:51 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     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, | 
					
						
							| 
									
										
										
										
											2023-12-21 14:16:21 +11:00
										 |  |  |     .fields = (const VMStateField[]) { | 
					
						
							| 
									
										
										
										
											2023-10-04 09:37:51 +01:00
										 |  |  |         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) |