1376b8519SHelge Deller /* 2376b8519SHelge Deller * HP-PARISC Lasi chipset emulation. 3376b8519SHelge Deller * 4376b8519SHelge Deller * (C) 2019 by Helge Deller <deller@gmx.de> 5376b8519SHelge Deller * 6376b8519SHelge Deller * This work is licensed under the GNU GPL license version 2 or later. 7376b8519SHelge Deller * 8376b8519SHelge Deller * Documentation available at: 9376b8519SHelge Deller * https://parisc.wiki.kernel.org/images-parisc/7/79/Lasi_ers.pdf 10376b8519SHelge Deller */ 11376b8519SHelge Deller 12376b8519SHelge Deller #include "qemu/osdep.h" 13376b8519SHelge Deller #include "qemu/units.h" 14b899fe41SHelge Deller #include "qemu/log.h" 15376b8519SHelge Deller #include "qapi/error.h" 16376b8519SHelge Deller #include "trace.h" 17376b8519SHelge Deller #include "hw/irq.h" 18376b8519SHelge Deller #include "sysemu/sysemu.h" 19376b8519SHelge Deller #include "sysemu/runstate.h" 20376b8519SHelge Deller #include "migration/vmstate.h" 21db1015e9SEduardo Habkost #include "qom/object.h" 2245f569a1SMark Cave-Ayland #include "hw/misc/lasi.h" 23376b8519SHelge Deller 24376b8519SHelge Deller 25376b8519SHelge Deller static bool lasi_chip_mem_valid(void *opaque, hwaddr addr, 26376b8519SHelge Deller unsigned size, bool is_write, 27376b8519SHelge Deller MemTxAttrs attrs) 28376b8519SHelge Deller { 29376b8519SHelge Deller bool ret = false; 30376b8519SHelge Deller 31376b8519SHelge Deller switch (addr) { 32376b8519SHelge Deller case LASI_IRR: 33376b8519SHelge Deller case LASI_IMR: 34376b8519SHelge Deller case LASI_IPR: 35376b8519SHelge Deller case LASI_ICR: 36376b8519SHelge Deller case LASI_IAR: 37376b8519SHelge Deller 38ca7b468bSMark Cave-Ayland case LASI_LPT: 39*32d26ea4SHelge Deller case LASI_AUDIO: 40*32d26ea4SHelge Deller case LASI_AUDIO + 4: 41ca7b468bSMark Cave-Ayland case LASI_UART: 42ca7b468bSMark Cave-Ayland case LASI_LAN: 43f2ffd6fbSHelge Deller case LASI_LAN + 12: /* LASI LAN MAC */ 44ca7b468bSMark Cave-Ayland case LASI_RTC: 45*32d26ea4SHelge Deller case LASI_FDC: 46376b8519SHelge Deller 47376b8519SHelge Deller case LASI_PCR ... LASI_AMR: 48376b8519SHelge Deller ret = true; 49376b8519SHelge Deller } 50376b8519SHelge Deller 51376b8519SHelge Deller trace_lasi_chip_mem_valid(addr, ret); 52376b8519SHelge Deller return ret; 53376b8519SHelge Deller } 54376b8519SHelge Deller 55376b8519SHelge Deller static MemTxResult lasi_chip_read_with_attrs(void *opaque, hwaddr addr, 56376b8519SHelge Deller uint64_t *data, unsigned size, 57376b8519SHelge Deller MemTxAttrs attrs) 58376b8519SHelge Deller { 59376b8519SHelge Deller LasiState *s = opaque; 60376b8519SHelge Deller MemTxResult ret = MEMTX_OK; 61376b8519SHelge Deller uint32_t val; 62376b8519SHelge Deller 63376b8519SHelge Deller switch (addr) { 64376b8519SHelge Deller case LASI_IRR: 65376b8519SHelge Deller val = s->irr; 66376b8519SHelge Deller break; 67376b8519SHelge Deller case LASI_IMR: 68376b8519SHelge Deller val = s->imr; 69376b8519SHelge Deller break; 70376b8519SHelge Deller case LASI_IPR: 71376b8519SHelge Deller val = s->ipr; 72376b8519SHelge Deller /* Any read to IPR clears the register. */ 73376b8519SHelge Deller s->ipr = 0; 74376b8519SHelge Deller break; 75376b8519SHelge Deller case LASI_ICR: 76376b8519SHelge Deller val = s->icr & ICR_BUS_ERROR_BIT; /* bus_error */ 77376b8519SHelge Deller break; 78376b8519SHelge Deller case LASI_IAR: 79376b8519SHelge Deller val = s->iar; 80376b8519SHelge Deller break; 81376b8519SHelge Deller 82ca7b468bSMark Cave-Ayland case LASI_LPT: 83ca7b468bSMark Cave-Ayland case LASI_UART: 84ca7b468bSMark Cave-Ayland case LASI_LAN: 85f2ffd6fbSHelge Deller case LASI_LAN + 12: 86*32d26ea4SHelge Deller case LASI_FDC: 87376b8519SHelge Deller val = 0; 88376b8519SHelge Deller break; 89ca7b468bSMark Cave-Ayland case LASI_RTC: 90376b8519SHelge Deller val = time(NULL); 91376b8519SHelge Deller val += s->rtc_ref; 92376b8519SHelge Deller break; 93376b8519SHelge Deller 94376b8519SHelge Deller case LASI_PCR: 95376b8519SHelge Deller case LASI_VER: /* only version 0 existed. */ 96376b8519SHelge Deller case LASI_IORESET: 97376b8519SHelge Deller val = 0; 98376b8519SHelge Deller break; 99376b8519SHelge Deller case LASI_ERRLOG: 100376b8519SHelge Deller val = s->errlog; 101376b8519SHelge Deller break; 102376b8519SHelge Deller case LASI_AMR: 103376b8519SHelge Deller val = s->amr; 104376b8519SHelge Deller break; 105376b8519SHelge Deller 106376b8519SHelge Deller default: 107376b8519SHelge Deller /* Controlled by lasi_chip_mem_valid above. */ 108376b8519SHelge Deller g_assert_not_reached(); 109376b8519SHelge Deller } 110376b8519SHelge Deller 111376b8519SHelge Deller trace_lasi_chip_read(addr, val); 112376b8519SHelge Deller 113376b8519SHelge Deller *data = val; 114376b8519SHelge Deller return ret; 115376b8519SHelge Deller } 116376b8519SHelge Deller 117376b8519SHelge Deller static MemTxResult lasi_chip_write_with_attrs(void *opaque, hwaddr addr, 118376b8519SHelge Deller uint64_t val, unsigned size, 119376b8519SHelge Deller MemTxAttrs attrs) 120376b8519SHelge Deller { 121376b8519SHelge Deller LasiState *s = opaque; 122376b8519SHelge Deller 123376b8519SHelge Deller trace_lasi_chip_write(addr, val); 124376b8519SHelge Deller 125376b8519SHelge Deller switch (addr) { 126376b8519SHelge Deller case LASI_IRR: 127376b8519SHelge Deller /* read-only. */ 128376b8519SHelge Deller break; 129376b8519SHelge Deller case LASI_IMR: 130b899fe41SHelge Deller s->imr = val; 13163588da8SMark Cave-Ayland if (((val & LASI_IRQ_BITS) != val) && (val != 0xffffffff)) { 132b899fe41SHelge Deller qemu_log_mask(LOG_GUEST_ERROR, 133b899fe41SHelge Deller "LASI: tried to set invalid %lx IMR value.\n", 134b899fe41SHelge Deller (unsigned long) val); 13563588da8SMark Cave-Ayland } 136376b8519SHelge Deller break; 137376b8519SHelge Deller case LASI_IPR: 138376b8519SHelge Deller /* Any write to IPR clears the register. */ 139376b8519SHelge Deller s->ipr = 0; 140376b8519SHelge Deller break; 141376b8519SHelge Deller case LASI_ICR: 142376b8519SHelge Deller s->icr = val; 143376b8519SHelge Deller /* if (val & ICR_TOC_BIT) issue_toc(); */ 144376b8519SHelge Deller break; 145376b8519SHelge Deller case LASI_IAR: 146376b8519SHelge Deller s->iar = val; 147376b8519SHelge Deller break; 148376b8519SHelge Deller 149ca7b468bSMark Cave-Ayland case LASI_LPT: 150376b8519SHelge Deller /* XXX: reset parallel port */ 151376b8519SHelge Deller break; 152*32d26ea4SHelge Deller case LASI_AUDIO: 153*32d26ea4SHelge Deller case LASI_AUDIO + 4: 154*32d26ea4SHelge Deller /* XXX: reset audio port */ 155*32d26ea4SHelge Deller break; 156ca7b468bSMark Cave-Ayland case LASI_UART: 157376b8519SHelge Deller /* XXX: reset serial port */ 158376b8519SHelge Deller break; 159ca7b468bSMark Cave-Ayland case LASI_LAN: 160ca7b468bSMark Cave-Ayland /* XXX: reset LAN card */ 161ca7b468bSMark Cave-Ayland break; 162*32d26ea4SHelge Deller case LASI_FDC: 163*32d26ea4SHelge Deller /* XXX: reset Floppy controller */ 164*32d26ea4SHelge Deller break; 165ca7b468bSMark Cave-Ayland case LASI_RTC: 166376b8519SHelge Deller s->rtc_ref = val - time(NULL); 167376b8519SHelge Deller break; 168376b8519SHelge Deller 169376b8519SHelge Deller case LASI_PCR: 17063588da8SMark Cave-Ayland if (val == 0x02) { /* immediately power off */ 171376b8519SHelge Deller qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 17263588da8SMark Cave-Ayland } 173376b8519SHelge Deller break; 174376b8519SHelge Deller case LASI_ERRLOG: 175376b8519SHelge Deller s->errlog = val; 176376b8519SHelge Deller break; 177376b8519SHelge Deller case LASI_VER: 178376b8519SHelge Deller /* read-only. */ 179376b8519SHelge Deller break; 180376b8519SHelge Deller case LASI_IORESET: 181376b8519SHelge Deller break; /* XXX: TODO: Reset various devices. */ 182376b8519SHelge Deller case LASI_AMR: 183376b8519SHelge Deller s->amr = val; 184376b8519SHelge Deller break; 185376b8519SHelge Deller 186376b8519SHelge Deller default: 187376b8519SHelge Deller /* Controlled by lasi_chip_mem_valid above. */ 188376b8519SHelge Deller g_assert_not_reached(); 189376b8519SHelge Deller } 190376b8519SHelge Deller return MEMTX_OK; 191376b8519SHelge Deller } 192376b8519SHelge Deller 193376b8519SHelge Deller static const MemoryRegionOps lasi_chip_ops = { 194376b8519SHelge Deller .read_with_attrs = lasi_chip_read_with_attrs, 195376b8519SHelge Deller .write_with_attrs = lasi_chip_write_with_attrs, 196376b8519SHelge Deller .endianness = DEVICE_BIG_ENDIAN, 197376b8519SHelge Deller .valid = { 198376b8519SHelge Deller .min_access_size = 1, 199376b8519SHelge Deller .max_access_size = 4, 200376b8519SHelge Deller .accepts = lasi_chip_mem_valid, 201376b8519SHelge Deller }, 202376b8519SHelge Deller .impl = { 203376b8519SHelge Deller .min_access_size = 1, 204376b8519SHelge Deller .max_access_size = 4, 205376b8519SHelge Deller }, 206376b8519SHelge Deller }; 207376b8519SHelge Deller 208376b8519SHelge Deller static const VMStateDescription vmstate_lasi = { 209376b8519SHelge Deller .name = "Lasi", 210a6450830SPaolo Bonzini .version_id = 2, 211376b8519SHelge Deller .minimum_version_id = 1, 212e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 213376b8519SHelge Deller VMSTATE_UINT32(irr, LasiState), 214376b8519SHelge Deller VMSTATE_UINT32(imr, LasiState), 215376b8519SHelge Deller VMSTATE_UINT32(ipr, LasiState), 216376b8519SHelge Deller VMSTATE_UINT32(icr, LasiState), 217376b8519SHelge Deller VMSTATE_UINT32(iar, LasiState), 218376b8519SHelge Deller VMSTATE_UINT32(errlog, LasiState), 219376b8519SHelge Deller VMSTATE_UINT32(amr, LasiState), 220a6450830SPaolo Bonzini VMSTATE_UINT32_V(rtc_ref, LasiState, 2), 221376b8519SHelge Deller VMSTATE_END_OF_LIST() 222376b8519SHelge Deller } 223376b8519SHelge Deller }; 224376b8519SHelge Deller 225376b8519SHelge Deller 226376b8519SHelge Deller static void lasi_set_irq(void *opaque, int irq, int level) 227376b8519SHelge Deller { 228376b8519SHelge Deller LasiState *s = opaque; 229376b8519SHelge Deller uint32_t bit = 1u << irq; 230376b8519SHelge Deller 231376b8519SHelge Deller if (level) { 232376b8519SHelge Deller s->ipr |= bit; 233376b8519SHelge Deller if (bit & s->imr) { 234376b8519SHelge Deller uint32_t iar = s->iar; 235376b8519SHelge Deller s->irr |= bit; 236376b8519SHelge Deller if ((s->icr & ICR_BUS_ERROR_BIT) == 0) { 237376b8519SHelge Deller stl_be_phys(&address_space_memory, iar & -32, iar & 31); 238376b8519SHelge Deller } 239376b8519SHelge Deller } 240376b8519SHelge Deller } 241376b8519SHelge Deller } 242376b8519SHelge Deller 243b3cdb7e4SMark Cave-Ayland static void lasi_reset(DeviceState *dev) 244b3cdb7e4SMark Cave-Ayland { 245b3cdb7e4SMark Cave-Ayland LasiState *s = LASI_CHIP(dev); 246b3cdb7e4SMark Cave-Ayland 2478e81ffe3SMark Cave-Ayland s->iar = 0xFFFB0000 + 3; /* CPU_HPA + 3 */ 248b3cdb7e4SMark Cave-Ayland 249b3cdb7e4SMark Cave-Ayland /* Real time clock (RTC), it's only one 32-bit counter @9000 */ 250b3cdb7e4SMark Cave-Ayland s->rtc_ref = 0; 251b3cdb7e4SMark Cave-Ayland } 252b3cdb7e4SMark Cave-Ayland 25346f2594cSMark Cave-Ayland static void lasi_init(Object *obj) 25446f2594cSMark Cave-Ayland { 25546f2594cSMark Cave-Ayland LasiState *s = LASI_CHIP(obj); 2562683758cSMark Cave-Ayland SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 25746f2594cSMark Cave-Ayland 25846f2594cSMark Cave-Ayland memory_region_init_io(&s->this_mem, OBJECT(s), &lasi_chip_ops, 25946f2594cSMark Cave-Ayland s, "lasi", 0x100000); 2602683758cSMark Cave-Ayland 2612683758cSMark Cave-Ayland sysbus_init_mmio(sbd, &s->this_mem); 262cb9f6c4bSMark Cave-Ayland 263cb9f6c4bSMark Cave-Ayland qdev_init_gpio_in(DEVICE(obj), lasi_set_irq, LASI_IRQS); 26446f2594cSMark Cave-Ayland } 26546f2594cSMark Cave-Ayland 266376b8519SHelge Deller static void lasi_class_init(ObjectClass *klass, void *data) 267376b8519SHelge Deller { 268376b8519SHelge Deller DeviceClass *dc = DEVICE_CLASS(klass); 269376b8519SHelge Deller 270b3cdb7e4SMark Cave-Ayland dc->reset = lasi_reset; 271376b8519SHelge Deller dc->vmsd = &vmstate_lasi; 272376b8519SHelge Deller } 273376b8519SHelge Deller 274376b8519SHelge Deller static const TypeInfo lasi_pcihost_info = { 275376b8519SHelge Deller .name = TYPE_LASI_CHIP, 276376b8519SHelge Deller .parent = TYPE_SYS_BUS_DEVICE, 27746f2594cSMark Cave-Ayland .instance_init = lasi_init, 278376b8519SHelge Deller .instance_size = sizeof(LasiState), 279376b8519SHelge Deller .class_init = lasi_class_init, 280376b8519SHelge Deller }; 281376b8519SHelge Deller 282376b8519SHelge Deller static void lasi_register_types(void) 283376b8519SHelge Deller { 284376b8519SHelge Deller type_register_static(&lasi_pcihost_info); 285376b8519SHelge Deller } 286376b8519SHelge Deller 287376b8519SHelge Deller type_init(lasi_register_types) 288