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