1*fa2ba3b8SLaurent Vivier /* 2*fa2ba3b8SLaurent Vivier * QEMU Macintosh Nubus 3*fa2ba3b8SLaurent Vivier * 4*fa2ba3b8SLaurent Vivier * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu> 5*fa2ba3b8SLaurent Vivier * 6*fa2ba3b8SLaurent Vivier * This work is licensed under the terms of the GNU GPL, version 2 or later. 7*fa2ba3b8SLaurent Vivier * See the COPYING file in the top-level directory. 8*fa2ba3b8SLaurent Vivier * 9*fa2ba3b8SLaurent Vivier */ 10*fa2ba3b8SLaurent Vivier 11*fa2ba3b8SLaurent Vivier #include "qemu/osdep.h" 12*fa2ba3b8SLaurent Vivier #include "hw/nubus/nubus.h" 13*fa2ba3b8SLaurent Vivier #include "qapi/error.h" 14*fa2ba3b8SLaurent Vivier 15*fa2ba3b8SLaurent Vivier 16*fa2ba3b8SLaurent Vivier /* The Format Block Structure */ 17*fa2ba3b8SLaurent Vivier 18*fa2ba3b8SLaurent Vivier #define FBLOCK_DIRECTORY_OFFSET 0 19*fa2ba3b8SLaurent Vivier #define FBLOCK_LENGTH 4 20*fa2ba3b8SLaurent Vivier #define FBLOCK_CRC 8 21*fa2ba3b8SLaurent Vivier #define FBLOCK_REVISION_LEVEL 12 22*fa2ba3b8SLaurent Vivier #define FBLOCK_FORMAT 13 23*fa2ba3b8SLaurent Vivier #define FBLOCK_TEST_PATTERN 14 24*fa2ba3b8SLaurent Vivier #define FBLOCK_RESERVED 18 25*fa2ba3b8SLaurent Vivier #define FBLOCK_BYTE_LANES 19 26*fa2ba3b8SLaurent Vivier 27*fa2ba3b8SLaurent Vivier #define FBLOCK_SIZE 20 28*fa2ba3b8SLaurent Vivier #define FBLOCK_PATTERN_VAL 0x5a932bc7 29*fa2ba3b8SLaurent Vivier 30*fa2ba3b8SLaurent Vivier static uint64_t nubus_fblock_read(void *opaque, hwaddr addr, unsigned int size) 31*fa2ba3b8SLaurent Vivier { 32*fa2ba3b8SLaurent Vivier NubusDevice *dev = opaque; 33*fa2ba3b8SLaurent Vivier uint64_t val; 34*fa2ba3b8SLaurent Vivier 35*fa2ba3b8SLaurent Vivier #define BYTE(v, b) (((v) >> (24 - 8 * (b))) & 0xff) 36*fa2ba3b8SLaurent Vivier switch (addr) { 37*fa2ba3b8SLaurent Vivier case FBLOCK_BYTE_LANES: 38*fa2ba3b8SLaurent Vivier val = dev->byte_lanes; 39*fa2ba3b8SLaurent Vivier val |= (val ^ 0xf) << 4; 40*fa2ba3b8SLaurent Vivier break; 41*fa2ba3b8SLaurent Vivier case FBLOCK_RESERVED: 42*fa2ba3b8SLaurent Vivier val = 0x00; 43*fa2ba3b8SLaurent Vivier break; 44*fa2ba3b8SLaurent Vivier case FBLOCK_TEST_PATTERN...FBLOCK_TEST_PATTERN + 3: 45*fa2ba3b8SLaurent Vivier val = BYTE(FBLOCK_PATTERN_VAL, addr - FBLOCK_TEST_PATTERN); 46*fa2ba3b8SLaurent Vivier break; 47*fa2ba3b8SLaurent Vivier case FBLOCK_FORMAT: 48*fa2ba3b8SLaurent Vivier val = dev->rom_format; 49*fa2ba3b8SLaurent Vivier break; 50*fa2ba3b8SLaurent Vivier case FBLOCK_REVISION_LEVEL: 51*fa2ba3b8SLaurent Vivier val = dev->rom_rev; 52*fa2ba3b8SLaurent Vivier break; 53*fa2ba3b8SLaurent Vivier case FBLOCK_CRC...FBLOCK_CRC + 3: 54*fa2ba3b8SLaurent Vivier val = BYTE(dev->rom_crc, addr - FBLOCK_CRC); 55*fa2ba3b8SLaurent Vivier break; 56*fa2ba3b8SLaurent Vivier case FBLOCK_LENGTH...FBLOCK_LENGTH + 3: 57*fa2ba3b8SLaurent Vivier val = BYTE(dev->rom_length, addr - FBLOCK_LENGTH); 58*fa2ba3b8SLaurent Vivier break; 59*fa2ba3b8SLaurent Vivier case FBLOCK_DIRECTORY_OFFSET...FBLOCK_DIRECTORY_OFFSET + 3: 60*fa2ba3b8SLaurent Vivier val = BYTE(dev->directory_offset, addr - FBLOCK_DIRECTORY_OFFSET); 61*fa2ba3b8SLaurent Vivier break; 62*fa2ba3b8SLaurent Vivier default: 63*fa2ba3b8SLaurent Vivier val = 0; 64*fa2ba3b8SLaurent Vivier break; 65*fa2ba3b8SLaurent Vivier } 66*fa2ba3b8SLaurent Vivier return val; 67*fa2ba3b8SLaurent Vivier } 68*fa2ba3b8SLaurent Vivier 69*fa2ba3b8SLaurent Vivier static void nubus_fblock_write(void *opaque, hwaddr addr, uint64_t val, 70*fa2ba3b8SLaurent Vivier unsigned int size) 71*fa2ba3b8SLaurent Vivier { 72*fa2ba3b8SLaurent Vivier /* read only */ 73*fa2ba3b8SLaurent Vivier } 74*fa2ba3b8SLaurent Vivier 75*fa2ba3b8SLaurent Vivier static const MemoryRegionOps nubus_format_block_ops = { 76*fa2ba3b8SLaurent Vivier .read = nubus_fblock_read, 77*fa2ba3b8SLaurent Vivier .write = nubus_fblock_write, 78*fa2ba3b8SLaurent Vivier .endianness = DEVICE_BIG_ENDIAN, 79*fa2ba3b8SLaurent Vivier .valid = { 80*fa2ba3b8SLaurent Vivier .min_access_size = 1, 81*fa2ba3b8SLaurent Vivier .max_access_size = 1, 82*fa2ba3b8SLaurent Vivier } 83*fa2ba3b8SLaurent Vivier }; 84*fa2ba3b8SLaurent Vivier 85*fa2ba3b8SLaurent Vivier static void nubus_register_format_block(NubusDevice *dev) 86*fa2ba3b8SLaurent Vivier { 87*fa2ba3b8SLaurent Vivier char *fblock_name; 88*fa2ba3b8SLaurent Vivier 89*fa2ba3b8SLaurent Vivier fblock_name = g_strdup_printf("nubus-slot-%d-format-block", 90*fa2ba3b8SLaurent Vivier dev->slot_nb); 91*fa2ba3b8SLaurent Vivier 92*fa2ba3b8SLaurent Vivier hwaddr fblock_offset = memory_region_size(&dev->slot_mem) - FBLOCK_SIZE; 93*fa2ba3b8SLaurent Vivier memory_region_init_io(&dev->fblock_io, NULL, &nubus_format_block_ops, 94*fa2ba3b8SLaurent Vivier dev, fblock_name, FBLOCK_SIZE); 95*fa2ba3b8SLaurent Vivier memory_region_add_subregion(&dev->slot_mem, fblock_offset, 96*fa2ba3b8SLaurent Vivier &dev->fblock_io); 97*fa2ba3b8SLaurent Vivier 98*fa2ba3b8SLaurent Vivier g_free(fblock_name); 99*fa2ba3b8SLaurent Vivier } 100*fa2ba3b8SLaurent Vivier 101*fa2ba3b8SLaurent Vivier static void mac_nubus_rom_write(void *opaque, hwaddr addr, uint64_t val, 102*fa2ba3b8SLaurent Vivier unsigned int size) 103*fa2ba3b8SLaurent Vivier { 104*fa2ba3b8SLaurent Vivier /* read only */ 105*fa2ba3b8SLaurent Vivier } 106*fa2ba3b8SLaurent Vivier 107*fa2ba3b8SLaurent Vivier static uint64_t mac_nubus_rom_read(void *opaque, hwaddr addr, 108*fa2ba3b8SLaurent Vivier unsigned int size) 109*fa2ba3b8SLaurent Vivier { 110*fa2ba3b8SLaurent Vivier NubusDevice *dev = opaque; 111*fa2ba3b8SLaurent Vivier 112*fa2ba3b8SLaurent Vivier return dev->rom[addr]; 113*fa2ba3b8SLaurent Vivier } 114*fa2ba3b8SLaurent Vivier 115*fa2ba3b8SLaurent Vivier static const MemoryRegionOps mac_nubus_rom_ops = { 116*fa2ba3b8SLaurent Vivier .read = mac_nubus_rom_read, 117*fa2ba3b8SLaurent Vivier .write = mac_nubus_rom_write, 118*fa2ba3b8SLaurent Vivier .endianness = DEVICE_BIG_ENDIAN, 119*fa2ba3b8SLaurent Vivier .valid = { 120*fa2ba3b8SLaurent Vivier .min_access_size = 1, 121*fa2ba3b8SLaurent Vivier .max_access_size = 1, 122*fa2ba3b8SLaurent Vivier }, 123*fa2ba3b8SLaurent Vivier }; 124*fa2ba3b8SLaurent Vivier 125*fa2ba3b8SLaurent Vivier 126*fa2ba3b8SLaurent Vivier void nubus_register_rom(NubusDevice *dev, const uint8_t *rom, uint32_t size, 127*fa2ba3b8SLaurent Vivier int revision, int format, uint8_t byte_lanes) 128*fa2ba3b8SLaurent Vivier { 129*fa2ba3b8SLaurent Vivier hwaddr rom_offset; 130*fa2ba3b8SLaurent Vivier char *rom_name; 131*fa2ba3b8SLaurent Vivier 132*fa2ba3b8SLaurent Vivier /* FIXME : really compute CRC */ 133*fa2ba3b8SLaurent Vivier dev->rom_length = 0; 134*fa2ba3b8SLaurent Vivier dev->rom_crc = 0; 135*fa2ba3b8SLaurent Vivier 136*fa2ba3b8SLaurent Vivier dev->rom_rev = revision; 137*fa2ba3b8SLaurent Vivier dev->rom_format = format; 138*fa2ba3b8SLaurent Vivier 139*fa2ba3b8SLaurent Vivier dev->byte_lanes = byte_lanes; 140*fa2ba3b8SLaurent Vivier dev->directory_offset = -size; 141*fa2ba3b8SLaurent Vivier 142*fa2ba3b8SLaurent Vivier /* ROM */ 143*fa2ba3b8SLaurent Vivier 144*fa2ba3b8SLaurent Vivier dev->rom = rom; 145*fa2ba3b8SLaurent Vivier rom_name = g_strdup_printf("nubus-slot-%d-rom", dev->slot_nb); 146*fa2ba3b8SLaurent Vivier memory_region_init_io(&dev->rom_io, NULL, &mac_nubus_rom_ops, 147*fa2ba3b8SLaurent Vivier dev, rom_name, size); 148*fa2ba3b8SLaurent Vivier memory_region_set_readonly(&dev->rom_io, true); 149*fa2ba3b8SLaurent Vivier 150*fa2ba3b8SLaurent Vivier rom_offset = memory_region_size(&dev->slot_mem) - FBLOCK_SIZE + 151*fa2ba3b8SLaurent Vivier dev->directory_offset; 152*fa2ba3b8SLaurent Vivier memory_region_add_subregion(&dev->slot_mem, rom_offset, &dev->rom_io); 153*fa2ba3b8SLaurent Vivier 154*fa2ba3b8SLaurent Vivier g_free(rom_name); 155*fa2ba3b8SLaurent Vivier } 156*fa2ba3b8SLaurent Vivier 157*fa2ba3b8SLaurent Vivier static void nubus_device_realize(DeviceState *dev, Error **errp) 158*fa2ba3b8SLaurent Vivier { 159*fa2ba3b8SLaurent Vivier NubusBus *nubus = NUBUS_BUS(qdev_get_parent_bus(DEVICE(dev))); 160*fa2ba3b8SLaurent Vivier NubusDevice *nd = NUBUS_DEVICE(dev); 161*fa2ba3b8SLaurent Vivier char *name; 162*fa2ba3b8SLaurent Vivier hwaddr slot_offset; 163*fa2ba3b8SLaurent Vivier 164*fa2ba3b8SLaurent Vivier if (nubus->current_slot < NUBUS_FIRST_SLOT || 165*fa2ba3b8SLaurent Vivier nubus->current_slot > NUBUS_LAST_SLOT) { 166*fa2ba3b8SLaurent Vivier error_setg(errp, "Cannot register nubus card, not enough slots"); 167*fa2ba3b8SLaurent Vivier return; 168*fa2ba3b8SLaurent Vivier } 169*fa2ba3b8SLaurent Vivier 170*fa2ba3b8SLaurent Vivier nd->slot_nb = nubus->current_slot++; 171*fa2ba3b8SLaurent Vivier name = g_strdup_printf("nubus-slot-%d", nd->slot_nb); 172*fa2ba3b8SLaurent Vivier 173*fa2ba3b8SLaurent Vivier if (nd->slot_nb < NUBUS_FIRST_SLOT) { 174*fa2ba3b8SLaurent Vivier /* Super */ 175*fa2ba3b8SLaurent Vivier slot_offset = (nd->slot_nb - 6) * NUBUS_SUPER_SLOT_SIZE; 176*fa2ba3b8SLaurent Vivier 177*fa2ba3b8SLaurent Vivier memory_region_init(&nd->slot_mem, OBJECT(dev), name, 178*fa2ba3b8SLaurent Vivier NUBUS_SUPER_SLOT_SIZE); 179*fa2ba3b8SLaurent Vivier memory_region_add_subregion(&nubus->super_slot_io, slot_offset, 180*fa2ba3b8SLaurent Vivier &nd->slot_mem); 181*fa2ba3b8SLaurent Vivier } else { 182*fa2ba3b8SLaurent Vivier /* Normal */ 183*fa2ba3b8SLaurent Vivier slot_offset = nd->slot_nb * NUBUS_SLOT_SIZE; 184*fa2ba3b8SLaurent Vivier 185*fa2ba3b8SLaurent Vivier memory_region_init(&nd->slot_mem, OBJECT(dev), name, NUBUS_SLOT_SIZE); 186*fa2ba3b8SLaurent Vivier memory_region_add_subregion(&nubus->slot_io, slot_offset, 187*fa2ba3b8SLaurent Vivier &nd->slot_mem); 188*fa2ba3b8SLaurent Vivier } 189*fa2ba3b8SLaurent Vivier 190*fa2ba3b8SLaurent Vivier g_free(name); 191*fa2ba3b8SLaurent Vivier nubus_register_format_block(nd); 192*fa2ba3b8SLaurent Vivier } 193*fa2ba3b8SLaurent Vivier 194*fa2ba3b8SLaurent Vivier static void nubus_device_class_init(ObjectClass *oc, void *data) 195*fa2ba3b8SLaurent Vivier { 196*fa2ba3b8SLaurent Vivier DeviceClass *dc = DEVICE_CLASS(oc); 197*fa2ba3b8SLaurent Vivier 198*fa2ba3b8SLaurent Vivier dc->realize = nubus_device_realize; 199*fa2ba3b8SLaurent Vivier dc->bus_type = TYPE_NUBUS_BUS; 200*fa2ba3b8SLaurent Vivier } 201*fa2ba3b8SLaurent Vivier 202*fa2ba3b8SLaurent Vivier static const TypeInfo nubus_device_type_info = { 203*fa2ba3b8SLaurent Vivier .name = TYPE_NUBUS_DEVICE, 204*fa2ba3b8SLaurent Vivier .parent = TYPE_DEVICE, 205*fa2ba3b8SLaurent Vivier .abstract = true, 206*fa2ba3b8SLaurent Vivier .instance_size = sizeof(NubusDevice), 207*fa2ba3b8SLaurent Vivier .class_init = nubus_device_class_init, 208*fa2ba3b8SLaurent Vivier }; 209*fa2ba3b8SLaurent Vivier 210*fa2ba3b8SLaurent Vivier static void nubus_register_types(void) 211*fa2ba3b8SLaurent Vivier { 212*fa2ba3b8SLaurent Vivier type_register_static(&nubus_device_type_info); 213*fa2ba3b8SLaurent Vivier } 214*fa2ba3b8SLaurent Vivier 215*fa2ba3b8SLaurent Vivier type_init(nubus_register_types) 216