xref: /openbmc/qemu/hw/misc/armsse-mhu.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
1cdf63440SPeter Maydell /*
2cdf63440SPeter Maydell  * ARM SSE-200 Message Handling Unit (MHU)
3cdf63440SPeter Maydell  *
4cdf63440SPeter Maydell  * Copyright (c) 2019 Linaro Limited
5cdf63440SPeter Maydell  * Written by Peter Maydell
6cdf63440SPeter Maydell  *
7cdf63440SPeter Maydell  *  This program is free software; you can redistribute it and/or modify
8cdf63440SPeter Maydell  *  it under the terms of the GNU General Public License version 2 or
9cdf63440SPeter Maydell  *  (at your option) any later version.
10cdf63440SPeter Maydell  */
11cdf63440SPeter Maydell 
12cdf63440SPeter Maydell /*
13cdf63440SPeter Maydell  * This is a model of the Message Handling Unit (MHU) which is part of the
14cdf63440SPeter Maydell  * Arm SSE-200 and documented in
1550b52b18SPeter Maydell  * https://developer.arm.com/documentation/101104/latest/
16cdf63440SPeter Maydell  */
17cdf63440SPeter Maydell 
18cdf63440SPeter Maydell #include "qemu/osdep.h"
19cdf63440SPeter Maydell #include "qemu/log.h"
200b8fa32fSMarkus Armbruster #include "qemu/module.h"
21cdf63440SPeter Maydell #include "trace.h"
22cdf63440SPeter Maydell #include "qapi/error.h"
23cdf63440SPeter Maydell #include "hw/sysbus.h"
24d6454270SMarkus Armbruster #include "migration/vmstate.h"
25cdf63440SPeter Maydell #include "hw/registerfields.h"
2664552b6bSMarkus Armbruster #include "hw/irq.h"
27cdf63440SPeter Maydell #include "hw/misc/armsse-mhu.h"
28cdf63440SPeter Maydell 
29cdf63440SPeter Maydell REG32(CPU0INTR_STAT, 0x0)
30cdf63440SPeter Maydell REG32(CPU0INTR_SET, 0x4)
31cdf63440SPeter Maydell REG32(CPU0INTR_CLR, 0x8)
32cdf63440SPeter Maydell REG32(CPU1INTR_STAT, 0x10)
33cdf63440SPeter Maydell REG32(CPU1INTR_SET, 0x14)
34cdf63440SPeter Maydell REG32(CPU1INTR_CLR, 0x18)
35cdf63440SPeter Maydell REG32(PID4, 0xfd0)
36cdf63440SPeter Maydell REG32(PID5, 0xfd4)
37cdf63440SPeter Maydell REG32(PID6, 0xfd8)
38cdf63440SPeter Maydell REG32(PID7, 0xfdc)
39cdf63440SPeter Maydell REG32(PID0, 0xfe0)
40cdf63440SPeter Maydell REG32(PID1, 0xfe4)
41cdf63440SPeter Maydell REG32(PID2, 0xfe8)
42cdf63440SPeter Maydell REG32(PID3, 0xfec)
43cdf63440SPeter Maydell REG32(CID0, 0xff0)
44cdf63440SPeter Maydell REG32(CID1, 0xff4)
45cdf63440SPeter Maydell REG32(CID2, 0xff8)
46cdf63440SPeter Maydell REG32(CID3, 0xffc)
47cdf63440SPeter Maydell 
48cdf63440SPeter Maydell /* Valid bits in the interrupt registers. If any are set the IRQ is raised */
49cdf63440SPeter Maydell #define INTR_MASK 0xf
50cdf63440SPeter Maydell 
51cdf63440SPeter Maydell /* PID/CID values */
52cdf63440SPeter Maydell static const int armsse_mhu_id[] = {
53cdf63440SPeter Maydell     0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
54cdf63440SPeter Maydell     0x56, 0xb8, 0x0b, 0x00, /* PID0..PID3 */
55cdf63440SPeter Maydell     0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
56cdf63440SPeter Maydell };
57cdf63440SPeter Maydell 
armsse_mhu_update(ARMSSEMHU * s)58cdf63440SPeter Maydell static void armsse_mhu_update(ARMSSEMHU *s)
59cdf63440SPeter Maydell {
60cdf63440SPeter Maydell     qemu_set_irq(s->cpu0irq, s->cpu0intr != 0);
61cdf63440SPeter Maydell     qemu_set_irq(s->cpu1irq, s->cpu1intr != 0);
62cdf63440SPeter Maydell }
63cdf63440SPeter Maydell 
armsse_mhu_read(void * opaque,hwaddr offset,unsigned size)64cdf63440SPeter Maydell static uint64_t armsse_mhu_read(void *opaque, hwaddr offset, unsigned size)
65cdf63440SPeter Maydell {
66cdf63440SPeter Maydell     ARMSSEMHU *s = ARMSSE_MHU(opaque);
67cdf63440SPeter Maydell     uint64_t r;
68cdf63440SPeter Maydell 
69cdf63440SPeter Maydell     switch (offset) {
70cdf63440SPeter Maydell     case A_CPU0INTR_STAT:
71cdf63440SPeter Maydell         r = s->cpu0intr;
72cdf63440SPeter Maydell         break;
73cdf63440SPeter Maydell 
74cdf63440SPeter Maydell     case A_CPU1INTR_STAT:
75cdf63440SPeter Maydell         r = s->cpu1intr;
76cdf63440SPeter Maydell         break;
77cdf63440SPeter Maydell 
78cdf63440SPeter Maydell     case A_PID4 ... A_CID3:
79cdf63440SPeter Maydell         r = armsse_mhu_id[(offset - A_PID4) / 4];
80cdf63440SPeter Maydell         break;
81cdf63440SPeter Maydell 
82cdf63440SPeter Maydell     case A_CPU0INTR_SET:
83cdf63440SPeter Maydell     case A_CPU0INTR_CLR:
84cdf63440SPeter Maydell     case A_CPU1INTR_SET:
85cdf63440SPeter Maydell     case A_CPU1INTR_CLR:
86cdf63440SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
87cdf63440SPeter Maydell                       "SSE MHU: read of write-only register at offset 0x%x\n",
88cdf63440SPeter Maydell                       (int)offset);
89cdf63440SPeter Maydell         r = 0;
90cdf63440SPeter Maydell         break;
91cdf63440SPeter Maydell 
92cdf63440SPeter Maydell     default:
93cdf63440SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
94cdf63440SPeter Maydell                       "SSE MHU read: bad offset 0x%x\n", (int)offset);
95cdf63440SPeter Maydell         r = 0;
96cdf63440SPeter Maydell         break;
97cdf63440SPeter Maydell     }
98cdf63440SPeter Maydell     trace_armsse_mhu_read(offset, r, size);
99cdf63440SPeter Maydell     return r;
100cdf63440SPeter Maydell }
101cdf63440SPeter Maydell 
armsse_mhu_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)102cdf63440SPeter Maydell static void armsse_mhu_write(void *opaque, hwaddr offset,
103cdf63440SPeter Maydell                              uint64_t value, unsigned size)
104cdf63440SPeter Maydell {
105cdf63440SPeter Maydell     ARMSSEMHU *s = ARMSSE_MHU(opaque);
106cdf63440SPeter Maydell 
107cdf63440SPeter Maydell     trace_armsse_mhu_write(offset, value, size);
108cdf63440SPeter Maydell 
109cdf63440SPeter Maydell     switch (offset) {
110cdf63440SPeter Maydell     case A_CPU0INTR_SET:
111cdf63440SPeter Maydell         s->cpu0intr |= (value & INTR_MASK);
112cdf63440SPeter Maydell         break;
113cdf63440SPeter Maydell     case A_CPU0INTR_CLR:
114cdf63440SPeter Maydell         s->cpu0intr &= ~(value & INTR_MASK);
115cdf63440SPeter Maydell         break;
116cdf63440SPeter Maydell     case A_CPU1INTR_SET:
117cdf63440SPeter Maydell         s->cpu1intr |= (value & INTR_MASK);
118cdf63440SPeter Maydell         break;
119cdf63440SPeter Maydell     case A_CPU1INTR_CLR:
120cdf63440SPeter Maydell         s->cpu1intr &= ~(value & INTR_MASK);
121cdf63440SPeter Maydell         break;
122cdf63440SPeter Maydell 
123cdf63440SPeter Maydell     case A_CPU0INTR_STAT:
124cdf63440SPeter Maydell     case A_CPU1INTR_STAT:
125cdf63440SPeter Maydell     case A_PID4 ... A_CID3:
126cdf63440SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
127cdf63440SPeter Maydell                       "SSE MHU: write to read-only register at offset 0x%x\n",
128cdf63440SPeter Maydell                       (int)offset);
129cdf63440SPeter Maydell         break;
130cdf63440SPeter Maydell 
131cdf63440SPeter Maydell     default:
132cdf63440SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
133cdf63440SPeter Maydell                       "SSE MHU write: bad offset 0x%x\n", (int)offset);
134cdf63440SPeter Maydell         break;
135cdf63440SPeter Maydell     }
136cdf63440SPeter Maydell 
137cdf63440SPeter Maydell     armsse_mhu_update(s);
138cdf63440SPeter Maydell }
139cdf63440SPeter Maydell 
140cdf63440SPeter Maydell static const MemoryRegionOps armsse_mhu_ops = {
141cdf63440SPeter Maydell     .read = armsse_mhu_read,
142cdf63440SPeter Maydell     .write = armsse_mhu_write,
143cdf63440SPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
144cdf63440SPeter Maydell     .valid.min_access_size = 4,
145cdf63440SPeter Maydell     .valid.max_access_size = 4,
146cdf63440SPeter Maydell };
147cdf63440SPeter Maydell 
armsse_mhu_reset(DeviceState * dev)148cdf63440SPeter Maydell static void armsse_mhu_reset(DeviceState *dev)
149cdf63440SPeter Maydell {
150cdf63440SPeter Maydell     ARMSSEMHU *s = ARMSSE_MHU(dev);
151cdf63440SPeter Maydell 
152cdf63440SPeter Maydell     s->cpu0intr = 0;
153cdf63440SPeter Maydell     s->cpu1intr = 0;
154cdf63440SPeter Maydell }
155cdf63440SPeter Maydell 
156cdf63440SPeter Maydell static const VMStateDescription armsse_mhu_vmstate = {
157cdf63440SPeter Maydell     .name = "armsse-mhu",
158cdf63440SPeter Maydell     .version_id = 1,
159cdf63440SPeter Maydell     .minimum_version_id = 1,
160e4ea952fSRichard Henderson     .fields = (const VMStateField[]) {
161cdf63440SPeter Maydell         VMSTATE_UINT32(cpu0intr, ARMSSEMHU),
162cdf63440SPeter Maydell         VMSTATE_UINT32(cpu1intr, ARMSSEMHU),
163cdf63440SPeter Maydell         VMSTATE_END_OF_LIST()
164cdf63440SPeter Maydell     },
165cdf63440SPeter Maydell };
166cdf63440SPeter Maydell 
armsse_mhu_init(Object * obj)167cdf63440SPeter Maydell static void armsse_mhu_init(Object *obj)
168cdf63440SPeter Maydell {
169cdf63440SPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
170cdf63440SPeter Maydell     ARMSSEMHU *s = ARMSSE_MHU(obj);
171cdf63440SPeter Maydell 
172cdf63440SPeter Maydell     memory_region_init_io(&s->iomem, obj, &armsse_mhu_ops,
173cdf63440SPeter Maydell                           s, "armsse-mhu", 0x1000);
174cdf63440SPeter Maydell     sysbus_init_mmio(sbd, &s->iomem);
175cdf63440SPeter Maydell     sysbus_init_irq(sbd, &s->cpu0irq);
176cdf63440SPeter Maydell     sysbus_init_irq(sbd, &s->cpu1irq);
177cdf63440SPeter Maydell }
178cdf63440SPeter Maydell 
armsse_mhu_class_init(ObjectClass * klass,void * data)179cdf63440SPeter Maydell static void armsse_mhu_class_init(ObjectClass *klass, void *data)
180cdf63440SPeter Maydell {
181cdf63440SPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
182cdf63440SPeter Maydell 
183*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, armsse_mhu_reset);
184cdf63440SPeter Maydell     dc->vmsd = &armsse_mhu_vmstate;
185cdf63440SPeter Maydell }
186cdf63440SPeter Maydell 
187cdf63440SPeter Maydell static const TypeInfo armsse_mhu_info = {
188cdf63440SPeter Maydell     .name = TYPE_ARMSSE_MHU,
189cdf63440SPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
190cdf63440SPeter Maydell     .instance_size = sizeof(ARMSSEMHU),
191cdf63440SPeter Maydell     .instance_init = armsse_mhu_init,
192cdf63440SPeter Maydell     .class_init = armsse_mhu_class_init,
193cdf63440SPeter Maydell };
194cdf63440SPeter Maydell 
armsse_mhu_register_types(void)195cdf63440SPeter Maydell static void armsse_mhu_register_types(void)
196cdf63440SPeter Maydell {
197cdf63440SPeter Maydell     type_register_static(&armsse_mhu_info);
198cdf63440SPeter Maydell }
199cdf63440SPeter Maydell 
200cdf63440SPeter Maydell type_init(armsse_mhu_register_types);
201