Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 1 | /* |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 2 | * HP-PARISC Dino PCI chipset emulation, as in B160L and similiar machines |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 3 | * |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 4 | * (C) 2017-2019 by Helge Deller <deller@gmx.de> |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 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" |
Markus Armbruster | 0b8fa32 | 2019-05-23 16:35:07 +0200 | [diff] [blame] | 14 | #include "qemu/module.h" |
Philippe Mathieu-Daudé | c108cc5 | 2018-06-25 09:42:11 -0300 | [diff] [blame] | 15 | #include "qemu/units.h" |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 16 | #include "qapi/error.h" |
Markus Armbruster | 64552b6 | 2019-08-12 07:23:42 +0200 | [diff] [blame] | 17 | #include "hw/irq.h" |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 18 | #include "hw/pci/pci.h" |
| 19 | #include "hw/pci/pci_bus.h" |
Markus Armbruster | d645427 | 2019-08-12 07:23:45 +0200 | [diff] [blame] | 20 | #include "migration/vmstate.h" |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 21 | #include "hppa_sys.h" |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 22 | #include "trace.h" |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 23 | #include "qom/object.h" |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 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 | |
Philippe Mathieu-Daudé | c108cc5 | 2018-06-25 09:42:11 -0300 | [diff] [blame] | 80 | #define DINO_MEM_CHUNK_SIZE (8 * MiB) |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 81 | |
Eduardo Habkost | 8063396 | 2020-09-16 14:25:19 -0400 | [diff] [blame] | 82 | OBJECT_DECLARE_SIMPLE_TYPE(DinoState, DINO_PCI_HOST_BRIDGE) |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 83 | |
Philippe Mathieu-Daudé | 6e4ed42 | 2020-02-18 07:33:53 +0100 | [diff] [blame] | 84 | #define DINO800_REGS (1 + (DINO_TLTIM - DINO_GMASK) / 4) |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 85 | static const uint32_t reg800_keep_bits[DINO800_REGS] = { |
Philippe Mathieu-Daudé | 422a264 | 2020-02-18 07:33:52 +0100 | [diff] [blame] | 86 | MAKE_64BIT_MASK(0, 1), /* GMASK */ |
| 87 | MAKE_64BIT_MASK(0, 7), /* PAMR */ |
| 88 | MAKE_64BIT_MASK(0, 7), /* PAPR */ |
| 89 | MAKE_64BIT_MASK(0, 8), /* DAMODE */ |
| 90 | MAKE_64BIT_MASK(0, 7), /* PCICMD */ |
| 91 | MAKE_64BIT_MASK(0, 9), /* PCISTS */ |
| 92 | MAKE_64BIT_MASK(0, 32), /* Undefined */ |
| 93 | MAKE_64BIT_MASK(0, 8), /* MLTIM */ |
| 94 | MAKE_64BIT_MASK(0, 30), /* BRDG_FEAT */ |
Philippe Mathieu-Daudé | c9cbfeb | 2020-02-18 07:33:54 +0100 | [diff] [blame] | 95 | MAKE_64BIT_MASK(0, 24), /* PCIROR */ |
Philippe Mathieu-Daudé | 422a264 | 2020-02-18 07:33:52 +0100 | [diff] [blame] | 96 | MAKE_64BIT_MASK(0, 22), /* PCIWOR */ |
Philippe Mathieu-Daudé | 6e4ed42 | 2020-02-18 07:33:53 +0100 | [diff] [blame] | 97 | MAKE_64BIT_MASK(0, 32), /* Undocumented */ |
Philippe Mathieu-Daudé | 422a264 | 2020-02-18 07:33:52 +0100 | [diff] [blame] | 98 | MAKE_64BIT_MASK(0, 9), /* TLTIM */ |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 99 | }; |
| 100 | |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 101 | struct DinoState { |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 102 | PCIHostState parent_obj; |
| 103 | |
| 104 | /* PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops, |
| 105 | so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops. */ |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 106 | uint32_t config_reg_dino; /* keep original copy, including 2 lowest bits */ |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 107 | |
| 108 | uint32_t iar0; |
| 109 | uint32_t iar1; |
| 110 | uint32_t imr; |
| 111 | uint32_t ipr; |
| 112 | uint32_t icr; |
| 113 | uint32_t ilr; |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 114 | uint32_t io_fbb_en; |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 115 | uint32_t io_addr_en; |
| 116 | uint32_t io_control; |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 117 | uint32_t toc_addr; |
| 118 | |
| 119 | uint32_t reg800[DINO800_REGS]; |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 120 | |
| 121 | MemoryRegion this_mem; |
| 122 | MemoryRegion pci_mem; |
| 123 | MemoryRegion pci_mem_alias[32]; |
| 124 | |
| 125 | AddressSpace bm_as; |
| 126 | MemoryRegion bm; |
| 127 | MemoryRegion bm_ram_alias; |
| 128 | MemoryRegion bm_pci_alias; |
Sven Schnelle | cb82c57 | 2019-02-11 20:20:39 +0100 | [diff] [blame] | 129 | MemoryRegion bm_cpu_alias; |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 130 | }; |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 131 | |
| 132 | /* |
| 133 | * Dino can forward memory accesses from the CPU in the range between |
| 134 | * 0xf0800000 and 0xff000000 to the PCI bus. |
| 135 | */ |
| 136 | static void gsc_to_pci_forwarding(DinoState *s) |
| 137 | { |
| 138 | uint32_t io_addr_en, tmp; |
| 139 | int enabled, i; |
| 140 | |
| 141 | tmp = extract32(s->io_control, 7, 2); |
| 142 | enabled = (tmp == 0x01); |
| 143 | io_addr_en = s->io_addr_en; |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 144 | /* Mask out first (=firmware) and last (=Dino) areas. */ |
| 145 | io_addr_en &= ~(BIT(31) | BIT(0)); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 146 | |
| 147 | memory_region_transaction_begin(); |
| 148 | for (i = 1; i < 31; i++) { |
| 149 | MemoryRegion *mem = &s->pci_mem_alias[i]; |
| 150 | if (enabled && (io_addr_en & (1U << i))) { |
| 151 | if (!memory_region_is_mapped(mem)) { |
| 152 | uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE; |
| 153 | memory_region_add_subregion(get_system_memory(), addr, mem); |
| 154 | } |
| 155 | } else if (memory_region_is_mapped(mem)) { |
| 156 | memory_region_del_subregion(get_system_memory(), mem); |
| 157 | } |
| 158 | } |
| 159 | memory_region_transaction_commit(); |
| 160 | } |
| 161 | |
| 162 | static bool dino_chip_mem_valid(void *opaque, hwaddr addr, |
Peter Maydell | 8372d38 | 2018-05-31 14:50:52 +0100 | [diff] [blame] | 163 | unsigned size, bool is_write, |
| 164 | MemTxAttrs attrs) |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 165 | { |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 166 | bool ret = false; |
| 167 | |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 168 | switch (addr) { |
| 169 | case DINO_IAR0: |
| 170 | case DINO_IAR1: |
| 171 | case DINO_IRR0: |
| 172 | case DINO_IRR1: |
| 173 | case DINO_IMR: |
| 174 | case DINO_IPR: |
| 175 | case DINO_ICR: |
| 176 | case DINO_ILR: |
| 177 | case DINO_IO_CONTROL: |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 178 | case DINO_IO_FBB_EN: |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 179 | case DINO_IO_ADDR_EN: |
| 180 | case DINO_PCI_IO_DATA: |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 181 | case DINO_TOC_ADDR: |
Philippe Mathieu-Daudé | 90e94c0 | 2020-02-18 07:33:55 +0100 | [diff] [blame] | 182 | case DINO_GMASK ... DINO_PCISTS: |
| 183 | case DINO_MLTIM ... DINO_PCIWOR: |
| 184 | case DINO_TLTIM: |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 185 | ret = true; |
| 186 | break; |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 187 | case DINO_PCI_IO_DATA + 2: |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 188 | ret = (size <= 2); |
| 189 | break; |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 190 | case DINO_PCI_IO_DATA + 1: |
| 191 | case DINO_PCI_IO_DATA + 3: |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 192 | ret = (size == 1); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 193 | } |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 194 | trace_dino_chip_mem_valid(addr, ret); |
| 195 | return ret; |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 196 | } |
| 197 | |
| 198 | static MemTxResult dino_chip_read_with_attrs(void *opaque, hwaddr addr, |
| 199 | uint64_t *data, unsigned size, |
| 200 | MemTxAttrs attrs) |
| 201 | { |
| 202 | DinoState *s = opaque; |
| 203 | MemTxResult ret = MEMTX_OK; |
| 204 | AddressSpace *io; |
| 205 | uint16_t ioaddr; |
| 206 | uint32_t val; |
| 207 | |
| 208 | switch (addr) { |
| 209 | case DINO_PCI_IO_DATA ... DINO_PCI_IO_DATA + 3: |
| 210 | /* Read from PCI IO space. */ |
| 211 | io = &address_space_io; |
Sven Schnelle | 368bec8 | 2019-02-18 19:33:14 +0100 | [diff] [blame] | 212 | ioaddr = s->parent_obj.config_reg + (addr & 3); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 213 | switch (size) { |
| 214 | case 1: |
| 215 | val = address_space_ldub(io, ioaddr, attrs, &ret); |
| 216 | break; |
| 217 | case 2: |
| 218 | val = address_space_lduw_be(io, ioaddr, attrs, &ret); |
| 219 | break; |
| 220 | case 4: |
| 221 | val = address_space_ldl_be(io, ioaddr, attrs, &ret); |
| 222 | break; |
| 223 | default: |
| 224 | g_assert_not_reached(); |
| 225 | } |
| 226 | break; |
| 227 | |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 228 | case DINO_IO_FBB_EN: |
| 229 | val = s->io_fbb_en; |
| 230 | break; |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 231 | case DINO_IO_ADDR_EN: |
| 232 | val = s->io_addr_en; |
| 233 | break; |
| 234 | case DINO_IO_CONTROL: |
| 235 | val = s->io_control; |
| 236 | break; |
| 237 | |
| 238 | case DINO_IAR0: |
| 239 | val = s->iar0; |
| 240 | break; |
| 241 | case DINO_IAR1: |
| 242 | val = s->iar1; |
| 243 | break; |
| 244 | case DINO_IMR: |
| 245 | val = s->imr; |
| 246 | break; |
| 247 | case DINO_ICR: |
| 248 | val = s->icr; |
| 249 | break; |
| 250 | case DINO_IPR: |
| 251 | val = s->ipr; |
| 252 | /* Any read to IPR clears the register. */ |
| 253 | s->ipr = 0; |
| 254 | break; |
| 255 | case DINO_ILR: |
| 256 | val = s->ilr; |
| 257 | break; |
| 258 | case DINO_IRR0: |
| 259 | val = s->ilr & s->imr & ~s->icr; |
| 260 | break; |
| 261 | case DINO_IRR1: |
| 262 | val = s->ilr & s->imr & s->icr; |
| 263 | break; |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 264 | case DINO_TOC_ADDR: |
| 265 | val = s->toc_addr; |
| 266 | break; |
| 267 | case DINO_GMASK ... DINO_TLTIM: |
| 268 | val = s->reg800[(addr - DINO_GMASK) / 4]; |
| 269 | if (addr == DINO_PAMR) { |
| 270 | val &= ~0x01; /* LSB is hardwired to 0 */ |
| 271 | } |
| 272 | if (addr == DINO_MLTIM) { |
| 273 | val &= ~0x07; /* 3 LSB are hardwired to 0 */ |
| 274 | } |
| 275 | if (addr == DINO_BRDG_FEAT) { |
| 276 | val &= ~(0x10710E0ul | 8); /* bits 5-7, 24 & 15 reserved */ |
| 277 | } |
| 278 | break; |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 279 | |
| 280 | default: |
| 281 | /* Controlled by dino_chip_mem_valid above. */ |
| 282 | g_assert_not_reached(); |
| 283 | } |
| 284 | |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 285 | trace_dino_chip_read(addr, val); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 286 | *data = val; |
| 287 | return ret; |
| 288 | } |
| 289 | |
| 290 | static MemTxResult dino_chip_write_with_attrs(void *opaque, hwaddr addr, |
| 291 | uint64_t val, unsigned size, |
| 292 | MemTxAttrs attrs) |
| 293 | { |
| 294 | DinoState *s = opaque; |
| 295 | AddressSpace *io; |
| 296 | MemTxResult ret; |
| 297 | uint16_t ioaddr; |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 298 | int i; |
| 299 | |
| 300 | trace_dino_chip_write(addr, val); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 301 | |
| 302 | switch (addr) { |
| 303 | case DINO_IO_DATA ... DINO_PCI_IO_DATA + 3: |
| 304 | /* Write into PCI IO space. */ |
| 305 | io = &address_space_io; |
Sven Schnelle | 368bec8 | 2019-02-18 19:33:14 +0100 | [diff] [blame] | 306 | ioaddr = s->parent_obj.config_reg + (addr & 3); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 307 | switch (size) { |
| 308 | case 1: |
| 309 | address_space_stb(io, ioaddr, val, attrs, &ret); |
| 310 | break; |
| 311 | case 2: |
| 312 | address_space_stw_be(io, ioaddr, val, attrs, &ret); |
| 313 | break; |
| 314 | case 4: |
| 315 | address_space_stl_be(io, ioaddr, val, attrs, &ret); |
| 316 | break; |
| 317 | default: |
| 318 | g_assert_not_reached(); |
| 319 | } |
| 320 | return ret; |
| 321 | |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 322 | case DINO_IO_FBB_EN: |
| 323 | s->io_fbb_en = val & 0x03; |
| 324 | break; |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 325 | case DINO_IO_ADDR_EN: |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 326 | s->io_addr_en = val; |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 327 | gsc_to_pci_forwarding(s); |
| 328 | break; |
| 329 | case DINO_IO_CONTROL: |
| 330 | s->io_control = val; |
| 331 | gsc_to_pci_forwarding(s); |
| 332 | break; |
| 333 | |
| 334 | case DINO_IAR0: |
| 335 | s->iar0 = val; |
| 336 | break; |
| 337 | case DINO_IAR1: |
| 338 | s->iar1 = val; |
| 339 | break; |
| 340 | case DINO_IMR: |
| 341 | s->imr = val; |
| 342 | break; |
| 343 | case DINO_ICR: |
| 344 | s->icr = val; |
| 345 | break; |
| 346 | case DINO_IPR: |
| 347 | /* Any write to IPR clears the register. */ |
| 348 | s->ipr = 0; |
| 349 | break; |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 350 | case DINO_TOC_ADDR: |
| 351 | /* IO_COMMAND of CPU with client_id bits */ |
| 352 | s->toc_addr = 0xFFFA0030 | (val & 0x1e000); |
| 353 | break; |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 354 | |
| 355 | case DINO_ILR: |
| 356 | case DINO_IRR0: |
| 357 | case DINO_IRR1: |
| 358 | /* These registers are read-only. */ |
| 359 | break; |
| 360 | |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 361 | case DINO_GMASK ... DINO_TLTIM: |
| 362 | i = (addr - DINO_GMASK) / 4; |
| 363 | val &= reg800_keep_bits[i]; |
| 364 | s->reg800[i] = val; |
| 365 | break; |
| 366 | |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 367 | default: |
| 368 | /* Controlled by dino_chip_mem_valid above. */ |
| 369 | g_assert_not_reached(); |
| 370 | } |
| 371 | return MEMTX_OK; |
| 372 | } |
| 373 | |
| 374 | static const MemoryRegionOps dino_chip_ops = { |
| 375 | .read_with_attrs = dino_chip_read_with_attrs, |
| 376 | .write_with_attrs = dino_chip_write_with_attrs, |
| 377 | .endianness = DEVICE_BIG_ENDIAN, |
| 378 | .valid = { |
| 379 | .min_access_size = 1, |
| 380 | .max_access_size = 4, |
| 381 | .accepts = dino_chip_mem_valid, |
| 382 | }, |
| 383 | .impl = { |
| 384 | .min_access_size = 1, |
| 385 | .max_access_size = 4, |
| 386 | }, |
| 387 | }; |
| 388 | |
| 389 | static const VMStateDescription vmstate_dino = { |
| 390 | .name = "Dino", |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 391 | .version_id = 2, |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 392 | .minimum_version_id = 1, |
| 393 | .fields = (VMStateField[]) { |
| 394 | VMSTATE_UINT32(iar0, DinoState), |
| 395 | VMSTATE_UINT32(iar1, DinoState), |
| 396 | VMSTATE_UINT32(imr, DinoState), |
| 397 | VMSTATE_UINT32(ipr, DinoState), |
| 398 | VMSTATE_UINT32(icr, DinoState), |
| 399 | VMSTATE_UINT32(ilr, DinoState), |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 400 | VMSTATE_UINT32(io_fbb_en, DinoState), |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 401 | VMSTATE_UINT32(io_addr_en, DinoState), |
| 402 | VMSTATE_UINT32(io_control, DinoState), |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 403 | VMSTATE_UINT32(toc_addr, DinoState), |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 404 | VMSTATE_END_OF_LIST() |
| 405 | } |
| 406 | }; |
| 407 | |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 408 | /* Unlike pci_config_data_le_ops, no check of high bit set in config_reg. */ |
| 409 | |
| 410 | static uint64_t dino_config_data_read(void *opaque, hwaddr addr, unsigned len) |
| 411 | { |
| 412 | PCIHostState *s = opaque; |
| 413 | return pci_data_read(s->bus, s->config_reg | (addr & 3), len); |
| 414 | } |
| 415 | |
| 416 | static void dino_config_data_write(void *opaque, hwaddr addr, |
| 417 | uint64_t val, unsigned len) |
| 418 | { |
| 419 | PCIHostState *s = opaque; |
| 420 | pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); |
| 421 | } |
| 422 | |
| 423 | static const MemoryRegionOps dino_config_data_ops = { |
| 424 | .read = dino_config_data_read, |
| 425 | .write = dino_config_data_write, |
| 426 | .endianness = DEVICE_LITTLE_ENDIAN, |
| 427 | }; |
| 428 | |
Sven Schnelle | 368bec8 | 2019-02-18 19:33:14 +0100 | [diff] [blame] | 429 | static uint64_t dino_config_addr_read(void *opaque, hwaddr addr, unsigned len) |
| 430 | { |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 431 | DinoState *s = opaque; |
| 432 | return s->config_reg_dino; |
Sven Schnelle | 368bec8 | 2019-02-18 19:33:14 +0100 | [diff] [blame] | 433 | } |
| 434 | |
| 435 | static void dino_config_addr_write(void *opaque, hwaddr addr, |
| 436 | uint64_t val, unsigned len) |
| 437 | { |
| 438 | PCIHostState *s = opaque; |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 439 | DinoState *ds = opaque; |
| 440 | ds->config_reg_dino = val; /* keep a copy of original value */ |
Sven Schnelle | 368bec8 | 2019-02-18 19:33:14 +0100 | [diff] [blame] | 441 | s->config_reg = val & ~3U; |
| 442 | } |
| 443 | |
| 444 | static const MemoryRegionOps dino_config_addr_ops = { |
| 445 | .read = dino_config_addr_read, |
| 446 | .write = dino_config_addr_write, |
| 447 | .valid.min_access_size = 4, |
| 448 | .valid.max_access_size = 4, |
| 449 | .endianness = DEVICE_BIG_ENDIAN, |
| 450 | }; |
| 451 | |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 452 | static AddressSpace *dino_pcihost_set_iommu(PCIBus *bus, void *opaque, |
| 453 | int devfn) |
| 454 | { |
| 455 | DinoState *s = opaque; |
| 456 | |
| 457 | return &s->bm_as; |
| 458 | } |
| 459 | |
| 460 | /* |
| 461 | * Dino interrupts are connected as shown on Page 78, Table 23 |
| 462 | * (Little-endian bit numbers) |
| 463 | * 0 PCI INTA |
| 464 | * 1 PCI INTB |
| 465 | * 2 PCI INTC |
| 466 | * 3 PCI INTD |
| 467 | * 4 PCI INTE |
| 468 | * 5 PCI INTF |
| 469 | * 6 GSC External Interrupt |
| 470 | * 7 Bus Error for "less than fatal" mode |
| 471 | * 8 PS2 |
| 472 | * 9 Unused |
| 473 | * 10 RS232 |
| 474 | */ |
| 475 | |
| 476 | static void dino_set_irq(void *opaque, int irq, int level) |
| 477 | { |
| 478 | DinoState *s = opaque; |
| 479 | uint32_t bit = 1u << irq; |
| 480 | uint32_t old_ilr = s->ilr; |
| 481 | |
| 482 | if (level) { |
| 483 | uint32_t ena = bit & ~old_ilr; |
| 484 | s->ipr |= ena; |
| 485 | s->ilr = old_ilr | bit; |
| 486 | if (ena & s->imr) { |
| 487 | uint32_t iar = (ena & s->icr ? s->iar1 : s->iar0); |
| 488 | stl_be_phys(&address_space_memory, iar & -32, iar & 31); |
| 489 | } |
| 490 | } else { |
| 491 | s->ilr = old_ilr & ~bit; |
| 492 | } |
| 493 | } |
| 494 | |
| 495 | static int dino_pci_map_irq(PCIDevice *d, int irq_num) |
| 496 | { |
Philippe Mathieu-Daudé | 8d40def | 2020-10-11 17:04:23 +0200 | [diff] [blame] | 497 | int slot = PCI_SLOT(d->devfn); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 498 | |
| 499 | assert(irq_num >= 0 && irq_num <= 3); |
| 500 | |
Laurent Vivier | 4a4ff4c | 2018-03-23 15:32:02 +0100 | [diff] [blame] | 501 | return slot & 0x03; |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 502 | } |
| 503 | |
| 504 | static void dino_set_timer_irq(void *opaque, int irq, int level) |
| 505 | { |
| 506 | /* ??? Not connected. */ |
| 507 | } |
| 508 | |
| 509 | static void dino_set_serial_irq(void *opaque, int irq, int level) |
| 510 | { |
| 511 | dino_set_irq(opaque, 10, level); |
| 512 | } |
| 513 | |
| 514 | PCIBus *dino_init(MemoryRegion *addr_space, |
| 515 | qemu_irq *p_rtc_irq, qemu_irq *p_ser_irq) |
| 516 | { |
| 517 | DeviceState *dev; |
| 518 | DinoState *s; |
| 519 | PCIBus *b; |
| 520 | int i; |
| 521 | |
Markus Armbruster | 3e80f69 | 2020-06-10 07:31:58 +0200 | [diff] [blame] | 522 | dev = qdev_new(TYPE_DINO_PCI_HOST_BRIDGE); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 523 | s = DINO_PCI_HOST_BRIDGE(dev); |
Helge Deller | 1809259 | 2019-12-20 22:15:07 +0100 | [diff] [blame] | 524 | s->iar0 = s->iar1 = CPU_HPA + 3; |
| 525 | s->toc_addr = 0xFFFA0030; /* IO_COMMAND of CPU */ |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 526 | |
| 527 | /* Dino PCI access from main memory. */ |
| 528 | memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops, |
| 529 | s, "dino", 4096); |
| 530 | memory_region_add_subregion(addr_space, DINO_HPA, &s->this_mem); |
| 531 | |
| 532 | /* Dino PCI config. */ |
| 533 | memory_region_init_io(&s->parent_obj.conf_mem, OBJECT(&s->parent_obj), |
Sven Schnelle | 368bec8 | 2019-02-18 19:33:14 +0100 | [diff] [blame] | 534 | &dino_config_addr_ops, dev, "pci-conf-idx", 4); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 535 | memory_region_init_io(&s->parent_obj.data_mem, OBJECT(&s->parent_obj), |
| 536 | &dino_config_data_ops, dev, "pci-conf-data", 4); |
| 537 | memory_region_add_subregion(&s->this_mem, DINO_PCI_CONFIG_ADDR, |
| 538 | &s->parent_obj.conf_mem); |
| 539 | memory_region_add_subregion(&s->this_mem, DINO_CONFIG_DATA, |
| 540 | &s->parent_obj.data_mem); |
| 541 | |
| 542 | /* Dino PCI bus memory. */ |
Philippe Mathieu-Daudé | 94c1253 | 2020-06-01 16:29:28 +0200 | [diff] [blame] | 543 | memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 4 * GiB); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 544 | |
| 545 | b = pci_register_root_bus(dev, "pci", dino_set_irq, dino_pci_map_irq, s, |
| 546 | &s->pci_mem, get_system_io(), |
| 547 | PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS); |
| 548 | s->parent_obj.bus = b; |
Markus Armbruster | 3c6ef47 | 2020-06-10 07:32:34 +0200 | [diff] [blame] | 549 | sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 550 | |
| 551 | /* Set up windows into PCI bus memory. */ |
| 552 | for (i = 1; i < 31; i++) { |
| 553 | uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE; |
| 554 | char *name = g_strdup_printf("PCI Outbound Window %d", i); |
| 555 | memory_region_init_alias(&s->pci_mem_alias[i], OBJECT(s), |
| 556 | name, &s->pci_mem, addr, |
| 557 | DINO_MEM_CHUNK_SIZE); |
Paolo Bonzini | 266a880 | 2019-10-01 15:36:24 +0200 | [diff] [blame] | 558 | g_free(name); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 559 | } |
| 560 | |
| 561 | /* Set up PCI view of memory: Bus master address space. */ |
Philippe Mathieu-Daudé | 94c1253 | 2020-06-01 16:29:28 +0200 | [diff] [blame] | 562 | memory_region_init(&s->bm, OBJECT(s), "bm-dino", 4 * GiB); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 563 | memory_region_init_alias(&s->bm_ram_alias, OBJECT(s), |
| 564 | "bm-system", addr_space, 0, |
| 565 | 0xf0000000 + DINO_MEM_CHUNK_SIZE); |
| 566 | memory_region_init_alias(&s->bm_pci_alias, OBJECT(s), |
| 567 | "bm-pci", &s->pci_mem, |
| 568 | 0xf0000000 + DINO_MEM_CHUNK_SIZE, |
Sven Schnelle | cb82c57 | 2019-02-11 20:20:39 +0100 | [diff] [blame] | 569 | 30 * DINO_MEM_CHUNK_SIZE); |
| 570 | memory_region_init_alias(&s->bm_cpu_alias, OBJECT(s), |
| 571 | "bm-cpu", addr_space, 0xfff00000, |
| 572 | 0xfffff); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 573 | memory_region_add_subregion(&s->bm, 0, |
| 574 | &s->bm_ram_alias); |
| 575 | memory_region_add_subregion(&s->bm, |
| 576 | 0xf0000000 + DINO_MEM_CHUNK_SIZE, |
| 577 | &s->bm_pci_alias); |
Sven Schnelle | cb82c57 | 2019-02-11 20:20:39 +0100 | [diff] [blame] | 578 | memory_region_add_subregion(&s->bm, 0xfff00000, |
| 579 | &s->bm_cpu_alias); |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 580 | address_space_init(&s->bm_as, &s->bm, "pci-bm"); |
| 581 | pci_setup_iommu(b, dino_pcihost_set_iommu, s); |
| 582 | |
| 583 | *p_rtc_irq = qemu_allocate_irq(dino_set_timer_irq, s, 0); |
| 584 | *p_ser_irq = qemu_allocate_irq(dino_set_serial_irq, s, 0); |
| 585 | |
| 586 | return b; |
| 587 | } |
| 588 | |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 589 | static void dino_pcihost_class_init(ObjectClass *klass, void *data) |
| 590 | { |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 591 | DeviceClass *dc = DEVICE_CLASS(klass); |
| 592 | |
Helge Deller | a72bd60 | 2017-10-08 16:47:27 -0400 | [diff] [blame] | 593 | dc->vmsd = &vmstate_dino; |
| 594 | } |
| 595 | |
| 596 | static const TypeInfo dino_pcihost_info = { |
| 597 | .name = TYPE_DINO_PCI_HOST_BRIDGE, |
| 598 | .parent = TYPE_PCI_HOST_BRIDGE, |
| 599 | .instance_size = sizeof(DinoState), |
| 600 | .class_init = dino_pcihost_class_init, |
| 601 | }; |
| 602 | |
| 603 | static void dino_register_types(void) |
| 604 | { |
| 605 | type_register_static(&dino_pcihost_info); |
| 606 | } |
| 607 | |
| 608 | type_init(dino_register_types) |