1 /* 2 * QEMU Eyetech AmigaOne/Mai Logic Teron emulation 3 * 4 * Copyright (c) 2023 BALATON Zoltan 5 * 6 * This work is licensed under the GNU GPL license version 2 or later. 7 * 8 */ 9 10 #include "qemu/osdep.h" 11 #include "qemu/units.h" 12 #include "qemu/datadir.h" 13 #include "qemu/log.h" 14 #include "qemu/error-report.h" 15 #include "qapi/error.h" 16 #include "hw/ppc/ppc.h" 17 #include "hw/boards.h" 18 #include "hw/loader.h" 19 #include "hw/pci-host/articia.h" 20 #include "hw/isa/vt82c686.h" 21 #include "hw/ide/pci.h" 22 #include "hw/i2c/smbus_eeprom.h" 23 #include "hw/ppc/ppc.h" 24 #include "system/block-backend.h" 25 #include "system/qtest.h" 26 #include "system/reset.h" 27 #include "kvm_ppc.h" 28 29 #include <zlib.h> /* for crc32 */ 30 31 #define BUS_FREQ_HZ 100000000 32 33 /* 34 * Firmware binary available at 35 * https://www.hyperion-entertainment.com/index.php/downloads?view=files&parent=28 36 * then "tail -c 524288 updater.image >u-boot-amigaone.bin" 37 * 38 * BIOS emulator in firmware cannot run QEMU vgabios and hangs on it, use 39 * -device VGA,romfile=VGABIOS-lgpl-latest.bin 40 * from http://www.nongnu.org/vgabios/ instead. 41 */ 42 #define PROM_ADDR 0xfff00000 43 #define PROM_SIZE (512 * KiB) 44 45 /* AmigaOS calls this routine from ROM, use this if no firmware loaded */ 46 static const char dummy_fw[] = { 47 0x54, 0x63, 0xc2, 0x3e, /* srwi r3,r3,8 */ 48 0x7c, 0x63, 0x18, 0xf8, /* not r3,r3 */ 49 0x4e, 0x80, 0x00, 0x20, /* blr */ 50 }; 51 52 #define NVRAM_ADDR 0xfd0e0000 53 #define NVRAM_SIZE (4 * KiB) 54 55 #define TYPE_A1_NVRAM "a1-nvram" 56 OBJECT_DECLARE_SIMPLE_TYPE(A1NVRAMState, A1_NVRAM) 57 58 struct A1NVRAMState { 59 SysBusDevice parent_obj; 60 61 MemoryRegion mr; 62 BlockBackend *blk; 63 }; 64 65 static uint64_t nvram_read(void *opaque, hwaddr addr, unsigned int size) 66 { 67 /* read callback not used because of romd mode */ 68 g_assert_not_reached(); 69 } 70 71 static void nvram_write(void *opaque, hwaddr addr, uint64_t val, 72 unsigned int size) 73 { 74 A1NVRAMState *s = opaque; 75 uint8_t *p = memory_region_get_ram_ptr(&s->mr); 76 77 p[addr] = val; 78 if (s->blk) { 79 blk_pwrite(s->blk, addr, 1, &val, 0); 80 } 81 } 82 83 static const MemoryRegionOps nvram_ops = { 84 .read = nvram_read, 85 .write = nvram_write, 86 .endianness = DEVICE_BIG_ENDIAN, 87 .impl = { 88 .min_access_size = 1, 89 .max_access_size = 1, 90 }, 91 }; 92 93 static void nvram_realize(DeviceState *dev, Error **errp) 94 { 95 A1NVRAMState *s = A1_NVRAM(dev); 96 void *p; 97 uint32_t *c; 98 99 memory_region_init_rom_device(&s->mr, NULL, &nvram_ops, s, "nvram", 100 NVRAM_SIZE, &error_fatal); 101 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); 102 c = p = memory_region_get_ram_ptr(&s->mr); 103 if (s->blk) { 104 if (blk_getlength(s->blk) != NVRAM_SIZE) { 105 error_setg(errp, "NVRAM backing file size must be %" PRId64 "bytes", 106 NVRAM_SIZE); 107 return; 108 } 109 blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, 110 BLK_PERM_ALL, &error_fatal); 111 if (blk_pread(s->blk, 0, NVRAM_SIZE, p, 0) < 0) { 112 error_setg(errp, "Cannot read NVRAM contents from backing file"); 113 return; 114 } 115 } 116 if (*c == 0) { 117 *c = cpu_to_be32(crc32(0, p + 4, NVRAM_SIZE - 4)); 118 if (s->blk) { 119 blk_pwrite(s->blk, 0, 4, p, 0); 120 } 121 } 122 } 123 124 static const Property nvram_properties[] = { 125 DEFINE_PROP_DRIVE("drive", A1NVRAMState, blk), 126 }; 127 128 static void nvram_class_init(ObjectClass *oc, void *data) 129 { 130 DeviceClass *dc = DEVICE_CLASS(oc); 131 132 dc->realize = nvram_realize; 133 device_class_set_props(dc, nvram_properties); 134 } 135 136 static const TypeInfo nvram_types[] = { 137 { 138 .name = TYPE_A1_NVRAM, 139 .parent = TYPE_SYS_BUS_DEVICE, 140 .instance_size = sizeof(A1NVRAMState), 141 .class_init = nvram_class_init, 142 }, 143 }; 144 DEFINE_TYPES(nvram_types) 145 146 static void amigaone_cpu_reset(void *opaque) 147 { 148 PowerPCCPU *cpu = opaque; 149 150 cpu_reset(CPU(cpu)); 151 cpu_ppc_tb_reset(&cpu->env); 152 } 153 154 static void fix_spd_data(uint8_t *spd) 155 { 156 uint32_t bank_size = 4 * MiB * spd[31]; 157 uint32_t rows = bank_size / spd[13] / spd[17]; 158 spd[3] = ctz32(rows) - spd[4]; 159 } 160 161 static void amigaone_init(MachineState *machine) 162 { 163 PowerPCCPU *cpu; 164 CPUPPCState *env; 165 MemoryRegion *rom, *pci_mem, *mr; 166 ssize_t sz; 167 PCIBus *pci_bus; 168 Object *via; 169 DeviceState *dev; 170 I2CBus *i2c_bus; 171 uint8_t *spd_data; 172 DriveInfo *di; 173 174 /* init CPU */ 175 cpu = POWERPC_CPU(cpu_create(machine->cpu_type)); 176 env = &cpu->env; 177 if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) { 178 error_report("Incompatible CPU, only 6xx bus supported"); 179 exit(1); 180 } 181 cpu_ppc_tb_init(env, BUS_FREQ_HZ / 4); 182 qemu_register_reset(amigaone_cpu_reset, cpu); 183 184 /* RAM */ 185 if (machine->ram_size > 2 * GiB) { 186 error_report("RAM size more than 2 GiB is not supported"); 187 exit(1); 188 } 189 memory_region_add_subregion(get_system_memory(), 0, machine->ram); 190 if (machine->ram_size < 1 * GiB + 32 * KiB) { 191 /* Firmware uses this area for startup */ 192 mr = g_new(MemoryRegion, 1); 193 memory_region_init_ram(mr, NULL, "init-cache", 32 * KiB, &error_fatal); 194 memory_region_add_subregion(get_system_memory(), 0x40000000, mr); 195 } 196 197 /* nvram */ 198 dev = qdev_new(TYPE_A1_NVRAM); 199 di = drive_get(IF_MTD, 0, 0); 200 if (di) { 201 qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(di)); 202 } 203 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 204 memory_region_add_subregion(get_system_memory(), NVRAM_ADDR, 205 sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); 206 207 /* allocate and load firmware */ 208 rom = g_new(MemoryRegion, 1); 209 memory_region_init_rom(rom, NULL, "rom", PROM_SIZE, &error_fatal); 210 memory_region_add_subregion(get_system_memory(), PROM_ADDR, rom); 211 if (!machine->firmware) { 212 rom_add_blob_fixed("dummy-fw", dummy_fw, sizeof(dummy_fw), 213 PROM_ADDR + PROM_SIZE - 0x80); 214 } else { 215 g_autofree char *filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, 216 machine->firmware); 217 if (!filename) { 218 error_report("Could not find firmware '%s'", machine->firmware); 219 exit(1); 220 } 221 sz = load_image_targphys(filename, PROM_ADDR, PROM_SIZE); 222 if (sz <= 0 || sz > PROM_SIZE) { 223 error_report("Could not load firmware '%s'", filename); 224 exit(1); 225 } 226 } 227 228 /* Articia S */ 229 dev = sysbus_create_simple(TYPE_ARTICIA, 0xfe000000, NULL); 230 231 i2c_bus = I2C_BUS(qdev_get_child_bus(dev, "smbus")); 232 if (machine->ram_size > 512 * MiB) { 233 spd_data = spd_data_generate(SDR, machine->ram_size / 2); 234 } else { 235 spd_data = spd_data_generate(SDR, machine->ram_size); 236 } 237 fix_spd_data(spd_data); 238 smbus_eeprom_init_one(i2c_bus, 0x51, spd_data); 239 if (machine->ram_size > 512 * MiB) { 240 smbus_eeprom_init_one(i2c_bus, 0x52, spd_data); 241 } 242 243 pci_mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); 244 mr = g_new(MemoryRegion, 1); 245 memory_region_init_alias(mr, OBJECT(dev), "pci-mem-low", pci_mem, 246 0, 0xe0000); 247 memory_region_add_subregion(get_system_memory(), 0xfd000000, mr); 248 mr = g_new(MemoryRegion, 1); 249 memory_region_init_alias(mr, OBJECT(dev), "pci-mem-high", pci_mem, 250 0x80000000, 0x7d000000); 251 memory_region_add_subregion(get_system_memory(), 0x80000000, mr); 252 pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0")); 253 254 /* VIA VT82c686B South Bridge (multifunction PCI device) */ 255 via = OBJECT(pci_create_simple_multifunction(pci_bus, PCI_DEVFN(7, 0), 256 TYPE_VT82C686B_ISA)); 257 object_property_add_alias(OBJECT(machine), "rtc-time", 258 object_resolve_path_component(via, "rtc"), 259 "date"); 260 qdev_connect_gpio_out_named(DEVICE(via), "intr", 0, 261 qdev_get_gpio_in(DEVICE(cpu), 262 PPC6xx_INPUT_INT)); 263 for (int i = 0; i < PCI_NUM_PINS; i++) { 264 qdev_connect_gpio_out(dev, i, qdev_get_gpio_in_named(DEVICE(via), 265 "pirq", i)); 266 } 267 pci_ide_create_devs(PCI_DEVICE(object_resolve_path_component(via, "ide"))); 268 pci_vga_init(pci_bus); 269 } 270 271 static void amigaone_machine_init(MachineClass *mc) 272 { 273 mc->desc = "Eyetech AmigaOne/Mai Logic Teron"; 274 mc->init = amigaone_init; 275 mc->block_default_type = IF_IDE; 276 mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("7457_v1.2"); 277 mc->default_display = "std"; 278 mc->default_ram_id = "ram"; 279 mc->default_ram_size = 512 * MiB; 280 } 281 282 DEFINE_MACHINE("amigaone", amigaone_machine_init) 283