145f569a1SMark Cave-Ayland /*
245f569a1SMark Cave-Ayland * HP-PARISC Lasi chipset emulation.
345f569a1SMark Cave-Ayland *
445f569a1SMark Cave-Ayland * (C) 2019 by Helge Deller <deller@gmx.de>
545f569a1SMark Cave-Ayland *
645f569a1SMark Cave-Ayland * This work is licensed under the GNU GPL license version 2 or later.
745f569a1SMark Cave-Ayland *
845f569a1SMark Cave-Ayland * Documentation available at:
945f569a1SMark Cave-Ayland * https://parisc.wiki.kernel.org/images-parisc/7/79/Lasi_ers.pdf
1045f569a1SMark Cave-Ayland */
1145f569a1SMark Cave-Ayland
1245f569a1SMark Cave-Ayland #include "qemu/osdep.h"
1345f569a1SMark Cave-Ayland #include "qemu/units.h"
1445f569a1SMark Cave-Ayland #include "qemu/log.h"
1545f569a1SMark Cave-Ayland #include "qapi/error.h"
1645f569a1SMark Cave-Ayland #include "trace.h"
1745f569a1SMark Cave-Ayland #include "hw/irq.h"
1845f569a1SMark Cave-Ayland #include "sysemu/sysemu.h"
1945f569a1SMark Cave-Ayland #include "sysemu/runstate.h"
2045f569a1SMark Cave-Ayland #include "migration/vmstate.h"
2145f569a1SMark Cave-Ayland #include "qom/object.h"
2245f569a1SMark Cave-Ayland #include "hw/misc/lasi.h"
2345f569a1SMark Cave-Ayland
2445f569a1SMark Cave-Ayland
lasi_chip_mem_valid(void * opaque,hwaddr addr,unsigned size,bool is_write,MemTxAttrs attrs)2545f569a1SMark Cave-Ayland static bool lasi_chip_mem_valid(void *opaque, hwaddr addr,
2645f569a1SMark Cave-Ayland unsigned size, bool is_write,
2745f569a1SMark Cave-Ayland MemTxAttrs attrs)
2845f569a1SMark Cave-Ayland {
2945f569a1SMark Cave-Ayland bool ret = false;
3045f569a1SMark Cave-Ayland
3145f569a1SMark Cave-Ayland switch (addr) {
3245f569a1SMark Cave-Ayland case LASI_IRR:
3345f569a1SMark Cave-Ayland case LASI_IMR:
3445f569a1SMark Cave-Ayland case LASI_IPR:
3545f569a1SMark Cave-Ayland case LASI_ICR:
3645f569a1SMark Cave-Ayland case LASI_IAR:
3745f569a1SMark Cave-Ayland
3845f569a1SMark Cave-Ayland case LASI_LPT:
3932d26ea4SHelge Deller case LASI_AUDIO:
4032d26ea4SHelge Deller case LASI_AUDIO + 4:
4145f569a1SMark Cave-Ayland case LASI_UART:
4245f569a1SMark Cave-Ayland case LASI_LAN:
43f2ffd6fbSHelge Deller case LASI_LAN + 12: /* LASI LAN MAC */
4445f569a1SMark Cave-Ayland case LASI_RTC:
4532d26ea4SHelge Deller case LASI_FDC:
4645f569a1SMark Cave-Ayland
4745f569a1SMark Cave-Ayland case LASI_PCR ... LASI_AMR:
4845f569a1SMark Cave-Ayland ret = true;
4945f569a1SMark Cave-Ayland }
5045f569a1SMark Cave-Ayland
5145f569a1SMark Cave-Ayland trace_lasi_chip_mem_valid(addr, ret);
5245f569a1SMark Cave-Ayland return ret;
5345f569a1SMark Cave-Ayland }
5445f569a1SMark Cave-Ayland
lasi_chip_read_with_attrs(void * opaque,hwaddr addr,uint64_t * data,unsigned size,MemTxAttrs attrs)5545f569a1SMark Cave-Ayland static MemTxResult lasi_chip_read_with_attrs(void *opaque, hwaddr addr,
5645f569a1SMark Cave-Ayland uint64_t *data, unsigned size,
5745f569a1SMark Cave-Ayland MemTxAttrs attrs)
5845f569a1SMark Cave-Ayland {
5945f569a1SMark Cave-Ayland LasiState *s = opaque;
6045f569a1SMark Cave-Ayland MemTxResult ret = MEMTX_OK;
6145f569a1SMark Cave-Ayland uint32_t val;
6245f569a1SMark Cave-Ayland
6345f569a1SMark Cave-Ayland switch (addr) {
6445f569a1SMark Cave-Ayland case LASI_IRR:
6545f569a1SMark Cave-Ayland val = s->irr;
6645f569a1SMark Cave-Ayland break;
6745f569a1SMark Cave-Ayland case LASI_IMR:
6845f569a1SMark Cave-Ayland val = s->imr;
6945f569a1SMark Cave-Ayland break;
7045f569a1SMark Cave-Ayland case LASI_IPR:
7145f569a1SMark Cave-Ayland val = s->ipr;
7245f569a1SMark Cave-Ayland /* Any read to IPR clears the register. */
7345f569a1SMark Cave-Ayland s->ipr = 0;
7445f569a1SMark Cave-Ayland break;
7545f569a1SMark Cave-Ayland case LASI_ICR:
7645f569a1SMark Cave-Ayland val = s->icr & ICR_BUS_ERROR_BIT; /* bus_error */
7745f569a1SMark Cave-Ayland break;
7845f569a1SMark Cave-Ayland case LASI_IAR:
7945f569a1SMark Cave-Ayland val = s->iar;
8045f569a1SMark Cave-Ayland break;
8145f569a1SMark Cave-Ayland
8245f569a1SMark Cave-Ayland case LASI_LPT:
8345f569a1SMark Cave-Ayland case LASI_UART:
8445f569a1SMark Cave-Ayland case LASI_LAN:
85f2ffd6fbSHelge Deller case LASI_LAN + 12:
8632d26ea4SHelge Deller case LASI_FDC:
8745f569a1SMark Cave-Ayland val = 0;
8845f569a1SMark Cave-Ayland break;
8945f569a1SMark Cave-Ayland case LASI_RTC:
9045f569a1SMark Cave-Ayland val = time(NULL);
9145f569a1SMark Cave-Ayland val += s->rtc_ref;
9245f569a1SMark Cave-Ayland break;
9345f569a1SMark Cave-Ayland
9445f569a1SMark Cave-Ayland case LASI_PCR:
9545f569a1SMark Cave-Ayland case LASI_VER: /* only version 0 existed. */
9645f569a1SMark Cave-Ayland case LASI_IORESET:
9745f569a1SMark Cave-Ayland val = 0;
9845f569a1SMark Cave-Ayland break;
9945f569a1SMark Cave-Ayland case LASI_ERRLOG:
10045f569a1SMark Cave-Ayland val = s->errlog;
10145f569a1SMark Cave-Ayland break;
10245f569a1SMark Cave-Ayland case LASI_AMR:
10345f569a1SMark Cave-Ayland val = s->amr;
10445f569a1SMark Cave-Ayland break;
10545f569a1SMark Cave-Ayland
10645f569a1SMark Cave-Ayland default:
10745f569a1SMark Cave-Ayland /* Controlled by lasi_chip_mem_valid above. */
10845f569a1SMark Cave-Ayland g_assert_not_reached();
10945f569a1SMark Cave-Ayland }
11045f569a1SMark Cave-Ayland
11145f569a1SMark Cave-Ayland trace_lasi_chip_read(addr, val);
11245f569a1SMark Cave-Ayland
11345f569a1SMark Cave-Ayland *data = val;
11445f569a1SMark Cave-Ayland return ret;
11545f569a1SMark Cave-Ayland }
11645f569a1SMark Cave-Ayland
lasi_chip_write_with_attrs(void * opaque,hwaddr addr,uint64_t val,unsigned size,MemTxAttrs attrs)11745f569a1SMark Cave-Ayland static MemTxResult lasi_chip_write_with_attrs(void *opaque, hwaddr addr,
11845f569a1SMark Cave-Ayland uint64_t val, unsigned size,
11945f569a1SMark Cave-Ayland MemTxAttrs attrs)
12045f569a1SMark Cave-Ayland {
12145f569a1SMark Cave-Ayland LasiState *s = opaque;
12245f569a1SMark Cave-Ayland
12345f569a1SMark Cave-Ayland trace_lasi_chip_write(addr, val);
12445f569a1SMark Cave-Ayland
12545f569a1SMark Cave-Ayland switch (addr) {
12645f569a1SMark Cave-Ayland case LASI_IRR:
12745f569a1SMark Cave-Ayland /* read-only. */
12845f569a1SMark Cave-Ayland break;
12945f569a1SMark Cave-Ayland case LASI_IMR:
13045f569a1SMark Cave-Ayland s->imr = val;
13145f569a1SMark Cave-Ayland if (((val & LASI_IRQ_BITS) != val) && (val != 0xffffffff)) {
13245f569a1SMark Cave-Ayland qemu_log_mask(LOG_GUEST_ERROR,
13345f569a1SMark Cave-Ayland "LASI: tried to set invalid %lx IMR value.\n",
13445f569a1SMark Cave-Ayland (unsigned long) val);
13545f569a1SMark Cave-Ayland }
13645f569a1SMark Cave-Ayland break;
13745f569a1SMark Cave-Ayland case LASI_IPR:
13845f569a1SMark Cave-Ayland /* Any write to IPR clears the register. */
13945f569a1SMark Cave-Ayland s->ipr = 0;
14045f569a1SMark Cave-Ayland break;
14145f569a1SMark Cave-Ayland case LASI_ICR:
14245f569a1SMark Cave-Ayland s->icr = val;
14345f569a1SMark Cave-Ayland /* if (val & ICR_TOC_BIT) issue_toc(); */
14445f569a1SMark Cave-Ayland break;
14545f569a1SMark Cave-Ayland case LASI_IAR:
14645f569a1SMark Cave-Ayland s->iar = val;
14745f569a1SMark Cave-Ayland break;
14845f569a1SMark Cave-Ayland
14945f569a1SMark Cave-Ayland case LASI_LPT:
15045f569a1SMark Cave-Ayland /* XXX: reset parallel port */
15145f569a1SMark Cave-Ayland break;
15232d26ea4SHelge Deller case LASI_AUDIO:
15332d26ea4SHelge Deller case LASI_AUDIO + 4:
15432d26ea4SHelge Deller /* XXX: reset audio port */
15532d26ea4SHelge Deller break;
15645f569a1SMark Cave-Ayland case LASI_UART:
15745f569a1SMark Cave-Ayland /* XXX: reset serial port */
15845f569a1SMark Cave-Ayland break;
15945f569a1SMark Cave-Ayland case LASI_LAN:
16045f569a1SMark Cave-Ayland /* XXX: reset LAN card */
16145f569a1SMark Cave-Ayland break;
16232d26ea4SHelge Deller case LASI_FDC:
16332d26ea4SHelge Deller /* XXX: reset Floppy controller */
16432d26ea4SHelge Deller break;
16545f569a1SMark Cave-Ayland case LASI_RTC:
16645f569a1SMark Cave-Ayland s->rtc_ref = val - time(NULL);
16745f569a1SMark Cave-Ayland break;
16845f569a1SMark Cave-Ayland
16945f569a1SMark Cave-Ayland case LASI_PCR:
17045f569a1SMark Cave-Ayland if (val == 0x02) { /* immediately power off */
17145f569a1SMark Cave-Ayland qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
17245f569a1SMark Cave-Ayland }
17345f569a1SMark Cave-Ayland break;
17445f569a1SMark Cave-Ayland case LASI_ERRLOG:
17545f569a1SMark Cave-Ayland s->errlog = val;
17645f569a1SMark Cave-Ayland break;
17745f569a1SMark Cave-Ayland case LASI_VER:
17845f569a1SMark Cave-Ayland /* read-only. */
17945f569a1SMark Cave-Ayland break;
18045f569a1SMark Cave-Ayland case LASI_IORESET:
18145f569a1SMark Cave-Ayland break; /* XXX: TODO: Reset various devices. */
18245f569a1SMark Cave-Ayland case LASI_AMR:
18345f569a1SMark Cave-Ayland s->amr = val;
18445f569a1SMark Cave-Ayland break;
18545f569a1SMark Cave-Ayland
18645f569a1SMark Cave-Ayland default:
18745f569a1SMark Cave-Ayland /* Controlled by lasi_chip_mem_valid above. */
18845f569a1SMark Cave-Ayland g_assert_not_reached();
18945f569a1SMark Cave-Ayland }
19045f569a1SMark Cave-Ayland return MEMTX_OK;
19145f569a1SMark Cave-Ayland }
19245f569a1SMark Cave-Ayland
19345f569a1SMark Cave-Ayland static const MemoryRegionOps lasi_chip_ops = {
19445f569a1SMark Cave-Ayland .read_with_attrs = lasi_chip_read_with_attrs,
19545f569a1SMark Cave-Ayland .write_with_attrs = lasi_chip_write_with_attrs,
19645f569a1SMark Cave-Ayland .endianness = DEVICE_BIG_ENDIAN,
19745f569a1SMark Cave-Ayland .valid = {
19845f569a1SMark Cave-Ayland .min_access_size = 1,
19945f569a1SMark Cave-Ayland .max_access_size = 4,
20045f569a1SMark Cave-Ayland .accepts = lasi_chip_mem_valid,
20145f569a1SMark Cave-Ayland },
20245f569a1SMark Cave-Ayland .impl = {
20345f569a1SMark Cave-Ayland .min_access_size = 1,
20445f569a1SMark Cave-Ayland .max_access_size = 4,
20545f569a1SMark Cave-Ayland },
20645f569a1SMark Cave-Ayland };
20745f569a1SMark Cave-Ayland
20845f569a1SMark Cave-Ayland static const VMStateDescription vmstate_lasi = {
20945f569a1SMark Cave-Ayland .name = "Lasi",
210a6450830SPaolo Bonzini .version_id = 2,
21145f569a1SMark Cave-Ayland .minimum_version_id = 1,
212e4ea952fSRichard Henderson .fields = (const VMStateField[]) {
21345f569a1SMark Cave-Ayland VMSTATE_UINT32(irr, LasiState),
21445f569a1SMark Cave-Ayland VMSTATE_UINT32(imr, LasiState),
21545f569a1SMark Cave-Ayland VMSTATE_UINT32(ipr, LasiState),
21645f569a1SMark Cave-Ayland VMSTATE_UINT32(icr, LasiState),
21745f569a1SMark Cave-Ayland VMSTATE_UINT32(iar, LasiState),
21845f569a1SMark Cave-Ayland VMSTATE_UINT32(errlog, LasiState),
21945f569a1SMark Cave-Ayland VMSTATE_UINT32(amr, LasiState),
220a6450830SPaolo Bonzini VMSTATE_UINT32_V(rtc_ref, LasiState, 2),
22145f569a1SMark Cave-Ayland VMSTATE_END_OF_LIST()
22245f569a1SMark Cave-Ayland }
22345f569a1SMark Cave-Ayland };
22445f569a1SMark Cave-Ayland
22545f569a1SMark Cave-Ayland
lasi_set_irq(void * opaque,int irq,int level)22645f569a1SMark Cave-Ayland static void lasi_set_irq(void *opaque, int irq, int level)
22745f569a1SMark Cave-Ayland {
22845f569a1SMark Cave-Ayland LasiState *s = opaque;
22945f569a1SMark Cave-Ayland uint32_t bit = 1u << irq;
23045f569a1SMark Cave-Ayland
23145f569a1SMark Cave-Ayland if (level) {
23245f569a1SMark Cave-Ayland s->ipr |= bit;
23345f569a1SMark Cave-Ayland if (bit & s->imr) {
23445f569a1SMark Cave-Ayland uint32_t iar = s->iar;
23545f569a1SMark Cave-Ayland s->irr |= bit;
23645f569a1SMark Cave-Ayland if ((s->icr & ICR_BUS_ERROR_BIT) == 0) {
23745f569a1SMark Cave-Ayland stl_be_phys(&address_space_memory, iar & -32, iar & 31);
23845f569a1SMark Cave-Ayland }
23945f569a1SMark Cave-Ayland }
24045f569a1SMark Cave-Ayland }
24145f569a1SMark Cave-Ayland }
24245f569a1SMark Cave-Ayland
lasi_reset(DeviceState * dev)24345f569a1SMark Cave-Ayland static void lasi_reset(DeviceState *dev)
24445f569a1SMark Cave-Ayland {
24545f569a1SMark Cave-Ayland LasiState *s = LASI_CHIP(dev);
24645f569a1SMark Cave-Ayland
24745f569a1SMark Cave-Ayland s->iar = 0xFFFB0000 + 3; /* CPU_HPA + 3 */
24845f569a1SMark Cave-Ayland
24945f569a1SMark Cave-Ayland /* Real time clock (RTC), it's only one 32-bit counter @9000 */
25045f569a1SMark Cave-Ayland s->rtc_ref = 0;
25145f569a1SMark Cave-Ayland }
25245f569a1SMark Cave-Ayland
lasi_init(Object * obj)25345f569a1SMark Cave-Ayland static void lasi_init(Object *obj)
25445f569a1SMark Cave-Ayland {
25545f569a1SMark Cave-Ayland LasiState *s = LASI_CHIP(obj);
25645f569a1SMark Cave-Ayland SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
25745f569a1SMark Cave-Ayland
25845f569a1SMark Cave-Ayland memory_region_init_io(&s->this_mem, OBJECT(s), &lasi_chip_ops,
25945f569a1SMark Cave-Ayland s, "lasi", 0x100000);
26045f569a1SMark Cave-Ayland
26145f569a1SMark Cave-Ayland sysbus_init_mmio(sbd, &s->this_mem);
26245f569a1SMark Cave-Ayland
26345f569a1SMark Cave-Ayland qdev_init_gpio_in(DEVICE(obj), lasi_set_irq, LASI_IRQS);
26445f569a1SMark Cave-Ayland }
26545f569a1SMark Cave-Ayland
lasi_class_init(ObjectClass * klass,void * data)26645f569a1SMark Cave-Ayland static void lasi_class_init(ObjectClass *klass, void *data)
26745f569a1SMark Cave-Ayland {
26845f569a1SMark Cave-Ayland DeviceClass *dc = DEVICE_CLASS(klass);
26945f569a1SMark Cave-Ayland
270*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, lasi_reset);
27145f569a1SMark Cave-Ayland dc->vmsd = &vmstate_lasi;
27245f569a1SMark Cave-Ayland }
27345f569a1SMark Cave-Ayland
27445f569a1SMark Cave-Ayland static const TypeInfo lasi_pcihost_info = {
27545f569a1SMark Cave-Ayland .name = TYPE_LASI_CHIP,
27645f569a1SMark Cave-Ayland .parent = TYPE_SYS_BUS_DEVICE,
27745f569a1SMark Cave-Ayland .instance_init = lasi_init,
27845f569a1SMark Cave-Ayland .instance_size = sizeof(LasiState),
27945f569a1SMark Cave-Ayland .class_init = lasi_class_init,
28045f569a1SMark Cave-Ayland };
28145f569a1SMark Cave-Ayland
lasi_register_types(void)28245f569a1SMark Cave-Ayland static void lasi_register_types(void)
28345f569a1SMark Cave-Ayland {
28445f569a1SMark Cave-Ayland type_register_static(&lasi_pcihost_info);
28545f569a1SMark Cave-Ayland }
28645f569a1SMark Cave-Ayland
28745f569a1SMark Cave-Ayland type_init(lasi_register_types)
288