aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 1 | /* |
| 2 | * QEMU PowerPC E500 embedded processors pci controller emulation |
| 3 | * |
| 4 | * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved. |
| 5 | * |
| 6 | * Author: Yu Liu, <yu.liu@freescale.com> |
| 7 | * |
| 8 | * This file is derived from hw/ppc4xx_pci.c, |
| 9 | * the copyright for that material belongs to the original owners. |
| 10 | * |
| 11 | * This is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License as published by |
| 13 | * the Free Software Foundation; either version 2 of the License, or |
| 14 | * (at your option) any later version. |
| 15 | */ |
| 16 | |
| 17 | #include "hw.h" |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 18 | #include "pci.h" |
| 19 | #include "pci_host.h" |
| 20 | #include "bswap.h" |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 21 | |
| 22 | #ifdef DEBUG_PCI |
Blue Swirl | 001faf3 | 2009-05-13 17:53:17 +0000 | [diff] [blame] | 23 | #define pci_debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 24 | #else |
Blue Swirl | 001faf3 | 2009-05-13 17:53:17 +0000 | [diff] [blame] | 25 | #define pci_debug(fmt, ...) |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 26 | #endif |
| 27 | |
| 28 | #define PCIE500_CFGADDR 0x0 |
| 29 | #define PCIE500_CFGDATA 0x4 |
| 30 | #define PCIE500_REG_BASE 0xC00 |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 31 | #define PCIE500_ALL_SIZE 0x1000 |
| 32 | #define PCIE500_REG_SIZE (PCIE500_ALL_SIZE - PCIE500_REG_BASE) |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 33 | |
| 34 | #define PPCE500_PCI_CONFIG_ADDR 0x0 |
| 35 | #define PPCE500_PCI_CONFIG_DATA 0x4 |
| 36 | #define PPCE500_PCI_INTACK 0x8 |
| 37 | |
| 38 | #define PPCE500_PCI_OW1 (0xC20 - PCIE500_REG_BASE) |
| 39 | #define PPCE500_PCI_OW2 (0xC40 - PCIE500_REG_BASE) |
| 40 | #define PPCE500_PCI_OW3 (0xC60 - PCIE500_REG_BASE) |
| 41 | #define PPCE500_PCI_OW4 (0xC80 - PCIE500_REG_BASE) |
| 42 | #define PPCE500_PCI_IW3 (0xDA0 - PCIE500_REG_BASE) |
| 43 | #define PPCE500_PCI_IW2 (0xDC0 - PCIE500_REG_BASE) |
| 44 | #define PPCE500_PCI_IW1 (0xDE0 - PCIE500_REG_BASE) |
| 45 | |
| 46 | #define PPCE500_PCI_GASKET_TIMR (0xE20 - PCIE500_REG_BASE) |
| 47 | |
| 48 | #define PCI_POTAR 0x0 |
| 49 | #define PCI_POTEAR 0x4 |
| 50 | #define PCI_POWBAR 0x8 |
| 51 | #define PCI_POWAR 0x10 |
| 52 | |
| 53 | #define PCI_PITAR 0x0 |
| 54 | #define PCI_PIWBAR 0x8 |
| 55 | #define PCI_PIWBEAR 0xC |
| 56 | #define PCI_PIWAR 0x10 |
| 57 | |
| 58 | #define PPCE500_PCI_NR_POBS 5 |
| 59 | #define PPCE500_PCI_NR_PIBS 3 |
| 60 | |
| 61 | struct pci_outbound { |
| 62 | uint32_t potar; |
| 63 | uint32_t potear; |
| 64 | uint32_t powbar; |
| 65 | uint32_t powar; |
| 66 | }; |
| 67 | |
| 68 | struct pci_inbound { |
| 69 | uint32_t pitar; |
| 70 | uint32_t piwbar; |
| 71 | uint32_t piwbear; |
| 72 | uint32_t piwar; |
| 73 | }; |
| 74 | |
Andreas Färber | 9c1a61f | 2012-08-20 19:08:03 +0200 | [diff] [blame] | 75 | #define TYPE_PPC_E500_PCI_HOST_BRIDGE "e500-pcihost" |
| 76 | |
| 77 | #define PPC_E500_PCI_HOST_BRIDGE(obj) \ |
| 78 | OBJECT_CHECK(PPCE500PCIState, (obj), TYPE_PPC_E500_PCI_HOST_BRIDGE) |
| 79 | |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 80 | struct PPCE500PCIState { |
Andreas Färber | 67c332f | 2012-08-20 19:08:09 +0200 | [diff] [blame] | 81 | PCIHostState parent_obj; |
Andreas Färber | 9c1a61f | 2012-08-20 19:08:03 +0200 | [diff] [blame] | 82 | |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 83 | struct pci_outbound pob[PPCE500_PCI_NR_POBS]; |
| 84 | struct pci_inbound pib[PPCE500_PCI_NR_PIBS]; |
| 85 | uint32_t gasket_time; |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 86 | qemu_irq irq[4]; |
| 87 | /* mmio maps */ |
Benoît Canet | cb4e15c | 2011-12-16 23:37:47 +0100 | [diff] [blame] | 88 | MemoryRegion container; |
Avi Kivity | cd5cba7 | 2011-11-20 11:52:58 +0200 | [diff] [blame] | 89 | MemoryRegion iomem; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 90 | }; |
| 91 | |
| 92 | typedef struct PPCE500PCIState PPCE500PCIState; |
| 93 | |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 94 | static uint64_t pci_reg_read4(void *opaque, hwaddr addr, |
Avi Kivity | cd5cba7 | 2011-11-20 11:52:58 +0200 | [diff] [blame] | 95 | unsigned size) |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 96 | { |
| 97 | PPCE500PCIState *pci = opaque; |
| 98 | unsigned long win; |
| 99 | uint32_t value = 0; |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 100 | int idx; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 101 | |
| 102 | win = addr & 0xfe0; |
| 103 | |
| 104 | switch (win) { |
| 105 | case PPCE500_PCI_OW1: |
| 106 | case PPCE500_PCI_OW2: |
| 107 | case PPCE500_PCI_OW3: |
| 108 | case PPCE500_PCI_OW4: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 109 | idx = (addr >> 5) & 0x7; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 110 | switch (addr & 0xC) { |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 111 | case PCI_POTAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 112 | value = pci->pob[idx].potar; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 113 | break; |
| 114 | case PCI_POTEAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 115 | value = pci->pob[idx].potear; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 116 | break; |
| 117 | case PCI_POWBAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 118 | value = pci->pob[idx].powbar; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 119 | break; |
| 120 | case PCI_POWAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 121 | value = pci->pob[idx].powar; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 122 | break; |
| 123 | default: |
| 124 | break; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 125 | } |
| 126 | break; |
| 127 | |
| 128 | case PPCE500_PCI_IW3: |
| 129 | case PPCE500_PCI_IW2: |
| 130 | case PPCE500_PCI_IW1: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 131 | idx = ((addr >> 5) & 0x3) - 1; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 132 | switch (addr & 0xC) { |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 133 | case PCI_PITAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 134 | value = pci->pib[idx].pitar; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 135 | break; |
| 136 | case PCI_PIWBAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 137 | value = pci->pib[idx].piwbar; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 138 | break; |
| 139 | case PCI_PIWBEAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 140 | value = pci->pib[idx].piwbear; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 141 | break; |
| 142 | case PCI_PIWAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 143 | value = pci->pib[idx].piwar; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 144 | break; |
| 145 | default: |
| 146 | break; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 147 | }; |
| 148 | break; |
| 149 | |
| 150 | case PPCE500_PCI_GASKET_TIMR: |
| 151 | value = pci->gasket_time; |
| 152 | break; |
| 153 | |
| 154 | default: |
| 155 | break; |
| 156 | } |
| 157 | |
Blue Swirl | c0a2a09 | 2009-07-20 10:37:51 +0000 | [diff] [blame] | 158 | pci_debug("%s: win:%lx(addr:" TARGET_FMT_plx ") -> value:%x\n", __func__, |
| 159 | win, addr, value); |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 160 | return value; |
| 161 | } |
| 162 | |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 163 | static void pci_reg_write4(void *opaque, hwaddr addr, |
Avi Kivity | cd5cba7 | 2011-11-20 11:52:58 +0200 | [diff] [blame] | 164 | uint64_t value, unsigned size) |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 165 | { |
| 166 | PPCE500PCIState *pci = opaque; |
| 167 | unsigned long win; |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 168 | int idx; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 169 | |
| 170 | win = addr & 0xfe0; |
| 171 | |
Blue Swirl | c0a2a09 | 2009-07-20 10:37:51 +0000 | [diff] [blame] | 172 | pci_debug("%s: value:%x -> win:%lx(addr:" TARGET_FMT_plx ")\n", |
Avi Kivity | cd5cba7 | 2011-11-20 11:52:58 +0200 | [diff] [blame] | 173 | __func__, (unsigned)value, win, addr); |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 174 | |
| 175 | switch (win) { |
| 176 | case PPCE500_PCI_OW1: |
| 177 | case PPCE500_PCI_OW2: |
| 178 | case PPCE500_PCI_OW3: |
| 179 | case PPCE500_PCI_OW4: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 180 | idx = (addr >> 5) & 0x7; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 181 | switch (addr & 0xC) { |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 182 | case PCI_POTAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 183 | pci->pob[idx].potar = value; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 184 | break; |
| 185 | case PCI_POTEAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 186 | pci->pob[idx].potear = value; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 187 | break; |
| 188 | case PCI_POWBAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 189 | pci->pob[idx].powbar = value; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 190 | break; |
| 191 | case PCI_POWAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 192 | pci->pob[idx].powar = value; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 193 | break; |
| 194 | default: |
| 195 | break; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 196 | }; |
| 197 | break; |
| 198 | |
| 199 | case PPCE500_PCI_IW3: |
| 200 | case PPCE500_PCI_IW2: |
| 201 | case PPCE500_PCI_IW1: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 202 | idx = ((addr >> 5) & 0x3) - 1; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 203 | switch (addr & 0xC) { |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 204 | case PCI_PITAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 205 | pci->pib[idx].pitar = value; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 206 | break; |
| 207 | case PCI_PIWBAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 208 | pci->pib[idx].piwbar = value; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 209 | break; |
| 210 | case PCI_PIWBEAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 211 | pci->pib[idx].piwbear = value; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 212 | break; |
| 213 | case PCI_PIWAR: |
Liu Yu-B13201 | eeae2e7 | 2011-09-29 17:52:50 +0000 | [diff] [blame] | 214 | pci->pib[idx].piwar = value; |
Liu Yu-B13201 | 6875dc8 | 2011-09-29 17:52:49 +0000 | [diff] [blame] | 215 | break; |
| 216 | default: |
| 217 | break; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 218 | }; |
| 219 | break; |
| 220 | |
| 221 | case PPCE500_PCI_GASKET_TIMR: |
| 222 | pci->gasket_time = value; |
| 223 | break; |
| 224 | |
| 225 | default: |
| 226 | break; |
| 227 | }; |
| 228 | } |
| 229 | |
Avi Kivity | cd5cba7 | 2011-11-20 11:52:58 +0200 | [diff] [blame] | 230 | static const MemoryRegionOps e500_pci_reg_ops = { |
| 231 | .read = pci_reg_read4, |
| 232 | .write = pci_reg_write4, |
| 233 | .endianness = DEVICE_BIG_ENDIAN, |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 234 | }; |
| 235 | |
| 236 | static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int irq_num) |
| 237 | { |
| 238 | int devno = pci_dev->devfn >> 3, ret = 0; |
| 239 | |
| 240 | switch (devno) { |
| 241 | /* Two PCI slot */ |
| 242 | case 0x11: |
| 243 | case 0x12: |
| 244 | ret = (irq_num + devno - 0x10) % 4; |
| 245 | break; |
| 246 | default: |
Scott Wood | 72b310e | 2011-04-08 17:06:37 -0500 | [diff] [blame] | 247 | printf("Error:%s:unknown dev number\n", __func__); |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 248 | } |
| 249 | |
| 250 | pci_debug("%s: devfn %x irq %d -> %d devno:%x\n", __func__, |
| 251 | pci_dev->devfn, irq_num, ret, devno); |
| 252 | |
| 253 | return ret; |
| 254 | } |
| 255 | |
Juan Quintela | 5d4e84c | 2009-08-28 15:28:17 +0200 | [diff] [blame] | 256 | static void mpc85xx_pci_set_irq(void *opaque, int irq_num, int level) |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 257 | { |
Juan Quintela | 5d4e84c | 2009-08-28 15:28:17 +0200 | [diff] [blame] | 258 | qemu_irq *pic = opaque; |
| 259 | |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 260 | pci_debug("%s: PCI irq %d, level:%d\n", __func__, irq_num, level); |
| 261 | |
| 262 | qemu_set_irq(pic[irq_num], level); |
| 263 | } |
| 264 | |
Juan Quintela | e0433ec | 2010-12-02 15:29:42 +0100 | [diff] [blame] | 265 | static const VMStateDescription vmstate_pci_outbound = { |
| 266 | .name = "pci_outbound", |
| 267 | .version_id = 0, |
| 268 | .minimum_version_id = 0, |
| 269 | .minimum_version_id_old = 0, |
| 270 | .fields = (VMStateField[]) { |
| 271 | VMSTATE_UINT32(potar, struct pci_outbound), |
| 272 | VMSTATE_UINT32(potear, struct pci_outbound), |
| 273 | VMSTATE_UINT32(powbar, struct pci_outbound), |
| 274 | VMSTATE_UINT32(powar, struct pci_outbound), |
| 275 | VMSTATE_END_OF_LIST() |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 276 | } |
Juan Quintela | e0433ec | 2010-12-02 15:29:42 +0100 | [diff] [blame] | 277 | }; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 278 | |
Juan Quintela | e0433ec | 2010-12-02 15:29:42 +0100 | [diff] [blame] | 279 | static const VMStateDescription vmstate_pci_inbound = { |
| 280 | .name = "pci_inbound", |
| 281 | .version_id = 0, |
| 282 | .minimum_version_id = 0, |
| 283 | .minimum_version_id_old = 0, |
| 284 | .fields = (VMStateField[]) { |
| 285 | VMSTATE_UINT32(pitar, struct pci_inbound), |
| 286 | VMSTATE_UINT32(piwbar, struct pci_inbound), |
| 287 | VMSTATE_UINT32(piwbear, struct pci_inbound), |
| 288 | VMSTATE_UINT32(piwar, struct pci_inbound), |
| 289 | VMSTATE_END_OF_LIST() |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 290 | } |
Juan Quintela | e0433ec | 2010-12-02 15:29:42 +0100 | [diff] [blame] | 291 | }; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 292 | |
Juan Quintela | e0433ec | 2010-12-02 15:29:42 +0100 | [diff] [blame] | 293 | static const VMStateDescription vmstate_ppce500_pci = { |
| 294 | .name = "ppce500_pci", |
| 295 | .version_id = 1, |
| 296 | .minimum_version_id = 1, |
| 297 | .minimum_version_id_old = 1, |
| 298 | .fields = (VMStateField[]) { |
Juan Quintela | e0433ec | 2010-12-02 15:29:42 +0100 | [diff] [blame] | 299 | VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1, |
| 300 | vmstate_pci_outbound, struct pci_outbound), |
| 301 | VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1, |
| 302 | vmstate_pci_outbound, struct pci_inbound), |
| 303 | VMSTATE_UINT32(gasket_time, PPCE500PCIState), |
| 304 | VMSTATE_END_OF_LIST() |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 305 | } |
Juan Quintela | e0433ec | 2010-12-02 15:29:42 +0100 | [diff] [blame] | 306 | }; |
aurel32 | 74c62ba | 2009-03-02 16:42:23 +0000 | [diff] [blame] | 307 | |
Avi Kivity | 1e39101 | 2011-07-26 14:26:19 +0300 | [diff] [blame] | 308 | #include "exec-memory.h" |
| 309 | |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 310 | static int e500_pcihost_initfn(SysBusDevice *dev) |
| 311 | { |
| 312 | PCIHostState *h; |
| 313 | PPCE500PCIState *s; |
| 314 | PCIBus *b; |
| 315 | int i; |
Avi Kivity | aee97b8 | 2011-08-08 16:09:04 +0300 | [diff] [blame] | 316 | MemoryRegion *address_space_mem = get_system_memory(); |
| 317 | MemoryRegion *address_space_io = get_system_io(); |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 318 | |
Andreas Färber | 8558d94 | 2012-08-20 19:08:08 +0200 | [diff] [blame] | 319 | h = PCI_HOST_BRIDGE(dev); |
Andreas Färber | 9c1a61f | 2012-08-20 19:08:03 +0200 | [diff] [blame] | 320 | s = PPC_E500_PCI_HOST_BRIDGE(dev); |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 321 | |
| 322 | for (i = 0; i < ARRAY_SIZE(s->irq); i++) { |
| 323 | sysbus_init_irq(dev, &s->irq[i]); |
| 324 | } |
| 325 | |
Andreas Färber | 9c1a61f | 2012-08-20 19:08:03 +0200 | [diff] [blame] | 326 | b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq, |
Avi Kivity | aee97b8 | 2011-08-08 16:09:04 +0300 | [diff] [blame] | 327 | mpc85xx_pci_map_irq, s->irq, address_space_mem, |
| 328 | address_space_io, PCI_DEVFN(0x11, 0), 4); |
Andreas Färber | 9c1a61f | 2012-08-20 19:08:03 +0200 | [diff] [blame] | 329 | h->bus = b; |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 330 | |
| 331 | pci_create_simple(b, 0, "e500-host-bridge"); |
| 332 | |
Benoît Canet | cb4e15c | 2011-12-16 23:37:47 +0100 | [diff] [blame] | 333 | memory_region_init(&s->container, "pci-container", PCIE500_ALL_SIZE); |
Avi Kivity | d0ed807 | 2011-07-24 17:47:18 +0300 | [diff] [blame] | 334 | memory_region_init_io(&h->conf_mem, &pci_host_conf_be_ops, h, |
| 335 | "pci-conf-idx", 4); |
| 336 | memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, h, |
| 337 | "pci-conf-data", 4); |
Avi Kivity | cd5cba7 | 2011-11-20 11:52:58 +0200 | [diff] [blame] | 338 | memory_region_init_io(&s->iomem, &e500_pci_reg_ops, s, |
| 339 | "pci.reg", PCIE500_REG_SIZE); |
Benoît Canet | cb4e15c | 2011-12-16 23:37:47 +0100 | [diff] [blame] | 340 | memory_region_add_subregion(&s->container, PCIE500_CFGADDR, &h->conf_mem); |
| 341 | memory_region_add_subregion(&s->container, PCIE500_CFGDATA, &h->data_mem); |
| 342 | memory_region_add_subregion(&s->container, PCIE500_REG_BASE, &s->iomem); |
| 343 | sysbus_init_mmio(dev, &s->container); |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 344 | |
| 345 | return 0; |
| 346 | } |
| 347 | |
Anthony Liguori | 40021f0 | 2011-12-04 12:22:06 -0600 | [diff] [blame] | 348 | static void e500_host_bridge_class_init(ObjectClass *klass, void *data) |
| 349 | { |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 350 | DeviceClass *dc = DEVICE_CLASS(klass); |
Anthony Liguori | 40021f0 | 2011-12-04 12:22:06 -0600 | [diff] [blame] | 351 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
| 352 | |
| 353 | k->vendor_id = PCI_VENDOR_ID_FREESCALE; |
| 354 | k->device_id = PCI_DEVICE_ID_MPC8533E; |
| 355 | k->class_id = PCI_CLASS_PROCESSOR_POWERPC; |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 356 | dc->desc = "Host bridge"; |
Anthony Liguori | 40021f0 | 2011-12-04 12:22:06 -0600 | [diff] [blame] | 357 | } |
| 358 | |
Andreas Färber | 4240abf | 2012-08-20 19:07:56 +0200 | [diff] [blame] | 359 | static const TypeInfo e500_host_bridge_info = { |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 360 | .name = "e500-host-bridge", |
| 361 | .parent = TYPE_PCI_DEVICE, |
| 362 | .instance_size = sizeof(PCIDevice), |
| 363 | .class_init = e500_host_bridge_class_init, |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 364 | }; |
| 365 | |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 366 | static void e500_pcihost_class_init(ObjectClass *klass, void *data) |
| 367 | { |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 368 | DeviceClass *dc = DEVICE_CLASS(klass); |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 369 | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
| 370 | |
| 371 | k->init = e500_pcihost_initfn; |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 372 | dc->vmsd = &vmstate_ppce500_pci; |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 373 | } |
| 374 | |
Andreas Färber | 4240abf | 2012-08-20 19:07:56 +0200 | [diff] [blame] | 375 | static const TypeInfo e500_pcihost_info = { |
Andreas Färber | 9c1a61f | 2012-08-20 19:08:03 +0200 | [diff] [blame] | 376 | .name = TYPE_PPC_E500_PCI_HOST_BRIDGE, |
Andreas Färber | 8558d94 | 2012-08-20 19:08:08 +0200 | [diff] [blame] | 377 | .parent = TYPE_PCI_HOST_BRIDGE, |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 378 | .instance_size = sizeof(PPCE500PCIState), |
| 379 | .class_init = e500_pcihost_class_init, |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 380 | }; |
| 381 | |
Andreas Färber | 83f7d43 | 2012-02-09 15:20:55 +0100 | [diff] [blame] | 382 | static void e500_pci_register_types(void) |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 383 | { |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 384 | type_register_static(&e500_pcihost_info); |
| 385 | type_register_static(&e500_host_bridge_info); |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 386 | } |
Andreas Färber | 83f7d43 | 2012-02-09 15:20:55 +0100 | [diff] [blame] | 387 | |
| 388 | type_init(e500_pci_register_types) |