xref: /openbmc/qemu/hw/misc/lasi.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
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