149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini * Copyright (C) 2010 Red Hat, Inc.
349ab747fSPaolo Bonzini *
449ab747fSPaolo Bonzini * written by Gerd Hoffmann <kraxel@redhat.com>
549ab747fSPaolo Bonzini *
649ab747fSPaolo Bonzini * This program is free software; you can redistribute it and/or
749ab747fSPaolo Bonzini * modify it under the terms of the GNU General Public License as
849ab747fSPaolo Bonzini * published by the Free Software Foundation; either version 2 or
949ab747fSPaolo Bonzini * (at your option) version 3 of the License.
1049ab747fSPaolo Bonzini *
1149ab747fSPaolo Bonzini * This program is distributed in the hope that it will be useful,
1249ab747fSPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of
1349ab747fSPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1449ab747fSPaolo Bonzini * GNU General Public License for more details.
1549ab747fSPaolo Bonzini *
1649ab747fSPaolo Bonzini * You should have received a copy of the GNU General Public License
1749ab747fSPaolo Bonzini * along with this program; if not, see <http://www.gnu.org/licenses/>.
1849ab747fSPaolo Bonzini */
1949ab747fSPaolo Bonzini
206086a565SPeter Maydell #include "qemu/osdep.h"
2149ab747fSPaolo Bonzini #include "hw/pci/pci.h"
22a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
2349ab747fSPaolo Bonzini #include "hw/pci/msi.h"
2449ab747fSPaolo Bonzini #include "qemu/timer.h"
25a6b0bdc8SMatt Parker #include "qemu/bitops.h"
267ec91067SGerd Hoffmann #include "qemu/log.h"
270b8fa32fSMarkus Armbruster #include "qemu/module.h"
28fcb541c1SGerd Hoffmann #include "qemu/error-report.h"
298a824e4dSEduardo Habkost #include "hw/audio/soundhw.h"
3047b43a1fSPaolo Bonzini #include "intel-hda.h"
31d6454270SMarkus Armbruster #include "migration/vmstate.h"
3247b43a1fSPaolo Bonzini #include "intel-hda-defs.h"
3349ab747fSPaolo Bonzini #include "sysemu/dma.h"
34bda8d9b8Sxiaoqiang zhao #include "qapi/error.h"
35db1015e9SEduardo Habkost #include "qom/object.h"
3649ab747fSPaolo Bonzini
3749ab747fSPaolo Bonzini /* --------------------------------------------------------------------- */
3849ab747fSPaolo Bonzini /* hda bus */
3949ab747fSPaolo Bonzini
4049ab747fSPaolo Bonzini static Property hda_props[] = {
4149ab747fSPaolo Bonzini DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
4249ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST()
4349ab747fSPaolo Bonzini };
4449ab747fSPaolo Bonzini
4549ab747fSPaolo Bonzini static const TypeInfo hda_codec_bus_info = {
4649ab747fSPaolo Bonzini .name = TYPE_HDA_BUS,
4749ab747fSPaolo Bonzini .parent = TYPE_BUS,
4849ab747fSPaolo Bonzini .instance_size = sizeof(HDACodecBus),
4949ab747fSPaolo Bonzini };
5049ab747fSPaolo Bonzini
hda_codec_bus_init(DeviceState * dev,HDACodecBus * bus,size_t bus_size,hda_codec_response_func response,hda_codec_xfer_func xfer)51ab809e84SAndreas Färber void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, size_t bus_size,
5249ab747fSPaolo Bonzini hda_codec_response_func response,
5349ab747fSPaolo Bonzini hda_codec_xfer_func xfer)
5449ab747fSPaolo Bonzini {
55d637e1dcSPeter Maydell qbus_init(bus, bus_size, TYPE_HDA_BUS, dev, NULL);
5649ab747fSPaolo Bonzini bus->response = response;
5749ab747fSPaolo Bonzini bus->xfer = xfer;
5849ab747fSPaolo Bonzini }
5949ab747fSPaolo Bonzini
hda_codec_dev_realize(DeviceState * qdev,Error ** errp)60bda8d9b8Sxiaoqiang zhao static void hda_codec_dev_realize(DeviceState *qdev, Error **errp)
6149ab747fSPaolo Bonzini {
62e19202afSxiaoqiang zhao HDACodecBus *bus = HDA_BUS(qdev->parent_bus);
63e19202afSxiaoqiang zhao HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev);
6449ab747fSPaolo Bonzini HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
6549ab747fSPaolo Bonzini
6649ab747fSPaolo Bonzini if (dev->cad == -1) {
6749ab747fSPaolo Bonzini dev->cad = bus->next_cad;
6849ab747fSPaolo Bonzini }
6949ab747fSPaolo Bonzini if (dev->cad >= 15) {
70bda8d9b8Sxiaoqiang zhao error_setg(errp, "HDA audio codec address is full");
71bda8d9b8Sxiaoqiang zhao return;
7249ab747fSPaolo Bonzini }
7349ab747fSPaolo Bonzini bus->next_cad = dev->cad + 1;
74b7639b7dSMartin Kletzander cdc->init(dev, errp);
7549ab747fSPaolo Bonzini }
7649ab747fSPaolo Bonzini
hda_codec_dev_unrealize(DeviceState * qdev)77b69c3c21SMarkus Armbruster static void hda_codec_dev_unrealize(DeviceState *qdev)
7849ab747fSPaolo Bonzini {
79e19202afSxiaoqiang zhao HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev);
8049ab747fSPaolo Bonzini HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
8149ab747fSPaolo Bonzini
8249ab747fSPaolo Bonzini if (cdc->exit) {
8349ab747fSPaolo Bonzini cdc->exit(dev);
8449ab747fSPaolo Bonzini }
8549ab747fSPaolo Bonzini }
8649ab747fSPaolo Bonzini
hda_codec_find(HDACodecBus * bus,uint32_t cad)8749ab747fSPaolo Bonzini HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
8849ab747fSPaolo Bonzini {
8949ab747fSPaolo Bonzini BusChild *kid;
9049ab747fSPaolo Bonzini HDACodecDevice *cdev;
9149ab747fSPaolo Bonzini
9249ab747fSPaolo Bonzini QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
9349ab747fSPaolo Bonzini DeviceState *qdev = kid->child;
94e19202afSxiaoqiang zhao cdev = HDA_CODEC_DEVICE(qdev);
9549ab747fSPaolo Bonzini if (cdev->cad == cad) {
9649ab747fSPaolo Bonzini return cdev;
9749ab747fSPaolo Bonzini }
9849ab747fSPaolo Bonzini }
9949ab747fSPaolo Bonzini return NULL;
10049ab747fSPaolo Bonzini }
10149ab747fSPaolo Bonzini
hda_codec_response(HDACodecDevice * dev,bool solicited,uint32_t response)10249ab747fSPaolo Bonzini void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response)
10349ab747fSPaolo Bonzini {
104e19202afSxiaoqiang zhao HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus);
10549ab747fSPaolo Bonzini bus->response(dev, solicited, response);
10649ab747fSPaolo Bonzini }
10749ab747fSPaolo Bonzini
hda_codec_xfer(HDACodecDevice * dev,uint32_t stnr,bool output,uint8_t * buf,uint32_t len)10849ab747fSPaolo Bonzini bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
10949ab747fSPaolo Bonzini uint8_t *buf, uint32_t len)
11049ab747fSPaolo Bonzini {
111e19202afSxiaoqiang zhao HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus);
11249ab747fSPaolo Bonzini return bus->xfer(dev, stnr, output, buf, len);
11349ab747fSPaolo Bonzini }
11449ab747fSPaolo Bonzini
11549ab747fSPaolo Bonzini /* --------------------------------------------------------------------- */
11649ab747fSPaolo Bonzini /* intel hda emulation */
11749ab747fSPaolo Bonzini
11849ab747fSPaolo Bonzini typedef struct IntelHDAStream IntelHDAStream;
11949ab747fSPaolo Bonzini typedef struct IntelHDAState IntelHDAState;
12049ab747fSPaolo Bonzini typedef struct IntelHDAReg IntelHDAReg;
12149ab747fSPaolo Bonzini
12249ab747fSPaolo Bonzini typedef struct bpl {
12349ab747fSPaolo Bonzini uint64_t addr;
12449ab747fSPaolo Bonzini uint32_t len;
12549ab747fSPaolo Bonzini uint32_t flags;
12649ab747fSPaolo Bonzini } bpl;
12749ab747fSPaolo Bonzini
12849ab747fSPaolo Bonzini struct IntelHDAStream {
12949ab747fSPaolo Bonzini /* registers */
13049ab747fSPaolo Bonzini uint32_t ctl;
13149ab747fSPaolo Bonzini uint32_t lpib;
13249ab747fSPaolo Bonzini uint32_t cbl;
13349ab747fSPaolo Bonzini uint32_t lvi;
13449ab747fSPaolo Bonzini uint32_t fmt;
13549ab747fSPaolo Bonzini uint32_t bdlp_lbase;
13649ab747fSPaolo Bonzini uint32_t bdlp_ubase;
13749ab747fSPaolo Bonzini
13849ab747fSPaolo Bonzini /* state */
13949ab747fSPaolo Bonzini bpl *bpl;
14049ab747fSPaolo Bonzini uint32_t bentries;
14149ab747fSPaolo Bonzini uint32_t bsize, be, bp;
14249ab747fSPaolo Bonzini };
14349ab747fSPaolo Bonzini
14449ab747fSPaolo Bonzini struct IntelHDAState {
14549ab747fSPaolo Bonzini PCIDevice pci;
14649ab747fSPaolo Bonzini const char *name;
14749ab747fSPaolo Bonzini HDACodecBus codecs;
14849ab747fSPaolo Bonzini
14949ab747fSPaolo Bonzini /* registers */
15049ab747fSPaolo Bonzini uint32_t g_ctl;
15149ab747fSPaolo Bonzini uint32_t wake_en;
15249ab747fSPaolo Bonzini uint32_t state_sts;
15349ab747fSPaolo Bonzini uint32_t int_ctl;
15449ab747fSPaolo Bonzini uint32_t int_sts;
15549ab747fSPaolo Bonzini uint32_t wall_clk;
15649ab747fSPaolo Bonzini
15749ab747fSPaolo Bonzini uint32_t corb_lbase;
15849ab747fSPaolo Bonzini uint32_t corb_ubase;
15949ab747fSPaolo Bonzini uint32_t corb_rp;
16049ab747fSPaolo Bonzini uint32_t corb_wp;
16149ab747fSPaolo Bonzini uint32_t corb_ctl;
16249ab747fSPaolo Bonzini uint32_t corb_sts;
16349ab747fSPaolo Bonzini uint32_t corb_size;
16449ab747fSPaolo Bonzini
16549ab747fSPaolo Bonzini uint32_t rirb_lbase;
16649ab747fSPaolo Bonzini uint32_t rirb_ubase;
16749ab747fSPaolo Bonzini uint32_t rirb_wp;
16849ab747fSPaolo Bonzini uint32_t rirb_cnt;
16949ab747fSPaolo Bonzini uint32_t rirb_ctl;
17049ab747fSPaolo Bonzini uint32_t rirb_sts;
17149ab747fSPaolo Bonzini uint32_t rirb_size;
17249ab747fSPaolo Bonzini
17349ab747fSPaolo Bonzini uint32_t dp_lbase;
17449ab747fSPaolo Bonzini uint32_t dp_ubase;
17549ab747fSPaolo Bonzini
17649ab747fSPaolo Bonzini uint32_t icw;
17749ab747fSPaolo Bonzini uint32_t irr;
17849ab747fSPaolo Bonzini uint32_t ics;
17949ab747fSPaolo Bonzini
18049ab747fSPaolo Bonzini /* streams */
18149ab747fSPaolo Bonzini IntelHDAStream st[8];
18249ab747fSPaolo Bonzini
18349ab747fSPaolo Bonzini /* state */
184a9d8ba2bSPhilippe Mathieu-Daudé MemoryRegion container;
18549ab747fSPaolo Bonzini MemoryRegion mmio;
186a9d8ba2bSPhilippe Mathieu-Daudé MemoryRegion alias;
18749ab747fSPaolo Bonzini uint32_t rirb_count;
18849ab747fSPaolo Bonzini int64_t wall_base_ns;
18949ab747fSPaolo Bonzini
19049ab747fSPaolo Bonzini /* debug logging */
19149ab747fSPaolo Bonzini const IntelHDAReg *last_reg;
19249ab747fSPaolo Bonzini uint32_t last_val;
19349ab747fSPaolo Bonzini uint32_t last_write;
19449ab747fSPaolo Bonzini uint32_t last_sec;
19549ab747fSPaolo Bonzini uint32_t repeat_count;
19649ab747fSPaolo Bonzini
19749ab747fSPaolo Bonzini /* properties */
19849ab747fSPaolo Bonzini uint32_t debug;
199c0f2abffSCao jin OnOffAuto msi;
200d209c744SJan Kiszka bool old_msi_addr;
20149ab747fSPaolo Bonzini };
20249ab747fSPaolo Bonzini
203062db740SPeter Crosthwaite #define TYPE_INTEL_HDA_GENERIC "intel-hda-generic"
204062db740SPeter Crosthwaite
2058110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(IntelHDAState, INTEL_HDA,
2068110fa1dSEduardo Habkost TYPE_INTEL_HDA_GENERIC)
20752bb7c6aSPeter Crosthwaite
20849ab747fSPaolo Bonzini struct IntelHDAReg {
20949ab747fSPaolo Bonzini const char *name; /* register name */
21049ab747fSPaolo Bonzini uint32_t size; /* size in bytes */
21149ab747fSPaolo Bonzini uint32_t reset; /* reset value */
21249ab747fSPaolo Bonzini uint32_t wmask; /* write mask */
21349ab747fSPaolo Bonzini uint32_t wclear; /* write 1 to clear bits */
21449ab747fSPaolo Bonzini uint32_t offset; /* location in IntelHDAState */
21549ab747fSPaolo Bonzini uint32_t shift; /* byte access entries for dwords */
21649ab747fSPaolo Bonzini uint32_t stream;
21749ab747fSPaolo Bonzini void (*whandler)(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old);
21849ab747fSPaolo Bonzini void (*rhandler)(IntelHDAState *d, const IntelHDAReg *reg);
21949ab747fSPaolo Bonzini };
22049ab747fSPaolo Bonzini
22149ab747fSPaolo Bonzini /* --------------------------------------------------------------------- */
22249ab747fSPaolo Bonzini
intel_hda_addr(uint32_t lbase,uint32_t ubase)22349ab747fSPaolo Bonzini static hwaddr intel_hda_addr(uint32_t lbase, uint32_t ubase)
22449ab747fSPaolo Bonzini {
2259be38598SEduardo Habkost return ((uint64_t)ubase << 32) | lbase;
22649ab747fSPaolo Bonzini }
22749ab747fSPaolo Bonzini
intel_hda_update_int_sts(IntelHDAState * d)22849ab747fSPaolo Bonzini static void intel_hda_update_int_sts(IntelHDAState *d)
22949ab747fSPaolo Bonzini {
23049ab747fSPaolo Bonzini uint32_t sts = 0;
23149ab747fSPaolo Bonzini uint32_t i;
23249ab747fSPaolo Bonzini
23349ab747fSPaolo Bonzini /* update controller status */
23449ab747fSPaolo Bonzini if (d->rirb_sts & ICH6_RBSTS_IRQ) {
23549ab747fSPaolo Bonzini sts |= (1 << 30);
23649ab747fSPaolo Bonzini }
23749ab747fSPaolo Bonzini if (d->rirb_sts & ICH6_RBSTS_OVERRUN) {
23849ab747fSPaolo Bonzini sts |= (1 << 30);
23949ab747fSPaolo Bonzini }
24049ab747fSPaolo Bonzini if (d->state_sts & d->wake_en) {
24149ab747fSPaolo Bonzini sts |= (1 << 30);
24249ab747fSPaolo Bonzini }
24349ab747fSPaolo Bonzini
24449ab747fSPaolo Bonzini /* update stream status */
24549ab747fSPaolo Bonzini for (i = 0; i < 8; i++) {
24649ab747fSPaolo Bonzini /* buffer completion interrupt */
24749ab747fSPaolo Bonzini if (d->st[i].ctl & (1 << 26)) {
24849ab747fSPaolo Bonzini sts |= (1 << i);
24949ab747fSPaolo Bonzini }
25049ab747fSPaolo Bonzini }
25149ab747fSPaolo Bonzini
25249ab747fSPaolo Bonzini /* update global status */
25349ab747fSPaolo Bonzini if (sts & d->int_ctl) {
254b1fe60cdSPeter Maydell sts |= (1U << 31);
25549ab747fSPaolo Bonzini }
25649ab747fSPaolo Bonzini
25749ab747fSPaolo Bonzini d->int_sts = sts;
25849ab747fSPaolo Bonzini }
25949ab747fSPaolo Bonzini
intel_hda_update_irq(IntelHDAState * d)26049ab747fSPaolo Bonzini static void intel_hda_update_irq(IntelHDAState *d)
26149ab747fSPaolo Bonzini {
262c0f2abffSCao jin bool msi = msi_enabled(&d->pci);
26349ab747fSPaolo Bonzini int level;
26449ab747fSPaolo Bonzini
26549ab747fSPaolo Bonzini intel_hda_update_int_sts(d);
266b1fe60cdSPeter Maydell if (d->int_sts & (1U << 31) && d->int_ctl & (1U << 31)) {
26749ab747fSPaolo Bonzini level = 1;
26849ab747fSPaolo Bonzini } else {
26949ab747fSPaolo Bonzini level = 0;
27049ab747fSPaolo Bonzini }
271a89f364aSAlistair Francis dprint(d, 2, "%s: level %d [%s]\n", __func__,
27249ab747fSPaolo Bonzini level, msi ? "msi" : "intx");
27349ab747fSPaolo Bonzini if (msi) {
27449ab747fSPaolo Bonzini if (level) {
27549ab747fSPaolo Bonzini msi_notify(&d->pci, 0);
27649ab747fSPaolo Bonzini }
27749ab747fSPaolo Bonzini } else {
2789e64f8a3SMarcel Apfelbaum pci_set_irq(&d->pci, level);
27949ab747fSPaolo Bonzini }
28049ab747fSPaolo Bonzini }
28149ab747fSPaolo Bonzini
intel_hda_send_command(IntelHDAState * d,uint32_t verb)28249ab747fSPaolo Bonzini static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
28349ab747fSPaolo Bonzini {
28449ab747fSPaolo Bonzini uint32_t cad, nid, data;
28549ab747fSPaolo Bonzini HDACodecDevice *codec;
28649ab747fSPaolo Bonzini HDACodecDeviceClass *cdc;
28749ab747fSPaolo Bonzini
28849ab747fSPaolo Bonzini cad = (verb >> 28) & 0x0f;
28949ab747fSPaolo Bonzini if (verb & (1 << 27)) {
29049ab747fSPaolo Bonzini /* indirect node addressing, not specified in HDA 1.0 */
291a89f364aSAlistair Francis dprint(d, 1, "%s: indirect node addressing (guest bug?)\n", __func__);
29249ab747fSPaolo Bonzini return -1;
29349ab747fSPaolo Bonzini }
29449ab747fSPaolo Bonzini nid = (verb >> 20) & 0x7f;
29549ab747fSPaolo Bonzini data = verb & 0xfffff;
29649ab747fSPaolo Bonzini
29749ab747fSPaolo Bonzini codec = hda_codec_find(&d->codecs, cad);
29849ab747fSPaolo Bonzini if (codec == NULL) {
299a89f364aSAlistair Francis dprint(d, 1, "%s: addressed non-existing codec\n", __func__);
30049ab747fSPaolo Bonzini return -1;
30149ab747fSPaolo Bonzini }
30249ab747fSPaolo Bonzini cdc = HDA_CODEC_DEVICE_GET_CLASS(codec);
30349ab747fSPaolo Bonzini cdc->command(codec, nid, data);
30449ab747fSPaolo Bonzini return 0;
30549ab747fSPaolo Bonzini }
30649ab747fSPaolo Bonzini
intel_hda_corb_run(IntelHDAState * d)30749ab747fSPaolo Bonzini static void intel_hda_corb_run(IntelHDAState *d)
30849ab747fSPaolo Bonzini {
30949ab747fSPaolo Bonzini hwaddr addr;
31049ab747fSPaolo Bonzini uint32_t rp, verb;
31149ab747fSPaolo Bonzini
31249ab747fSPaolo Bonzini if (d->ics & ICH6_IRS_BUSY) {
313a89f364aSAlistair Francis dprint(d, 2, "%s: [icw] verb 0x%08x\n", __func__, d->icw);
31449ab747fSPaolo Bonzini intel_hda_send_command(d, d->icw);
31549ab747fSPaolo Bonzini return;
31649ab747fSPaolo Bonzini }
31749ab747fSPaolo Bonzini
31849ab747fSPaolo Bonzini for (;;) {
31949ab747fSPaolo Bonzini if (!(d->corb_ctl & ICH6_CORBCTL_RUN)) {
320a89f364aSAlistair Francis dprint(d, 2, "%s: !run\n", __func__);
32149ab747fSPaolo Bonzini return;
32249ab747fSPaolo Bonzini }
32349ab747fSPaolo Bonzini if ((d->corb_rp & 0xff) == d->corb_wp) {
324a89f364aSAlistair Francis dprint(d, 2, "%s: corb ring empty\n", __func__);
32549ab747fSPaolo Bonzini return;
32649ab747fSPaolo Bonzini }
32749ab747fSPaolo Bonzini if (d->rirb_count == d->rirb_cnt) {
328a89f364aSAlistair Francis dprint(d, 2, "%s: rirb count reached\n", __func__);
32949ab747fSPaolo Bonzini return;
33049ab747fSPaolo Bonzini }
33149ab747fSPaolo Bonzini
33249ab747fSPaolo Bonzini rp = (d->corb_rp + 1) & 0xff;
33349ab747fSPaolo Bonzini addr = intel_hda_addr(d->corb_lbase, d->corb_ubase);
3344a63054bSPhilippe Mathieu-Daudé ldl_le_pci_dma(&d->pci, addr + 4 * rp, &verb, MEMTXATTRS_UNSPECIFIED);
33549ab747fSPaolo Bonzini d->corb_rp = rp;
33649ab747fSPaolo Bonzini
337a89f364aSAlistair Francis dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __func__, rp, verb);
33849ab747fSPaolo Bonzini intel_hda_send_command(d, verb);
33949ab747fSPaolo Bonzini }
34049ab747fSPaolo Bonzini }
34149ab747fSPaolo Bonzini
intel_hda_response(HDACodecDevice * dev,bool solicited,uint32_t response)34249ab747fSPaolo Bonzini static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response)
34349ab747fSPaolo Bonzini {
34479fa9983SPhilippe Mathieu-Daudé const MemTxAttrs attrs = { .memory = true };
345e19202afSxiaoqiang zhao HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus);
34649ab747fSPaolo Bonzini IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
34749ab747fSPaolo Bonzini hwaddr addr;
34849ab747fSPaolo Bonzini uint32_t wp, ex;
349be5a8cf3SPhilippe Mathieu-Daudé MemTxResult res = MEMTX_OK;
35049ab747fSPaolo Bonzini
35149ab747fSPaolo Bonzini if (d->ics & ICH6_IRS_BUSY) {
35249ab747fSPaolo Bonzini dprint(d, 2, "%s: [irr] response 0x%x, cad 0x%x\n",
353a89f364aSAlistair Francis __func__, response, dev->cad);
35449ab747fSPaolo Bonzini d->irr = response;
35549ab747fSPaolo Bonzini d->ics &= ~(ICH6_IRS_BUSY | 0xf0);
35649ab747fSPaolo Bonzini d->ics |= (ICH6_IRS_VALID | (dev->cad << 4));
35749ab747fSPaolo Bonzini return;
35849ab747fSPaolo Bonzini }
35949ab747fSPaolo Bonzini
36049ab747fSPaolo Bonzini if (!(d->rirb_ctl & ICH6_RBCTL_DMA_EN)) {
361a89f364aSAlistair Francis dprint(d, 1, "%s: rirb dma disabled, drop codec response\n", __func__);
36249ab747fSPaolo Bonzini return;
36349ab747fSPaolo Bonzini }
36449ab747fSPaolo Bonzini
36549ab747fSPaolo Bonzini ex = (solicited ? 0 : (1 << 4)) | dev->cad;
36649ab747fSPaolo Bonzini wp = (d->rirb_wp + 1) & 0xff;
36749ab747fSPaolo Bonzini addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase);
368be5a8cf3SPhilippe Mathieu-Daudé res |= stl_le_pci_dma(&d->pci, addr + 8 * wp, response, attrs);
369be5a8cf3SPhilippe Mathieu-Daudé res |= stl_le_pci_dma(&d->pci, addr + 8 * wp + 4, ex, attrs);
370be5a8cf3SPhilippe Mathieu-Daudé if (res != MEMTX_OK && (d->rirb_ctl & ICH6_RBCTL_OVERRUN_EN)) {
371be5a8cf3SPhilippe Mathieu-Daudé d->rirb_sts |= ICH6_RBSTS_OVERRUN;
372be5a8cf3SPhilippe Mathieu-Daudé intel_hda_update_irq(d);
373be5a8cf3SPhilippe Mathieu-Daudé }
37449ab747fSPaolo Bonzini d->rirb_wp = wp;
37549ab747fSPaolo Bonzini
37649ab747fSPaolo Bonzini dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n",
377a89f364aSAlistair Francis __func__, wp, response, ex);
37849ab747fSPaolo Bonzini
37949ab747fSPaolo Bonzini d->rirb_count++;
38049ab747fSPaolo Bonzini if (d->rirb_count == d->rirb_cnt) {
381a89f364aSAlistair Francis dprint(d, 2, "%s: rirb count reached (%d)\n", __func__, d->rirb_count);
38249ab747fSPaolo Bonzini if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
38349ab747fSPaolo Bonzini d->rirb_sts |= ICH6_RBSTS_IRQ;
38449ab747fSPaolo Bonzini intel_hda_update_irq(d);
38549ab747fSPaolo Bonzini }
38649ab747fSPaolo Bonzini } else if ((d->corb_rp & 0xff) == d->corb_wp) {
387a89f364aSAlistair Francis dprint(d, 2, "%s: corb ring empty (%d/%d)\n", __func__,
38849ab747fSPaolo Bonzini d->rirb_count, d->rirb_cnt);
38949ab747fSPaolo Bonzini if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
39049ab747fSPaolo Bonzini d->rirb_sts |= ICH6_RBSTS_IRQ;
39149ab747fSPaolo Bonzini intel_hda_update_irq(d);
39249ab747fSPaolo Bonzini }
39349ab747fSPaolo Bonzini }
39449ab747fSPaolo Bonzini }
39549ab747fSPaolo Bonzini
intel_hda_xfer(HDACodecDevice * dev,uint32_t stnr,bool output,uint8_t * buf,uint32_t len)39649ab747fSPaolo Bonzini static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
39749ab747fSPaolo Bonzini uint8_t *buf, uint32_t len)
39849ab747fSPaolo Bonzini {
399a423a1b5SPhilippe Mathieu-Daudé const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
400e19202afSxiaoqiang zhao HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus);
40149ab747fSPaolo Bonzini IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
40249ab747fSPaolo Bonzini hwaddr addr;
40349ab747fSPaolo Bonzini uint32_t s, copy, left;
40449ab747fSPaolo Bonzini IntelHDAStream *st;
40549ab747fSPaolo Bonzini bool irq = false;
40649ab747fSPaolo Bonzini
40749ab747fSPaolo Bonzini st = output ? d->st + 4 : d->st;
40849ab747fSPaolo Bonzini for (s = 0; s < 4; s++) {
40949ab747fSPaolo Bonzini if (stnr == ((st[s].ctl >> 20) & 0x0f)) {
41049ab747fSPaolo Bonzini st = st + s;
41149ab747fSPaolo Bonzini break;
41249ab747fSPaolo Bonzini }
41349ab747fSPaolo Bonzini }
41449ab747fSPaolo Bonzini if (s == 4) {
41549ab747fSPaolo Bonzini return false;
41649ab747fSPaolo Bonzini }
41749ab747fSPaolo Bonzini if (st->bpl == NULL) {
41849ab747fSPaolo Bonzini return false;
41949ab747fSPaolo Bonzini }
42049ab747fSPaolo Bonzini
42149ab747fSPaolo Bonzini left = len;
4220c0fc2b5SPrasad J Pandit s = st->bentries;
4230c0fc2b5SPrasad J Pandit while (left > 0 && s-- > 0) {
42449ab747fSPaolo Bonzini copy = left;
42549ab747fSPaolo Bonzini if (copy > st->bsize - st->lpib)
42649ab747fSPaolo Bonzini copy = st->bsize - st->lpib;
42749ab747fSPaolo Bonzini if (copy > st->bpl[st->be].len - st->bp)
42849ab747fSPaolo Bonzini copy = st->bpl[st->be].len - st->bp;
42949ab747fSPaolo Bonzini
43049ab747fSPaolo Bonzini dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n",
43149ab747fSPaolo Bonzini st->be, st->bp, st->bpl[st->be].len, copy);
43249ab747fSPaolo Bonzini
433e2d784b6SPhilippe Mathieu-Daudé pci_dma_rw(&d->pci, st->bpl[st->be].addr + st->bp, buf, copy, !output,
434a423a1b5SPhilippe Mathieu-Daudé attrs);
43549ab747fSPaolo Bonzini st->lpib += copy;
43649ab747fSPaolo Bonzini st->bp += copy;
43749ab747fSPaolo Bonzini buf += copy;
43849ab747fSPaolo Bonzini left -= copy;
43949ab747fSPaolo Bonzini
44049ab747fSPaolo Bonzini if (st->bpl[st->be].len == st->bp) {
44149ab747fSPaolo Bonzini /* bpl entry filled */
44249ab747fSPaolo Bonzini if (st->bpl[st->be].flags & 0x01) {
44349ab747fSPaolo Bonzini irq = true;
44449ab747fSPaolo Bonzini }
44549ab747fSPaolo Bonzini st->bp = 0;
44649ab747fSPaolo Bonzini st->be++;
44749ab747fSPaolo Bonzini if (st->be == st->bentries) {
44849ab747fSPaolo Bonzini /* bpl wrap around */
44949ab747fSPaolo Bonzini st->be = 0;
45049ab747fSPaolo Bonzini st->lpib = 0;
45149ab747fSPaolo Bonzini }
45249ab747fSPaolo Bonzini }
45349ab747fSPaolo Bonzini }
45449ab747fSPaolo Bonzini if (d->dp_lbase & 0x01) {
455d58ce68aSGerd Hoffmann s = st - d->st;
45649ab747fSPaolo Bonzini addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase);
457a423a1b5SPhilippe Mathieu-Daudé stl_le_pci_dma(&d->pci, addr + 8 * s, st->lpib, attrs);
45849ab747fSPaolo Bonzini }
45949ab747fSPaolo Bonzini dprint(d, 3, "dma: --\n");
46049ab747fSPaolo Bonzini
46149ab747fSPaolo Bonzini if (irq) {
46249ab747fSPaolo Bonzini st->ctl |= (1 << 26); /* buffer completion interrupt */
46349ab747fSPaolo Bonzini intel_hda_update_irq(d);
46449ab747fSPaolo Bonzini }
46549ab747fSPaolo Bonzini return true;
46649ab747fSPaolo Bonzini }
46749ab747fSPaolo Bonzini
intel_hda_parse_bdl(IntelHDAState * d,IntelHDAStream * st)46849ab747fSPaolo Bonzini static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
46949ab747fSPaolo Bonzini {
47049ab747fSPaolo Bonzini hwaddr addr;
47149ab747fSPaolo Bonzini uint8_t buf[16];
47249ab747fSPaolo Bonzini uint32_t i;
47349ab747fSPaolo Bonzini
47449ab747fSPaolo Bonzini addr = intel_hda_addr(st->bdlp_lbase, st->bdlp_ubase);
47549ab747fSPaolo Bonzini st->bentries = st->lvi +1;
47649ab747fSPaolo Bonzini g_free(st->bpl);
477b21e2380SMarkus Armbruster st->bpl = g_new(bpl, st->bentries);
47849ab747fSPaolo Bonzini for (i = 0; i < st->bentries; i++, addr += 16) {
47949ab747fSPaolo Bonzini pci_dma_read(&d->pci, addr, buf, 16);
48049ab747fSPaolo Bonzini st->bpl[i].addr = le64_to_cpu(*(uint64_t *)buf);
48149ab747fSPaolo Bonzini st->bpl[i].len = le32_to_cpu(*(uint32_t *)(buf + 8));
48249ab747fSPaolo Bonzini st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12));
48349ab747fSPaolo Bonzini dprint(d, 1, "bdl/%d: 0x%" PRIx64 " +0x%x, 0x%x\n",
48449ab747fSPaolo Bonzini i, st->bpl[i].addr, st->bpl[i].len, st->bpl[i].flags);
48549ab747fSPaolo Bonzini }
48649ab747fSPaolo Bonzini
48749ab747fSPaolo Bonzini st->bsize = st->cbl;
48849ab747fSPaolo Bonzini st->lpib = 0;
48949ab747fSPaolo Bonzini st->be = 0;
49049ab747fSPaolo Bonzini st->bp = 0;
49149ab747fSPaolo Bonzini }
49249ab747fSPaolo Bonzini
intel_hda_notify_codecs(IntelHDAState * d,uint32_t stream,bool running,bool output)49349ab747fSPaolo Bonzini static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output)
49449ab747fSPaolo Bonzini {
49549ab747fSPaolo Bonzini BusChild *kid;
49649ab747fSPaolo Bonzini HDACodecDevice *cdev;
49749ab747fSPaolo Bonzini
49849ab747fSPaolo Bonzini QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
49949ab747fSPaolo Bonzini DeviceState *qdev = kid->child;
50049ab747fSPaolo Bonzini HDACodecDeviceClass *cdc;
50149ab747fSPaolo Bonzini
502e19202afSxiaoqiang zhao cdev = HDA_CODEC_DEVICE(qdev);
50349ab747fSPaolo Bonzini cdc = HDA_CODEC_DEVICE_GET_CLASS(cdev);
50449ab747fSPaolo Bonzini if (cdc->stream) {
50549ab747fSPaolo Bonzini cdc->stream(cdev, stream, running, output);
50649ab747fSPaolo Bonzini }
50749ab747fSPaolo Bonzini }
50849ab747fSPaolo Bonzini }
50949ab747fSPaolo Bonzini
51049ab747fSPaolo Bonzini /* --------------------------------------------------------------------- */
51149ab747fSPaolo Bonzini
intel_hda_set_g_ctl(IntelHDAState * d,const IntelHDAReg * reg,uint32_t old)51249ab747fSPaolo Bonzini static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
51349ab747fSPaolo Bonzini {
51449ab747fSPaolo Bonzini if ((d->g_ctl & ICH6_GCTL_RESET) == 0) {
5153e95ef49SPeter Maydell device_cold_reset(DEVICE(d));
51649ab747fSPaolo Bonzini }
51749ab747fSPaolo Bonzini }
51849ab747fSPaolo Bonzini
intel_hda_set_wake_en(IntelHDAState * d,const IntelHDAReg * reg,uint32_t old)51949ab747fSPaolo Bonzini static void intel_hda_set_wake_en(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
52049ab747fSPaolo Bonzini {
52149ab747fSPaolo Bonzini intel_hda_update_irq(d);
52249ab747fSPaolo Bonzini }
52349ab747fSPaolo Bonzini
intel_hda_set_state_sts(IntelHDAState * d,const IntelHDAReg * reg,uint32_t old)52449ab747fSPaolo Bonzini static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
52549ab747fSPaolo Bonzini {
52649ab747fSPaolo Bonzini intel_hda_update_irq(d);
52749ab747fSPaolo Bonzini }
52849ab747fSPaolo Bonzini
intel_hda_set_int_ctl(IntelHDAState * d,const IntelHDAReg * reg,uint32_t old)52949ab747fSPaolo Bonzini static void intel_hda_set_int_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
53049ab747fSPaolo Bonzini {
53149ab747fSPaolo Bonzini intel_hda_update_irq(d);
53249ab747fSPaolo Bonzini }
53349ab747fSPaolo Bonzini
intel_hda_get_wall_clk(IntelHDAState * d,const IntelHDAReg * reg)53449ab747fSPaolo Bonzini static void intel_hda_get_wall_clk(IntelHDAState *d, const IntelHDAReg *reg)
53549ab747fSPaolo Bonzini {
53649ab747fSPaolo Bonzini int64_t ns;
53749ab747fSPaolo Bonzini
538bc72ad67SAlex Bligh ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - d->wall_base_ns;
53949ab747fSPaolo Bonzini d->wall_clk = (uint32_t)(ns * 24 / 1000); /* 24 MHz */
54049ab747fSPaolo Bonzini }
54149ab747fSPaolo Bonzini
intel_hda_set_corb_wp(IntelHDAState * d,const IntelHDAReg * reg,uint32_t old)54249ab747fSPaolo Bonzini static void intel_hda_set_corb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
54349ab747fSPaolo Bonzini {
54449ab747fSPaolo Bonzini intel_hda_corb_run(d);
54549ab747fSPaolo Bonzini }
54649ab747fSPaolo Bonzini
intel_hda_set_corb_ctl(IntelHDAState * d,const IntelHDAReg * reg,uint32_t old)54749ab747fSPaolo Bonzini static void intel_hda_set_corb_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
54849ab747fSPaolo Bonzini {
54949ab747fSPaolo Bonzini intel_hda_corb_run(d);
55049ab747fSPaolo Bonzini }
55149ab747fSPaolo Bonzini
intel_hda_set_rirb_wp(IntelHDAState * d,const IntelHDAReg * reg,uint32_t old)55249ab747fSPaolo Bonzini static void intel_hda_set_rirb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
55349ab747fSPaolo Bonzini {
55449ab747fSPaolo Bonzini if (d->rirb_wp & ICH6_RIRBWP_RST) {
55549ab747fSPaolo Bonzini d->rirb_wp = 0;
55649ab747fSPaolo Bonzini }
55749ab747fSPaolo Bonzini }
55849ab747fSPaolo Bonzini
intel_hda_set_rirb_sts(IntelHDAState * d,const IntelHDAReg * reg,uint32_t old)55949ab747fSPaolo Bonzini static void intel_hda_set_rirb_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
56049ab747fSPaolo Bonzini {
56149ab747fSPaolo Bonzini intel_hda_update_irq(d);
56249ab747fSPaolo Bonzini
56349ab747fSPaolo Bonzini if ((old & ICH6_RBSTS_IRQ) && !(d->rirb_sts & ICH6_RBSTS_IRQ)) {
56449ab747fSPaolo Bonzini /* cleared ICH6_RBSTS_IRQ */
56549ab747fSPaolo Bonzini d->rirb_count = 0;
56649ab747fSPaolo Bonzini intel_hda_corb_run(d);
56749ab747fSPaolo Bonzini }
56849ab747fSPaolo Bonzini }
56949ab747fSPaolo Bonzini
intel_hda_set_ics(IntelHDAState * d,const IntelHDAReg * reg,uint32_t old)57049ab747fSPaolo Bonzini static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
57149ab747fSPaolo Bonzini {
57249ab747fSPaolo Bonzini if (d->ics & ICH6_IRS_BUSY) {
57349ab747fSPaolo Bonzini intel_hda_corb_run(d);
57449ab747fSPaolo Bonzini }
57549ab747fSPaolo Bonzini }
57649ab747fSPaolo Bonzini
intel_hda_set_st_ctl(IntelHDAState * d,const IntelHDAReg * reg,uint32_t old)57749ab747fSPaolo Bonzini static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
57849ab747fSPaolo Bonzini {
57949ab747fSPaolo Bonzini bool output = reg->stream >= 4;
58049ab747fSPaolo Bonzini IntelHDAStream *st = d->st + reg->stream;
58149ab747fSPaolo Bonzini
58249ab747fSPaolo Bonzini if (st->ctl & 0x01) {
58349ab747fSPaolo Bonzini /* reset */
58449ab747fSPaolo Bonzini dprint(d, 1, "st #%d: reset\n", reg->stream);
585ecd5f288SVolker Rümelin st->ctl = SD_STS_FIFO_READY << 24 | SD_CTL_STREAM_RESET;
58649ab747fSPaolo Bonzini }
58749ab747fSPaolo Bonzini if ((st->ctl & 0x02) != (old & 0x02)) {
58849ab747fSPaolo Bonzini uint32_t stnr = (st->ctl >> 20) & 0x0f;
58949ab747fSPaolo Bonzini /* run bit flipped */
59049ab747fSPaolo Bonzini if (st->ctl & 0x02) {
59149ab747fSPaolo Bonzini /* start */
59249ab747fSPaolo Bonzini dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n",
59349ab747fSPaolo Bonzini reg->stream, stnr, st->cbl);
59449ab747fSPaolo Bonzini intel_hda_parse_bdl(d, st);
59549ab747fSPaolo Bonzini intel_hda_notify_codecs(d, stnr, true, output);
59649ab747fSPaolo Bonzini } else {
59749ab747fSPaolo Bonzini /* stop */
59849ab747fSPaolo Bonzini dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr);
59949ab747fSPaolo Bonzini intel_hda_notify_codecs(d, stnr, false, output);
60049ab747fSPaolo Bonzini }
60149ab747fSPaolo Bonzini }
60249ab747fSPaolo Bonzini intel_hda_update_irq(d);
60349ab747fSPaolo Bonzini }
60449ab747fSPaolo Bonzini
60549ab747fSPaolo Bonzini /* --------------------------------------------------------------------- */
60649ab747fSPaolo Bonzini
60749ab747fSPaolo Bonzini #define ST_REG(_n, _o) (0x80 + (_n) * 0x20 + (_o))
60849ab747fSPaolo Bonzini
60949ab747fSPaolo Bonzini static const struct IntelHDAReg regtab[] = {
61049ab747fSPaolo Bonzini /* global */
61149ab747fSPaolo Bonzini [ ICH6_REG_GCAP ] = {
61249ab747fSPaolo Bonzini .name = "GCAP",
61349ab747fSPaolo Bonzini .size = 2,
61449ab747fSPaolo Bonzini .reset = 0x4401,
61549ab747fSPaolo Bonzini },
61649ab747fSPaolo Bonzini [ ICH6_REG_VMIN ] = {
61749ab747fSPaolo Bonzini .name = "VMIN",
61849ab747fSPaolo Bonzini .size = 1,
61949ab747fSPaolo Bonzini },
62049ab747fSPaolo Bonzini [ ICH6_REG_VMAJ ] = {
62149ab747fSPaolo Bonzini .name = "VMAJ",
62249ab747fSPaolo Bonzini .size = 1,
62349ab747fSPaolo Bonzini .reset = 1,
62449ab747fSPaolo Bonzini },
62549ab747fSPaolo Bonzini [ ICH6_REG_OUTPAY ] = {
62649ab747fSPaolo Bonzini .name = "OUTPAY",
62749ab747fSPaolo Bonzini .size = 2,
62849ab747fSPaolo Bonzini .reset = 0x3c,
62949ab747fSPaolo Bonzini },
63049ab747fSPaolo Bonzini [ ICH6_REG_INPAY ] = {
63149ab747fSPaolo Bonzini .name = "INPAY",
63249ab747fSPaolo Bonzini .size = 2,
63349ab747fSPaolo Bonzini .reset = 0x1d,
63449ab747fSPaolo Bonzini },
63549ab747fSPaolo Bonzini [ ICH6_REG_GCTL ] = {
63649ab747fSPaolo Bonzini .name = "GCTL",
63749ab747fSPaolo Bonzini .size = 4,
63849ab747fSPaolo Bonzini .wmask = 0x0103,
63949ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, g_ctl),
64049ab747fSPaolo Bonzini .whandler = intel_hda_set_g_ctl,
64149ab747fSPaolo Bonzini },
64249ab747fSPaolo Bonzini [ ICH6_REG_WAKEEN ] = {
64349ab747fSPaolo Bonzini .name = "WAKEEN",
64449ab747fSPaolo Bonzini .size = 2,
64549ab747fSPaolo Bonzini .wmask = 0x7fff,
64649ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, wake_en),
64749ab747fSPaolo Bonzini .whandler = intel_hda_set_wake_en,
64849ab747fSPaolo Bonzini },
64949ab747fSPaolo Bonzini [ ICH6_REG_STATESTS ] = {
65049ab747fSPaolo Bonzini .name = "STATESTS",
65149ab747fSPaolo Bonzini .size = 2,
65249ab747fSPaolo Bonzini .wmask = 0x7fff,
65349ab747fSPaolo Bonzini .wclear = 0x7fff,
65449ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, state_sts),
65549ab747fSPaolo Bonzini .whandler = intel_hda_set_state_sts,
65649ab747fSPaolo Bonzini },
65749ab747fSPaolo Bonzini
65849ab747fSPaolo Bonzini /* interrupts */
65949ab747fSPaolo Bonzini [ ICH6_REG_INTCTL ] = {
66049ab747fSPaolo Bonzini .name = "INTCTL",
66149ab747fSPaolo Bonzini .size = 4,
66249ab747fSPaolo Bonzini .wmask = 0xc00000ff,
66349ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, int_ctl),
66449ab747fSPaolo Bonzini .whandler = intel_hda_set_int_ctl,
66549ab747fSPaolo Bonzini },
66649ab747fSPaolo Bonzini [ ICH6_REG_INTSTS ] = {
66749ab747fSPaolo Bonzini .name = "INTSTS",
66849ab747fSPaolo Bonzini .size = 4,
66949ab747fSPaolo Bonzini .wmask = 0xc00000ff,
67049ab747fSPaolo Bonzini .wclear = 0xc00000ff,
67149ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, int_sts),
67249ab747fSPaolo Bonzini },
67349ab747fSPaolo Bonzini
67449ab747fSPaolo Bonzini /* misc */
67549ab747fSPaolo Bonzini [ ICH6_REG_WALLCLK ] = {
67649ab747fSPaolo Bonzini .name = "WALLCLK",
67749ab747fSPaolo Bonzini .size = 4,
67849ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, wall_clk),
67949ab747fSPaolo Bonzini .rhandler = intel_hda_get_wall_clk,
68049ab747fSPaolo Bonzini },
68149ab747fSPaolo Bonzini
68249ab747fSPaolo Bonzini /* dma engine */
68349ab747fSPaolo Bonzini [ ICH6_REG_CORBLBASE ] = {
68449ab747fSPaolo Bonzini .name = "CORBLBASE",
68549ab747fSPaolo Bonzini .size = 4,
68649ab747fSPaolo Bonzini .wmask = 0xffffff80,
68749ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, corb_lbase),
68849ab747fSPaolo Bonzini },
68949ab747fSPaolo Bonzini [ ICH6_REG_CORBUBASE ] = {
69049ab747fSPaolo Bonzini .name = "CORBUBASE",
69149ab747fSPaolo Bonzini .size = 4,
69249ab747fSPaolo Bonzini .wmask = 0xffffffff,
69349ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, corb_ubase),
69449ab747fSPaolo Bonzini },
69549ab747fSPaolo Bonzini [ ICH6_REG_CORBWP ] = {
69649ab747fSPaolo Bonzini .name = "CORBWP",
69749ab747fSPaolo Bonzini .size = 2,
69849ab747fSPaolo Bonzini .wmask = 0xff,
69949ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, corb_wp),
70049ab747fSPaolo Bonzini .whandler = intel_hda_set_corb_wp,
70149ab747fSPaolo Bonzini },
70249ab747fSPaolo Bonzini [ ICH6_REG_CORBRP ] = {
70349ab747fSPaolo Bonzini .name = "CORBRP",
70449ab747fSPaolo Bonzini .size = 2,
70549ab747fSPaolo Bonzini .wmask = 0x80ff,
70649ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, corb_rp),
70749ab747fSPaolo Bonzini },
70849ab747fSPaolo Bonzini [ ICH6_REG_CORBCTL ] = {
70949ab747fSPaolo Bonzini .name = "CORBCTL",
71049ab747fSPaolo Bonzini .size = 1,
71149ab747fSPaolo Bonzini .wmask = 0x03,
71249ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, corb_ctl),
71349ab747fSPaolo Bonzini .whandler = intel_hda_set_corb_ctl,
71449ab747fSPaolo Bonzini },
71549ab747fSPaolo Bonzini [ ICH6_REG_CORBSTS ] = {
71649ab747fSPaolo Bonzini .name = "CORBSTS",
71749ab747fSPaolo Bonzini .size = 1,
71849ab747fSPaolo Bonzini .wmask = 0x01,
71949ab747fSPaolo Bonzini .wclear = 0x01,
72049ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, corb_sts),
72149ab747fSPaolo Bonzini },
72249ab747fSPaolo Bonzini [ ICH6_REG_CORBSIZE ] = {
72349ab747fSPaolo Bonzini .name = "CORBSIZE",
72449ab747fSPaolo Bonzini .size = 1,
72549ab747fSPaolo Bonzini .reset = 0x42,
72649ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, corb_size),
72749ab747fSPaolo Bonzini },
72849ab747fSPaolo Bonzini [ ICH6_REG_RIRBLBASE ] = {
72949ab747fSPaolo Bonzini .name = "RIRBLBASE",
73049ab747fSPaolo Bonzini .size = 4,
73149ab747fSPaolo Bonzini .wmask = 0xffffff80,
73249ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, rirb_lbase),
73349ab747fSPaolo Bonzini },
73449ab747fSPaolo Bonzini [ ICH6_REG_RIRBUBASE ] = {
73549ab747fSPaolo Bonzini .name = "RIRBUBASE",
73649ab747fSPaolo Bonzini .size = 4,
73749ab747fSPaolo Bonzini .wmask = 0xffffffff,
73849ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, rirb_ubase),
73949ab747fSPaolo Bonzini },
74049ab747fSPaolo Bonzini [ ICH6_REG_RIRBWP ] = {
74149ab747fSPaolo Bonzini .name = "RIRBWP",
74249ab747fSPaolo Bonzini .size = 2,
74349ab747fSPaolo Bonzini .wmask = 0x8000,
74449ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, rirb_wp),
74549ab747fSPaolo Bonzini .whandler = intel_hda_set_rirb_wp,
74649ab747fSPaolo Bonzini },
74749ab747fSPaolo Bonzini [ ICH6_REG_RINTCNT ] = {
74849ab747fSPaolo Bonzini .name = "RINTCNT",
74949ab747fSPaolo Bonzini .size = 2,
75049ab747fSPaolo Bonzini .wmask = 0xff,
75149ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, rirb_cnt),
75249ab747fSPaolo Bonzini },
75349ab747fSPaolo Bonzini [ ICH6_REG_RIRBCTL ] = {
75449ab747fSPaolo Bonzini .name = "RIRBCTL",
75549ab747fSPaolo Bonzini .size = 1,
75649ab747fSPaolo Bonzini .wmask = 0x07,
75749ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, rirb_ctl),
75849ab747fSPaolo Bonzini },
75949ab747fSPaolo Bonzini [ ICH6_REG_RIRBSTS ] = {
76049ab747fSPaolo Bonzini .name = "RIRBSTS",
76149ab747fSPaolo Bonzini .size = 1,
76249ab747fSPaolo Bonzini .wmask = 0x05,
76349ab747fSPaolo Bonzini .wclear = 0x05,
76449ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, rirb_sts),
76549ab747fSPaolo Bonzini .whandler = intel_hda_set_rirb_sts,
76649ab747fSPaolo Bonzini },
76749ab747fSPaolo Bonzini [ ICH6_REG_RIRBSIZE ] = {
76849ab747fSPaolo Bonzini .name = "RIRBSIZE",
76949ab747fSPaolo Bonzini .size = 1,
77049ab747fSPaolo Bonzini .reset = 0x42,
77149ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, rirb_size),
77249ab747fSPaolo Bonzini },
77349ab747fSPaolo Bonzini
77449ab747fSPaolo Bonzini [ ICH6_REG_DPLBASE ] = {
77549ab747fSPaolo Bonzini .name = "DPLBASE",
77649ab747fSPaolo Bonzini .size = 4,
77749ab747fSPaolo Bonzini .wmask = 0xffffff81,
77849ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, dp_lbase),
77949ab747fSPaolo Bonzini },
78049ab747fSPaolo Bonzini [ ICH6_REG_DPUBASE ] = {
78149ab747fSPaolo Bonzini .name = "DPUBASE",
78249ab747fSPaolo Bonzini .size = 4,
78349ab747fSPaolo Bonzini .wmask = 0xffffffff,
78449ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, dp_ubase),
78549ab747fSPaolo Bonzini },
78649ab747fSPaolo Bonzini
78749ab747fSPaolo Bonzini [ ICH6_REG_IC ] = {
78849ab747fSPaolo Bonzini .name = "ICW",
78949ab747fSPaolo Bonzini .size = 4,
79049ab747fSPaolo Bonzini .wmask = 0xffffffff,
79149ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, icw),
79249ab747fSPaolo Bonzini },
79349ab747fSPaolo Bonzini [ ICH6_REG_IR ] = {
79449ab747fSPaolo Bonzini .name = "IRR",
79549ab747fSPaolo Bonzini .size = 4,
79649ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, irr),
79749ab747fSPaolo Bonzini },
79849ab747fSPaolo Bonzini [ ICH6_REG_IRS ] = {
79949ab747fSPaolo Bonzini .name = "ICS",
80049ab747fSPaolo Bonzini .size = 2,
80149ab747fSPaolo Bonzini .wmask = 0x0003,
80249ab747fSPaolo Bonzini .wclear = 0x0002,
80349ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, ics),
80449ab747fSPaolo Bonzini .whandler = intel_hda_set_ics,
80549ab747fSPaolo Bonzini },
80649ab747fSPaolo Bonzini
80749ab747fSPaolo Bonzini #define HDA_STREAM(_t, _i) \
80849ab747fSPaolo Bonzini [ ST_REG(_i, ICH6_REG_SD_CTL) ] = { \
80949ab747fSPaolo Bonzini .stream = _i, \
81049ab747fSPaolo Bonzini .name = _t stringify(_i) " CTL", \
81149ab747fSPaolo Bonzini .size = 4, \
81249ab747fSPaolo Bonzini .wmask = 0x1cff001f, \
81349ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, st[_i].ctl), \
81449ab747fSPaolo Bonzini .whandler = intel_hda_set_st_ctl, \
81549ab747fSPaolo Bonzini }, \
81649ab747fSPaolo Bonzini [ ST_REG(_i, ICH6_REG_SD_CTL) + 2] = { \
81749ab747fSPaolo Bonzini .stream = _i, \
81849ab747fSPaolo Bonzini .name = _t stringify(_i) " CTL(stnr)", \
81949ab747fSPaolo Bonzini .size = 1, \
82049ab747fSPaolo Bonzini .shift = 16, \
82149ab747fSPaolo Bonzini .wmask = 0x00ff0000, \
82249ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, st[_i].ctl), \
82349ab747fSPaolo Bonzini .whandler = intel_hda_set_st_ctl, \
82449ab747fSPaolo Bonzini }, \
82549ab747fSPaolo Bonzini [ ST_REG(_i, ICH6_REG_SD_STS)] = { \
82649ab747fSPaolo Bonzini .stream = _i, \
82749ab747fSPaolo Bonzini .name = _t stringify(_i) " CTL(sts)", \
82849ab747fSPaolo Bonzini .size = 1, \
82949ab747fSPaolo Bonzini .shift = 24, \
83049ab747fSPaolo Bonzini .wmask = 0x1c000000, \
83149ab747fSPaolo Bonzini .wclear = 0x1c000000, \
83249ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, st[_i].ctl), \
83349ab747fSPaolo Bonzini .whandler = intel_hda_set_st_ctl, \
834a2554a33SStanislav Vorobiov .reset = SD_STS_FIFO_READY << 24 \
83549ab747fSPaolo Bonzini }, \
83649ab747fSPaolo Bonzini [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \
83749ab747fSPaolo Bonzini .stream = _i, \
83849ab747fSPaolo Bonzini .name = _t stringify(_i) " LPIB", \
83949ab747fSPaolo Bonzini .size = 4, \
84049ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, st[_i].lpib), \
84149ab747fSPaolo Bonzini }, \
84249ab747fSPaolo Bonzini [ ST_REG(_i, ICH6_REG_SD_CBL) ] = { \
84349ab747fSPaolo Bonzini .stream = _i, \
84449ab747fSPaolo Bonzini .name = _t stringify(_i) " CBL", \
84549ab747fSPaolo Bonzini .size = 4, \
84649ab747fSPaolo Bonzini .wmask = 0xffffffff, \
84749ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, st[_i].cbl), \
84849ab747fSPaolo Bonzini }, \
84949ab747fSPaolo Bonzini [ ST_REG(_i, ICH6_REG_SD_LVI) ] = { \
85049ab747fSPaolo Bonzini .stream = _i, \
85149ab747fSPaolo Bonzini .name = _t stringify(_i) " LVI", \
85249ab747fSPaolo Bonzini .size = 2, \
85349ab747fSPaolo Bonzini .wmask = 0x00ff, \
85449ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, st[_i].lvi), \
85549ab747fSPaolo Bonzini }, \
85649ab747fSPaolo Bonzini [ ST_REG(_i, ICH6_REG_SD_FIFOSIZE) ] = { \
85749ab747fSPaolo Bonzini .stream = _i, \
85849ab747fSPaolo Bonzini .name = _t stringify(_i) " FIFOS", \
85949ab747fSPaolo Bonzini .size = 2, \
86049ab747fSPaolo Bonzini .reset = HDA_BUFFER_SIZE, \
86149ab747fSPaolo Bonzini }, \
86249ab747fSPaolo Bonzini [ ST_REG(_i, ICH6_REG_SD_FORMAT) ] = { \
86349ab747fSPaolo Bonzini .stream = _i, \
86449ab747fSPaolo Bonzini .name = _t stringify(_i) " FMT", \
86549ab747fSPaolo Bonzini .size = 2, \
86649ab747fSPaolo Bonzini .wmask = 0x7f7f, \
86749ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, st[_i].fmt), \
86849ab747fSPaolo Bonzini }, \
86949ab747fSPaolo Bonzini [ ST_REG(_i, ICH6_REG_SD_BDLPL) ] = { \
87049ab747fSPaolo Bonzini .stream = _i, \
87149ab747fSPaolo Bonzini .name = _t stringify(_i) " BDLPL", \
87249ab747fSPaolo Bonzini .size = 4, \
87349ab747fSPaolo Bonzini .wmask = 0xffffff80, \
87449ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, st[_i].bdlp_lbase), \
87549ab747fSPaolo Bonzini }, \
87649ab747fSPaolo Bonzini [ ST_REG(_i, ICH6_REG_SD_BDLPU) ] = { \
87749ab747fSPaolo Bonzini .stream = _i, \
87849ab747fSPaolo Bonzini .name = _t stringify(_i) " BDLPU", \
87949ab747fSPaolo Bonzini .size = 4, \
88049ab747fSPaolo Bonzini .wmask = 0xffffffff, \
88149ab747fSPaolo Bonzini .offset = offsetof(IntelHDAState, st[_i].bdlp_ubase), \
88249ab747fSPaolo Bonzini }, \
88349ab747fSPaolo Bonzini
88449ab747fSPaolo Bonzini HDA_STREAM("IN", 0)
88549ab747fSPaolo Bonzini HDA_STREAM("IN", 1)
88649ab747fSPaolo Bonzini HDA_STREAM("IN", 2)
88749ab747fSPaolo Bonzini HDA_STREAM("IN", 3)
88849ab747fSPaolo Bonzini
88949ab747fSPaolo Bonzini HDA_STREAM("OUT", 4)
89049ab747fSPaolo Bonzini HDA_STREAM("OUT", 5)
89149ab747fSPaolo Bonzini HDA_STREAM("OUT", 6)
89249ab747fSPaolo Bonzini HDA_STREAM("OUT", 7)
89349ab747fSPaolo Bonzini
89449ab747fSPaolo Bonzini };
89549ab747fSPaolo Bonzini
intel_hda_reg_find(IntelHDAState * d,hwaddr addr)89649ab747fSPaolo Bonzini static const IntelHDAReg *intel_hda_reg_find(IntelHDAState *d, hwaddr addr)
89749ab747fSPaolo Bonzini {
89849ab747fSPaolo Bonzini const IntelHDAReg *reg;
89949ab747fSPaolo Bonzini
900dff7424dSStefan Weil if (addr >= ARRAY_SIZE(regtab)) {
90149ab747fSPaolo Bonzini goto noreg;
90249ab747fSPaolo Bonzini }
90349ab747fSPaolo Bonzini reg = regtab+addr;
90449ab747fSPaolo Bonzini if (reg->name == NULL) {
90549ab747fSPaolo Bonzini goto noreg;
90649ab747fSPaolo Bonzini }
90749ab747fSPaolo Bonzini return reg;
90849ab747fSPaolo Bonzini
90949ab747fSPaolo Bonzini noreg:
91049ab747fSPaolo Bonzini dprint(d, 1, "unknown register, addr 0x%x\n", (int) addr);
91149ab747fSPaolo Bonzini return NULL;
91249ab747fSPaolo Bonzini }
91349ab747fSPaolo Bonzini
intel_hda_reg_addr(IntelHDAState * d,const IntelHDAReg * reg)91449ab747fSPaolo Bonzini static uint32_t *intel_hda_reg_addr(IntelHDAState *d, const IntelHDAReg *reg)
91549ab747fSPaolo Bonzini {
91649ab747fSPaolo Bonzini uint8_t *addr = (void*)d;
91749ab747fSPaolo Bonzini
91849ab747fSPaolo Bonzini addr += reg->offset;
91949ab747fSPaolo Bonzini return (uint32_t*)addr;
92049ab747fSPaolo Bonzini }
92149ab747fSPaolo Bonzini
intel_hda_reg_write(IntelHDAState * d,const IntelHDAReg * reg,uint32_t val,uint32_t wmask)92249ab747fSPaolo Bonzini static void intel_hda_reg_write(IntelHDAState *d, const IntelHDAReg *reg, uint32_t val,
92349ab747fSPaolo Bonzini uint32_t wmask)
92449ab747fSPaolo Bonzini {
92549ab747fSPaolo Bonzini uint32_t *addr;
92649ab747fSPaolo Bonzini uint32_t old;
92749ab747fSPaolo Bonzini
92849ab747fSPaolo Bonzini if (!reg) {
92949ab747fSPaolo Bonzini return;
93049ab747fSPaolo Bonzini }
9317ec91067SGerd Hoffmann if (!reg->wmask) {
9327ec91067SGerd Hoffmann qemu_log_mask(LOG_GUEST_ERROR, "intel-hda: write to r/o reg %s\n",
9337ec91067SGerd Hoffmann reg->name);
9347ec91067SGerd Hoffmann return;
9357ec91067SGerd Hoffmann }
93649ab747fSPaolo Bonzini
93749ab747fSPaolo Bonzini if (d->debug) {
93849ab747fSPaolo Bonzini time_t now = time(NULL);
93949ab747fSPaolo Bonzini if (d->last_write && d->last_reg == reg && d->last_val == val) {
94049ab747fSPaolo Bonzini d->repeat_count++;
94149ab747fSPaolo Bonzini if (d->last_sec != now) {
94249ab747fSPaolo Bonzini dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
94349ab747fSPaolo Bonzini d->last_sec = now;
94449ab747fSPaolo Bonzini d->repeat_count = 0;
94549ab747fSPaolo Bonzini }
94649ab747fSPaolo Bonzini } else {
94749ab747fSPaolo Bonzini if (d->repeat_count) {
94849ab747fSPaolo Bonzini dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
94949ab747fSPaolo Bonzini }
95049ab747fSPaolo Bonzini dprint(d, 2, "write %-16s: 0x%x (%x)\n", reg->name, val, wmask);
95149ab747fSPaolo Bonzini d->last_write = 1;
95249ab747fSPaolo Bonzini d->last_reg = reg;
95349ab747fSPaolo Bonzini d->last_val = val;
95449ab747fSPaolo Bonzini d->last_sec = now;
95549ab747fSPaolo Bonzini d->repeat_count = 0;
95649ab747fSPaolo Bonzini }
95749ab747fSPaolo Bonzini }
95849ab747fSPaolo Bonzini assert(reg->offset != 0);
95949ab747fSPaolo Bonzini
96049ab747fSPaolo Bonzini addr = intel_hda_reg_addr(d, reg);
96149ab747fSPaolo Bonzini old = *addr;
96249ab747fSPaolo Bonzini
96349ab747fSPaolo Bonzini if (reg->shift) {
96449ab747fSPaolo Bonzini val <<= reg->shift;
96549ab747fSPaolo Bonzini wmask <<= reg->shift;
96649ab747fSPaolo Bonzini }
96749ab747fSPaolo Bonzini wmask &= reg->wmask;
96849ab747fSPaolo Bonzini *addr &= ~wmask;
96949ab747fSPaolo Bonzini *addr |= wmask & val;
97049ab747fSPaolo Bonzini *addr &= ~(val & reg->wclear);
97149ab747fSPaolo Bonzini
97249ab747fSPaolo Bonzini if (reg->whandler) {
97349ab747fSPaolo Bonzini reg->whandler(d, reg, old);
97449ab747fSPaolo Bonzini }
97549ab747fSPaolo Bonzini }
97649ab747fSPaolo Bonzini
intel_hda_reg_read(IntelHDAState * d,const IntelHDAReg * reg,uint32_t rmask)97749ab747fSPaolo Bonzini static uint32_t intel_hda_reg_read(IntelHDAState *d, const IntelHDAReg *reg,
97849ab747fSPaolo Bonzini uint32_t rmask)
97949ab747fSPaolo Bonzini {
98049ab747fSPaolo Bonzini uint32_t *addr, ret;
98149ab747fSPaolo Bonzini
98249ab747fSPaolo Bonzini if (!reg) {
98349ab747fSPaolo Bonzini return 0;
98449ab747fSPaolo Bonzini }
98549ab747fSPaolo Bonzini
98649ab747fSPaolo Bonzini if (reg->rhandler) {
98749ab747fSPaolo Bonzini reg->rhandler(d, reg);
98849ab747fSPaolo Bonzini }
98949ab747fSPaolo Bonzini
99049ab747fSPaolo Bonzini if (reg->offset == 0) {
99149ab747fSPaolo Bonzini /* constant read-only register */
99249ab747fSPaolo Bonzini ret = reg->reset;
99349ab747fSPaolo Bonzini } else {
99449ab747fSPaolo Bonzini addr = intel_hda_reg_addr(d, reg);
99549ab747fSPaolo Bonzini ret = *addr;
99649ab747fSPaolo Bonzini if (reg->shift) {
99749ab747fSPaolo Bonzini ret >>= reg->shift;
99849ab747fSPaolo Bonzini }
99949ab747fSPaolo Bonzini ret &= rmask;
100049ab747fSPaolo Bonzini }
100149ab747fSPaolo Bonzini if (d->debug) {
100249ab747fSPaolo Bonzini time_t now = time(NULL);
100349ab747fSPaolo Bonzini if (!d->last_write && d->last_reg == reg && d->last_val == ret) {
100449ab747fSPaolo Bonzini d->repeat_count++;
100549ab747fSPaolo Bonzini if (d->last_sec != now) {
100649ab747fSPaolo Bonzini dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
100749ab747fSPaolo Bonzini d->last_sec = now;
100849ab747fSPaolo Bonzini d->repeat_count = 0;
100949ab747fSPaolo Bonzini }
101049ab747fSPaolo Bonzini } else {
101149ab747fSPaolo Bonzini if (d->repeat_count) {
101249ab747fSPaolo Bonzini dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
101349ab747fSPaolo Bonzini }
101449ab747fSPaolo Bonzini dprint(d, 2, "read %-16s: 0x%x (%x)\n", reg->name, ret, rmask);
101549ab747fSPaolo Bonzini d->last_write = 0;
101649ab747fSPaolo Bonzini d->last_reg = reg;
101749ab747fSPaolo Bonzini d->last_val = ret;
101849ab747fSPaolo Bonzini d->last_sec = now;
101949ab747fSPaolo Bonzini d->repeat_count = 0;
102049ab747fSPaolo Bonzini }
102149ab747fSPaolo Bonzini }
102249ab747fSPaolo Bonzini return ret;
102349ab747fSPaolo Bonzini }
102449ab747fSPaolo Bonzini
intel_hda_regs_reset(IntelHDAState * d)102549ab747fSPaolo Bonzini static void intel_hda_regs_reset(IntelHDAState *d)
102649ab747fSPaolo Bonzini {
102749ab747fSPaolo Bonzini uint32_t *addr;
102849ab747fSPaolo Bonzini int i;
102949ab747fSPaolo Bonzini
1030dff7424dSStefan Weil for (i = 0; i < ARRAY_SIZE(regtab); i++) {
103149ab747fSPaolo Bonzini if (regtab[i].name == NULL) {
103249ab747fSPaolo Bonzini continue;
103349ab747fSPaolo Bonzini }
103449ab747fSPaolo Bonzini if (regtab[i].offset == 0) {
103549ab747fSPaolo Bonzini continue;
103649ab747fSPaolo Bonzini }
103749ab747fSPaolo Bonzini addr = intel_hda_reg_addr(d, regtab + i);
103849ab747fSPaolo Bonzini *addr = regtab[i].reset;
103949ab747fSPaolo Bonzini }
104049ab747fSPaolo Bonzini }
104149ab747fSPaolo Bonzini
104249ab747fSPaolo Bonzini /* --------------------------------------------------------------------- */
104349ab747fSPaolo Bonzini
intel_hda_mmio_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)1044a6b0bdc8SMatt Parker static void intel_hda_mmio_write(void *opaque, hwaddr addr, uint64_t val,
1045a6b0bdc8SMatt Parker unsigned size)
104649ab747fSPaolo Bonzini {
104749ab747fSPaolo Bonzini IntelHDAState *d = opaque;
104849ab747fSPaolo Bonzini const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
104949ab747fSPaolo Bonzini
1050a6b0bdc8SMatt Parker intel_hda_reg_write(d, reg, val, MAKE_64BIT_MASK(0, size * 8));
105149ab747fSPaolo Bonzini }
105249ab747fSPaolo Bonzini
intel_hda_mmio_read(void * opaque,hwaddr addr,unsigned size)1053a6b0bdc8SMatt Parker static uint64_t intel_hda_mmio_read(void *opaque, hwaddr addr, unsigned size)
105449ab747fSPaolo Bonzini {
105549ab747fSPaolo Bonzini IntelHDAState *d = opaque;
105649ab747fSPaolo Bonzini const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
105749ab747fSPaolo Bonzini
1058a6b0bdc8SMatt Parker return intel_hda_reg_read(d, reg, MAKE_64BIT_MASK(0, size * 8));
105949ab747fSPaolo Bonzini }
106049ab747fSPaolo Bonzini
106149ab747fSPaolo Bonzini static const MemoryRegionOps intel_hda_mmio_ops = {
1062a6b0bdc8SMatt Parker .read = intel_hda_mmio_read,
1063a6b0bdc8SMatt Parker .write = intel_hda_mmio_write,
1064a6b0bdc8SMatt Parker .impl = {
1065a6b0bdc8SMatt Parker .min_access_size = 1,
1066a6b0bdc8SMatt Parker .max_access_size = 4,
106749ab747fSPaolo Bonzini },
106849ab747fSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
106949ab747fSPaolo Bonzini };
107049ab747fSPaolo Bonzini
107149ab747fSPaolo Bonzini /* --------------------------------------------------------------------- */
107249ab747fSPaolo Bonzini
intel_hda_reset(DeviceState * dev)107349ab747fSPaolo Bonzini static void intel_hda_reset(DeviceState *dev)
107449ab747fSPaolo Bonzini {
107549ab747fSPaolo Bonzini BusChild *kid;
107652bb7c6aSPeter Crosthwaite IntelHDAState *d = INTEL_HDA(dev);
107749ab747fSPaolo Bonzini HDACodecDevice *cdev;
107849ab747fSPaolo Bonzini
107949ab747fSPaolo Bonzini intel_hda_regs_reset(d);
1080bc72ad67SAlex Bligh d->wall_base_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
108149ab747fSPaolo Bonzini
108249ab747fSPaolo Bonzini QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
108349ab747fSPaolo Bonzini DeviceState *qdev = kid->child;
1084e19202afSxiaoqiang zhao cdev = HDA_CODEC_DEVICE(qdev);
108549ab747fSPaolo Bonzini d->state_sts |= (1 << cdev->cad);
108649ab747fSPaolo Bonzini }
108749ab747fSPaolo Bonzini intel_hda_update_irq(d);
108849ab747fSPaolo Bonzini }
108949ab747fSPaolo Bonzini
intel_hda_realize(PCIDevice * pci,Error ** errp)10909af21dbeSMarkus Armbruster static void intel_hda_realize(PCIDevice *pci, Error **errp)
109149ab747fSPaolo Bonzini {
109252bb7c6aSPeter Crosthwaite IntelHDAState *d = INTEL_HDA(pci);
109349ab747fSPaolo Bonzini uint8_t *conf = d->pci.config;
10941108b2f8SCao jin Error *err = NULL;
10951108b2f8SCao jin int ret;
109649ab747fSPaolo Bonzini
109749ab747fSPaolo Bonzini d->name = object_get_typename(OBJECT(d));
109849ab747fSPaolo Bonzini
109949ab747fSPaolo Bonzini pci_config_set_interrupt_pin(conf, 1);
110049ab747fSPaolo Bonzini
110149ab747fSPaolo Bonzini /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
110249ab747fSPaolo Bonzini conf[0x40] = 0x01;
110349ab747fSPaolo Bonzini
11041108b2f8SCao jin if (d->msi != ON_OFF_AUTO_OFF) {
11051108b2f8SCao jin ret = msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60,
11061108b2f8SCao jin 1, true, false, &err);
11071108b2f8SCao jin /* Any error other than -ENOTSUP(board's MSI support is broken)
11081108b2f8SCao jin * is a programming error */
11091108b2f8SCao jin assert(!ret || ret == -ENOTSUP);
11101108b2f8SCao jin if (ret && d->msi == ON_OFF_AUTO_ON) {
11111108b2f8SCao jin /* Can't satisfy user's explicit msi=on request, fail */
11121108b2f8SCao jin error_append_hint(&err, "You have to use msi=auto (default) or "
11131108b2f8SCao jin "msi=off with this machine type.\n");
11141108b2f8SCao jin error_propagate(errp, err);
11151108b2f8SCao jin return;
11161108b2f8SCao jin }
11171108b2f8SCao jin assert(!err || d->msi == ON_OFF_AUTO_AUTO);
11181108b2f8SCao jin /* With msi=auto, we fall back to MSI off silently */
11191108b2f8SCao jin error_free(err);
11201108b2f8SCao jin }
11211108b2f8SCao jin
1122a9d8ba2bSPhilippe Mathieu-Daudé memory_region_init(&d->container, OBJECT(d),
1123a9d8ba2bSPhilippe Mathieu-Daudé "intel-hda-container", 0x4000);
112464bde0f3SPaolo Bonzini memory_region_init_io(&d->mmio, OBJECT(d), &intel_hda_mmio_ops, d,
1125a9d8ba2bSPhilippe Mathieu-Daudé "intel-hda", 0x2000);
1126a9d8ba2bSPhilippe Mathieu-Daudé memory_region_add_subregion(&d->container, 0x0000, &d->mmio);
1127a9d8ba2bSPhilippe Mathieu-Daudé memory_region_init_alias(&d->alias, OBJECT(d), "intel-hda-alias",
1128a9d8ba2bSPhilippe Mathieu-Daudé &d->mmio, 0, 0x2000);
1129a9d8ba2bSPhilippe Mathieu-Daudé memory_region_add_subregion(&d->container, 0x2000, &d->alias);
1130a9d8ba2bSPhilippe Mathieu-Daudé pci_register_bar(&d->pci, 0, 0, &d->container);
113149ab747fSPaolo Bonzini
1132ab809e84SAndreas Färber hda_codec_bus_init(DEVICE(pci), &d->codecs, sizeof(d->codecs),
113349ab747fSPaolo Bonzini intel_hda_response, intel_hda_xfer);
113449ab747fSPaolo Bonzini }
113549ab747fSPaolo Bonzini
intel_hda_exit(PCIDevice * pci)113649ab747fSPaolo Bonzini static void intel_hda_exit(PCIDevice *pci)
113749ab747fSPaolo Bonzini {
113852bb7c6aSPeter Crosthwaite IntelHDAState *d = INTEL_HDA(pci);
113949ab747fSPaolo Bonzini
114049ab747fSPaolo Bonzini msi_uninit(&d->pci);
114149ab747fSPaolo Bonzini }
114249ab747fSPaolo Bonzini
intel_hda_post_load(void * opaque,int version)114349ab747fSPaolo Bonzini static int intel_hda_post_load(void *opaque, int version)
114449ab747fSPaolo Bonzini {
114549ab747fSPaolo Bonzini IntelHDAState* d = opaque;
114649ab747fSPaolo Bonzini int i;
114749ab747fSPaolo Bonzini
1148a89f364aSAlistair Francis dprint(d, 1, "%s\n", __func__);
114949ab747fSPaolo Bonzini for (i = 0; i < ARRAY_SIZE(d->st); i++) {
115049ab747fSPaolo Bonzini if (d->st[i].ctl & 0x02) {
115149ab747fSPaolo Bonzini intel_hda_parse_bdl(d, &d->st[i]);
115249ab747fSPaolo Bonzini }
115349ab747fSPaolo Bonzini }
115449ab747fSPaolo Bonzini intel_hda_update_irq(d);
115549ab747fSPaolo Bonzini return 0;
115649ab747fSPaolo Bonzini }
115749ab747fSPaolo Bonzini
115849ab747fSPaolo Bonzini static const VMStateDescription vmstate_intel_hda_stream = {
115949ab747fSPaolo Bonzini .name = "intel-hda-stream",
116049ab747fSPaolo Bonzini .version_id = 1,
1161856a6fe4SRichard Henderson .fields = (const VMStateField[]) {
116249ab747fSPaolo Bonzini VMSTATE_UINT32(ctl, IntelHDAStream),
116349ab747fSPaolo Bonzini VMSTATE_UINT32(lpib, IntelHDAStream),
116449ab747fSPaolo Bonzini VMSTATE_UINT32(cbl, IntelHDAStream),
116549ab747fSPaolo Bonzini VMSTATE_UINT32(lvi, IntelHDAStream),
116649ab747fSPaolo Bonzini VMSTATE_UINT32(fmt, IntelHDAStream),
116749ab747fSPaolo Bonzini VMSTATE_UINT32(bdlp_lbase, IntelHDAStream),
116849ab747fSPaolo Bonzini VMSTATE_UINT32(bdlp_ubase, IntelHDAStream),
116949ab747fSPaolo Bonzini VMSTATE_END_OF_LIST()
117049ab747fSPaolo Bonzini }
117149ab747fSPaolo Bonzini };
117249ab747fSPaolo Bonzini
117349ab747fSPaolo Bonzini static const VMStateDescription vmstate_intel_hda = {
117449ab747fSPaolo Bonzini .name = "intel-hda",
117549ab747fSPaolo Bonzini .version_id = 1,
117649ab747fSPaolo Bonzini .post_load = intel_hda_post_load,
1177856a6fe4SRichard Henderson .fields = (const VMStateField[]) {
117849ab747fSPaolo Bonzini VMSTATE_PCI_DEVICE(pci, IntelHDAState),
117949ab747fSPaolo Bonzini
118049ab747fSPaolo Bonzini /* registers */
118149ab747fSPaolo Bonzini VMSTATE_UINT32(g_ctl, IntelHDAState),
118249ab747fSPaolo Bonzini VMSTATE_UINT32(wake_en, IntelHDAState),
118349ab747fSPaolo Bonzini VMSTATE_UINT32(state_sts, IntelHDAState),
118449ab747fSPaolo Bonzini VMSTATE_UINT32(int_ctl, IntelHDAState),
118549ab747fSPaolo Bonzini VMSTATE_UINT32(int_sts, IntelHDAState),
118649ab747fSPaolo Bonzini VMSTATE_UINT32(wall_clk, IntelHDAState),
118749ab747fSPaolo Bonzini VMSTATE_UINT32(corb_lbase, IntelHDAState),
118849ab747fSPaolo Bonzini VMSTATE_UINT32(corb_ubase, IntelHDAState),
118949ab747fSPaolo Bonzini VMSTATE_UINT32(corb_rp, IntelHDAState),
119049ab747fSPaolo Bonzini VMSTATE_UINT32(corb_wp, IntelHDAState),
119149ab747fSPaolo Bonzini VMSTATE_UINT32(corb_ctl, IntelHDAState),
119249ab747fSPaolo Bonzini VMSTATE_UINT32(corb_sts, IntelHDAState),
119349ab747fSPaolo Bonzini VMSTATE_UINT32(corb_size, IntelHDAState),
119449ab747fSPaolo Bonzini VMSTATE_UINT32(rirb_lbase, IntelHDAState),
119549ab747fSPaolo Bonzini VMSTATE_UINT32(rirb_ubase, IntelHDAState),
119649ab747fSPaolo Bonzini VMSTATE_UINT32(rirb_wp, IntelHDAState),
119749ab747fSPaolo Bonzini VMSTATE_UINT32(rirb_cnt, IntelHDAState),
119849ab747fSPaolo Bonzini VMSTATE_UINT32(rirb_ctl, IntelHDAState),
119949ab747fSPaolo Bonzini VMSTATE_UINT32(rirb_sts, IntelHDAState),
120049ab747fSPaolo Bonzini VMSTATE_UINT32(rirb_size, IntelHDAState),
120149ab747fSPaolo Bonzini VMSTATE_UINT32(dp_lbase, IntelHDAState),
120249ab747fSPaolo Bonzini VMSTATE_UINT32(dp_ubase, IntelHDAState),
120349ab747fSPaolo Bonzini VMSTATE_UINT32(icw, IntelHDAState),
120449ab747fSPaolo Bonzini VMSTATE_UINT32(irr, IntelHDAState),
120549ab747fSPaolo Bonzini VMSTATE_UINT32(ics, IntelHDAState),
120649ab747fSPaolo Bonzini VMSTATE_STRUCT_ARRAY(st, IntelHDAState, 8, 0,
120749ab747fSPaolo Bonzini vmstate_intel_hda_stream,
120849ab747fSPaolo Bonzini IntelHDAStream),
120949ab747fSPaolo Bonzini
121049ab747fSPaolo Bonzini /* additional state info */
121149ab747fSPaolo Bonzini VMSTATE_UINT32(rirb_count, IntelHDAState),
121249ab747fSPaolo Bonzini VMSTATE_INT64(wall_base_ns, IntelHDAState),
121349ab747fSPaolo Bonzini
121449ab747fSPaolo Bonzini VMSTATE_END_OF_LIST()
121549ab747fSPaolo Bonzini }
121649ab747fSPaolo Bonzini };
121749ab747fSPaolo Bonzini
121849ab747fSPaolo Bonzini static Property intel_hda_properties[] = {
121949ab747fSPaolo Bonzini DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
1220c0f2abffSCao jin DEFINE_PROP_ON_OFF_AUTO("msi", IntelHDAState, msi, ON_OFF_AUTO_AUTO),
1221d209c744SJan Kiszka DEFINE_PROP_BOOL("old_msi_addr", IntelHDAState, old_msi_addr, false),
122249ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
122349ab747fSPaolo Bonzini };
122449ab747fSPaolo Bonzini
intel_hda_class_init(ObjectClass * klass,void * data)1225062db740SPeter Crosthwaite static void intel_hda_class_init(ObjectClass *klass, void *data)
122649ab747fSPaolo Bonzini {
122749ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
122849ab747fSPaolo Bonzini PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
122949ab747fSPaolo Bonzini
12309af21dbeSMarkus Armbruster k->realize = intel_hda_realize;
123149ab747fSPaolo Bonzini k->exit = intel_hda_exit;
123249ab747fSPaolo Bonzini k->vendor_id = PCI_VENDOR_ID_INTEL;
123349ab747fSPaolo Bonzini k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO;
1234*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, intel_hda_reset);
123549ab747fSPaolo Bonzini dc->vmsd = &vmstate_intel_hda;
12364f67d30bSMarc-André Lureau device_class_set_props(dc, intel_hda_properties);
123749ab747fSPaolo Bonzini }
123849ab747fSPaolo Bonzini
intel_hda_class_init_ich6(ObjectClass * klass,void * data)123949ab747fSPaolo Bonzini static void intel_hda_class_init_ich6(ObjectClass *klass, void *data)
124049ab747fSPaolo Bonzini {
124149ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
124249ab747fSPaolo Bonzini PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
124349ab747fSPaolo Bonzini
124449ab747fSPaolo Bonzini k->device_id = 0x2668;
124549ab747fSPaolo Bonzini k->revision = 1;
1246125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
124749ab747fSPaolo Bonzini dc->desc = "Intel HD Audio Controller (ich6)";
124849ab747fSPaolo Bonzini }
124949ab747fSPaolo Bonzini
intel_hda_class_init_ich9(ObjectClass * klass,void * data)125049ab747fSPaolo Bonzini static void intel_hda_class_init_ich9(ObjectClass *klass, void *data)
125149ab747fSPaolo Bonzini {
125249ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
125349ab747fSPaolo Bonzini PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
125449ab747fSPaolo Bonzini
125549ab747fSPaolo Bonzini k->device_id = 0x293e;
125649ab747fSPaolo Bonzini k->revision = 3;
1257125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
125849ab747fSPaolo Bonzini dc->desc = "Intel HD Audio Controller (ich9)";
125949ab747fSPaolo Bonzini }
126049ab747fSPaolo Bonzini
1261062db740SPeter Crosthwaite static const TypeInfo intel_hda_info = {
1262062db740SPeter Crosthwaite .name = TYPE_INTEL_HDA_GENERIC,
126349ab747fSPaolo Bonzini .parent = TYPE_PCI_DEVICE,
126449ab747fSPaolo Bonzini .instance_size = sizeof(IntelHDAState),
1265062db740SPeter Crosthwaite .class_init = intel_hda_class_init,
1266062db740SPeter Crosthwaite .abstract = true,
1267fd3b02c8SEduardo Habkost .interfaces = (InterfaceInfo[]) {
1268fd3b02c8SEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE },
1269fd3b02c8SEduardo Habkost { },
1270fd3b02c8SEduardo Habkost },
1271062db740SPeter Crosthwaite };
1272062db740SPeter Crosthwaite
1273062db740SPeter Crosthwaite static const TypeInfo intel_hda_info_ich6 = {
1274062db740SPeter Crosthwaite .name = "intel-hda",
1275062db740SPeter Crosthwaite .parent = TYPE_INTEL_HDA_GENERIC,
127649ab747fSPaolo Bonzini .class_init = intel_hda_class_init_ich6,
127749ab747fSPaolo Bonzini };
127849ab747fSPaolo Bonzini
127949ab747fSPaolo Bonzini static const TypeInfo intel_hda_info_ich9 = {
128049ab747fSPaolo Bonzini .name = "ich9-intel-hda",
1281062db740SPeter Crosthwaite .parent = TYPE_INTEL_HDA_GENERIC,
128249ab747fSPaolo Bonzini .class_init = intel_hda_class_init_ich9,
128349ab747fSPaolo Bonzini };
128449ab747fSPaolo Bonzini
hda_codec_device_class_init(ObjectClass * klass,void * data)128549ab747fSPaolo Bonzini static void hda_codec_device_class_init(ObjectClass *klass, void *data)
128649ab747fSPaolo Bonzini {
128749ab747fSPaolo Bonzini DeviceClass *k = DEVICE_CLASS(klass);
1288bda8d9b8Sxiaoqiang zhao k->realize = hda_codec_dev_realize;
12898ac55351SZihan Yang k->unrealize = hda_codec_dev_unrealize;
1290125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_SOUND, k->categories);
129149ab747fSPaolo Bonzini k->bus_type = TYPE_HDA_BUS;
12924f67d30bSMarc-André Lureau device_class_set_props(k, hda_props);
129349ab747fSPaolo Bonzini }
129449ab747fSPaolo Bonzini
129549ab747fSPaolo Bonzini static const TypeInfo hda_codec_device_type_info = {
129649ab747fSPaolo Bonzini .name = TYPE_HDA_CODEC_DEVICE,
129749ab747fSPaolo Bonzini .parent = TYPE_DEVICE,
129849ab747fSPaolo Bonzini .instance_size = sizeof(HDACodecDevice),
129949ab747fSPaolo Bonzini .abstract = true,
130049ab747fSPaolo Bonzini .class_size = sizeof(HDACodecDeviceClass),
130149ab747fSPaolo Bonzini .class_init = hda_codec_device_class_init,
130249ab747fSPaolo Bonzini };
130349ab747fSPaolo Bonzini
130449ab747fSPaolo Bonzini /*
130549ab747fSPaolo Bonzini * create intel hda controller with codec attached to it,
130649ab747fSPaolo Bonzini * so '-soundhw hda' works.
130749ab747fSPaolo Bonzini */
intel_hda_and_codec_init(PCIBus * bus,const char * audiodev)1308039a6837SPaolo Bonzini static int intel_hda_and_codec_init(PCIBus *bus, const char *audiodev)
130949ab747fSPaolo Bonzini {
131052bb7c6aSPeter Crosthwaite DeviceState *controller;
131149ab747fSPaolo Bonzini BusState *hdabus;
131249ab747fSPaolo Bonzini DeviceState *codec;
131349ab747fSPaolo Bonzini
131452bb7c6aSPeter Crosthwaite controller = DEVICE(pci_create_simple(bus, -1, "intel-hda"));
131552bb7c6aSPeter Crosthwaite hdabus = QLIST_FIRST(&controller->child_bus);
13163e80f690SMarkus Armbruster codec = qdev_new("hda-duplex");
1317039a6837SPaolo Bonzini qdev_prop_set_string(codec, "audiodev", audiodev);
13183e80f690SMarkus Armbruster qdev_realize_and_unref(codec, hdabus, &error_fatal);
131949ab747fSPaolo Bonzini return 0;
132049ab747fSPaolo Bonzini }
132149ab747fSPaolo Bonzini
intel_hda_register_types(void)132236cd6f6fSPaolo Bonzini static void intel_hda_register_types(void)
132336cd6f6fSPaolo Bonzini {
132436cd6f6fSPaolo Bonzini type_register_static(&hda_codec_bus_info);
1325062db740SPeter Crosthwaite type_register_static(&intel_hda_info);
132636cd6f6fSPaolo Bonzini type_register_static(&intel_hda_info_ich6);
132736cd6f6fSPaolo Bonzini type_register_static(&intel_hda_info_ich9);
132836cd6f6fSPaolo Bonzini type_register_static(&hda_codec_device_type_info);
132936cd6f6fSPaolo Bonzini pci_register_soundhw("hda", "Intel HD Audio", intel_hda_and_codec_init);
133036cd6f6fSPaolo Bonzini }
133136cd6f6fSPaolo Bonzini
133236cd6f6fSPaolo Bonzini type_init(intel_hda_register_types)
1333