1 | /* |
2 | * Copyright (C) 2010 Red Hat, Inc. |
3 | * |
4 | * written by Gerd Hoffmann <kraxel@redhat.com> |
5 | * |
6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License as |
8 | * published by the Free Software Foundation; either version 2 or |
9 | * (at your option) version 3 of the License. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
18 | */ |
19 | |
20 | #include "qemu/osdep.h" |
21 | #include "hw/pci/pci.h" |
22 | #include "hw/qdev-properties.h" |
23 | #include "hw/pci/msi.h" |
24 | #include "qemu/timer.h" |
25 | #include "qemu/bitops.h" |
26 | #include "qemu/log.h" |
27 | #include "qemu/module.h" |
28 | #include "hw/audio/soundhw.h" |
29 | #include "intel-hda.h" |
30 | #include "migration/vmstate.h" |
31 | #include "intel-hda-defs.h" |
32 | #include "sysemu/dma.h" |
33 | #include "qapi/error.h" |
34 | |
35 | /* --------------------------------------------------------------------- */ |
36 | /* hda bus */ |
37 | |
38 | static Property hda_props[] = { |
39 | DEFINE_PROP_UINT32("cad" , HDACodecDevice, cad, -1), |
40 | DEFINE_PROP_END_OF_LIST() |
41 | }; |
42 | |
43 | static const TypeInfo hda_codec_bus_info = { |
44 | .name = TYPE_HDA_BUS, |
45 | .parent = TYPE_BUS, |
46 | .instance_size = sizeof(HDACodecBus), |
47 | }; |
48 | |
49 | void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, size_t bus_size, |
50 | hda_codec_response_func response, |
51 | hda_codec_xfer_func xfer) |
52 | { |
53 | qbus_create_inplace(bus, bus_size, TYPE_HDA_BUS, dev, NULL); |
54 | bus->response = response; |
55 | bus->xfer = xfer; |
56 | } |
57 | |
58 | static void hda_codec_dev_realize(DeviceState *qdev, Error **errp) |
59 | { |
60 | HDACodecBus *bus = HDA_BUS(qdev->parent_bus); |
61 | HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev); |
62 | HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev); |
63 | |
64 | if (dev->cad == -1) { |
65 | dev->cad = bus->next_cad; |
66 | } |
67 | if (dev->cad >= 15) { |
68 | error_setg(errp, "HDA audio codec address is full" ); |
69 | return; |
70 | } |
71 | bus->next_cad = dev->cad + 1; |
72 | if (cdc->init(dev) != 0) { |
73 | error_setg(errp, "HDA audio init failed" ); |
74 | } |
75 | } |
76 | |
77 | static void hda_codec_dev_unrealize(DeviceState *qdev, Error **errp) |
78 | { |
79 | HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev); |
80 | HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev); |
81 | |
82 | if (cdc->exit) { |
83 | cdc->exit(dev); |
84 | } |
85 | } |
86 | |
87 | HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad) |
88 | { |
89 | BusChild *kid; |
90 | HDACodecDevice *cdev; |
91 | |
92 | QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { |
93 | DeviceState *qdev = kid->child; |
94 | cdev = HDA_CODEC_DEVICE(qdev); |
95 | if (cdev->cad == cad) { |
96 | return cdev; |
97 | } |
98 | } |
99 | return NULL; |
100 | } |
101 | |
102 | void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response) |
103 | { |
104 | HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus); |
105 | bus->response(dev, solicited, response); |
106 | } |
107 | |
108 | bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, |
109 | uint8_t *buf, uint32_t len) |
110 | { |
111 | HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus); |
112 | return bus->xfer(dev, stnr, output, buf, len); |
113 | } |
114 | |
115 | /* --------------------------------------------------------------------- */ |
116 | /* intel hda emulation */ |
117 | |
118 | typedef struct IntelHDAStream IntelHDAStream; |
119 | typedef struct IntelHDAState IntelHDAState; |
120 | typedef struct IntelHDAReg IntelHDAReg; |
121 | |
122 | typedef struct bpl { |
123 | uint64_t addr; |
124 | uint32_t len; |
125 | uint32_t flags; |
126 | } bpl; |
127 | |
128 | struct IntelHDAStream { |
129 | /* registers */ |
130 | uint32_t ctl; |
131 | uint32_t lpib; |
132 | uint32_t cbl; |
133 | uint32_t lvi; |
134 | uint32_t fmt; |
135 | uint32_t bdlp_lbase; |
136 | uint32_t bdlp_ubase; |
137 | |
138 | /* state */ |
139 | bpl *bpl; |
140 | uint32_t bentries; |
141 | uint32_t bsize, be, bp; |
142 | }; |
143 | |
144 | struct IntelHDAState { |
145 | PCIDevice pci; |
146 | const char *name; |
147 | HDACodecBus codecs; |
148 | |
149 | /* registers */ |
150 | uint32_t g_ctl; |
151 | uint32_t wake_en; |
152 | uint32_t state_sts; |
153 | uint32_t int_ctl; |
154 | uint32_t int_sts; |
155 | uint32_t wall_clk; |
156 | |
157 | uint32_t corb_lbase; |
158 | uint32_t corb_ubase; |
159 | uint32_t corb_rp; |
160 | uint32_t corb_wp; |
161 | uint32_t corb_ctl; |
162 | uint32_t corb_sts; |
163 | uint32_t corb_size; |
164 | |
165 | uint32_t rirb_lbase; |
166 | uint32_t rirb_ubase; |
167 | uint32_t rirb_wp; |
168 | uint32_t rirb_cnt; |
169 | uint32_t rirb_ctl; |
170 | uint32_t rirb_sts; |
171 | uint32_t rirb_size; |
172 | |
173 | uint32_t dp_lbase; |
174 | uint32_t dp_ubase; |
175 | |
176 | uint32_t icw; |
177 | uint32_t irr; |
178 | uint32_t ics; |
179 | |
180 | /* streams */ |
181 | IntelHDAStream st[8]; |
182 | |
183 | /* state */ |
184 | MemoryRegion mmio; |
185 | uint32_t rirb_count; |
186 | int64_t wall_base_ns; |
187 | |
188 | /* debug logging */ |
189 | const IntelHDAReg *last_reg; |
190 | uint32_t last_val; |
191 | uint32_t last_write; |
192 | uint32_t last_sec; |
193 | uint32_t repeat_count; |
194 | |
195 | /* properties */ |
196 | uint32_t debug; |
197 | OnOffAuto msi; |
198 | bool old_msi_addr; |
199 | }; |
200 | |
201 | #define TYPE_INTEL_HDA_GENERIC "intel-hda-generic" |
202 | |
203 | #define INTEL_HDA(obj) \ |
204 | OBJECT_CHECK(IntelHDAState, (obj), TYPE_INTEL_HDA_GENERIC) |
205 | |
206 | struct IntelHDAReg { |
207 | const char *name; /* register name */ |
208 | uint32_t size; /* size in bytes */ |
209 | uint32_t reset; /* reset value */ |
210 | uint32_t wmask; /* write mask */ |
211 | uint32_t wclear; /* write 1 to clear bits */ |
212 | uint32_t offset; /* location in IntelHDAState */ |
213 | uint32_t shift; /* byte access entries for dwords */ |
214 | uint32_t stream; |
215 | void (*whandler)(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old); |
216 | void (*rhandler)(IntelHDAState *d, const IntelHDAReg *reg); |
217 | }; |
218 | |
219 | static void intel_hda_reset(DeviceState *dev); |
220 | |
221 | /* --------------------------------------------------------------------- */ |
222 | |
223 | static hwaddr intel_hda_addr(uint32_t lbase, uint32_t ubase) |
224 | { |
225 | return ((uint64_t)ubase << 32) | lbase; |
226 | } |
227 | |
228 | static void intel_hda_update_int_sts(IntelHDAState *d) |
229 | { |
230 | uint32_t sts = 0; |
231 | uint32_t i; |
232 | |
233 | /* update controller status */ |
234 | if (d->rirb_sts & ICH6_RBSTS_IRQ) { |
235 | sts |= (1 << 30); |
236 | } |
237 | if (d->rirb_sts & ICH6_RBSTS_OVERRUN) { |
238 | sts |= (1 << 30); |
239 | } |
240 | if (d->state_sts & d->wake_en) { |
241 | sts |= (1 << 30); |
242 | } |
243 | |
244 | /* update stream status */ |
245 | for (i = 0; i < 8; i++) { |
246 | /* buffer completion interrupt */ |
247 | if (d->st[i].ctl & (1 << 26)) { |
248 | sts |= (1 << i); |
249 | } |
250 | } |
251 | |
252 | /* update global status */ |
253 | if (sts & d->int_ctl) { |
254 | sts |= (1U << 31); |
255 | } |
256 | |
257 | d->int_sts = sts; |
258 | } |
259 | |
260 | static void intel_hda_update_irq(IntelHDAState *d) |
261 | { |
262 | bool msi = msi_enabled(&d->pci); |
263 | int level; |
264 | |
265 | intel_hda_update_int_sts(d); |
266 | if (d->int_sts & (1U << 31) && d->int_ctl & (1U << 31)) { |
267 | level = 1; |
268 | } else { |
269 | level = 0; |
270 | } |
271 | dprint(d, 2, "%s: level %d [%s]\n" , __func__, |
272 | level, msi ? "msi" : "intx" ); |
273 | if (msi) { |
274 | if (level) { |
275 | msi_notify(&d->pci, 0); |
276 | } |
277 | } else { |
278 | pci_set_irq(&d->pci, level); |
279 | } |
280 | } |
281 | |
282 | static int intel_hda_send_command(IntelHDAState *d, uint32_t verb) |
283 | { |
284 | uint32_t cad, nid, data; |
285 | HDACodecDevice *codec; |
286 | HDACodecDeviceClass *cdc; |
287 | |
288 | cad = (verb >> 28) & 0x0f; |
289 | if (verb & (1 << 27)) { |
290 | /* indirect node addressing, not specified in HDA 1.0 */ |
291 | dprint(d, 1, "%s: indirect node addressing (guest bug?)\n" , __func__); |
292 | return -1; |
293 | } |
294 | nid = (verb >> 20) & 0x7f; |
295 | data = verb & 0xfffff; |
296 | |
297 | codec = hda_codec_find(&d->codecs, cad); |
298 | if (codec == NULL) { |
299 | dprint(d, 1, "%s: addressed non-existing codec\n" , __func__); |
300 | return -1; |
301 | } |
302 | cdc = HDA_CODEC_DEVICE_GET_CLASS(codec); |
303 | cdc->command(codec, nid, data); |
304 | return 0; |
305 | } |
306 | |
307 | static void intel_hda_corb_run(IntelHDAState *d) |
308 | { |
309 | hwaddr addr; |
310 | uint32_t rp, verb; |
311 | |
312 | if (d->ics & ICH6_IRS_BUSY) { |
313 | dprint(d, 2, "%s: [icw] verb 0x%08x\n" , __func__, d->icw); |
314 | intel_hda_send_command(d, d->icw); |
315 | return; |
316 | } |
317 | |
318 | for (;;) { |
319 | if (!(d->corb_ctl & ICH6_CORBCTL_RUN)) { |
320 | dprint(d, 2, "%s: !run\n" , __func__); |
321 | return; |
322 | } |
323 | if ((d->corb_rp & 0xff) == d->corb_wp) { |
324 | dprint(d, 2, "%s: corb ring empty\n" , __func__); |
325 | return; |
326 | } |
327 | if (d->rirb_count == d->rirb_cnt) { |
328 | dprint(d, 2, "%s: rirb count reached\n" , __func__); |
329 | return; |
330 | } |
331 | |
332 | rp = (d->corb_rp + 1) & 0xff; |
333 | addr = intel_hda_addr(d->corb_lbase, d->corb_ubase); |
334 | verb = ldl_le_pci_dma(&d->pci, addr + 4*rp); |
335 | d->corb_rp = rp; |
336 | |
337 | dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n" , __func__, rp, verb); |
338 | intel_hda_send_command(d, verb); |
339 | } |
340 | } |
341 | |
342 | static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response) |
343 | { |
344 | HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus); |
345 | IntelHDAState *d = container_of(bus, IntelHDAState, codecs); |
346 | hwaddr addr; |
347 | uint32_t wp, ex; |
348 | |
349 | if (d->ics & ICH6_IRS_BUSY) { |
350 | dprint(d, 2, "%s: [irr] response 0x%x, cad 0x%x\n" , |
351 | __func__, response, dev->cad); |
352 | d->irr = response; |
353 | d->ics &= ~(ICH6_IRS_BUSY | 0xf0); |
354 | d->ics |= (ICH6_IRS_VALID | (dev->cad << 4)); |
355 | return; |
356 | } |
357 | |
358 | if (!(d->rirb_ctl & ICH6_RBCTL_DMA_EN)) { |
359 | dprint(d, 1, "%s: rirb dma disabled, drop codec response\n" , __func__); |
360 | return; |
361 | } |
362 | |
363 | ex = (solicited ? 0 : (1 << 4)) | dev->cad; |
364 | wp = (d->rirb_wp + 1) & 0xff; |
365 | addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase); |
366 | stl_le_pci_dma(&d->pci, addr + 8*wp, response); |
367 | stl_le_pci_dma(&d->pci, addr + 8*wp + 4, ex); |
368 | d->rirb_wp = wp; |
369 | |
370 | dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n" , |
371 | __func__, wp, response, ex); |
372 | |
373 | d->rirb_count++; |
374 | if (d->rirb_count == d->rirb_cnt) { |
375 | dprint(d, 2, "%s: rirb count reached (%d)\n" , __func__, d->rirb_count); |
376 | if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) { |
377 | d->rirb_sts |= ICH6_RBSTS_IRQ; |
378 | intel_hda_update_irq(d); |
379 | } |
380 | } else if ((d->corb_rp & 0xff) == d->corb_wp) { |
381 | dprint(d, 2, "%s: corb ring empty (%d/%d)\n" , __func__, |
382 | d->rirb_count, d->rirb_cnt); |
383 | if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) { |
384 | d->rirb_sts |= ICH6_RBSTS_IRQ; |
385 | intel_hda_update_irq(d); |
386 | } |
387 | } |
388 | } |
389 | |
390 | static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, |
391 | uint8_t *buf, uint32_t len) |
392 | { |
393 | HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus); |
394 | IntelHDAState *d = container_of(bus, IntelHDAState, codecs); |
395 | hwaddr addr; |
396 | uint32_t s, copy, left; |
397 | IntelHDAStream *st; |
398 | bool irq = false; |
399 | |
400 | st = output ? d->st + 4 : d->st; |
401 | for (s = 0; s < 4; s++) { |
402 | if (stnr == ((st[s].ctl >> 20) & 0x0f)) { |
403 | st = st + s; |
404 | break; |
405 | } |
406 | } |
407 | if (s == 4) { |
408 | return false; |
409 | } |
410 | if (st->bpl == NULL) { |
411 | return false; |
412 | } |
413 | |
414 | left = len; |
415 | s = st->bentries; |
416 | while (left > 0 && s-- > 0) { |
417 | copy = left; |
418 | if (copy > st->bsize - st->lpib) |
419 | copy = st->bsize - st->lpib; |
420 | if (copy > st->bpl[st->be].len - st->bp) |
421 | copy = st->bpl[st->be].len - st->bp; |
422 | |
423 | dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n" , |
424 | st->be, st->bp, st->bpl[st->be].len, copy); |
425 | |
426 | pci_dma_rw(&d->pci, st->bpl[st->be].addr + st->bp, buf, copy, !output); |
427 | st->lpib += copy; |
428 | st->bp += copy; |
429 | buf += copy; |
430 | left -= copy; |
431 | |
432 | if (st->bpl[st->be].len == st->bp) { |
433 | /* bpl entry filled */ |
434 | if (st->bpl[st->be].flags & 0x01) { |
435 | irq = true; |
436 | } |
437 | st->bp = 0; |
438 | st->be++; |
439 | if (st->be == st->bentries) { |
440 | /* bpl wrap around */ |
441 | st->be = 0; |
442 | st->lpib = 0; |
443 | } |
444 | } |
445 | } |
446 | if (d->dp_lbase & 0x01) { |
447 | s = st - d->st; |
448 | addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase); |
449 | stl_le_pci_dma(&d->pci, addr + 8*s, st->lpib); |
450 | } |
451 | dprint(d, 3, "dma: --\n" ); |
452 | |
453 | if (irq) { |
454 | st->ctl |= (1 << 26); /* buffer completion interrupt */ |
455 | intel_hda_update_irq(d); |
456 | } |
457 | return true; |
458 | } |
459 | |
460 | static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st) |
461 | { |
462 | hwaddr addr; |
463 | uint8_t buf[16]; |
464 | uint32_t i; |
465 | |
466 | addr = intel_hda_addr(st->bdlp_lbase, st->bdlp_ubase); |
467 | st->bentries = st->lvi +1; |
468 | g_free(st->bpl); |
469 | st->bpl = g_malloc(sizeof(bpl) * st->bentries); |
470 | for (i = 0; i < st->bentries; i++, addr += 16) { |
471 | pci_dma_read(&d->pci, addr, buf, 16); |
472 | st->bpl[i].addr = le64_to_cpu(*(uint64_t *)buf); |
473 | st->bpl[i].len = le32_to_cpu(*(uint32_t *)(buf + 8)); |
474 | st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12)); |
475 | dprint(d, 1, "bdl/%d: 0x%" PRIx64 " +0x%x, 0x%x\n" , |
476 | i, st->bpl[i].addr, st->bpl[i].len, st->bpl[i].flags); |
477 | } |
478 | |
479 | st->bsize = st->cbl; |
480 | st->lpib = 0; |
481 | st->be = 0; |
482 | st->bp = 0; |
483 | } |
484 | |
485 | static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output) |
486 | { |
487 | BusChild *kid; |
488 | HDACodecDevice *cdev; |
489 | |
490 | QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) { |
491 | DeviceState *qdev = kid->child; |
492 | HDACodecDeviceClass *cdc; |
493 | |
494 | cdev = HDA_CODEC_DEVICE(qdev); |
495 | cdc = HDA_CODEC_DEVICE_GET_CLASS(cdev); |
496 | if (cdc->stream) { |
497 | cdc->stream(cdev, stream, running, output); |
498 | } |
499 | } |
500 | } |
501 | |
502 | /* --------------------------------------------------------------------- */ |
503 | |
504 | static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) |
505 | { |
506 | if ((d->g_ctl & ICH6_GCTL_RESET) == 0) { |
507 | intel_hda_reset(DEVICE(d)); |
508 | } |
509 | } |
510 | |
511 | static void intel_hda_set_wake_en(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) |
512 | { |
513 | intel_hda_update_irq(d); |
514 | } |
515 | |
516 | static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) |
517 | { |
518 | intel_hda_update_irq(d); |
519 | } |
520 | |
521 | static void intel_hda_set_int_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) |
522 | { |
523 | intel_hda_update_irq(d); |
524 | } |
525 | |
526 | static void intel_hda_get_wall_clk(IntelHDAState *d, const IntelHDAReg *reg) |
527 | { |
528 | int64_t ns; |
529 | |
530 | ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - d->wall_base_ns; |
531 | d->wall_clk = (uint32_t)(ns * 24 / 1000); /* 24 MHz */ |
532 | } |
533 | |
534 | static void intel_hda_set_corb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) |
535 | { |
536 | intel_hda_corb_run(d); |
537 | } |
538 | |
539 | static void intel_hda_set_corb_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) |
540 | { |
541 | intel_hda_corb_run(d); |
542 | } |
543 | |
544 | static void intel_hda_set_rirb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) |
545 | { |
546 | if (d->rirb_wp & ICH6_RIRBWP_RST) { |
547 | d->rirb_wp = 0; |
548 | } |
549 | } |
550 | |
551 | static void intel_hda_set_rirb_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) |
552 | { |
553 | intel_hda_update_irq(d); |
554 | |
555 | if ((old & ICH6_RBSTS_IRQ) && !(d->rirb_sts & ICH6_RBSTS_IRQ)) { |
556 | /* cleared ICH6_RBSTS_IRQ */ |
557 | d->rirb_count = 0; |
558 | intel_hda_corb_run(d); |
559 | } |
560 | } |
561 | |
562 | static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) |
563 | { |
564 | if (d->ics & ICH6_IRS_BUSY) { |
565 | intel_hda_corb_run(d); |
566 | } |
567 | } |
568 | |
569 | static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) |
570 | { |
571 | bool output = reg->stream >= 4; |
572 | IntelHDAStream *st = d->st + reg->stream; |
573 | |
574 | if (st->ctl & 0x01) { |
575 | /* reset */ |
576 | dprint(d, 1, "st #%d: reset\n" , reg->stream); |
577 | st->ctl = SD_STS_FIFO_READY << 24; |
578 | } |
579 | if ((st->ctl & 0x02) != (old & 0x02)) { |
580 | uint32_t stnr = (st->ctl >> 20) & 0x0f; |
581 | /* run bit flipped */ |
582 | if (st->ctl & 0x02) { |
583 | /* start */ |
584 | dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n" , |
585 | reg->stream, stnr, st->cbl); |
586 | intel_hda_parse_bdl(d, st); |
587 | intel_hda_notify_codecs(d, stnr, true, output); |
588 | } else { |
589 | /* stop */ |
590 | dprint(d, 1, "st #%d: stop %d\n" , reg->stream, stnr); |
591 | intel_hda_notify_codecs(d, stnr, false, output); |
592 | } |
593 | } |
594 | intel_hda_update_irq(d); |
595 | } |
596 | |
597 | /* --------------------------------------------------------------------- */ |
598 | |
599 | #define ST_REG(_n, _o) (0x80 + (_n) * 0x20 + (_o)) |
600 | |
601 | static const struct IntelHDAReg regtab[] = { |
602 | /* global */ |
603 | [ ICH6_REG_GCAP ] = { |
604 | .name = "GCAP" , |
605 | .size = 2, |
606 | .reset = 0x4401, |
607 | }, |
608 | [ ICH6_REG_VMIN ] = { |
609 | .name = "VMIN" , |
610 | .size = 1, |
611 | }, |
612 | [ ICH6_REG_VMAJ ] = { |
613 | .name = "VMAJ" , |
614 | .size = 1, |
615 | .reset = 1, |
616 | }, |
617 | [ ICH6_REG_OUTPAY ] = { |
618 | .name = "OUTPAY" , |
619 | .size = 2, |
620 | .reset = 0x3c, |
621 | }, |
622 | [ ICH6_REG_INPAY ] = { |
623 | .name = "INPAY" , |
624 | .size = 2, |
625 | .reset = 0x1d, |
626 | }, |
627 | [ ICH6_REG_GCTL ] = { |
628 | .name = "GCTL" , |
629 | .size = 4, |
630 | .wmask = 0x0103, |
631 | .offset = offsetof(IntelHDAState, g_ctl), |
632 | .whandler = intel_hda_set_g_ctl, |
633 | }, |
634 | [ ICH6_REG_WAKEEN ] = { |
635 | .name = "WAKEEN" , |
636 | .size = 2, |
637 | .wmask = 0x7fff, |
638 | .offset = offsetof(IntelHDAState, wake_en), |
639 | .whandler = intel_hda_set_wake_en, |
640 | }, |
641 | [ ICH6_REG_STATESTS ] = { |
642 | .name = "STATESTS" , |
643 | .size = 2, |
644 | .wmask = 0x7fff, |
645 | .wclear = 0x7fff, |
646 | .offset = offsetof(IntelHDAState, state_sts), |
647 | .whandler = intel_hda_set_state_sts, |
648 | }, |
649 | |
650 | /* interrupts */ |
651 | [ ICH6_REG_INTCTL ] = { |
652 | .name = "INTCTL" , |
653 | .size = 4, |
654 | .wmask = 0xc00000ff, |
655 | .offset = offsetof(IntelHDAState, int_ctl), |
656 | .whandler = intel_hda_set_int_ctl, |
657 | }, |
658 | [ ICH6_REG_INTSTS ] = { |
659 | .name = "INTSTS" , |
660 | .size = 4, |
661 | .wmask = 0xc00000ff, |
662 | .wclear = 0xc00000ff, |
663 | .offset = offsetof(IntelHDAState, int_sts), |
664 | }, |
665 | |
666 | /* misc */ |
667 | [ ICH6_REG_WALLCLK ] = { |
668 | .name = "WALLCLK" , |
669 | .size = 4, |
670 | .offset = offsetof(IntelHDAState, wall_clk), |
671 | .rhandler = intel_hda_get_wall_clk, |
672 | }, |
673 | [ ICH6_REG_WALLCLK + 0x2000 ] = { |
674 | .name = "WALLCLK(alias)" , |
675 | .size = 4, |
676 | .offset = offsetof(IntelHDAState, wall_clk), |
677 | .rhandler = intel_hda_get_wall_clk, |
678 | }, |
679 | |
680 | /* dma engine */ |
681 | [ ICH6_REG_CORBLBASE ] = { |
682 | .name = "CORBLBASE" , |
683 | .size = 4, |
684 | .wmask = 0xffffff80, |
685 | .offset = offsetof(IntelHDAState, corb_lbase), |
686 | }, |
687 | [ ICH6_REG_CORBUBASE ] = { |
688 | .name = "CORBUBASE" , |
689 | .size = 4, |
690 | .wmask = 0xffffffff, |
691 | .offset = offsetof(IntelHDAState, corb_ubase), |
692 | }, |
693 | [ ICH6_REG_CORBWP ] = { |
694 | .name = "CORBWP" , |
695 | .size = 2, |
696 | .wmask = 0xff, |
697 | .offset = offsetof(IntelHDAState, corb_wp), |
698 | .whandler = intel_hda_set_corb_wp, |
699 | }, |
700 | [ ICH6_REG_CORBRP ] = { |
701 | .name = "CORBRP" , |
702 | .size = 2, |
703 | .wmask = 0x80ff, |
704 | .offset = offsetof(IntelHDAState, corb_rp), |
705 | }, |
706 | [ ICH6_REG_CORBCTL ] = { |
707 | .name = "CORBCTL" , |
708 | .size = 1, |
709 | .wmask = 0x03, |
710 | .offset = offsetof(IntelHDAState, corb_ctl), |
711 | .whandler = intel_hda_set_corb_ctl, |
712 | }, |
713 | [ ICH6_REG_CORBSTS ] = { |
714 | .name = "CORBSTS" , |
715 | .size = 1, |
716 | .wmask = 0x01, |
717 | .wclear = 0x01, |
718 | .offset = offsetof(IntelHDAState, corb_sts), |
719 | }, |
720 | [ ICH6_REG_CORBSIZE ] = { |
721 | .name = "CORBSIZE" , |
722 | .size = 1, |
723 | .reset = 0x42, |
724 | .offset = offsetof(IntelHDAState, corb_size), |
725 | }, |
726 | [ ICH6_REG_RIRBLBASE ] = { |
727 | .name = "RIRBLBASE" , |
728 | .size = 4, |
729 | .wmask = 0xffffff80, |
730 | .offset = offsetof(IntelHDAState, rirb_lbase), |
731 | }, |
732 | [ ICH6_REG_RIRBUBASE ] = { |
733 | .name = "RIRBUBASE" , |
734 | .size = 4, |
735 | .wmask = 0xffffffff, |
736 | .offset = offsetof(IntelHDAState, rirb_ubase), |
737 | }, |
738 | [ ICH6_REG_RIRBWP ] = { |
739 | .name = "RIRBWP" , |
740 | .size = 2, |
741 | .wmask = 0x8000, |
742 | .offset = offsetof(IntelHDAState, rirb_wp), |
743 | .whandler = intel_hda_set_rirb_wp, |
744 | }, |
745 | [ ICH6_REG_RINTCNT ] = { |
746 | .name = "RINTCNT" , |
747 | .size = 2, |
748 | .wmask = 0xff, |
749 | .offset = offsetof(IntelHDAState, rirb_cnt), |
750 | }, |
751 | [ ICH6_REG_RIRBCTL ] = { |
752 | .name = "RIRBCTL" , |
753 | .size = 1, |
754 | .wmask = 0x07, |
755 | .offset = offsetof(IntelHDAState, rirb_ctl), |
756 | }, |
757 | [ ICH6_REG_RIRBSTS ] = { |
758 | .name = "RIRBSTS" , |
759 | .size = 1, |
760 | .wmask = 0x05, |
761 | .wclear = 0x05, |
762 | .offset = offsetof(IntelHDAState, rirb_sts), |
763 | .whandler = intel_hda_set_rirb_sts, |
764 | }, |
765 | [ ICH6_REG_RIRBSIZE ] = { |
766 | .name = "RIRBSIZE" , |
767 | .size = 1, |
768 | .reset = 0x42, |
769 | .offset = offsetof(IntelHDAState, rirb_size), |
770 | }, |
771 | |
772 | [ ICH6_REG_DPLBASE ] = { |
773 | .name = "DPLBASE" , |
774 | .size = 4, |
775 | .wmask = 0xffffff81, |
776 | .offset = offsetof(IntelHDAState, dp_lbase), |
777 | }, |
778 | [ ICH6_REG_DPUBASE ] = { |
779 | .name = "DPUBASE" , |
780 | .size = 4, |
781 | .wmask = 0xffffffff, |
782 | .offset = offsetof(IntelHDAState, dp_ubase), |
783 | }, |
784 | |
785 | [ ICH6_REG_IC ] = { |
786 | .name = "ICW" , |
787 | .size = 4, |
788 | .wmask = 0xffffffff, |
789 | .offset = offsetof(IntelHDAState, icw), |
790 | }, |
791 | [ ICH6_REG_IR ] = { |
792 | .name = "IRR" , |
793 | .size = 4, |
794 | .offset = offsetof(IntelHDAState, irr), |
795 | }, |
796 | [ ICH6_REG_IRS ] = { |
797 | .name = "ICS" , |
798 | .size = 2, |
799 | .wmask = 0x0003, |
800 | .wclear = 0x0002, |
801 | .offset = offsetof(IntelHDAState, ics), |
802 | .whandler = intel_hda_set_ics, |
803 | }, |
804 | |
805 | #define HDA_STREAM(_t, _i) \ |
806 | [ ST_REG(_i, ICH6_REG_SD_CTL) ] = { \ |
807 | .stream = _i, \ |
808 | .name = _t stringify(_i) " CTL", \ |
809 | .size = 4, \ |
810 | .wmask = 0x1cff001f, \ |
811 | .offset = offsetof(IntelHDAState, st[_i].ctl), \ |
812 | .whandler = intel_hda_set_st_ctl, \ |
813 | }, \ |
814 | [ ST_REG(_i, ICH6_REG_SD_CTL) + 2] = { \ |
815 | .stream = _i, \ |
816 | .name = _t stringify(_i) " CTL(stnr)", \ |
817 | .size = 1, \ |
818 | .shift = 16, \ |
819 | .wmask = 0x00ff0000, \ |
820 | .offset = offsetof(IntelHDAState, st[_i].ctl), \ |
821 | .whandler = intel_hda_set_st_ctl, \ |
822 | }, \ |
823 | [ ST_REG(_i, ICH6_REG_SD_STS)] = { \ |
824 | .stream = _i, \ |
825 | .name = _t stringify(_i) " CTL(sts)", \ |
826 | .size = 1, \ |
827 | .shift = 24, \ |
828 | .wmask = 0x1c000000, \ |
829 | .wclear = 0x1c000000, \ |
830 | .offset = offsetof(IntelHDAState, st[_i].ctl), \ |
831 | .whandler = intel_hda_set_st_ctl, \ |
832 | .reset = SD_STS_FIFO_READY << 24 \ |
833 | }, \ |
834 | [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \ |
835 | .stream = _i, \ |
836 | .name = _t stringify(_i) " LPIB", \ |
837 | .size = 4, \ |
838 | .offset = offsetof(IntelHDAState, st[_i].lpib), \ |
839 | }, \ |
840 | [ ST_REG(_i, ICH6_REG_SD_LPIB) + 0x2000 ] = { \ |
841 | .stream = _i, \ |
842 | .name = _t stringify(_i) " LPIB(alias)", \ |
843 | .size = 4, \ |
844 | .offset = offsetof(IntelHDAState, st[_i].lpib), \ |
845 | }, \ |
846 | [ ST_REG(_i, ICH6_REG_SD_CBL) ] = { \ |
847 | .stream = _i, \ |
848 | .name = _t stringify(_i) " CBL", \ |
849 | .size = 4, \ |
850 | .wmask = 0xffffffff, \ |
851 | .offset = offsetof(IntelHDAState, st[_i].cbl), \ |
852 | }, \ |
853 | [ ST_REG(_i, ICH6_REG_SD_LVI) ] = { \ |
854 | .stream = _i, \ |
855 | .name = _t stringify(_i) " LVI", \ |
856 | .size = 2, \ |
857 | .wmask = 0x00ff, \ |
858 | .offset = offsetof(IntelHDAState, st[_i].lvi), \ |
859 | }, \ |
860 | [ ST_REG(_i, ICH6_REG_SD_FIFOSIZE) ] = { \ |
861 | .stream = _i, \ |
862 | .name = _t stringify(_i) " FIFOS", \ |
863 | .size = 2, \ |
864 | .reset = HDA_BUFFER_SIZE, \ |
865 | }, \ |
866 | [ ST_REG(_i, ICH6_REG_SD_FORMAT) ] = { \ |
867 | .stream = _i, \ |
868 | .name = _t stringify(_i) " FMT", \ |
869 | .size = 2, \ |
870 | .wmask = 0x7f7f, \ |
871 | .offset = offsetof(IntelHDAState, st[_i].fmt), \ |
872 | }, \ |
873 | [ ST_REG(_i, ICH6_REG_SD_BDLPL) ] = { \ |
874 | .stream = _i, \ |
875 | .name = _t stringify(_i) " BDLPL", \ |
876 | .size = 4, \ |
877 | .wmask = 0xffffff80, \ |
878 | .offset = offsetof(IntelHDAState, st[_i].bdlp_lbase), \ |
879 | }, \ |
880 | [ ST_REG(_i, ICH6_REG_SD_BDLPU) ] = { \ |
881 | .stream = _i, \ |
882 | .name = _t stringify(_i) " BDLPU", \ |
883 | .size = 4, \ |
884 | .wmask = 0xffffffff, \ |
885 | .offset = offsetof(IntelHDAState, st[_i].bdlp_ubase), \ |
886 | }, \ |
887 | |
888 | HDA_STREAM("IN" , 0) |
889 | HDA_STREAM("IN" , 1) |
890 | HDA_STREAM("IN" , 2) |
891 | HDA_STREAM("IN" , 3) |
892 | |
893 | HDA_STREAM("OUT" , 4) |
894 | HDA_STREAM("OUT" , 5) |
895 | HDA_STREAM("OUT" , 6) |
896 | HDA_STREAM("OUT" , 7) |
897 | |
898 | }; |
899 | |
900 | static const IntelHDAReg *intel_hda_reg_find(IntelHDAState *d, hwaddr addr) |
901 | { |
902 | const IntelHDAReg *reg; |
903 | |
904 | if (addr >= ARRAY_SIZE(regtab)) { |
905 | goto noreg; |
906 | } |
907 | reg = regtab+addr; |
908 | if (reg->name == NULL) { |
909 | goto noreg; |
910 | } |
911 | return reg; |
912 | |
913 | noreg: |
914 | dprint(d, 1, "unknown register, addr 0x%x\n" , (int) addr); |
915 | return NULL; |
916 | } |
917 | |
918 | static uint32_t *intel_hda_reg_addr(IntelHDAState *d, const IntelHDAReg *reg) |
919 | { |
920 | uint8_t *addr = (void*)d; |
921 | |
922 | addr += reg->offset; |
923 | return (uint32_t*)addr; |
924 | } |
925 | |
926 | static void intel_hda_reg_write(IntelHDAState *d, const IntelHDAReg *reg, uint32_t val, |
927 | uint32_t wmask) |
928 | { |
929 | uint32_t *addr; |
930 | uint32_t old; |
931 | |
932 | if (!reg) { |
933 | return; |
934 | } |
935 | if (!reg->wmask) { |
936 | qemu_log_mask(LOG_GUEST_ERROR, "intel-hda: write to r/o reg %s\n" , |
937 | reg->name); |
938 | return; |
939 | } |
940 | |
941 | if (d->debug) { |
942 | time_t now = time(NULL); |
943 | if (d->last_write && d->last_reg == reg && d->last_val == val) { |
944 | d->repeat_count++; |
945 | if (d->last_sec != now) { |
946 | dprint(d, 2, "previous register op repeated %d times\n" , d->repeat_count); |
947 | d->last_sec = now; |
948 | d->repeat_count = 0; |
949 | } |
950 | } else { |
951 | if (d->repeat_count) { |
952 | dprint(d, 2, "previous register op repeated %d times\n" , d->repeat_count); |
953 | } |
954 | dprint(d, 2, "write %-16s: 0x%x (%x)\n" , reg->name, val, wmask); |
955 | d->last_write = 1; |
956 | d->last_reg = reg; |
957 | d->last_val = val; |
958 | d->last_sec = now; |
959 | d->repeat_count = 0; |
960 | } |
961 | } |
962 | assert(reg->offset != 0); |
963 | |
964 | addr = intel_hda_reg_addr(d, reg); |
965 | old = *addr; |
966 | |
967 | if (reg->shift) { |
968 | val <<= reg->shift; |
969 | wmask <<= reg->shift; |
970 | } |
971 | wmask &= reg->wmask; |
972 | *addr &= ~wmask; |
973 | *addr |= wmask & val; |
974 | *addr &= ~(val & reg->wclear); |
975 | |
976 | if (reg->whandler) { |
977 | reg->whandler(d, reg, old); |
978 | } |
979 | } |
980 | |
981 | static uint32_t intel_hda_reg_read(IntelHDAState *d, const IntelHDAReg *reg, |
982 | uint32_t rmask) |
983 | { |
984 | uint32_t *addr, ret; |
985 | |
986 | if (!reg) { |
987 | return 0; |
988 | } |
989 | |
990 | if (reg->rhandler) { |
991 | reg->rhandler(d, reg); |
992 | } |
993 | |
994 | if (reg->offset == 0) { |
995 | /* constant read-only register */ |
996 | ret = reg->reset; |
997 | } else { |
998 | addr = intel_hda_reg_addr(d, reg); |
999 | ret = *addr; |
1000 | if (reg->shift) { |
1001 | ret >>= reg->shift; |
1002 | } |
1003 | ret &= rmask; |
1004 | } |
1005 | if (d->debug) { |
1006 | time_t now = time(NULL); |
1007 | if (!d->last_write && d->last_reg == reg && d->last_val == ret) { |
1008 | d->repeat_count++; |
1009 | if (d->last_sec != now) { |
1010 | dprint(d, 2, "previous register op repeated %d times\n" , d->repeat_count); |
1011 | d->last_sec = now; |
1012 | d->repeat_count = 0; |
1013 | } |
1014 | } else { |
1015 | if (d->repeat_count) { |
1016 | dprint(d, 2, "previous register op repeated %d times\n" , d->repeat_count); |
1017 | } |
1018 | dprint(d, 2, "read %-16s: 0x%x (%x)\n" , reg->name, ret, rmask); |
1019 | d->last_write = 0; |
1020 | d->last_reg = reg; |
1021 | d->last_val = ret; |
1022 | d->last_sec = now; |
1023 | d->repeat_count = 0; |
1024 | } |
1025 | } |
1026 | return ret; |
1027 | } |
1028 | |
1029 | static void intel_hda_regs_reset(IntelHDAState *d) |
1030 | { |
1031 | uint32_t *addr; |
1032 | int i; |
1033 | |
1034 | for (i = 0; i < ARRAY_SIZE(regtab); i++) { |
1035 | if (regtab[i].name == NULL) { |
1036 | continue; |
1037 | } |
1038 | if (regtab[i].offset == 0) { |
1039 | continue; |
1040 | } |
1041 | addr = intel_hda_reg_addr(d, regtab + i); |
1042 | *addr = regtab[i].reset; |
1043 | } |
1044 | } |
1045 | |
1046 | /* --------------------------------------------------------------------- */ |
1047 | |
1048 | static void intel_hda_mmio_write(void *opaque, hwaddr addr, uint64_t val, |
1049 | unsigned size) |
1050 | { |
1051 | IntelHDAState *d = opaque; |
1052 | const IntelHDAReg *reg = intel_hda_reg_find(d, addr); |
1053 | |
1054 | intel_hda_reg_write(d, reg, val, MAKE_64BIT_MASK(0, size * 8)); |
1055 | } |
1056 | |
1057 | static uint64_t intel_hda_mmio_read(void *opaque, hwaddr addr, unsigned size) |
1058 | { |
1059 | IntelHDAState *d = opaque; |
1060 | const IntelHDAReg *reg = intel_hda_reg_find(d, addr); |
1061 | |
1062 | return intel_hda_reg_read(d, reg, MAKE_64BIT_MASK(0, size * 8)); |
1063 | } |
1064 | |
1065 | static const MemoryRegionOps intel_hda_mmio_ops = { |
1066 | .read = intel_hda_mmio_read, |
1067 | .write = intel_hda_mmio_write, |
1068 | .impl = { |
1069 | .min_access_size = 1, |
1070 | .max_access_size = 4, |
1071 | }, |
1072 | .endianness = DEVICE_NATIVE_ENDIAN, |
1073 | }; |
1074 | |
1075 | /* --------------------------------------------------------------------- */ |
1076 | |
1077 | static void intel_hda_reset(DeviceState *dev) |
1078 | { |
1079 | BusChild *kid; |
1080 | IntelHDAState *d = INTEL_HDA(dev); |
1081 | HDACodecDevice *cdev; |
1082 | |
1083 | intel_hda_regs_reset(d); |
1084 | d->wall_base_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); |
1085 | |
1086 | /* reset codecs */ |
1087 | QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) { |
1088 | DeviceState *qdev = kid->child; |
1089 | cdev = HDA_CODEC_DEVICE(qdev); |
1090 | device_reset(DEVICE(cdev)); |
1091 | d->state_sts |= (1 << cdev->cad); |
1092 | } |
1093 | intel_hda_update_irq(d); |
1094 | } |
1095 | |
1096 | static void intel_hda_realize(PCIDevice *pci, Error **errp) |
1097 | { |
1098 | IntelHDAState *d = INTEL_HDA(pci); |
1099 | uint8_t *conf = d->pci.config; |
1100 | Error *err = NULL; |
1101 | int ret; |
1102 | |
1103 | d->name = object_get_typename(OBJECT(d)); |
1104 | |
1105 | pci_config_set_interrupt_pin(conf, 1); |
1106 | |
1107 | /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */ |
1108 | conf[0x40] = 0x01; |
1109 | |
1110 | if (d->msi != ON_OFF_AUTO_OFF) { |
1111 | ret = msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60, |
1112 | 1, true, false, &err); |
1113 | /* Any error other than -ENOTSUP(board's MSI support is broken) |
1114 | * is a programming error */ |
1115 | assert(!ret || ret == -ENOTSUP); |
1116 | if (ret && d->msi == ON_OFF_AUTO_ON) { |
1117 | /* Can't satisfy user's explicit msi=on request, fail */ |
1118 | error_append_hint(&err, "You have to use msi=auto (default) or " |
1119 | "msi=off with this machine type.\n" ); |
1120 | error_propagate(errp, err); |
1121 | return; |
1122 | } |
1123 | assert(!err || d->msi == ON_OFF_AUTO_AUTO); |
1124 | /* With msi=auto, we fall back to MSI off silently */ |
1125 | error_free(err); |
1126 | } |
1127 | |
1128 | memory_region_init_io(&d->mmio, OBJECT(d), &intel_hda_mmio_ops, d, |
1129 | "intel-hda" , 0x4000); |
1130 | pci_register_bar(&d->pci, 0, 0, &d->mmio); |
1131 | |
1132 | hda_codec_bus_init(DEVICE(pci), &d->codecs, sizeof(d->codecs), |
1133 | intel_hda_response, intel_hda_xfer); |
1134 | } |
1135 | |
1136 | static void intel_hda_exit(PCIDevice *pci) |
1137 | { |
1138 | IntelHDAState *d = INTEL_HDA(pci); |
1139 | |
1140 | msi_uninit(&d->pci); |
1141 | } |
1142 | |
1143 | static int intel_hda_post_load(void *opaque, int version) |
1144 | { |
1145 | IntelHDAState* d = opaque; |
1146 | int i; |
1147 | |
1148 | dprint(d, 1, "%s\n" , __func__); |
1149 | for (i = 0; i < ARRAY_SIZE(d->st); i++) { |
1150 | if (d->st[i].ctl & 0x02) { |
1151 | intel_hda_parse_bdl(d, &d->st[i]); |
1152 | } |
1153 | } |
1154 | intel_hda_update_irq(d); |
1155 | return 0; |
1156 | } |
1157 | |
1158 | static const VMStateDescription vmstate_intel_hda_stream = { |
1159 | .name = "intel-hda-stream" , |
1160 | .version_id = 1, |
1161 | .fields = (VMStateField[]) { |
1162 | VMSTATE_UINT32(ctl, IntelHDAStream), |
1163 | VMSTATE_UINT32(lpib, IntelHDAStream), |
1164 | VMSTATE_UINT32(cbl, IntelHDAStream), |
1165 | VMSTATE_UINT32(lvi, IntelHDAStream), |
1166 | VMSTATE_UINT32(fmt, IntelHDAStream), |
1167 | VMSTATE_UINT32(bdlp_lbase, IntelHDAStream), |
1168 | VMSTATE_UINT32(bdlp_ubase, IntelHDAStream), |
1169 | VMSTATE_END_OF_LIST() |
1170 | } |
1171 | }; |
1172 | |
1173 | static const VMStateDescription vmstate_intel_hda = { |
1174 | .name = "intel-hda" , |
1175 | .version_id = 1, |
1176 | .post_load = intel_hda_post_load, |
1177 | .fields = (VMStateField[]) { |
1178 | VMSTATE_PCI_DEVICE(pci, IntelHDAState), |
1179 | |
1180 | /* registers */ |
1181 | VMSTATE_UINT32(g_ctl, IntelHDAState), |
1182 | VMSTATE_UINT32(wake_en, IntelHDAState), |
1183 | VMSTATE_UINT32(state_sts, IntelHDAState), |
1184 | VMSTATE_UINT32(int_ctl, IntelHDAState), |
1185 | VMSTATE_UINT32(int_sts, IntelHDAState), |
1186 | VMSTATE_UINT32(wall_clk, IntelHDAState), |
1187 | VMSTATE_UINT32(corb_lbase, IntelHDAState), |
1188 | VMSTATE_UINT32(corb_ubase, IntelHDAState), |
1189 | VMSTATE_UINT32(corb_rp, IntelHDAState), |
1190 | VMSTATE_UINT32(corb_wp, IntelHDAState), |
1191 | VMSTATE_UINT32(corb_ctl, IntelHDAState), |
1192 | VMSTATE_UINT32(corb_sts, IntelHDAState), |
1193 | VMSTATE_UINT32(corb_size, IntelHDAState), |
1194 | VMSTATE_UINT32(rirb_lbase, IntelHDAState), |
1195 | VMSTATE_UINT32(rirb_ubase, IntelHDAState), |
1196 | VMSTATE_UINT32(rirb_wp, IntelHDAState), |
1197 | VMSTATE_UINT32(rirb_cnt, IntelHDAState), |
1198 | VMSTATE_UINT32(rirb_ctl, IntelHDAState), |
1199 | VMSTATE_UINT32(rirb_sts, IntelHDAState), |
1200 | VMSTATE_UINT32(rirb_size, IntelHDAState), |
1201 | VMSTATE_UINT32(dp_lbase, IntelHDAState), |
1202 | VMSTATE_UINT32(dp_ubase, IntelHDAState), |
1203 | VMSTATE_UINT32(icw, IntelHDAState), |
1204 | VMSTATE_UINT32(irr, IntelHDAState), |
1205 | VMSTATE_UINT32(ics, IntelHDAState), |
1206 | VMSTATE_STRUCT_ARRAY(st, IntelHDAState, 8, 0, |
1207 | vmstate_intel_hda_stream, |
1208 | IntelHDAStream), |
1209 | |
1210 | /* additional state info */ |
1211 | VMSTATE_UINT32(rirb_count, IntelHDAState), |
1212 | VMSTATE_INT64(wall_base_ns, IntelHDAState), |
1213 | |
1214 | VMSTATE_END_OF_LIST() |
1215 | } |
1216 | }; |
1217 | |
1218 | static Property intel_hda_properties[] = { |
1219 | DEFINE_PROP_UINT32("debug" , IntelHDAState, debug, 0), |
1220 | DEFINE_PROP_ON_OFF_AUTO("msi" , IntelHDAState, msi, ON_OFF_AUTO_AUTO), |
1221 | DEFINE_PROP_BOOL("old_msi_addr" , IntelHDAState, old_msi_addr, false), |
1222 | DEFINE_PROP_END_OF_LIST(), |
1223 | }; |
1224 | |
1225 | static void intel_hda_class_init(ObjectClass *klass, void *data) |
1226 | { |
1227 | DeviceClass *dc = DEVICE_CLASS(klass); |
1228 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
1229 | |
1230 | k->realize = intel_hda_realize; |
1231 | k->exit = intel_hda_exit; |
1232 | k->vendor_id = PCI_VENDOR_ID_INTEL; |
1233 | k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO; |
1234 | dc->reset = intel_hda_reset; |
1235 | dc->vmsd = &vmstate_intel_hda; |
1236 | dc->props = intel_hda_properties; |
1237 | } |
1238 | |
1239 | static void intel_hda_class_init_ich6(ObjectClass *klass, void *data) |
1240 | { |
1241 | DeviceClass *dc = DEVICE_CLASS(klass); |
1242 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
1243 | |
1244 | k->device_id = 0x2668; |
1245 | k->revision = 1; |
1246 | set_bit(DEVICE_CATEGORY_SOUND, dc->categories); |
1247 | dc->desc = "Intel HD Audio Controller (ich6)" ; |
1248 | } |
1249 | |
1250 | static void intel_hda_class_init_ich9(ObjectClass *klass, void *data) |
1251 | { |
1252 | DeviceClass *dc = DEVICE_CLASS(klass); |
1253 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
1254 | |
1255 | k->device_id = 0x293e; |
1256 | k->revision = 3; |
1257 | set_bit(DEVICE_CATEGORY_SOUND, dc->categories); |
1258 | dc->desc = "Intel HD Audio Controller (ich9)" ; |
1259 | } |
1260 | |
1261 | static const TypeInfo intel_hda_info = { |
1262 | .name = TYPE_INTEL_HDA_GENERIC, |
1263 | .parent = TYPE_PCI_DEVICE, |
1264 | .instance_size = sizeof(IntelHDAState), |
1265 | .class_init = intel_hda_class_init, |
1266 | .abstract = true, |
1267 | .interfaces = (InterfaceInfo[]) { |
1268 | { INTERFACE_CONVENTIONAL_PCI_DEVICE }, |
1269 | { }, |
1270 | }, |
1271 | }; |
1272 | |
1273 | static const TypeInfo intel_hda_info_ich6 = { |
1274 | .name = "intel-hda" , |
1275 | .parent = TYPE_INTEL_HDA_GENERIC, |
1276 | .class_init = intel_hda_class_init_ich6, |
1277 | }; |
1278 | |
1279 | static const TypeInfo intel_hda_info_ich9 = { |
1280 | .name = "ich9-intel-hda" , |
1281 | .parent = TYPE_INTEL_HDA_GENERIC, |
1282 | .class_init = intel_hda_class_init_ich9, |
1283 | }; |
1284 | |
1285 | static void hda_codec_device_class_init(ObjectClass *klass, void *data) |
1286 | { |
1287 | DeviceClass *k = DEVICE_CLASS(klass); |
1288 | k->realize = hda_codec_dev_realize; |
1289 | k->unrealize = hda_codec_dev_unrealize; |
1290 | set_bit(DEVICE_CATEGORY_SOUND, k->categories); |
1291 | k->bus_type = TYPE_HDA_BUS; |
1292 | k->props = hda_props; |
1293 | } |
1294 | |
1295 | static const TypeInfo hda_codec_device_type_info = { |
1296 | .name = TYPE_HDA_CODEC_DEVICE, |
1297 | .parent = TYPE_DEVICE, |
1298 | .instance_size = sizeof(HDACodecDevice), |
1299 | .abstract = true, |
1300 | .class_size = sizeof(HDACodecDeviceClass), |
1301 | .class_init = hda_codec_device_class_init, |
1302 | }; |
1303 | |
1304 | /* |
1305 | * create intel hda controller with codec attached to it, |
1306 | * so '-soundhw hda' works. |
1307 | */ |
1308 | static int intel_hda_and_codec_init(PCIBus *bus) |
1309 | { |
1310 | DeviceState *controller; |
1311 | BusState *hdabus; |
1312 | DeviceState *codec; |
1313 | |
1314 | controller = DEVICE(pci_create_simple(bus, -1, "intel-hda" )); |
1315 | hdabus = QLIST_FIRST(&controller->child_bus); |
1316 | codec = qdev_create(hdabus, "hda-duplex" ); |
1317 | qdev_init_nofail(codec); |
1318 | return 0; |
1319 | } |
1320 | |
1321 | static void intel_hda_register_types(void) |
1322 | { |
1323 | type_register_static(&hda_codec_bus_info); |
1324 | type_register_static(&intel_hda_info); |
1325 | type_register_static(&intel_hda_info_ich6); |
1326 | type_register_static(&intel_hda_info_ich9); |
1327 | type_register_static(&hda_codec_device_type_info); |
1328 | pci_register_soundhw("hda" , "Intel HD Audio" , intel_hda_and_codec_init); |
1329 | } |
1330 | |
1331 | type_init(intel_hda_register_types) |
1332 | |