qemu
1/*
2* HP-PARISC Lasi chipset emulation.
3*
4* (C) 2019 by Helge Deller <deller@gmx.de>
5*
6* This work is licensed under the GNU GPL license version 2 or later.
7*
8* Documentation available at:
9* https://parisc.wiki.kernel.org/images-parisc/7/79/Lasi_ers.pdf
10*/
11
12#include "qemu/osdep.h"13#include "qemu/units.h"14#include "qemu/log.h"15#include "qapi/error.h"16#include "trace.h"17#include "hw/irq.h"18#include "sysemu/sysemu.h"19#include "sysemu/runstate.h"20#include "migration/vmstate.h"21#include "qom/object.h"22#include "hw/misc/lasi.h"23
24
25static bool lasi_chip_mem_valid(void *opaque, hwaddr addr,26unsigned size, bool is_write,27MemTxAttrs attrs)28{
29bool ret = false;30
31switch (addr) {32case LASI_IRR:33case LASI_IMR:34case LASI_IPR:35case LASI_ICR:36case LASI_IAR:37
38case LASI_LPT:39case LASI_AUDIO:40case LASI_AUDIO + 4:41case LASI_UART:42case LASI_LAN:43case LASI_LAN + 12: /* LASI LAN MAC */44case LASI_RTC:45case LASI_FDC:46
47case LASI_PCR ... LASI_AMR:48ret = true;49}50
51trace_lasi_chip_mem_valid(addr, ret);52return ret;53}
54
55static MemTxResult lasi_chip_read_with_attrs(void *opaque, hwaddr addr,56uint64_t *data, unsigned size,57MemTxAttrs attrs)58{
59LasiState *s = opaque;60MemTxResult ret = MEMTX_OK;61uint32_t val;62
63switch (addr) {64case LASI_IRR:65val = s->irr;66break;67case LASI_IMR:68val = s->imr;69break;70case LASI_IPR:71val = s->ipr;72/* Any read to IPR clears the register. */73s->ipr = 0;74break;75case LASI_ICR:76val = s->icr & ICR_BUS_ERROR_BIT; /* bus_error */77break;78case LASI_IAR:79val = s->iar;80break;81
82case LASI_LPT:83case LASI_UART:84case LASI_LAN:85case LASI_LAN + 12:86case LASI_FDC:87val = 0;88break;89case LASI_RTC:90val = time(NULL);91val += s->rtc_ref;92break;93
94case LASI_PCR:95case LASI_VER: /* only version 0 existed. */96case LASI_IORESET:97val = 0;98break;99case LASI_ERRLOG:100val = s->errlog;101break;102case LASI_AMR:103val = s->amr;104break;105
106default:107/* Controlled by lasi_chip_mem_valid above. */108g_assert_not_reached();109}110
111trace_lasi_chip_read(addr, val);112
113*data = val;114return ret;115}
116
117static MemTxResult lasi_chip_write_with_attrs(void *opaque, hwaddr addr,118uint64_t val, unsigned size,119MemTxAttrs attrs)120{
121LasiState *s = opaque;122
123trace_lasi_chip_write(addr, val);124
125switch (addr) {126case LASI_IRR:127/* read-only. */128break;129case LASI_IMR:130s->imr = val;131if (((val & LASI_IRQ_BITS) != val) && (val != 0xffffffff)) {132qemu_log_mask(LOG_GUEST_ERROR,133"LASI: tried to set invalid %lx IMR value.\n",134(unsigned long) val);135}136break;137case LASI_IPR:138/* Any write to IPR clears the register. */139s->ipr = 0;140break;141case LASI_ICR:142s->icr = val;143/* if (val & ICR_TOC_BIT) issue_toc(); */144break;145case LASI_IAR:146s->iar = val;147break;148
149case LASI_LPT:150/* XXX: reset parallel port */151break;152case LASI_AUDIO:153case LASI_AUDIO + 4:154/* XXX: reset audio port */155break;156case LASI_UART:157/* XXX: reset serial port */158break;159case LASI_LAN:160/* XXX: reset LAN card */161break;162case LASI_FDC:163/* XXX: reset Floppy controller */164break;165case LASI_RTC:166s->rtc_ref = val - time(NULL);167break;168
169case LASI_PCR:170if (val == 0x02) { /* immediately power off */171qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);172}173break;174case LASI_ERRLOG:175s->errlog = val;176break;177case LASI_VER:178/* read-only. */179break;180case LASI_IORESET:181break; /* XXX: TODO: Reset various devices. */182case LASI_AMR:183s->amr = val;184break;185
186default:187/* Controlled by lasi_chip_mem_valid above. */188g_assert_not_reached();189}190return MEMTX_OK;191}
192
193static const MemoryRegionOps lasi_chip_ops = {194.read_with_attrs = lasi_chip_read_with_attrs,195.write_with_attrs = lasi_chip_write_with_attrs,196.endianness = DEVICE_BIG_ENDIAN,197.valid = {198.min_access_size = 1,199.max_access_size = 4,200.accepts = lasi_chip_mem_valid,201},202.impl = {203.min_access_size = 1,204.max_access_size = 4,205},206};207
208static const VMStateDescription vmstate_lasi = {209.name = "Lasi",210.version_id = 2,211.minimum_version_id = 1,212.fields = (const VMStateField[]) {213VMSTATE_UINT32(irr, LasiState),214VMSTATE_UINT32(imr, LasiState),215VMSTATE_UINT32(ipr, LasiState),216VMSTATE_UINT32(icr, LasiState),217VMSTATE_UINT32(iar, LasiState),218VMSTATE_UINT32(errlog, LasiState),219VMSTATE_UINT32(amr, LasiState),220VMSTATE_UINT32_V(rtc_ref, LasiState, 2),221VMSTATE_END_OF_LIST()222}223};224
225
226static void lasi_set_irq(void *opaque, int irq, int level)227{
228LasiState *s = opaque;229uint32_t bit = 1u << irq;230
231if (level) {232s->ipr |= bit;233if (bit & s->imr) {234uint32_t iar = s->iar;235s->irr |= bit;236if ((s->icr & ICR_BUS_ERROR_BIT) == 0) {237stl_be_phys(&address_space_memory, iar & -32, iar & 31);238}239}240}241}
242
243static void lasi_reset(DeviceState *dev)244{
245LasiState *s = LASI_CHIP(dev);246
247s->iar = 0xFFFB0000 + 3; /* CPU_HPA + 3 */248
249/* Real time clock (RTC), it's only one 32-bit counter @9000 */250s->rtc_ref = 0;251}
252
253static void lasi_init(Object *obj)254{
255LasiState *s = LASI_CHIP(obj);256SysBusDevice *sbd = SYS_BUS_DEVICE(obj);257
258memory_region_init_io(&s->this_mem, OBJECT(s), &lasi_chip_ops,259s, "lasi", 0x100000);260
261sysbus_init_mmio(sbd, &s->this_mem);262
263qdev_init_gpio_in(DEVICE(obj), lasi_set_irq, LASI_IRQS);264}
265
266static void lasi_class_init(ObjectClass *klass, void *data)267{
268DeviceClass *dc = DEVICE_CLASS(klass);269
270dc->reset = lasi_reset;271dc->vmsd = &vmstate_lasi;272}
273
274static const TypeInfo lasi_pcihost_info = {275.name = TYPE_LASI_CHIP,276.parent = TYPE_SYS_BUS_DEVICE,277.instance_init = lasi_init,278.instance_size = sizeof(LasiState),279.class_init = lasi_class_init,280};281
282static void lasi_register_types(void)283{
284type_register_static(&lasi_pcihost_info);285}
286
287type_init(lasi_register_types)288