]> Git Repo - qemu.git/blob - hw/hppa/dino.c
fw_cfg: Allow reboot-timeout=-1 again
[qemu.git] / hw / hppa / dino.c
1 /*
2  * HP-PARISC Dino PCI chipset emulation.
3  *
4  * (C) 2017 by Helge Deller <[email protected]>
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/9/91/Dino_ers.pdf
10  * https://parisc.wiki.kernel.org/images-parisc/7/70/Dino_3_1_Errata.pdf
11  */
12
13 #include "qemu/osdep.h"
14 #include "qemu/module.h"
15 #include "qemu/units.h"
16 #include "qapi/error.h"
17 #include "cpu.h"
18 #include "hw/irq.h"
19 #include "hw/pci/pci.h"
20 #include "hw/pci/pci_bus.h"
21 #include "migration/vmstate.h"
22 #include "hppa_sys.h"
23 #include "exec/address-spaces.h"
24
25
26 #define TYPE_DINO_PCI_HOST_BRIDGE "dino-pcihost"
27
28 #define DINO_IAR0               0x004
29 #define DINO_IODC               0x008
30 #define DINO_IRR0               0x00C  /* RO */
31 #define DINO_IAR1               0x010
32 #define DINO_IRR1               0x014  /* RO */
33 #define DINO_IMR                0x018
34 #define DINO_IPR                0x01C
35 #define DINO_TOC_ADDR           0x020
36 #define DINO_ICR                0x024
37 #define DINO_ILR                0x028  /* RO */
38 #define DINO_IO_COMMAND         0x030  /* WO */
39 #define DINO_IO_STATUS          0x034  /* RO */
40 #define DINO_IO_CONTROL         0x038
41 #define DINO_IO_GSC_ERR_RESP    0x040  /* RO */
42 #define DINO_IO_ERR_INFO        0x044  /* RO */
43 #define DINO_IO_PCI_ERR_RESP    0x048  /* RO */
44 #define DINO_IO_FBB_EN          0x05c
45 #define DINO_IO_ADDR_EN         0x060
46 #define DINO_PCI_CONFIG_ADDR    0x064
47 #define DINO_PCI_CONFIG_DATA    0x068
48 #define DINO_PCI_IO_DATA        0x06c
49 #define DINO_PCI_MEM_DATA       0x070  /* Dino 3.x only */
50 #define DINO_GSC2X_CONFIG       0x7b4  /* RO */
51 #define DINO_GMASK              0x800
52 #define DINO_PAMR               0x804
53 #define DINO_PAPR               0x808
54 #define DINO_DAMODE             0x80c
55 #define DINO_PCICMD             0x810
56 #define DINO_PCISTS             0x814  /* R/WC */
57 #define DINO_MLTIM              0x81c
58 #define DINO_BRDG_FEAT          0x820
59 #define DINO_PCIROR             0x824
60 #define DINO_PCIWOR             0x828
61 #define DINO_TLTIM              0x830
62
63 #define DINO_IRQS         11      /* bits 0-10 are architected */
64 #define DINO_IRR_MASK     0x5ff   /* only 10 bits are implemented */
65 #define DINO_LOCAL_IRQS   (DINO_IRQS + 1)
66 #define DINO_MASK_IRQ(x)  (1 << (x))
67
68 #define PCIINTA   0x001
69 #define PCIINTB   0x002
70 #define PCIINTC   0x004
71 #define PCIINTD   0x008
72 #define PCIINTE   0x010
73 #define PCIINTF   0x020
74 #define GSCEXTINT 0x040
75 /* #define xxx       0x080 - bit 7 is "default" */
76 /* #define xxx    0x100 - bit 8 not used */
77 /* #define xxx    0x200 - bit 9 not used */
78 #define RS232INT  0x400
79
80 #define DINO_MEM_CHUNK_SIZE (8 * MiB)
81
82 #define DINO_PCI_HOST_BRIDGE(obj) \
83     OBJECT_CHECK(DinoState, (obj), TYPE_DINO_PCI_HOST_BRIDGE)
84
85 typedef struct DinoState {
86     PCIHostState parent_obj;
87
88     /* PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops,
89        so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops.  */
90
91     uint32_t iar0;
92     uint32_t iar1;
93     uint32_t imr;
94     uint32_t ipr;
95     uint32_t icr;
96     uint32_t ilr;
97     uint32_t io_addr_en;
98     uint32_t io_control;
99
100     MemoryRegion this_mem;
101     MemoryRegion pci_mem;
102     MemoryRegion pci_mem_alias[32];
103
104     AddressSpace bm_as;
105     MemoryRegion bm;
106     MemoryRegion bm_ram_alias;
107     MemoryRegion bm_pci_alias;
108     MemoryRegion bm_cpu_alias;
109
110     MemoryRegion cpu0_eir_mem;
111 } DinoState;
112
113 /*
114  * Dino can forward memory accesses from the CPU in the range between
115  * 0xf0800000 and 0xff000000 to the PCI bus.
116  */
117 static void gsc_to_pci_forwarding(DinoState *s)
118 {
119     uint32_t io_addr_en, tmp;
120     int enabled, i;
121
122     tmp = extract32(s->io_control, 7, 2);
123     enabled = (tmp == 0x01);
124     io_addr_en = s->io_addr_en;
125
126     memory_region_transaction_begin();
127     for (i = 1; i < 31; i++) {
128         MemoryRegion *mem = &s->pci_mem_alias[i];
129         if (enabled && (io_addr_en & (1U << i))) {
130             if (!memory_region_is_mapped(mem)) {
131                 uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE;
132                 memory_region_add_subregion(get_system_memory(), addr, mem);
133             }
134         } else if (memory_region_is_mapped(mem)) {
135             memory_region_del_subregion(get_system_memory(), mem);
136         }
137     }
138     memory_region_transaction_commit();
139 }
140
141 static bool dino_chip_mem_valid(void *opaque, hwaddr addr,
142                                 unsigned size, bool is_write,
143                                 MemTxAttrs attrs)
144 {
145     switch (addr) {
146     case DINO_IAR0:
147     case DINO_IAR1:
148     case DINO_IRR0:
149     case DINO_IRR1:
150     case DINO_IMR:
151     case DINO_IPR:
152     case DINO_ICR:
153     case DINO_ILR:
154     case DINO_IO_CONTROL:
155     case DINO_IO_ADDR_EN:
156     case DINO_PCI_IO_DATA:
157         return true;
158     case DINO_PCI_IO_DATA + 2:
159         return size <= 2;
160     case DINO_PCI_IO_DATA + 1:
161     case DINO_PCI_IO_DATA + 3:
162         return size == 1;
163     }
164     return false;
165 }
166
167 static MemTxResult dino_chip_read_with_attrs(void *opaque, hwaddr addr,
168                                              uint64_t *data, unsigned size,
169                                              MemTxAttrs attrs)
170 {
171     DinoState *s = opaque;
172     MemTxResult ret = MEMTX_OK;
173     AddressSpace *io;
174     uint16_t ioaddr;
175     uint32_t val;
176
177     switch (addr) {
178     case DINO_PCI_IO_DATA ... DINO_PCI_IO_DATA + 3:
179         /* Read from PCI IO space. */
180         io = &address_space_io;
181         ioaddr = s->parent_obj.config_reg + (addr & 3);
182         switch (size) {
183         case 1:
184             val = address_space_ldub(io, ioaddr, attrs, &ret);
185             break;
186         case 2:
187             val = address_space_lduw_be(io, ioaddr, attrs, &ret);
188             break;
189         case 4:
190             val = address_space_ldl_be(io, ioaddr, attrs, &ret);
191             break;
192         default:
193             g_assert_not_reached();
194         }
195         break;
196
197     case DINO_IO_ADDR_EN:
198         val = s->io_addr_en;
199         break;
200     case DINO_IO_CONTROL:
201         val = s->io_control;
202         break;
203
204     case DINO_IAR0:
205         val = s->iar0;
206         break;
207     case DINO_IAR1:
208         val = s->iar1;
209         break;
210     case DINO_IMR:
211         val = s->imr;
212         break;
213     case DINO_ICR:
214         val = s->icr;
215         break;
216     case DINO_IPR:
217         val = s->ipr;
218         /* Any read to IPR clears the register.  */
219         s->ipr = 0;
220         break;
221     case DINO_ILR:
222         val = s->ilr;
223         break;
224     case DINO_IRR0:
225         val = s->ilr & s->imr & ~s->icr;
226         break;
227     case DINO_IRR1:
228         val = s->ilr & s->imr & s->icr;
229         break;
230
231     default:
232         /* Controlled by dino_chip_mem_valid above.  */
233         g_assert_not_reached();
234     }
235
236     *data = val;
237     return ret;
238 }
239
240 static MemTxResult dino_chip_write_with_attrs(void *opaque, hwaddr addr,
241                                               uint64_t val, unsigned size,
242                                               MemTxAttrs attrs)
243 {
244     DinoState *s = opaque;
245     AddressSpace *io;
246     MemTxResult ret;
247     uint16_t ioaddr;
248
249     switch (addr) {
250     case DINO_IO_DATA ... DINO_PCI_IO_DATA + 3:
251         /* Write into PCI IO space.  */
252         io = &address_space_io;
253         ioaddr = s->parent_obj.config_reg + (addr & 3);
254         switch (size) {
255         case 1:
256             address_space_stb(io, ioaddr, val, attrs, &ret);
257             break;
258         case 2:
259             address_space_stw_be(io, ioaddr, val, attrs, &ret);
260             break;
261         case 4:
262             address_space_stl_be(io, ioaddr, val, attrs, &ret);
263             break;
264         default:
265             g_assert_not_reached();
266         }
267         return ret;
268
269     case DINO_IO_ADDR_EN:
270         /* Never allow first (=firmware) and last (=Dino) areas.  */
271         s->io_addr_en = val & 0x7ffffffe;
272         gsc_to_pci_forwarding(s);
273         break;
274     case DINO_IO_CONTROL:
275         s->io_control = val;
276         gsc_to_pci_forwarding(s);
277         break;
278
279     case DINO_IAR0:
280         s->iar0 = val;
281         break;
282     case DINO_IAR1:
283         s->iar1 = val;
284         break;
285     case DINO_IMR:
286         s->imr = val;
287         break;
288     case DINO_ICR:
289         s->icr = val;
290         break;
291     case DINO_IPR:
292         /* Any write to IPR clears the register.  */
293         s->ipr = 0;
294         break;
295
296     case DINO_ILR:
297     case DINO_IRR0:
298     case DINO_IRR1:
299         /* These registers are read-only.  */
300         break;
301
302     default:
303         /* Controlled by dino_chip_mem_valid above.  */
304         g_assert_not_reached();
305     }
306     return MEMTX_OK;
307 }
308
309 static const MemoryRegionOps dino_chip_ops = {
310     .read_with_attrs = dino_chip_read_with_attrs,
311     .write_with_attrs = dino_chip_write_with_attrs,
312     .endianness = DEVICE_BIG_ENDIAN,
313     .valid = {
314         .min_access_size = 1,
315         .max_access_size = 4,
316         .accepts = dino_chip_mem_valid,
317     },
318     .impl = {
319         .min_access_size = 1,
320         .max_access_size = 4,
321     },
322 };
323
324 static const VMStateDescription vmstate_dino = {
325     .name = "Dino",
326     .version_id = 1,
327     .minimum_version_id = 1,
328     .fields = (VMStateField[]) {
329         VMSTATE_UINT32(iar0, DinoState),
330         VMSTATE_UINT32(iar1, DinoState),
331         VMSTATE_UINT32(imr, DinoState),
332         VMSTATE_UINT32(ipr, DinoState),
333         VMSTATE_UINT32(icr, DinoState),
334         VMSTATE_UINT32(ilr, DinoState),
335         VMSTATE_UINT32(io_addr_en, DinoState),
336         VMSTATE_UINT32(io_control, DinoState),
337         VMSTATE_END_OF_LIST()
338     }
339 };
340
341
342 /* Unlike pci_config_data_le_ops, no check of high bit set in config_reg.  */
343
344 static uint64_t dino_config_data_read(void *opaque, hwaddr addr, unsigned len)
345 {
346     PCIHostState *s = opaque;
347     return pci_data_read(s->bus, s->config_reg | (addr & 3), len);
348 }
349
350 static void dino_config_data_write(void *opaque, hwaddr addr,
351                                    uint64_t val, unsigned len)
352 {
353     PCIHostState *s = opaque;
354     pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
355 }
356
357 static const MemoryRegionOps dino_config_data_ops = {
358     .read = dino_config_data_read,
359     .write = dino_config_data_write,
360     .endianness = DEVICE_LITTLE_ENDIAN,
361 };
362
363 static uint64_t dino_config_addr_read(void *opaque, hwaddr addr, unsigned len)
364 {
365     PCIHostState *s = opaque;
366     return s->config_reg;
367 }
368
369 static void dino_config_addr_write(void *opaque, hwaddr addr,
370                                    uint64_t val, unsigned len)
371 {
372     PCIHostState *s = opaque;
373     s->config_reg = val & ~3U;
374 }
375
376 static const MemoryRegionOps dino_config_addr_ops = {
377     .read = dino_config_addr_read,
378     .write = dino_config_addr_write,
379     .valid.min_access_size = 4,
380     .valid.max_access_size = 4,
381     .endianness = DEVICE_BIG_ENDIAN,
382 };
383
384 static AddressSpace *dino_pcihost_set_iommu(PCIBus *bus, void *opaque,
385                                             int devfn)
386 {
387     DinoState *s = opaque;
388
389     return &s->bm_as;
390 }
391
392 /*
393  * Dino interrupts are connected as shown on Page 78, Table 23
394  * (Little-endian bit numbers)
395  *    0   PCI INTA
396  *    1   PCI INTB
397  *    2   PCI INTC
398  *    3   PCI INTD
399  *    4   PCI INTE
400  *    5   PCI INTF
401  *    6   GSC External Interrupt
402  *    7   Bus Error for "less than fatal" mode
403  *    8   PS2
404  *    9   Unused
405  *    10  RS232
406  */
407
408 static void dino_set_irq(void *opaque, int irq, int level)
409 {
410     DinoState *s = opaque;
411     uint32_t bit = 1u << irq;
412     uint32_t old_ilr = s->ilr;
413
414     if (level) {
415         uint32_t ena = bit & ~old_ilr;
416         s->ipr |= ena;
417         s->ilr = old_ilr | bit;
418         if (ena & s->imr) {
419             uint32_t iar = (ena & s->icr ? s->iar1 : s->iar0);
420             stl_be_phys(&address_space_memory, iar & -32, iar & 31);
421         }
422     } else {
423         s->ilr = old_ilr & ~bit;
424     }
425 }
426
427 static int dino_pci_map_irq(PCIDevice *d, int irq_num)
428 {
429     int slot = d->devfn >> 3;
430
431     assert(irq_num >= 0 && irq_num <= 3);
432
433     return slot & 0x03;
434 }
435
436 static void dino_set_timer_irq(void *opaque, int irq, int level)
437 {
438     /* ??? Not connected.  */
439 }
440
441 static void dino_set_serial_irq(void *opaque, int irq, int level)
442 {
443     dino_set_irq(opaque, 10, level);
444 }
445
446 PCIBus *dino_init(MemoryRegion *addr_space,
447                   qemu_irq *p_rtc_irq, qemu_irq *p_ser_irq)
448 {
449     DeviceState *dev;
450     DinoState *s;
451     PCIBus *b;
452     int i;
453
454     dev = qdev_create(NULL, TYPE_DINO_PCI_HOST_BRIDGE);
455     s = DINO_PCI_HOST_BRIDGE(dev);
456
457     /* Dino PCI access from main memory.  */
458     memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops,
459                           s, "dino", 4096);
460     memory_region_add_subregion(addr_space, DINO_HPA, &s->this_mem);
461
462     /* Dino PCI config. */
463     memory_region_init_io(&s->parent_obj.conf_mem, OBJECT(&s->parent_obj),
464                           &dino_config_addr_ops, dev, "pci-conf-idx", 4);
465     memory_region_init_io(&s->parent_obj.data_mem, OBJECT(&s->parent_obj),
466                           &dino_config_data_ops, dev, "pci-conf-data", 4);
467     memory_region_add_subregion(&s->this_mem, DINO_PCI_CONFIG_ADDR,
468                                 &s->parent_obj.conf_mem);
469     memory_region_add_subregion(&s->this_mem, DINO_CONFIG_DATA,
470                                 &s->parent_obj.data_mem);
471
472     /* Dino PCI bus memory.  */
473     memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 1ull << 32);
474
475     b = pci_register_root_bus(dev, "pci", dino_set_irq, dino_pci_map_irq, s,
476                               &s->pci_mem, get_system_io(),
477                               PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS);
478     s->parent_obj.bus = b;
479     qdev_init_nofail(dev);
480
481     /* Set up windows into PCI bus memory.  */
482     for (i = 1; i < 31; i++) {
483         uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE;
484         char *name = g_strdup_printf("PCI Outbound Window %d", i);
485         memory_region_init_alias(&s->pci_mem_alias[i], OBJECT(s),
486                                  name, &s->pci_mem, addr,
487                                  DINO_MEM_CHUNK_SIZE);
488         g_free(name);
489     }
490
491     /* Set up PCI view of memory: Bus master address space.  */
492     memory_region_init(&s->bm, OBJECT(s), "bm-dino", 1ull << 32);
493     memory_region_init_alias(&s->bm_ram_alias, OBJECT(s),
494                              "bm-system", addr_space, 0,
495                              0xf0000000 + DINO_MEM_CHUNK_SIZE);
496     memory_region_init_alias(&s->bm_pci_alias, OBJECT(s),
497                              "bm-pci", &s->pci_mem,
498                              0xf0000000 + DINO_MEM_CHUNK_SIZE,
499                              30 * DINO_MEM_CHUNK_SIZE);
500     memory_region_init_alias(&s->bm_cpu_alias, OBJECT(s),
501                              "bm-cpu", addr_space, 0xfff00000,
502                              0xfffff);
503     memory_region_add_subregion(&s->bm, 0,
504                                 &s->bm_ram_alias);
505     memory_region_add_subregion(&s->bm,
506                                 0xf0000000 + DINO_MEM_CHUNK_SIZE,
507                                 &s->bm_pci_alias);
508     memory_region_add_subregion(&s->bm, 0xfff00000,
509                                 &s->bm_cpu_alias);
510     address_space_init(&s->bm_as, &s->bm, "pci-bm");
511     pci_setup_iommu(b, dino_pcihost_set_iommu, s);
512
513     *p_rtc_irq = qemu_allocate_irq(dino_set_timer_irq, s, 0);
514     *p_ser_irq = qemu_allocate_irq(dino_set_serial_irq, s, 0);
515
516     return b;
517 }
518
519 static void dino_pcihost_class_init(ObjectClass *klass, void *data)
520 {
521     DeviceClass *dc = DEVICE_CLASS(klass);
522
523     dc->vmsd = &vmstate_dino;
524 }
525
526 static const TypeInfo dino_pcihost_info = {
527     .name          = TYPE_DINO_PCI_HOST_BRIDGE,
528     .parent        = TYPE_PCI_HOST_BRIDGE,
529     .instance_size = sizeof(DinoState),
530     .class_init    = dino_pcihost_class_init,
531 };
532
533 static void dino_register_types(void)
534 {
535     type_register_static(&dino_pcihost_info);
536 }
537
538 type_init(dino_register_types)
This page took 0.053803 seconds and 4 git commands to generate.