Revision 47934d0a
b/default-configs/i386-softmmu.mak | ||
---|---|---|
35 | 35 |
CONFIG_PC_SYSFW=y |
36 | 36 |
CONFIG_XEN_I386=$(CONFIG_XEN) |
37 | 37 |
CONFIG_ISA_DEBUG=y |
38 |
CONFIG_LPC_ICH9=y |
b/default-configs/mips-softmmu.mak | ||
---|---|---|
33 | 33 |
CONFIG_I8259=y |
34 | 34 |
CONFIG_JAZZ_LED=y |
35 | 35 |
CONFIG_MC146818RTC=y |
36 |
CONFIG_VT82C686=y |
b/default-configs/mips64-softmmu.mak | ||
---|---|---|
33 | 33 |
CONFIG_I8259=y |
34 | 34 |
CONFIG_JAZZ_LED=y |
35 | 35 |
CONFIG_MC146818RTC=y |
36 |
CONFIG_VT82C686=y |
b/default-configs/mips64el-softmmu.mak | ||
---|---|---|
35 | 35 |
CONFIG_I8259=y |
36 | 36 |
CONFIG_JAZZ_LED=y |
37 | 37 |
CONFIG_MC146818RTC=y |
38 |
CONFIG_VT82C686=y |
b/default-configs/mipsel-softmmu.mak | ||
---|---|---|
33 | 33 |
CONFIG_I8259=y |
34 | 34 |
CONFIG_JAZZ_LED=y |
35 | 35 |
CONFIG_MC146818RTC=y |
36 |
CONFIG_VT82C686=y |
b/default-configs/x86_64-softmmu.mak | ||
---|---|---|
35 | 35 |
CONFIG_PC_SYSFW=y |
36 | 36 |
CONFIG_XEN_I386=$(CONFIG_XEN) |
37 | 37 |
CONFIG_ISA_DEBUG=y |
38 |
CONFIG_LPC_ICH9=y |
b/hw/i386/Makefile.objs | ||
---|---|---|
2 | 2 |
obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o |
3 | 3 |
obj-y += vmport.o |
4 | 4 |
obj-y += debugexit.o |
5 |
obj-y += lpc_ich9.o q35.o
|
|
5 |
obj-y += q35.o |
|
6 | 6 |
obj-y += kvm/ |
7 | 7 |
obj-y += pc-testdev.o |
8 | 8 |
|
b/hw/isa/Makefile.objs | ||
---|---|---|
4 | 4 |
common-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o |
5 | 5 |
common-obj-$(CONFIG_PC87312) += pc87312.o |
6 | 6 |
common-obj-$(CONFIG_PIIX4) += piix4.o |
7 |
common-obj-$(CONFIG_VT82C686) += vt82c686.o |
|
7 | 8 |
|
9 |
obj-$(CONFIG_LPC_ICH9) += lpc_ich9.o |
b/hw/isa/lpc_ich9.c | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU ICH9 Emulation |
|
3 |
* |
|
4 |
* Copyright (c) 2006 Fabrice Bellard |
|
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. |
|
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 |
*/ |
|
30 |
#include "qemu-common.h" |
|
31 |
#include "hw/hw.h" |
|
32 |
#include "qemu/range.h" |
|
33 |
#include "hw/isa/isa.h" |
|
34 |
#include "hw/sysbus.h" |
|
35 |
#include "hw/i386/pc.h" |
|
36 |
#include "hw/isa/apm.h" |
|
37 |
#include "hw/i386/ioapic.h" |
|
38 |
#include "hw/pci/pci.h" |
|
39 |
#include "hw/pci/pcie_host.h" |
|
40 |
#include "hw/pci/pci_bridge.h" |
|
41 |
#include "hw/i386/ich9.h" |
|
42 |
#include "hw/acpi/acpi.h" |
|
43 |
#include "hw/acpi/ich9.h" |
|
44 |
#include "hw/pci/pci_bus.h" |
|
45 |
#include "exec/address-spaces.h" |
|
46 |
#include "sysemu/sysemu.h" |
|
47 |
|
|
48 |
static int ich9_lpc_sci_irq(ICH9LPCState *lpc); |
|
49 |
|
|
50 |
/*****************************************************************************/ |
|
51 |
/* ICH9 LPC PCI to ISA bridge */ |
|
52 |
|
|
53 |
static void ich9_lpc_reset(DeviceState *qdev); |
|
54 |
|
|
55 |
/* chipset configuration register |
|
56 |
* to access chipset configuration registers, pci_[sg]et_{byte, word, long} |
|
57 |
* are used. |
|
58 |
* Although it's not pci configuration space, it's little endian as Intel. |
|
59 |
*/ |
|
60 |
|
|
61 |
static void ich9_cc_update_ir(uint8_t irr[PCI_NUM_PINS], uint16_t ir) |
|
62 |
{ |
|
63 |
int intx; |
|
64 |
for (intx = 0; intx < PCI_NUM_PINS; intx++) { |
|
65 |
irr[intx] = (ir >> (intx * ICH9_CC_DIR_SHIFT)) & ICH9_CC_DIR_MASK; |
|
66 |
} |
|
67 |
} |
|
68 |
|
|
69 |
static void ich9_cc_update(ICH9LPCState *lpc) |
|
70 |
{ |
|
71 |
int slot; |
|
72 |
int pci_intx; |
|
73 |
|
|
74 |
const int reg_offsets[] = { |
|
75 |
ICH9_CC_D25IR, |
|
76 |
ICH9_CC_D26IR, |
|
77 |
ICH9_CC_D27IR, |
|
78 |
ICH9_CC_D28IR, |
|
79 |
ICH9_CC_D29IR, |
|
80 |
ICH9_CC_D30IR, |
|
81 |
ICH9_CC_D31IR, |
|
82 |
}; |
|
83 |
const int *offset; |
|
84 |
|
|
85 |
/* D{25 - 31}IR, but D30IR is read only to 0. */ |
|
86 |
for (slot = 25, offset = reg_offsets; slot < 32; slot++, offset++) { |
|
87 |
if (slot == 30) { |
|
88 |
continue; |
|
89 |
} |
|
90 |
ich9_cc_update_ir(lpc->irr[slot], |
|
91 |
pci_get_word(lpc->chip_config + *offset)); |
|
92 |
} |
|
93 |
|
|
94 |
/* |
|
95 |
* D30: DMI2PCI bridge |
|
96 |
* It is arbitrarily decided how INTx lines of PCI devicesbehind the bridge |
|
97 |
* are connected to pirq lines. Our choice is PIRQ[E-H]. |
|
98 |
* INT[A-D] are connected to PIRQ[E-H] |
|
99 |
*/ |
|
100 |
for (pci_intx = 0; pci_intx < PCI_NUM_PINS; pci_intx++) { |
|
101 |
lpc->irr[30][pci_intx] = pci_intx + 4; |
|
102 |
} |
|
103 |
} |
|
104 |
|
|
105 |
static void ich9_cc_init(ICH9LPCState *lpc) |
|
106 |
{ |
|
107 |
int slot; |
|
108 |
int intx; |
|
109 |
|
|
110 |
/* the default irq routing is arbitrary as long as it matches with |
|
111 |
* acpi irq routing table. |
|
112 |
* The one that is incompatible with piix_pci(= bochs) one is |
|
113 |
* intentionally chosen to let the users know that the different |
|
114 |
* board is used. |
|
115 |
* |
|
116 |
* int[A-D] -> pirq[E-F] |
|
117 |
* avoid pirq A-D because they are used for pci express port |
|
118 |
*/ |
|
119 |
for (slot = 0; slot < PCI_SLOT_MAX; slot++) { |
|
120 |
for (intx = 0; intx < PCI_NUM_PINS; intx++) { |
|
121 |
lpc->irr[slot][intx] = (slot + intx) % 4 + 4; |
|
122 |
} |
|
123 |
} |
|
124 |
ich9_cc_update(lpc); |
|
125 |
} |
|
126 |
|
|
127 |
static void ich9_cc_reset(ICH9LPCState *lpc) |
|
128 |
{ |
|
129 |
uint8_t *c = lpc->chip_config; |
|
130 |
|
|
131 |
memset(lpc->chip_config, 0, sizeof(lpc->chip_config)); |
|
132 |
|
|
133 |
pci_set_long(c + ICH9_CC_D31IR, ICH9_CC_DIR_DEFAULT); |
|
134 |
pci_set_long(c + ICH9_CC_D30IR, ICH9_CC_D30IR_DEFAULT); |
|
135 |
pci_set_long(c + ICH9_CC_D29IR, ICH9_CC_DIR_DEFAULT); |
|
136 |
pci_set_long(c + ICH9_CC_D28IR, ICH9_CC_DIR_DEFAULT); |
|
137 |
pci_set_long(c + ICH9_CC_D27IR, ICH9_CC_DIR_DEFAULT); |
|
138 |
pci_set_long(c + ICH9_CC_D26IR, ICH9_CC_DIR_DEFAULT); |
|
139 |
pci_set_long(c + ICH9_CC_D25IR, ICH9_CC_DIR_DEFAULT); |
|
140 |
|
|
141 |
ich9_cc_update(lpc); |
|
142 |
} |
|
143 |
|
|
144 |
static void ich9_cc_addr_len(uint64_t *addr, unsigned *len) |
|
145 |
{ |
|
146 |
*addr &= ICH9_CC_ADDR_MASK; |
|
147 |
if (*addr + *len >= ICH9_CC_SIZE) { |
|
148 |
*len = ICH9_CC_SIZE - *addr; |
|
149 |
} |
|
150 |
} |
|
151 |
|
|
152 |
/* val: little endian */ |
|
153 |
static void ich9_cc_write(void *opaque, hwaddr addr, |
|
154 |
uint64_t val, unsigned len) |
|
155 |
{ |
|
156 |
ICH9LPCState *lpc = (ICH9LPCState *)opaque; |
|
157 |
|
|
158 |
ich9_cc_addr_len(&addr, &len); |
|
159 |
memcpy(lpc->chip_config + addr, &val, len); |
|
160 |
pci_bus_fire_intx_routing_notifier(lpc->d.bus); |
|
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 |
{ |
|
252 |
int level = 0; |
|
253 |
|
|
254 |
if (gsi >= ICH9_LPC_PIC_NUM_PINS) { |
|
255 |
level |= pci_bus_get_irq_level(lpc->d.bus, ich9_gsi_to_pirq(gsi)); |
|
256 |
} |
|
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 |
PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin) |
|
290 |
{ |
|
291 |
ICH9LPCState *lpc = opaque; |
|
292 |
PCIINTxRoute route; |
|
293 |
int pic_irq; |
|
294 |
int pic_dis; |
|
295 |
|
|
296 |
assert(0 <= pirq_pin); |
|
297 |
assert(pirq_pin < ICH9_LPC_NB_PIRQS); |
|
298 |
|
|
299 |
route.mode = PCI_INTX_ENABLED; |
|
300 |
ich9_lpc_pic_irq(lpc, pirq_pin, &pic_irq, &pic_dis); |
|
301 |
if (!pic_dis) { |
|
302 |
if (pic_irq < ICH9_LPC_PIC_NUM_PINS) { |
|
303 |
route.irq = pic_irq; |
|
304 |
} else { |
|
305 |
route.mode = PCI_INTX_DISABLED; |
|
306 |
route.irq = -1; |
|
307 |
} |
|
308 |
} else { |
|
309 |
route.irq = ich9_pirq_to_gsi(pirq_pin); |
|
310 |
} |
|
311 |
|
|
312 |
return route; |
|
313 |
} |
|
314 |
|
|
315 |
static int ich9_lpc_sci_irq(ICH9LPCState *lpc) |
|
316 |
{ |
|
317 |
switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] & |
|
318 |
ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK) { |
|
319 |
case ICH9_LPC_ACPI_CTRL_9: |
|
320 |
return 9; |
|
321 |
case ICH9_LPC_ACPI_CTRL_10: |
|
322 |
return 10; |
|
323 |
case ICH9_LPC_ACPI_CTRL_11: |
|
324 |
return 11; |
|
325 |
case ICH9_LPC_ACPI_CTRL_20: |
|
326 |
return 20; |
|
327 |
case ICH9_LPC_ACPI_CTRL_21: |
|
328 |
return 21; |
|
329 |
default: |
|
330 |
/* reserved */ |
|
331 |
break; |
|
332 |
} |
|
333 |
return -1; |
|
334 |
} |
|
335 |
|
|
336 |
static void ich9_set_sci(void *opaque, int irq_num, int level) |
|
337 |
{ |
|
338 |
ICH9LPCState *lpc = opaque; |
|
339 |
int irq; |
|
340 |
|
|
341 |
assert(irq_num == 0); |
|
342 |
level = !!level; |
|
343 |
if (level == lpc->sci_level) { |
|
344 |
return; |
|
345 |
} |
|
346 |
lpc->sci_level = level; |
|
347 |
|
|
348 |
irq = ich9_lpc_sci_irq(lpc); |
|
349 |
if (irq < 0) { |
|
350 |
return; |
|
351 |
} |
|
352 |
|
|
353 |
ich9_lpc_update_apic(lpc, irq); |
|
354 |
if (irq < ICH9_LPC_PIC_NUM_PINS) { |
|
355 |
ich9_lpc_update_pic(lpc, irq); |
|
356 |
} |
|
357 |
} |
|
358 |
|
|
359 |
void ich9_lpc_pm_init(PCIDevice *lpc_pci, qemu_irq cmos_s3) |
|
360 |
{ |
|
361 |
ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci); |
|
362 |
qemu_irq *sci_irq; |
|
363 |
|
|
364 |
sci_irq = qemu_allocate_irqs(ich9_set_sci, lpc, 1); |
|
365 |
ich9_pm_init(lpc_pci, &lpc->pm, sci_irq[0], cmos_s3); |
|
366 |
|
|
367 |
ich9_lpc_reset(&lpc->d.qdev); |
|
368 |
} |
|
369 |
|
|
370 |
/* APM */ |
|
371 |
|
|
372 |
static void ich9_apm_ctrl_changed(uint32_t val, void *arg) |
|
373 |
{ |
|
374 |
ICH9LPCState *lpc = arg; |
|
375 |
|
|
376 |
/* ACPI specs 3.0, 4.7.2.5 */ |
|
377 |
acpi_pm1_cnt_update(&lpc->pm.acpi_regs, |
|
378 |
val == ICH9_APM_ACPI_ENABLE, |
|
379 |
val == ICH9_APM_ACPI_DISABLE); |
|
380 |
|
|
381 |
/* SMI_EN = PMBASE + 30. SMI control and enable register */ |
|
382 |
if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) { |
|
383 |
cpu_interrupt(CPU(x86_env_get_cpu(first_cpu)), CPU_INTERRUPT_SMI); |
|
384 |
} |
|
385 |
} |
|
386 |
|
|
387 |
/* config:PMBASE */ |
|
388 |
static void |
|
389 |
ich9_lpc_pmbase_update(ICH9LPCState *lpc) |
|
390 |
{ |
|
391 |
uint32_t pm_io_base = pci_get_long(lpc->d.config + ICH9_LPC_PMBASE); |
|
392 |
pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK; |
|
393 |
|
|
394 |
ich9_pm_iospace_update(&lpc->pm, pm_io_base); |
|
395 |
} |
|
396 |
|
|
397 |
/* config:RBCA */ |
|
398 |
static void ich9_lpc_rcba_update(ICH9LPCState *lpc, uint32_t rbca_old) |
|
399 |
{ |
|
400 |
uint32_t rbca = pci_get_long(lpc->d.config + ICH9_LPC_RCBA); |
|
401 |
|
|
402 |
if (rbca_old & ICH9_LPC_RCBA_EN) { |
|
403 |
memory_region_del_subregion(get_system_memory(), &lpc->rbca_mem); |
|
404 |
} |
|
405 |
if (rbca & ICH9_LPC_RCBA_EN) { |
|
406 |
memory_region_add_subregion_overlap(get_system_memory(), |
|
407 |
rbca & ICH9_LPC_RCBA_BA_MASK, |
|
408 |
&lpc->rbca_mem, 1); |
|
409 |
} |
|
410 |
} |
|
411 |
|
|
412 |
static int ich9_lpc_post_load(void *opaque, int version_id) |
|
413 |
{ |
|
414 |
ICH9LPCState *lpc = opaque; |
|
415 |
|
|
416 |
ich9_lpc_pmbase_update(lpc); |
|
417 |
ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */); |
|
418 |
return 0; |
|
419 |
} |
|
420 |
|
|
421 |
static void ich9_lpc_config_write(PCIDevice *d, |
|
422 |
uint32_t addr, uint32_t val, int len) |
|
423 |
{ |
|
424 |
ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); |
|
425 |
uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA); |
|
426 |
|
|
427 |
pci_default_write_config(d, addr, val, len); |
|
428 |
if (ranges_overlap(addr, len, ICH9_LPC_PMBASE, 4)) { |
|
429 |
ich9_lpc_pmbase_update(lpc); |
|
430 |
} |
|
431 |
if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) { |
|
432 |
ich9_lpc_rcba_update(lpc, rbca_old); |
|
433 |
} |
|
434 |
if (ranges_overlap(addr, len, ICH9_LPC_PIRQA_ROUT, 4)) { |
|
435 |
pci_bus_fire_intx_routing_notifier(lpc->d.bus); |
|
436 |
} |
|
437 |
if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) { |
|
438 |
pci_bus_fire_intx_routing_notifier(lpc->d.bus); |
|
439 |
} |
|
440 |
} |
|
441 |
|
|
442 |
static void ich9_lpc_reset(DeviceState *qdev) |
|
443 |
{ |
|
444 |
PCIDevice *d = PCI_DEVICE(qdev); |
|
445 |
ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); |
|
446 |
uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA); |
|
447 |
int i; |
|
448 |
|
|
449 |
for (i = 0; i < 4; i++) { |
|
450 |
pci_set_byte(d->config + ICH9_LPC_PIRQA_ROUT + i, |
|
451 |
ICH9_LPC_PIRQ_ROUT_DEFAULT); |
|
452 |
} |
|
453 |
for (i = 0; i < 4; i++) { |
|
454 |
pci_set_byte(d->config + ICH9_LPC_PIRQE_ROUT + i, |
|
455 |
ICH9_LPC_PIRQ_ROUT_DEFAULT); |
|
456 |
} |
|
457 |
pci_set_byte(d->config + ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_DEFAULT); |
|
458 |
|
|
459 |
pci_set_long(d->config + ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_DEFAULT); |
|
460 |
pci_set_long(d->config + ICH9_LPC_RCBA, ICH9_LPC_RCBA_DEFAULT); |
|
461 |
|
|
462 |
ich9_cc_reset(lpc); |
|
463 |
|
|
464 |
ich9_lpc_pmbase_update(lpc); |
|
465 |
ich9_lpc_rcba_update(lpc, rbca_old); |
|
466 |
|
|
467 |
lpc->sci_level = 0; |
|
468 |
lpc->rst_cnt = 0; |
|
469 |
} |
|
470 |
|
|
471 |
static const MemoryRegionOps rbca_mmio_ops = { |
|
472 |
.read = ich9_cc_read, |
|
473 |
.write = ich9_cc_write, |
|
474 |
.endianness = DEVICE_LITTLE_ENDIAN, |
|
475 |
}; |
|
476 |
|
|
477 |
static void ich9_lpc_machine_ready(Notifier *n, void *opaque) |
|
478 |
{ |
|
479 |
ICH9LPCState *s = container_of(n, ICH9LPCState, machine_ready); |
|
480 |
uint8_t *pci_conf; |
|
481 |
|
|
482 |
pci_conf = s->d.config; |
|
483 |
if (isa_is_ioport_assigned(0x3f8)) { |
|
484 |
/* com1 */ |
|
485 |
pci_conf[0x82] |= 0x01; |
|
486 |
} |
|
487 |
if (isa_is_ioport_assigned(0x2f8)) { |
|
488 |
/* com2 */ |
|
489 |
pci_conf[0x82] |= 0x02; |
|
490 |
} |
|
491 |
if (isa_is_ioport_assigned(0x378)) { |
|
492 |
/* lpt */ |
|
493 |
pci_conf[0x82] |= 0x04; |
|
494 |
} |
|
495 |
if (isa_is_ioport_assigned(0x3f0)) { |
|
496 |
/* floppy */ |
|
497 |
pci_conf[0x82] |= 0x08; |
|
498 |
} |
|
499 |
} |
|
500 |
|
|
501 |
/* reset control */ |
|
502 |
static void ich9_rst_cnt_write(void *opaque, hwaddr addr, uint64_t val, |
|
503 |
unsigned len) |
|
504 |
{ |
|
505 |
ICH9LPCState *lpc = opaque; |
|
506 |
|
|
507 |
if (val & 4) { |
|
508 |
qemu_system_reset_request(); |
|
509 |
return; |
|
510 |
} |
|
511 |
lpc->rst_cnt = val & 0xA; /* keep FULL_RST (bit 3) and SYS_RST (bit 1) */ |
|
512 |
} |
|
513 |
|
|
514 |
static uint64_t ich9_rst_cnt_read(void *opaque, hwaddr addr, unsigned len) |
|
515 |
{ |
|
516 |
ICH9LPCState *lpc = opaque; |
|
517 |
|
|
518 |
return lpc->rst_cnt; |
|
519 |
} |
|
520 |
|
|
521 |
static const MemoryRegionOps ich9_rst_cnt_ops = { |
|
522 |
.read = ich9_rst_cnt_read, |
|
523 |
.write = ich9_rst_cnt_write, |
|
524 |
.endianness = DEVICE_LITTLE_ENDIAN |
|
525 |
}; |
|
526 |
|
|
527 |
static int ich9_lpc_initfn(PCIDevice *d) |
|
528 |
{ |
|
529 |
ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); |
|
530 |
ISABus *isa_bus; |
|
531 |
|
|
532 |
isa_bus = isa_bus_new(&d->qdev, get_system_io()); |
|
533 |
|
|
534 |
pci_set_long(d->wmask + ICH9_LPC_PMBASE, |
|
535 |
ICH9_LPC_PMBASE_BASE_ADDRESS_MASK); |
|
536 |
|
|
537 |
memory_region_init_io(&lpc->rbca_mem, &rbca_mmio_ops, lpc, |
|
538 |
"lpc-rbca-mmio", ICH9_CC_SIZE); |
|
539 |
|
|
540 |
lpc->isa_bus = isa_bus; |
|
541 |
|
|
542 |
ich9_cc_init(lpc); |
|
543 |
apm_init(d, &lpc->apm, ich9_apm_ctrl_changed, lpc); |
|
544 |
|
|
545 |
lpc->machine_ready.notify = ich9_lpc_machine_ready; |
|
546 |
qemu_add_machine_init_done_notifier(&lpc->machine_ready); |
|
547 |
|
|
548 |
memory_region_init_io(&lpc->rst_cnt_mem, &ich9_rst_cnt_ops, lpc, |
|
549 |
"lpc-reset-control", 1); |
|
550 |
memory_region_add_subregion_overlap(pci_address_space_io(d), |
|
551 |
ICH9_RST_CNT_IOPORT, &lpc->rst_cnt_mem, |
|
552 |
1); |
|
553 |
|
|
554 |
return 0; |
|
555 |
} |
|
556 |
|
|
557 |
static bool ich9_rst_cnt_needed(void *opaque) |
|
558 |
{ |
|
559 |
ICH9LPCState *lpc = opaque; |
|
560 |
|
|
561 |
return (lpc->rst_cnt != 0); |
|
562 |
} |
|
563 |
|
|
564 |
static const VMStateDescription vmstate_ich9_rst_cnt = { |
|
565 |
.name = "ICH9LPC/rst_cnt", |
|
566 |
.version_id = 1, |
|
567 |
.minimum_version_id = 1, |
|
568 |
.fields = (VMStateField[]) { |
|
569 |
VMSTATE_UINT8(rst_cnt, ICH9LPCState), |
|
570 |
VMSTATE_END_OF_LIST() |
|
571 |
} |
|
572 |
}; |
|
573 |
|
|
574 |
static const VMStateDescription vmstate_ich9_lpc = { |
|
575 |
.name = "ICH9LPC", |
|
576 |
.version_id = 1, |
|
577 |
.minimum_version_id = 1, |
|
578 |
.minimum_version_id_old = 1, |
|
579 |
.post_load = ich9_lpc_post_load, |
|
580 |
.fields = (VMStateField[]) { |
|
581 |
VMSTATE_PCI_DEVICE(d, ICH9LPCState), |
|
582 |
VMSTATE_STRUCT(apm, ICH9LPCState, 0, vmstate_apm, APMState), |
|
583 |
VMSTATE_STRUCT(pm, ICH9LPCState, 0, vmstate_ich9_pm, ICH9LPCPMRegs), |
|
584 |
VMSTATE_UINT8_ARRAY(chip_config, ICH9LPCState, ICH9_CC_SIZE), |
|
585 |
VMSTATE_UINT32(sci_level, ICH9LPCState), |
|
586 |
VMSTATE_END_OF_LIST() |
|
587 |
}, |
|
588 |
.subsections = (VMStateSubsection[]) { |
|
589 |
{ |
|
590 |
.vmsd = &vmstate_ich9_rst_cnt, |
|
591 |
.needed = ich9_rst_cnt_needed |
|
592 |
}, |
|
593 |
{ 0 } |
|
594 |
} |
|
595 |
}; |
|
596 |
|
|
597 |
static void ich9_lpc_class_init(ObjectClass *klass, void *data) |
|
598 |
{ |
|
599 |
DeviceClass *dc = DEVICE_CLASS(klass); |
|
600 |
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
|
601 |
|
|
602 |
dc->reset = ich9_lpc_reset; |
|
603 |
k->init = ich9_lpc_initfn; |
|
604 |
dc->vmsd = &vmstate_ich9_lpc; |
|
605 |
dc->no_user = 1; |
|
606 |
k->config_write = ich9_lpc_config_write; |
|
607 |
dc->desc = "ICH9 LPC bridge"; |
|
608 |
k->vendor_id = PCI_VENDOR_ID_INTEL; |
|
609 |
k->device_id = PCI_DEVICE_ID_INTEL_ICH9_8; |
|
610 |
k->revision = ICH9_A2_LPC_REVISION; |
|
611 |
k->class_id = PCI_CLASS_BRIDGE_ISA; |
|
612 |
|
|
613 |
} |
|
614 |
|
|
615 |
static const TypeInfo ich9_lpc_info = { |
|
616 |
.name = TYPE_ICH9_LPC_DEVICE, |
|
617 |
.parent = TYPE_PCI_DEVICE, |
|
618 |
.instance_size = sizeof(struct ICH9LPCState), |
|
619 |
.class_init = ich9_lpc_class_init, |
|
620 |
}; |
|
621 |
|
|
622 |
static void ich9_lpc_register(void) |
|
623 |
{ |
|
624 |
type_register_static(&ich9_lpc_info); |
|
625 |
} |
|
626 |
|
|
627 |
type_init(ich9_lpc_register); |
b/hw/isa/vt82c686.c | ||
---|---|---|
1 |
/* |
|
2 |
* VT82C686B south bridge support |
|
3 |
* |
|
4 |
* Copyright (c) 2008 yajin (yajin@vm-kernel.org) |
|
5 |
* Copyright (c) 2009 chenming (chenming@rdc.faw.com.cn) |
|
6 |
* Copyright (c) 2010 Huacai Chen (zltjiangshi@gmail.com) |
|
7 |
* This code is licensed under the GNU GPL v2. |
|
8 |
* |
|
9 |
* Contributions after 2012-01-13 are licensed under the terms of the |
|
10 |
* GNU GPL, version 2 or (at your option) any later version. |
|
11 |
*/ |
|
12 |
|
|
13 |
#include "hw/hw.h" |
|
14 |
#include "hw/i386/pc.h" |
|
15 |
#include "hw/isa/vt82c686.h" |
|
16 |
#include "hw/i2c/i2c.h" |
|
17 |
#include "hw/i2c/smbus.h" |
|
18 |
#include "hw/pci/pci.h" |
|
19 |
#include "hw/isa/isa.h" |
|
20 |
#include "hw/sysbus.h" |
|
21 |
#include "hw/mips/mips.h" |
|
22 |
#include "hw/isa/apm.h" |
|
23 |
#include "hw/acpi/acpi.h" |
|
24 |
#include "hw/i2c/pm_smbus.h" |
|
25 |
#include "sysemu/sysemu.h" |
|
26 |
#include "qemu/timer.h" |
|
27 |
#include "exec/address-spaces.h" |
|
28 |
|
|
29 |
//#define DEBUG_VT82C686B |
|
30 |
|
|
31 |
#ifdef DEBUG_VT82C686B |
|
32 |
#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__) |
|
33 |
#else |
|
34 |
#define DPRINTF(fmt, ...) |
|
35 |
#endif |
|
36 |
|
|
37 |
typedef struct SuperIOConfig |
|
38 |
{ |
|
39 |
uint8_t config[0xff]; |
|
40 |
uint8_t index; |
|
41 |
uint8_t data; |
|
42 |
} SuperIOConfig; |
|
43 |
|
|
44 |
typedef struct VT82C686BState { |
|
45 |
PCIDevice dev; |
|
46 |
SuperIOConfig superio_conf; |
|
47 |
} VT82C686BState; |
|
48 |
|
|
49 |
static void superio_ioport_writeb(void *opaque, uint32_t addr, uint32_t data) |
|
50 |
{ |
|
51 |
int can_write; |
|
52 |
SuperIOConfig *superio_conf = opaque; |
|
53 |
|
|
54 |
DPRINTF("superio_ioport_writeb address 0x%x val 0x%x\n", addr, data); |
|
55 |
if (addr == 0x3f0) { |
|
56 |
superio_conf->index = data & 0xff; |
|
57 |
} else { |
|
58 |
/* 0x3f1 */ |
|
59 |
switch (superio_conf->index) { |
|
60 |
case 0x00 ... 0xdf: |
|
61 |
case 0xe4: |
|
62 |
case 0xe5: |
|
63 |
case 0xe9 ... 0xed: |
|
64 |
case 0xf3: |
|
65 |
case 0xf5: |
|
66 |
case 0xf7: |
|
67 |
case 0xf9 ... 0xfb: |
|
68 |
case 0xfd ... 0xff: |
|
69 |
can_write = 0; |
|
70 |
break; |
|
71 |
default: |
|
72 |
can_write = 1; |
|
73 |
|
|
74 |
if (can_write) { |
|
75 |
switch (superio_conf->index) { |
|
76 |
case 0xe7: |
|
77 |
if ((data & 0xff) != 0xfe) { |
|
78 |
DPRINTF("chage uart 1 base. unsupported yet\n"); |
|
79 |
} |
|
80 |
break; |
|
81 |
case 0xe8: |
|
82 |
if ((data & 0xff) != 0xbe) { |
|
83 |
DPRINTF("chage uart 2 base. unsupported yet\n"); |
|
84 |
} |
|
85 |
break; |
|
86 |
|
|
87 |
default: |
|
88 |
superio_conf->config[superio_conf->index] = data & 0xff; |
|
89 |
} |
|
90 |
} |
|
91 |
} |
|
92 |
superio_conf->config[superio_conf->index] = data & 0xff; |
|
93 |
} |
|
94 |
} |
|
95 |
|
|
96 |
static uint32_t superio_ioport_readb(void *opaque, uint32_t addr) |
|
97 |
{ |
|
98 |
SuperIOConfig *superio_conf = opaque; |
|
99 |
|
|
100 |
DPRINTF("superio_ioport_readb address 0x%x\n", addr); |
|
101 |
return (superio_conf->config[superio_conf->index]); |
|
102 |
} |
|
103 |
|
|
104 |
static void vt82c686b_reset(void * opaque) |
|
105 |
{ |
|
106 |
PCIDevice *d = opaque; |
|
107 |
uint8_t *pci_conf = d->config; |
|
108 |
VT82C686BState *vt82c = DO_UPCAST(VT82C686BState, dev, d); |
|
109 |
|
|
110 |
pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0); |
|
111 |
pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | |
|
112 |
PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL); |
|
113 |
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM); |
|
114 |
|
|
115 |
pci_conf[0x48] = 0x01; /* Miscellaneous Control 3 */ |
|
116 |
pci_conf[0x4a] = 0x04; /* IDE interrupt Routing */ |
|
117 |
pci_conf[0x4f] = 0x03; /* DMA/Master Mem Access Control 3 */ |
|
118 |
pci_conf[0x50] = 0x2d; /* PnP DMA Request Control */ |
|
119 |
pci_conf[0x59] = 0x04; |
|
120 |
pci_conf[0x5a] = 0x04; /* KBC/RTC Control*/ |
|
121 |
pci_conf[0x5f] = 0x04; |
|
122 |
pci_conf[0x77] = 0x10; /* GPIO Control 1/2/3/4 */ |
|
123 |
|
|
124 |
vt82c->superio_conf.config[0xe0] = 0x3c; |
|
125 |
vt82c->superio_conf.config[0xe2] = 0x03; |
|
126 |
vt82c->superio_conf.config[0xe3] = 0xfc; |
|
127 |
vt82c->superio_conf.config[0xe6] = 0xde; |
|
128 |
vt82c->superio_conf.config[0xe7] = 0xfe; |
|
129 |
vt82c->superio_conf.config[0xe8] = 0xbe; |
|
130 |
} |
|
131 |
|
|
132 |
/* write config pci function0 registers. PCI-ISA bridge */ |
|
133 |
static void vt82c686b_write_config(PCIDevice * d, uint32_t address, |
|
134 |
uint32_t val, int len) |
|
135 |
{ |
|
136 |
VT82C686BState *vt686 = DO_UPCAST(VT82C686BState, dev, d); |
|
137 |
|
|
138 |
DPRINTF("vt82c686b_write_config address 0x%x val 0x%x len 0x%x\n", |
|
139 |
address, val, len); |
|
140 |
|
|
141 |
pci_default_write_config(d, address, val, len); |
|
142 |
if (address == 0x85) { /* enable or disable super IO configure */ |
|
143 |
if (val & 0x2) { |
|
144 |
/* floppy also uses 0x3f0 and 0x3f1. |
|
145 |
* But we do not emulate flopy,so just set it here. */ |
|
146 |
isa_unassign_ioport(0x3f0, 2); |
|
147 |
register_ioport_read(0x3f0, 2, 1, superio_ioport_readb, |
|
148 |
&vt686->superio_conf); |
|
149 |
register_ioport_write(0x3f0, 2, 1, superio_ioport_writeb, |
|
150 |
&vt686->superio_conf); |
|
151 |
} else { |
|
152 |
isa_unassign_ioport(0x3f0, 2); |
|
153 |
} |
|
154 |
} |
|
155 |
} |
|
156 |
|
|
157 |
#define ACPI_DBG_IO_ADDR 0xb044 |
|
158 |
|
|
159 |
typedef struct VT686PMState { |
|
160 |
PCIDevice dev; |
|
161 |
MemoryRegion io; |
|
162 |
ACPIREGS ar; |
|
163 |
APMState apm; |
|
164 |
PMSMBus smb; |
|
165 |
uint32_t smb_io_base; |
|
166 |
} VT686PMState; |
|
167 |
|
|
168 |
typedef struct VT686AC97State { |
|
169 |
PCIDevice dev; |
|
170 |
} VT686AC97State; |
|
171 |
|
|
172 |
typedef struct VT686MC97State { |
|
173 |
PCIDevice dev; |
|
174 |
} VT686MC97State; |
|
175 |
|
|
176 |
static void pm_update_sci(VT686PMState *s) |
|
177 |
{ |
|
178 |
int sci_level, pmsts; |
|
179 |
|
|
180 |
pmsts = acpi_pm1_evt_get_sts(&s->ar); |
|
181 |
sci_level = (((pmsts & s->ar.pm1.evt.en) & |
|
182 |
(ACPI_BITMASK_RT_CLOCK_ENABLE | |
|
183 |
ACPI_BITMASK_POWER_BUTTON_ENABLE | |
|
184 |
ACPI_BITMASK_GLOBAL_LOCK_ENABLE | |
|
185 |
ACPI_BITMASK_TIMER_ENABLE)) != 0); |
|
186 |
qemu_set_irq(s->dev.irq[0], sci_level); |
|
187 |
/* schedule a timer interruption if needed */ |
|
188 |
acpi_pm_tmr_update(&s->ar, (s->ar.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) && |
|
189 |
!(pmsts & ACPI_BITMASK_TIMER_STATUS)); |
|
190 |
} |
|
191 |
|
|
192 |
static void pm_tmr_timer(ACPIREGS *ar) |
|
193 |
{ |
|
194 |
VT686PMState *s = container_of(ar, VT686PMState, ar); |
|
195 |
pm_update_sci(s); |
|
196 |
} |
|
197 |
|
|
198 |
static void pm_io_space_update(VT686PMState *s) |
|
199 |
{ |
|
200 |
uint32_t pm_io_base; |
|
201 |
|
|
202 |
pm_io_base = pci_get_long(s->dev.config + 0x40); |
|
203 |
pm_io_base &= 0xffc0; |
|
204 |
|
|
205 |
memory_region_transaction_begin(); |
|
206 |
memory_region_set_enabled(&s->io, s->dev.config[0x80] & 1); |
|
207 |
memory_region_set_address(&s->io, pm_io_base); |
|
208 |
memory_region_transaction_commit(); |
|
209 |
} |
|
210 |
|
|
211 |
static void pm_write_config(PCIDevice *d, |
|
212 |
uint32_t address, uint32_t val, int len) |
|
213 |
{ |
|
214 |
DPRINTF("pm_write_config address 0x%x val 0x%x len 0x%x\n", |
|
215 |
address, val, len); |
|
216 |
pci_default_write_config(d, address, val, len); |
|
217 |
} |
|
218 |
|
|
219 |
static int vmstate_acpi_post_load(void *opaque, int version_id) |
|
220 |
{ |
|
221 |
VT686PMState *s = opaque; |
|
222 |
|
|
223 |
pm_io_space_update(s); |
|
224 |
return 0; |
|
225 |
} |
|
226 |
|
|
227 |
static const VMStateDescription vmstate_acpi = { |
|
228 |
.name = "vt82c686b_pm", |
|
229 |
.version_id = 1, |
|
230 |
.minimum_version_id = 1, |
|
231 |
.minimum_version_id_old = 1, |
|
232 |
.post_load = vmstate_acpi_post_load, |
|
233 |
.fields = (VMStateField []) { |
|
234 |
VMSTATE_PCI_DEVICE(dev, VT686PMState), |
|
235 |
VMSTATE_UINT16(ar.pm1.evt.sts, VT686PMState), |
|
236 |
VMSTATE_UINT16(ar.pm1.evt.en, VT686PMState), |
|
237 |
VMSTATE_UINT16(ar.pm1.cnt.cnt, VT686PMState), |
|
238 |
VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState), |
|
239 |
VMSTATE_TIMER(ar.tmr.timer, VT686PMState), |
|
240 |
VMSTATE_INT64(ar.tmr.overflow_time, VT686PMState), |
|
241 |
VMSTATE_END_OF_LIST() |
|
242 |
} |
|
243 |
}; |
|
244 |
|
|
245 |
/* |
|
246 |
* TODO: vt82c686b_ac97_init() and vt82c686b_mc97_init() |
|
247 |
* just register a PCI device now, functionalities will be implemented later. |
|
248 |
*/ |
|
249 |
|
|
250 |
static int vt82c686b_ac97_initfn(PCIDevice *dev) |
|
251 |
{ |
|
252 |
VT686AC97State *s = DO_UPCAST(VT686AC97State, dev, dev); |
|
253 |
uint8_t *pci_conf = s->dev.config; |
|
254 |
|
|
255 |
pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE | |
|
256 |
PCI_COMMAND_PARITY); |
|
257 |
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST | |
|
258 |
PCI_STATUS_DEVSEL_MEDIUM); |
|
259 |
pci_set_long(pci_conf + PCI_INTERRUPT_PIN, 0x03); |
|
260 |
|
|
261 |
return 0; |
|
262 |
} |
|
263 |
|
|
264 |
void vt82c686b_ac97_init(PCIBus *bus, int devfn) |
|
265 |
{ |
|
266 |
PCIDevice *dev; |
|
267 |
|
|
268 |
dev = pci_create(bus, devfn, "VT82C686B_AC97"); |
|
269 |
qdev_init_nofail(&dev->qdev); |
|
270 |
} |
|
271 |
|
|
272 |
static void via_ac97_class_init(ObjectClass *klass, void *data) |
|
273 |
{ |
|
274 |
DeviceClass *dc = DEVICE_CLASS(klass); |
|
275 |
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
|
276 |
|
|
277 |
k->init = vt82c686b_ac97_initfn; |
|
278 |
k->vendor_id = PCI_VENDOR_ID_VIA; |
|
279 |
k->device_id = PCI_DEVICE_ID_VIA_AC97; |
|
280 |
k->revision = 0x50; |
|
281 |
k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO; |
|
282 |
dc->desc = "AC97"; |
|
283 |
} |
|
284 |
|
|
285 |
static const TypeInfo via_ac97_info = { |
|
286 |
.name = "VT82C686B_AC97", |
|
287 |
.parent = TYPE_PCI_DEVICE, |
|
288 |
.instance_size = sizeof(VT686AC97State), |
|
289 |
.class_init = via_ac97_class_init, |
|
290 |
}; |
|
291 |
|
|
292 |
static int vt82c686b_mc97_initfn(PCIDevice *dev) |
|
293 |
{ |
|
294 |
VT686MC97State *s = DO_UPCAST(VT686MC97State, dev, dev); |
|
295 |
uint8_t *pci_conf = s->dev.config; |
|
296 |
|
|
297 |
pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE | |
|
298 |
PCI_COMMAND_VGA_PALETTE); |
|
299 |
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM); |
|
300 |
pci_set_long(pci_conf + PCI_INTERRUPT_PIN, 0x03); |
|
301 |
|
|
302 |
return 0; |
|
303 |
} |
|
304 |
|
|
305 |
void vt82c686b_mc97_init(PCIBus *bus, int devfn) |
|
306 |
{ |
|
307 |
PCIDevice *dev; |
|
308 |
|
|
309 |
dev = pci_create(bus, devfn, "VT82C686B_MC97"); |
|
310 |
qdev_init_nofail(&dev->qdev); |
|
311 |
} |
|
312 |
|
|
313 |
static void via_mc97_class_init(ObjectClass *klass, void *data) |
|
314 |
{ |
|
315 |
DeviceClass *dc = DEVICE_CLASS(klass); |
|
316 |
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
|
317 |
|
|
318 |
k->init = vt82c686b_mc97_initfn; |
|
319 |
k->vendor_id = PCI_VENDOR_ID_VIA; |
|
320 |
k->device_id = PCI_DEVICE_ID_VIA_MC97; |
|
321 |
k->class_id = PCI_CLASS_COMMUNICATION_OTHER; |
|
322 |
k->revision = 0x30; |
|
323 |
dc->desc = "MC97"; |
|
324 |
} |
|
325 |
|
|
326 |
static const TypeInfo via_mc97_info = { |
|
327 |
.name = "VT82C686B_MC97", |
|
328 |
.parent = TYPE_PCI_DEVICE, |
|
329 |
.instance_size = sizeof(VT686MC97State), |
|
330 |
.class_init = via_mc97_class_init, |
|
331 |
}; |
|
332 |
|
|
333 |
/* vt82c686 pm init */ |
|
334 |
static int vt82c686b_pm_initfn(PCIDevice *dev) |
|
335 |
{ |
|
336 |
VT686PMState *s = DO_UPCAST(VT686PMState, dev, dev); |
|
337 |
uint8_t *pci_conf; |
|
338 |
|
|
339 |
pci_conf = s->dev.config; |
|
340 |
pci_set_word(pci_conf + PCI_COMMAND, 0); |
|
341 |
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK | |
|
342 |
PCI_STATUS_DEVSEL_MEDIUM); |
|
343 |
|
|
344 |
/* 0x48-0x4B is Power Management I/O Base */ |
|
345 |
pci_set_long(pci_conf + 0x48, 0x00000001); |
|
346 |
|
|
347 |
/* SMB ports:0xeee0~0xeeef */ |
|
348 |
s->smb_io_base =((s->smb_io_base & 0xfff0) + 0x0); |
|
349 |
pci_conf[0x90] = s->smb_io_base | 1; |
|
350 |
pci_conf[0x91] = s->smb_io_base >> 8; |
|
351 |
pci_conf[0xd2] = 0x90; |
|
352 |
pm_smbus_init(&s->dev.qdev, &s->smb); |
|
353 |
memory_region_add_subregion(get_system_io(), s->smb_io_base, &s->smb.io); |
|
354 |
|
|
355 |
apm_init(dev, &s->apm, NULL, s); |
|
356 |
|
|
357 |
memory_region_init(&s->io, "vt82c686-pm", 64); |
|
358 |
memory_region_set_enabled(&s->io, false); |
|
359 |
memory_region_add_subregion(get_system_io(), 0, &s->io); |
|
360 |
|
|
361 |
acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io); |
|
362 |
acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io); |
|
363 |
acpi_pm1_cnt_init(&s->ar, &s->io, 2); |
|
364 |
|
|
365 |
return 0; |
|
366 |
} |
|
367 |
|
|
368 |
i2c_bus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, |
|
369 |
qemu_irq sci_irq) |
|
370 |
{ |
|
371 |
PCIDevice *dev; |
|
372 |
VT686PMState *s; |
|
373 |
|
|
374 |
dev = pci_create(bus, devfn, "VT82C686B_PM"); |
|
375 |
qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base); |
|
376 |
|
|
377 |
s = DO_UPCAST(VT686PMState, dev, dev); |
|
378 |
|
|
379 |
qdev_init_nofail(&dev->qdev); |
|
380 |
|
|
381 |
return s->smb.smbus; |
|
382 |
} |
|
383 |
|
|
384 |
static Property via_pm_properties[] = { |
|
385 |
DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0), |
|
386 |
DEFINE_PROP_END_OF_LIST(), |
|
387 |
}; |
|
388 |
|
|
389 |
static void via_pm_class_init(ObjectClass *klass, void *data) |
|
390 |
{ |
|
391 |
DeviceClass *dc = DEVICE_CLASS(klass); |
|
392 |
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
|
393 |
|
|
394 |
k->init = vt82c686b_pm_initfn; |
|
395 |
k->config_write = pm_write_config; |
|
396 |
k->vendor_id = PCI_VENDOR_ID_VIA; |
|
397 |
k->device_id = PCI_DEVICE_ID_VIA_ACPI; |
|
398 |
k->class_id = PCI_CLASS_BRIDGE_OTHER; |
|
399 |
k->revision = 0x40; |
|
400 |
dc->desc = "PM"; |
|
401 |
dc->vmsd = &vmstate_acpi; |
|
402 |
dc->props = via_pm_properties; |
|
403 |
} |
|
404 |
|
|
405 |
static const TypeInfo via_pm_info = { |
|
406 |
.name = "VT82C686B_PM", |
|
407 |
.parent = TYPE_PCI_DEVICE, |
|
408 |
.instance_size = sizeof(VT686PMState), |
|
409 |
.class_init = via_pm_class_init, |
|
410 |
}; |
|
411 |
|
|
412 |
static const VMStateDescription vmstate_via = { |
|
413 |
.name = "vt82c686b", |
|
414 |
.version_id = 1, |
|
415 |
.minimum_version_id = 1, |
|
416 |
.minimum_version_id_old = 1, |
|
417 |
.fields = (VMStateField []) { |
|
418 |
VMSTATE_PCI_DEVICE(dev, VT82C686BState), |
|
419 |
VMSTATE_END_OF_LIST() |
|
420 |
} |
|
421 |
}; |
|
422 |
|
|
423 |
/* init the PCI-to-ISA bridge */ |
|
424 |
static int vt82c686b_initfn(PCIDevice *d) |
|
425 |
{ |
|
426 |
uint8_t *pci_conf; |
|
427 |
uint8_t *wmask; |
|
428 |
int i; |
|
429 |
|
|
430 |
isa_bus_new(&d->qdev, pci_address_space_io(d)); |
|
431 |
|
|
432 |
pci_conf = d->config; |
|
433 |
pci_config_set_prog_interface(pci_conf, 0x0); |
|
434 |
|
|
435 |
wmask = d->wmask; |
|
436 |
for (i = 0x00; i < 0xff; i++) { |
|
437 |
if (i<=0x03 || (i>=0x08 && i<=0x3f)) { |
|
438 |
wmask[i] = 0x00; |
|
439 |
} |
|
440 |
} |
|
441 |
|
|
442 |
qemu_register_reset(vt82c686b_reset, d); |
|
443 |
|
|
444 |
return 0; |
|
445 |
} |
|
446 |
|
|
447 |
ISABus *vt82c686b_init(PCIBus *bus, int devfn) |
|
448 |
{ |
|
449 |
PCIDevice *d; |
|
450 |
|
|
451 |
d = pci_create_simple_multifunction(bus, devfn, true, "VT82C686B"); |
|
452 |
|
|
453 |
return DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&d->qdev, "isa.0")); |
|
454 |
} |
|
455 |
|
|
456 |
static void via_class_init(ObjectClass *klass, void *data) |
|
457 |
{ |
|
458 |
DeviceClass *dc = DEVICE_CLASS(klass); |
|
459 |
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
|
460 |
|
|
461 |
k->init = vt82c686b_initfn; |
|
462 |
k->config_write = vt82c686b_write_config; |
|
463 |
k->vendor_id = PCI_VENDOR_ID_VIA; |
|
464 |
k->device_id = PCI_DEVICE_ID_VIA_ISA_BRIDGE; |
|
465 |
k->class_id = PCI_CLASS_BRIDGE_ISA; |
|
466 |
k->revision = 0x40; |
|
467 |
dc->desc = "ISA bridge"; |
|
468 |
dc->no_user = 1; |
|
469 |
dc->vmsd = &vmstate_via; |
|
470 |
} |
|
471 |
|
|
472 |
static const TypeInfo via_info = { |
|
473 |
.name = "VT82C686B", |
|
474 |
.parent = TYPE_PCI_DEVICE, |
|
475 |
.instance_size = sizeof(VT82C686BState), |
|
476 |
.class_init = via_class_init, |
|
477 |
}; |
|
478 |
|
|
479 |
static void vt82c686b_register_types(void) |
|
480 |
{ |
|
481 |
type_register_static(&via_ac97_info); |
|
482 |
type_register_static(&via_mc97_info); |
|
483 |
type_register_static(&via_pm_info); |
|
484 |
type_register_static(&via_info); |
|
485 |
} |
|
486 |
|
|
487 |
type_init(vt82c686b_register_types) |
/dev/null | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU ICH9 Emulation |
|
3 |
* |
|
4 |
* Copyright (c) 2006 Fabrice Bellard |
|
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. |
|
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 |
*/ |
|
30 |
#include "qemu-common.h" |
|
31 |
#include "hw/hw.h" |
|
32 |
#include "qemu/range.h" |
|
33 |
#include "hw/isa/isa.h" |
|
34 |
#include "hw/sysbus.h" |
|
35 |
#include "hw/i386/pc.h" |
|
36 |
#include "hw/isa/apm.h" |
|
37 |
#include "hw/i386/ioapic.h" |
|
38 |
#include "hw/pci/pci.h" |
|
39 |
#include "hw/pci/pcie_host.h" |
|
40 |
#include "hw/pci/pci_bridge.h" |
|
41 |
#include "hw/i386/ich9.h" |
|
42 |
#include "hw/acpi/acpi.h" |
|
43 |
#include "hw/acpi/ich9.h" |
|
44 |
#include "hw/pci/pci_bus.h" |
|
45 |
#include "exec/address-spaces.h" |
|
46 |
#include "sysemu/sysemu.h" |
|
47 |
|
|
48 |
static int ich9_lpc_sci_irq(ICH9LPCState *lpc); |
|
49 |
|
|
50 |
/*****************************************************************************/ |
|
51 |
/* ICH9 LPC PCI to ISA bridge */ |
|
52 |
|
|
53 |
static void ich9_lpc_reset(DeviceState *qdev); |
|
54 |
|
|
55 |
/* chipset configuration register |
|
56 |
* to access chipset configuration registers, pci_[sg]et_{byte, word, long} |
|
57 |
* are used. |
|
58 |
* Although it's not pci configuration space, it's little endian as Intel. |
|
59 |
*/ |
|
60 |
|
|
61 |
static void ich9_cc_update_ir(uint8_t irr[PCI_NUM_PINS], uint16_t ir) |
|
62 |
{ |
|
63 |
int intx; |
|
64 |
for (intx = 0; intx < PCI_NUM_PINS; intx++) { |
|
65 |
irr[intx] = (ir >> (intx * ICH9_CC_DIR_SHIFT)) & ICH9_CC_DIR_MASK; |
|
66 |
} |
|
67 |
} |
|
68 |
|
|
69 |
static void ich9_cc_update(ICH9LPCState *lpc) |
|
70 |
{ |
|
71 |
int slot; |
|
72 |
int pci_intx; |
|
73 |
|
|
74 |
const int reg_offsets[] = { |
|
75 |
ICH9_CC_D25IR, |
|
76 |
ICH9_CC_D26IR, |
|
77 |
ICH9_CC_D27IR, |
|
78 |
ICH9_CC_D28IR, |
|
79 |
ICH9_CC_D29IR, |
|
80 |
ICH9_CC_D30IR, |
|
81 |
ICH9_CC_D31IR, |
|
82 |
}; |
|
83 |
const int *offset; |
|
84 |
|
|
85 |
/* D{25 - 31}IR, but D30IR is read only to 0. */ |
|
86 |
for (slot = 25, offset = reg_offsets; slot < 32; slot++, offset++) { |
|
87 |
if (slot == 30) { |
|
88 |
continue; |
|
89 |
} |
|
90 |
ich9_cc_update_ir(lpc->irr[slot], |
|
91 |
pci_get_word(lpc->chip_config + *offset)); |
|
92 |
} |
|
93 |
|
|
94 |
/* |
|
95 |
* D30: DMI2PCI bridge |
|
96 |
* It is arbitrarily decided how INTx lines of PCI devicesbehind the bridge |
|
97 |
* are connected to pirq lines. Our choice is PIRQ[E-H]. |
|
98 |
* INT[A-D] are connected to PIRQ[E-H] |
|
99 |
*/ |
|
100 |
for (pci_intx = 0; pci_intx < PCI_NUM_PINS; pci_intx++) { |
|
101 |
lpc->irr[30][pci_intx] = pci_intx + 4; |
|
102 |
} |
|
103 |
} |
|
104 |
|
|
105 |
static void ich9_cc_init(ICH9LPCState *lpc) |
|
106 |
{ |
|
107 |
int slot; |
|
108 |
int intx; |
|
109 |
|
|
110 |
/* the default irq routing is arbitrary as long as it matches with |
|
111 |
* acpi irq routing table. |
|
112 |
* The one that is incompatible with piix_pci(= bochs) one is |
|
113 |
* intentionally chosen to let the users know that the different |
|
114 |
* board is used. |
|
115 |
* |
|
116 |
* int[A-D] -> pirq[E-F] |
|
117 |
* avoid pirq A-D because they are used for pci express port |
|
118 |
*/ |
|
119 |
for (slot = 0; slot < PCI_SLOT_MAX; slot++) { |
|
120 |
for (intx = 0; intx < PCI_NUM_PINS; intx++) { |
|
121 |
lpc->irr[slot][intx] = (slot + intx) % 4 + 4; |
|
122 |
} |
|
123 |
} |
|
124 |
ich9_cc_update(lpc); |
|
125 |
} |
|
126 |
|
|
127 |
static void ich9_cc_reset(ICH9LPCState *lpc) |
|
128 |
{ |
|
129 |
uint8_t *c = lpc->chip_config; |
|
130 |
|
|
131 |
memset(lpc->chip_config, 0, sizeof(lpc->chip_config)); |
|
132 |
|
|
133 |
pci_set_long(c + ICH9_CC_D31IR, ICH9_CC_DIR_DEFAULT); |
|
134 |
pci_set_long(c + ICH9_CC_D30IR, ICH9_CC_D30IR_DEFAULT); |
|
135 |
pci_set_long(c + ICH9_CC_D29IR, ICH9_CC_DIR_DEFAULT); |
|
136 |
pci_set_long(c + ICH9_CC_D28IR, ICH9_CC_DIR_DEFAULT); |
|
137 |
pci_set_long(c + ICH9_CC_D27IR, ICH9_CC_DIR_DEFAULT); |
|
138 |
pci_set_long(c + ICH9_CC_D26IR, ICH9_CC_DIR_DEFAULT); |
|
139 |
pci_set_long(c + ICH9_CC_D25IR, ICH9_CC_DIR_DEFAULT); |
|
140 |
|
|
141 |
ich9_cc_update(lpc); |
|
142 |
} |
|
143 |
|
|
144 |
static void ich9_cc_addr_len(uint64_t *addr, unsigned *len) |
|
145 |
{ |
|
146 |
*addr &= ICH9_CC_ADDR_MASK; |
|
147 |
if (*addr + *len >= ICH9_CC_SIZE) { |
|
148 |
*len = ICH9_CC_SIZE - *addr; |
|
149 |
} |
|
150 |
} |
|
151 |
|
|
152 |
/* val: little endian */ |
|
153 |
static void ich9_cc_write(void *opaque, hwaddr addr, |
|
154 |
uint64_t val, unsigned len) |
|
155 |
{ |
|
156 |
ICH9LPCState *lpc = (ICH9LPCState *)opaque; |
|
157 |
|
|
158 |
ich9_cc_addr_len(&addr, &len); |
|
159 |
memcpy(lpc->chip_config + addr, &val, len); |
|
160 |
pci_bus_fire_intx_routing_notifier(lpc->d.bus); |
|
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 |
{ |
|
252 |
int level = 0; |
|
253 |
|
|
254 |
if (gsi >= ICH9_LPC_PIC_NUM_PINS) { |
|
255 |
level |= pci_bus_get_irq_level(lpc->d.bus, ich9_gsi_to_pirq(gsi)); |
|
256 |
} |
|
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)]; |
Also available in: Unified diff