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