Jason Baron | 4d00636 | 2012-11-14 15:54:05 -0500 | [diff] [blame] | 1 | /* |
Jason Baron | 6f918e4 | 2012-10-29 22:11:31 -0400 | [diff] [blame] | 2 | * QEMU ICH9 Emulation |
| 3 | * |
Jason Baron | 4d00636 | 2012-11-14 15:54:05 -0500 | [diff] [blame] | 4 | * Copyright (c) 2006 Fabrice Bellard |
Jason Baron | 6f918e4 | 2012-10-29 22:11:31 -0400 | [diff] [blame] | 5 | * Copyright (c) 2009, 2010, 2011 |
| 6 | * Isaku Yamahata <yamahata at valinux co jp> |
| 7 | * VA Linux Systems Japan K.K. |
| 8 | * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> |
| 9 | * |
| 10 | * This is based on piix_pci.c, but heavily modified. |
Jason Baron | 4d00636 | 2012-11-14 15:54:05 -0500 | [diff] [blame] | 11 | * |
| 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 13 | * of this software and associated documentation files (the "Software"), to deal |
| 14 | * in the Software without restriction, including without limitation the rights |
| 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 16 | * copies of the Software, and to permit persons to whom the Software is |
| 17 | * furnished to do so, subject to the following conditions: |
| 18 | * |
| 19 | * The above copyright notice and this permission notice shall be included in |
| 20 | * all copies or substantial portions of the Software. |
| 21 | * |
| 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 25 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 28 | * THE SOFTWARE. |
| 29 | */ |
Jason Baron | 4d00636 | 2012-11-14 15:54:05 -0500 | [diff] [blame] | 30 | #include "qemu-common.h" |
| 31 | #include "hw.h" |
| 32 | #include "range.h" |
| 33 | #include "isa.h" |
| 34 | #include "sysbus.h" |
| 35 | #include "pc.h" |
| 36 | #include "apm.h" |
| 37 | #include "ioapic.h" |
Michael S. Tsirkin | a2cb15b | 2012-12-12 14:24:50 +0200 | [diff] [blame^] | 38 | #include "pci/pci.h" |
| 39 | #include "pci/pcie_host.h" |
| 40 | #include "pci/pci_bridge.h" |
Jason Baron | 4d00636 | 2012-11-14 15:54:05 -0500 | [diff] [blame] | 41 | #include "ich9.h" |
| 42 | #include "acpi.h" |
| 43 | #include "acpi_ich9.h" |
| 44 | #include "pam.h" |
Michael S. Tsirkin | a2cb15b | 2012-12-12 14:24:50 +0200 | [diff] [blame^] | 45 | #include "pci/pci_internals.h" |
Jason Baron | 4d00636 | 2012-11-14 15:54:05 -0500 | [diff] [blame] | 46 | #include "exec-memory.h" |
Gerd Hoffmann | 3f5bc9e | 2012-11-23 15:02:18 +0100 | [diff] [blame] | 47 | #include "sysemu.h" |
Jason Baron | 4d00636 | 2012-11-14 15:54:05 -0500 | [diff] [blame] | 48 | |
| 49 | static int ich9_lpc_sci_irq(ICH9LPCState *lpc); |
| 50 | |
| 51 | /*****************************************************************************/ |
| 52 | /* ICH9 LPC PCI to ISA bridge */ |
| 53 | |
| 54 | static void ich9_lpc_reset(DeviceState *qdev); |
| 55 | |
| 56 | /* chipset configuration register |
| 57 | * to access chipset configuration registers, pci_[sg]et_{byte, word, long} |
| 58 | * are used. |
| 59 | * Although it's not pci configuration space, it's little endian as Intel. |
| 60 | */ |
| 61 | |
| 62 | static void ich9_cc_update_ir(uint8_t irr[PCI_NUM_PINS], uint16_t ir) |
| 63 | { |
| 64 | int intx; |
| 65 | for (intx = 0; intx < PCI_NUM_PINS; intx++) { |
| 66 | irr[intx] = (ir >> (intx * ICH9_CC_DIR_SHIFT)) & ICH9_CC_DIR_MASK; |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | static void ich9_cc_update(ICH9LPCState *lpc) |
| 71 | { |
| 72 | int slot; |
| 73 | int pci_intx; |
| 74 | |
| 75 | const int reg_offsets[] = { |
| 76 | ICH9_CC_D25IR, |
| 77 | ICH9_CC_D26IR, |
| 78 | ICH9_CC_D27IR, |
| 79 | ICH9_CC_D28IR, |
| 80 | ICH9_CC_D29IR, |
| 81 | ICH9_CC_D30IR, |
| 82 | ICH9_CC_D31IR, |
| 83 | }; |
| 84 | const int *offset; |
| 85 | |
| 86 | /* D{25 - 31}IR, but D30IR is read only to 0. */ |
| 87 | for (slot = 25, offset = reg_offsets; slot < 32; slot++, offset++) { |
| 88 | if (slot == 30) { |
| 89 | continue; |
| 90 | } |
| 91 | ich9_cc_update_ir(lpc->irr[slot], |
| 92 | pci_get_word(lpc->chip_config + *offset)); |
| 93 | } |
| 94 | |
| 95 | /* |
| 96 | * D30: DMI2PCI bridge |
| 97 | * It is arbitrarily decided how INTx lines of PCI devicesbehind the bridge |
| 98 | * are connected to pirq lines. Our choice is PIRQ[E-H]. |
| 99 | * INT[A-D] are connected to PIRQ[E-H] |
| 100 | */ |
| 101 | for (pci_intx = 0; pci_intx < PCI_NUM_PINS; pci_intx++) { |
| 102 | lpc->irr[30][pci_intx] = pci_intx + 4; |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | static void ich9_cc_init(ICH9LPCState *lpc) |
| 107 | { |
| 108 | int slot; |
| 109 | int intx; |
| 110 | |
| 111 | /* the default irq routing is arbitrary as long as it matches with |
| 112 | * acpi irq routing table. |
| 113 | * The one that is incompatible with piix_pci(= bochs) one is |
| 114 | * intentionally chosen to let the users know that the different |
| 115 | * board is used. |
| 116 | * |
| 117 | * int[A-D] -> pirq[E-F] |
| 118 | * avoid pirq A-D because they are used for pci express port |
| 119 | */ |
| 120 | for (slot = 0; slot < PCI_SLOT_MAX; slot++) { |
| 121 | for (intx = 0; intx < PCI_NUM_PINS; intx++) { |
| 122 | lpc->irr[slot][intx] = (slot + intx) % 4 + 4; |
| 123 | } |
| 124 | } |
| 125 | ich9_cc_update(lpc); |
| 126 | } |
| 127 | |
| 128 | static void ich9_cc_reset(ICH9LPCState *lpc) |
| 129 | { |
| 130 | uint8_t *c = lpc->chip_config; |
| 131 | |
| 132 | memset(lpc->chip_config, 0, sizeof(lpc->chip_config)); |
| 133 | |
| 134 | pci_set_long(c + ICH9_CC_D31IR, ICH9_CC_DIR_DEFAULT); |
| 135 | pci_set_long(c + ICH9_CC_D30IR, ICH9_CC_D30IR_DEFAULT); |
| 136 | pci_set_long(c + ICH9_CC_D29IR, ICH9_CC_DIR_DEFAULT); |
| 137 | pci_set_long(c + ICH9_CC_D28IR, ICH9_CC_DIR_DEFAULT); |
| 138 | pci_set_long(c + ICH9_CC_D27IR, ICH9_CC_DIR_DEFAULT); |
| 139 | pci_set_long(c + ICH9_CC_D26IR, ICH9_CC_DIR_DEFAULT); |
| 140 | pci_set_long(c + ICH9_CC_D25IR, ICH9_CC_DIR_DEFAULT); |
| 141 | |
| 142 | ich9_cc_update(lpc); |
| 143 | } |
| 144 | |
| 145 | static void ich9_cc_addr_len(uint64_t *addr, unsigned *len) |
| 146 | { |
| 147 | *addr &= ICH9_CC_ADDR_MASK; |
| 148 | if (*addr + *len >= ICH9_CC_SIZE) { |
| 149 | *len = ICH9_CC_SIZE - *addr; |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | /* val: little endian */ |
| 154 | static void ich9_cc_write(void *opaque, hwaddr addr, |
| 155 | uint64_t val, unsigned len) |
| 156 | { |
| 157 | ICH9LPCState *lpc = (ICH9LPCState *)opaque; |
| 158 | |
| 159 | ich9_cc_addr_len(&addr, &len); |
| 160 | memcpy(lpc->chip_config + addr, &val, len); |
| 161 | ich9_cc_update(lpc); |
| 162 | } |
| 163 | |
| 164 | /* return value: little endian */ |
| 165 | static uint64_t ich9_cc_read(void *opaque, hwaddr addr, |
| 166 | unsigned len) |
| 167 | { |
| 168 | ICH9LPCState *lpc = (ICH9LPCState *)opaque; |
| 169 | |
| 170 | uint32_t val = 0; |
| 171 | ich9_cc_addr_len(&addr, &len); |
| 172 | memcpy(&val, lpc->chip_config + addr, len); |
| 173 | return val; |
| 174 | } |
| 175 | |
| 176 | /* IRQ routing */ |
| 177 | /* */ |
| 178 | static void ich9_lpc_rout(uint8_t pirq_rout, int *pic_irq, int *pic_dis) |
| 179 | { |
| 180 | *pic_irq = pirq_rout & ICH9_LPC_PIRQ_ROUT_MASK; |
| 181 | *pic_dis = pirq_rout & ICH9_LPC_PIRQ_ROUT_IRQEN; |
| 182 | } |
| 183 | |
| 184 | static void ich9_lpc_pic_irq(ICH9LPCState *lpc, int pirq_num, |
| 185 | int *pic_irq, int *pic_dis) |
| 186 | { |
| 187 | switch (pirq_num) { |
| 188 | case 0 ... 3: /* A-D */ |
| 189 | ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQA_ROUT + pirq_num], |
| 190 | pic_irq, pic_dis); |
| 191 | return; |
| 192 | case 4 ... 7: /* E-H */ |
| 193 | ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQE_ROUT + (pirq_num - 4)], |
| 194 | pic_irq, pic_dis); |
| 195 | return; |
| 196 | default: |
| 197 | break; |
| 198 | } |
| 199 | abort(); |
| 200 | } |
| 201 | |
| 202 | /* pic_irq: i8254 irq 0-15 */ |
| 203 | static void ich9_lpc_update_pic(ICH9LPCState *lpc, int pic_irq) |
| 204 | { |
| 205 | int i, pic_level; |
| 206 | |
| 207 | /* The pic level is the logical OR of all the PCI irqs mapped to it */ |
| 208 | pic_level = 0; |
| 209 | for (i = 0; i < ICH9_LPC_NB_PIRQS; i++) { |
| 210 | int tmp_irq; |
| 211 | int tmp_dis; |
| 212 | ich9_lpc_pic_irq(lpc, i, &tmp_irq, &tmp_dis); |
| 213 | if (!tmp_dis && pic_irq == tmp_irq) { |
| 214 | pic_level |= pci_bus_get_irq_level(lpc->d.bus, i); |
| 215 | } |
| 216 | } |
| 217 | if (pic_irq == ich9_lpc_sci_irq(lpc)) { |
| 218 | pic_level |= lpc->sci_level; |
| 219 | } |
| 220 | |
| 221 | qemu_set_irq(lpc->pic[pic_irq], pic_level); |
| 222 | } |
| 223 | |
| 224 | /* pirq: pirq[A-H] 0-7*/ |
| 225 | static void ich9_lpc_update_by_pirq(ICH9LPCState *lpc, int pirq) |
| 226 | { |
| 227 | int pic_irq; |
| 228 | int pic_dis; |
| 229 | |
| 230 | ich9_lpc_pic_irq(lpc, pirq, &pic_irq, &pic_dis); |
| 231 | assert(pic_irq < ICH9_LPC_PIC_NUM_PINS); |
| 232 | if (pic_dis) { |
| 233 | return; |
| 234 | } |
| 235 | |
| 236 | ich9_lpc_update_pic(lpc, pic_irq); |
| 237 | } |
| 238 | |
| 239 | /* APIC mode: GSIx: PIRQ[A-H] -> GSI 16, ... no pirq shares same APIC pins. */ |
| 240 | static int ich9_pirq_to_gsi(int pirq) |
| 241 | { |
| 242 | return pirq + ICH9_LPC_PIC_NUM_PINS; |
| 243 | } |
| 244 | |
| 245 | static int ich9_gsi_to_pirq(int gsi) |
| 246 | { |
| 247 | return gsi - ICH9_LPC_PIC_NUM_PINS; |
| 248 | } |
| 249 | |
| 250 | static void ich9_lpc_update_apic(ICH9LPCState *lpc, int gsi) |
| 251 | { |
Jan Kiszka | 243b951 | 2012-11-14 15:54:08 -0500 | [diff] [blame] | 252 | int level = 0; |
Jason Baron | 4d00636 | 2012-11-14 15:54:05 -0500 | [diff] [blame] | 253 | |
Jan Kiszka | 243b951 | 2012-11-14 15:54:08 -0500 | [diff] [blame] | 254 | if (gsi >= ICH9_LPC_PIC_NUM_PINS) { |
| 255 | level |= pci_bus_get_irq_level(lpc->d.bus, ich9_gsi_to_pirq(gsi)); |
| 256 | } |
Jason Baron | 4d00636 | 2012-11-14 15:54:05 -0500 | [diff] [blame] | 257 | if (gsi == ich9_lpc_sci_irq(lpc)) { |
| 258 | level |= lpc->sci_level; |
| 259 | } |
| 260 | |
| 261 | qemu_set_irq(lpc->ioapic[gsi], level); |
| 262 | } |
| 263 | |
| 264 | void ich9_lpc_set_irq(void *opaque, int pirq, int level) |
| 265 | { |
| 266 | ICH9LPCState *lpc = opaque; |
| 267 | |
| 268 | assert(0 <= pirq); |
| 269 | assert(pirq < ICH9_LPC_NB_PIRQS); |
| 270 | |
| 271 | ich9_lpc_update_apic(lpc, ich9_pirq_to_gsi(pirq)); |
| 272 | ich9_lpc_update_by_pirq(lpc, pirq); |
| 273 | } |
| 274 | |
| 275 | /* return the pirq number (PIRQ[A-H]:0-7) corresponding to |
| 276 | * a given device irq pin. |
| 277 | */ |
| 278 | int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx) |
| 279 | { |
| 280 | BusState *bus = qdev_get_parent_bus(&pci_dev->qdev); |
| 281 | PCIBus *pci_bus = PCI_BUS(bus); |
| 282 | PCIDevice *lpc_pdev = |
| 283 | pci_bus->devices[PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC)]; |
| 284 | ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pdev); |
| 285 | |
| 286 | return lpc->irr[PCI_SLOT(pci_dev->devfn)][intx]; |
| 287 | } |
| 288 | |
| 289 | static int ich9_lpc_sci_irq(ICH9LPCState *lpc) |
| 290 | { |
| 291 | switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] & |
| 292 | ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK) { |
| 293 | case ICH9_LPC_ACPI_CTRL_9: |
| 294 | return 9; |
| 295 | case ICH9_LPC_ACPI_CTRL_10: |
| 296 | return 10; |
| 297 | case ICH9_LPC_ACPI_CTRL_11: |
| 298 | return 11; |
| 299 | case ICH9_LPC_ACPI_CTRL_20: |
| 300 | return 20; |
| 301 | case ICH9_LPC_ACPI_CTRL_21: |
| 302 | return 21; |
| 303 | default: |
| 304 | /* reserved */ |
| 305 | break; |
| 306 | } |
| 307 | return -1; |
| 308 | } |
| 309 | |
| 310 | static void ich9_set_sci(void *opaque, int irq_num, int level) |
| 311 | { |
| 312 | ICH9LPCState *lpc = opaque; |
| 313 | int irq; |
| 314 | |
| 315 | assert(irq_num == 0); |
| 316 | level = !!level; |
| 317 | if (level == lpc->sci_level) { |
| 318 | return; |
| 319 | } |
| 320 | lpc->sci_level = level; |
| 321 | |
| 322 | irq = ich9_lpc_sci_irq(lpc); |
| 323 | if (irq < 0) { |
| 324 | return; |
| 325 | } |
| 326 | |
| 327 | ich9_lpc_update_apic(lpc, irq); |
| 328 | if (irq < ICH9_LPC_PIC_NUM_PINS) { |
| 329 | ich9_lpc_update_pic(lpc, irq); |
| 330 | } |
| 331 | } |
| 332 | |
| 333 | void ich9_lpc_pm_init(PCIDevice *lpc_pci, qemu_irq cmos_s3) |
| 334 | { |
| 335 | ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci); |
| 336 | qemu_irq *sci_irq; |
| 337 | |
| 338 | sci_irq = qemu_allocate_irqs(ich9_set_sci, lpc, 1); |
| 339 | ich9_pm_init(&lpc->pm, sci_irq[0], cmos_s3); |
| 340 | |
| 341 | ich9_lpc_reset(&lpc->d.qdev); |
| 342 | } |
| 343 | |
| 344 | /* APM */ |
| 345 | |
| 346 | static void ich9_apm_ctrl_changed(uint32_t val, void *arg) |
| 347 | { |
| 348 | ICH9LPCState *lpc = arg; |
| 349 | |
| 350 | /* ACPI specs 3.0, 4.7.2.5 */ |
| 351 | acpi_pm1_cnt_update(&lpc->pm.acpi_regs, |
| 352 | val == ICH9_APM_ACPI_ENABLE, |
| 353 | val == ICH9_APM_ACPI_DISABLE); |
| 354 | |
| 355 | /* SMI_EN = PMBASE + 30. SMI control and enable register */ |
| 356 | if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) { |
| 357 | cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI); |
| 358 | } |
| 359 | } |
| 360 | |
| 361 | /* config:PMBASE */ |
| 362 | static void |
| 363 | ich9_lpc_pmbase_update(ICH9LPCState *lpc) |
| 364 | { |
| 365 | uint32_t pm_io_base = pci_get_long(lpc->d.config + ICH9_LPC_PMBASE); |
| 366 | pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK; |
| 367 | |
| 368 | ich9_pm_iospace_update(&lpc->pm, pm_io_base); |
| 369 | } |
| 370 | |
| 371 | /* config:RBCA */ |
| 372 | static void ich9_lpc_rcba_update(ICH9LPCState *lpc, uint32_t rbca_old) |
| 373 | { |
| 374 | uint32_t rbca = pci_get_long(lpc->d.config + ICH9_LPC_RCBA); |
| 375 | |
| 376 | if (rbca_old & ICH9_LPC_RCBA_EN) { |
| 377 | memory_region_del_subregion(get_system_memory(), &lpc->rbca_mem); |
| 378 | } |
| 379 | if (rbca & ICH9_LPC_RCBA_EN) { |
| 380 | memory_region_add_subregion_overlap(get_system_memory(), |
| 381 | rbca & ICH9_LPC_RCBA_BA_MASK, |
| 382 | &lpc->rbca_mem, 1); |
| 383 | } |
| 384 | } |
| 385 | |
| 386 | static int ich9_lpc_post_load(void *opaque, int version_id) |
| 387 | { |
| 388 | ICH9LPCState *lpc = opaque; |
| 389 | |
| 390 | ich9_lpc_pmbase_update(lpc); |
| 391 | ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */); |
| 392 | return 0; |
| 393 | } |
| 394 | |
| 395 | static void ich9_lpc_config_write(PCIDevice *d, |
| 396 | uint32_t addr, uint32_t val, int len) |
| 397 | { |
| 398 | ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); |
| 399 | uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA); |
| 400 | |
| 401 | pci_default_write_config(d, addr, val, len); |
| 402 | if (ranges_overlap(addr, len, ICH9_LPC_PMBASE, 4)) { |
| 403 | ich9_lpc_pmbase_update(lpc); |
| 404 | } |
| 405 | if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) { |
| 406 | ich9_lpc_rcba_update(lpc, rbca_old); |
| 407 | } |
| 408 | } |
| 409 | |
| 410 | static void ich9_lpc_reset(DeviceState *qdev) |
| 411 | { |
| 412 | PCIDevice *d = PCI_DEVICE(qdev); |
| 413 | ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); |
| 414 | uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA); |
| 415 | int i; |
| 416 | |
| 417 | for (i = 0; i < 4; i++) { |
| 418 | pci_set_byte(d->config + ICH9_LPC_PIRQA_ROUT + i, |
| 419 | ICH9_LPC_PIRQ_ROUT_DEFAULT); |
| 420 | } |
| 421 | for (i = 0; i < 4; i++) { |
| 422 | pci_set_byte(d->config + ICH9_LPC_PIRQE_ROUT + i, |
| 423 | ICH9_LPC_PIRQ_ROUT_DEFAULT); |
| 424 | } |
| 425 | pci_set_byte(d->config + ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_DEFAULT); |
| 426 | |
| 427 | pci_set_long(d->config + ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_DEFAULT); |
| 428 | pci_set_long(d->config + ICH9_LPC_RCBA, ICH9_LPC_RCBA_DEFAULT); |
| 429 | |
| 430 | ich9_cc_reset(lpc); |
| 431 | |
| 432 | ich9_lpc_pmbase_update(lpc); |
| 433 | ich9_lpc_rcba_update(lpc, rbca_old); |
| 434 | |
| 435 | lpc->sci_level = 0; |
| 436 | } |
| 437 | |
| 438 | static const MemoryRegionOps rbca_mmio_ops = { |
| 439 | .read = ich9_cc_read, |
| 440 | .write = ich9_cc_write, |
| 441 | .endianness = DEVICE_LITTLE_ENDIAN, |
| 442 | }; |
| 443 | |
Gerd Hoffmann | 3f5bc9e | 2012-11-23 15:02:18 +0100 | [diff] [blame] | 444 | static void ich9_lpc_machine_ready(Notifier *n, void *opaque) |
| 445 | { |
| 446 | ICH9LPCState *s = container_of(n, ICH9LPCState, machine_ready); |
| 447 | uint8_t *pci_conf; |
| 448 | |
| 449 | pci_conf = s->d.config; |
| 450 | if (isa_is_ioport_assigned(0x3f8)) { |
| 451 | /* com1 */ |
| 452 | pci_conf[0x82] |= 0x01; |
| 453 | } |
| 454 | if (isa_is_ioport_assigned(0x2f8)) { |
| 455 | /* com2 */ |
| 456 | pci_conf[0x82] |= 0x02; |
| 457 | } |
| 458 | if (isa_is_ioport_assigned(0x378)) { |
| 459 | /* lpt */ |
| 460 | pci_conf[0x82] |= 0x04; |
| 461 | } |
| 462 | if (isa_is_ioport_assigned(0x3f0)) { |
| 463 | /* floppy */ |
| 464 | pci_conf[0x82] |= 0x08; |
| 465 | } |
| 466 | } |
| 467 | |
Jason Baron | 4d00636 | 2012-11-14 15:54:05 -0500 | [diff] [blame] | 468 | static int ich9_lpc_initfn(PCIDevice *d) |
| 469 | { |
| 470 | ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); |
| 471 | ISABus *isa_bus; |
| 472 | |
| 473 | isa_bus = isa_bus_new(&d->qdev, get_system_io()); |
| 474 | |
| 475 | pci_set_long(d->wmask + ICH9_LPC_PMBASE, |
| 476 | ICH9_LPC_PMBASE_BASE_ADDRESS_MASK); |
| 477 | |
| 478 | memory_region_init_io(&lpc->rbca_mem, &rbca_mmio_ops, lpc, |
| 479 | "lpc-rbca-mmio", ICH9_CC_SIZE); |
| 480 | |
| 481 | lpc->isa_bus = isa_bus; |
| 482 | |
| 483 | ich9_cc_init(lpc); |
Julien Grall | 42d8a3c | 2012-09-19 12:50:03 +0100 | [diff] [blame] | 484 | apm_init(d, &lpc->apm, ich9_apm_ctrl_changed, lpc); |
Gerd Hoffmann | 3f5bc9e | 2012-11-23 15:02:18 +0100 | [diff] [blame] | 485 | |
| 486 | lpc->machine_ready.notify = ich9_lpc_machine_ready; |
| 487 | qemu_add_machine_init_done_notifier(&lpc->machine_ready); |
| 488 | |
Jason Baron | 4d00636 | 2012-11-14 15:54:05 -0500 | [diff] [blame] | 489 | return 0; |
| 490 | } |
| 491 | |
| 492 | static const VMStateDescription vmstate_ich9_lpc = { |
| 493 | .name = "ICH9LPC", |
| 494 | .version_id = 1, |
| 495 | .minimum_version_id = 1, |
| 496 | .minimum_version_id_old = 1, |
| 497 | .post_load = ich9_lpc_post_load, |
| 498 | .fields = (VMStateField[]) { |
| 499 | VMSTATE_PCI_DEVICE(d, ICH9LPCState), |
| 500 | VMSTATE_STRUCT(apm, ICH9LPCState, 0, vmstate_apm, APMState), |
| 501 | VMSTATE_STRUCT(pm, ICH9LPCState, 0, vmstate_ich9_pm, ICH9LPCPMRegs), |
| 502 | VMSTATE_UINT8_ARRAY(chip_config, ICH9LPCState, ICH9_CC_SIZE), |
| 503 | VMSTATE_UINT32(sci_level, ICH9LPCState), |
| 504 | VMSTATE_END_OF_LIST() |
| 505 | } |
| 506 | }; |
| 507 | |
| 508 | static void ich9_lpc_class_init(ObjectClass *klass, void *data) |
| 509 | { |
| 510 | DeviceClass *dc = DEVICE_CLASS(klass); |
| 511 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
| 512 | |
| 513 | dc->reset = ich9_lpc_reset; |
| 514 | k->init = ich9_lpc_initfn; |
| 515 | dc->vmsd = &vmstate_ich9_lpc; |
| 516 | dc->no_user = 1; |
| 517 | k->config_write = ich9_lpc_config_write; |
| 518 | dc->desc = "ICH9 LPC bridge"; |
| 519 | k->vendor_id = PCI_VENDOR_ID_INTEL; |
| 520 | k->device_id = PCI_DEVICE_ID_INTEL_ICH9_8; |
| 521 | k->revision = ICH9_A2_LPC_REVISION; |
| 522 | k->class_id = PCI_CLASS_BRIDGE_ISA; |
| 523 | |
| 524 | } |
| 525 | |
| 526 | static const TypeInfo ich9_lpc_info = { |
| 527 | .name = TYPE_ICH9_LPC_DEVICE, |
| 528 | .parent = TYPE_PCI_DEVICE, |
| 529 | .instance_size = sizeof(struct ICH9LPCState), |
| 530 | .class_init = ich9_lpc_class_init, |
| 531 | }; |
| 532 | |
| 533 | static void ich9_lpc_register(void) |
| 534 | { |
| 535 | type_register_static(&ich9_lpc_info); |
| 536 | } |
| 537 | |
| 538 | type_init(ich9_lpc_register); |