184659b24SMichael Zeller /*- 284659b24SMichael Zeller * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 384659b24SMichael Zeller * 484659b24SMichael Zeller * Copyright (c) 2016 Alex Teaca <iateaca@FreeBSD.org> 584659b24SMichael Zeller * All rights reserved. 684659b24SMichael Zeller * 784659b24SMichael Zeller * Redistribution and use in source and binary forms, with or without 884659b24SMichael Zeller * modification, are permitted provided that the following conditions 984659b24SMichael Zeller * are met: 1084659b24SMichael Zeller * 1. Redistributions of source code must retain the above copyright 1184659b24SMichael Zeller * notice, this list of conditions and the following disclaimer. 1284659b24SMichael Zeller * 2. Redistributions in binary form must reproduce the above copyright 1384659b24SMichael Zeller * notice, this list of conditions and the following disclaimer in the 1484659b24SMichael Zeller * documentation and/or other materials provided with the distribution. 1584659b24SMichael Zeller * 1684659b24SMichael Zeller * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 1784659b24SMichael Zeller * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1884659b24SMichael Zeller * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1984659b24SMichael Zeller * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2084659b24SMichael Zeller * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2184659b24SMichael Zeller * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2284659b24SMichael Zeller * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2384659b24SMichael Zeller * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2484659b24SMichael Zeller * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2584659b24SMichael Zeller * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2684659b24SMichael Zeller * SUCH DAMAGE. 2784659b24SMichael Zeller * 2884659b24SMichael Zeller */ 2984659b24SMichael Zeller 3084659b24SMichael Zeller #include <sys/cdefs.h> 3184659b24SMichael Zeller __FBSDID("$FreeBSD$"); 3284659b24SMichael Zeller 3384659b24SMichael Zeller #include <time.h> 3484659b24SMichael Zeller 3584659b24SMichael Zeller #include "pci_hda.h" 3684659b24SMichael Zeller #include "bhyverun.h" 372b948146SAndy Fiddaman #include "config.h" 3884659b24SMichael Zeller #include "pci_emul.h" 3984659b24SMichael Zeller #include "hdac_reg.h" 4084659b24SMichael Zeller 4184659b24SMichael Zeller /* 4284659b24SMichael Zeller * HDA defines 4384659b24SMichael Zeller */ 4484659b24SMichael Zeller #define PCIR_HDCTL 0x40 4584659b24SMichael Zeller #define INTEL_VENDORID 0x8086 4684659b24SMichael Zeller #define HDA_INTEL_82801G 0x27d8 4784659b24SMichael Zeller 4884659b24SMichael Zeller #define HDA_IOSS_NO 0x08 4984659b24SMichael Zeller #define HDA_OSS_NO 0x04 5084659b24SMichael Zeller #define HDA_ISS_NO 0x04 5184659b24SMichael Zeller #define HDA_CODEC_MAX 0x0f 5284659b24SMichael Zeller #define HDA_LAST_OFFSET \ 5384659b24SMichael Zeller (0x2084 + ((HDA_ISS_NO) * 0x20) + ((HDA_OSS_NO) * 0x20)) 5484659b24SMichael Zeller #define HDA_SET_REG_TABLE_SZ \ 5584659b24SMichael Zeller (0x80 + ((HDA_ISS_NO) * 0x20) + ((HDA_OSS_NO) * 0x20)) 5684659b24SMichael Zeller #define HDA_CORB_ENTRY_LEN 0x04 5784659b24SMichael Zeller #define HDA_RIRB_ENTRY_LEN 0x08 5884659b24SMichael Zeller #define HDA_BDL_ENTRY_LEN 0x10 5984659b24SMichael Zeller #define HDA_DMA_PIB_ENTRY_LEN 0x08 6084659b24SMichael Zeller #define HDA_STREAM_TAGS_CNT 0x10 6184659b24SMichael Zeller #define HDA_STREAM_REGS_BASE 0x80 6284659b24SMichael Zeller #define HDA_STREAM_REGS_LEN 0x20 6384659b24SMichael Zeller 6484659b24SMichael Zeller #define HDA_DMA_ACCESS_LEN (sizeof(uint32_t)) 6584659b24SMichael Zeller #define HDA_BDL_MAX_LEN 0x0100 6684659b24SMichael Zeller 6784659b24SMichael Zeller #define HDAC_SDSTS_FIFORDY (1 << 5) 6884659b24SMichael Zeller 6984659b24SMichael Zeller #define HDA_RIRBSTS_IRQ_MASK (HDAC_RIRBSTS_RINTFL | HDAC_RIRBSTS_RIRBOIS) 7084659b24SMichael Zeller #define HDA_STATESTS_IRQ_MASK ((1 << HDA_CODEC_MAX) - 1) 7184659b24SMichael Zeller #define HDA_SDSTS_IRQ_MASK \ 7284659b24SMichael Zeller (HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS) 7384659b24SMichael Zeller 7484659b24SMichael Zeller /* 7584659b24SMichael Zeller * HDA data structures 7684659b24SMichael Zeller */ 7784659b24SMichael Zeller 7884659b24SMichael Zeller struct hda_softc; 7984659b24SMichael Zeller 8084659b24SMichael Zeller typedef void (*hda_set_reg_handler)(struct hda_softc *sc, uint32_t offset, 8184659b24SMichael Zeller uint32_t old); 8284659b24SMichael Zeller 8384659b24SMichael Zeller struct hda_bdle { 8484659b24SMichael Zeller uint32_t addrl; 8584659b24SMichael Zeller uint32_t addrh; 8684659b24SMichael Zeller uint32_t len; 8784659b24SMichael Zeller uint32_t ioc; 8884659b24SMichael Zeller } __packed; 8984659b24SMichael Zeller 9084659b24SMichael Zeller struct hda_bdle_desc { 9184659b24SMichael Zeller void *addr; 9284659b24SMichael Zeller uint8_t ioc; 9384659b24SMichael Zeller uint32_t len; 9484659b24SMichael Zeller }; 9584659b24SMichael Zeller 9684659b24SMichael Zeller struct hda_codec_cmd_ctl { 974f3f3e9aSAndy Fiddaman const char *name; 9884659b24SMichael Zeller void *dma_vaddr; 9984659b24SMichael Zeller uint8_t run; 10084659b24SMichael Zeller uint16_t rp; 10184659b24SMichael Zeller uint16_t size; 10284659b24SMichael Zeller uint16_t wp; 10384659b24SMichael Zeller }; 10484659b24SMichael Zeller 10584659b24SMichael Zeller struct hda_stream_desc { 10684659b24SMichael Zeller uint8_t dir; 10784659b24SMichael Zeller uint8_t run; 10884659b24SMichael Zeller uint8_t stream; 10984659b24SMichael Zeller 11084659b24SMichael Zeller /* bp is the no. of bytes transferred in the current bdle */ 11184659b24SMichael Zeller uint32_t bp; 11284659b24SMichael Zeller /* be is the no. of bdles transferred in the bdl */ 11384659b24SMichael Zeller uint32_t be; 11484659b24SMichael Zeller 11584659b24SMichael Zeller uint32_t bdl_cnt; 11684659b24SMichael Zeller struct hda_bdle_desc bdl[HDA_BDL_MAX_LEN]; 11784659b24SMichael Zeller }; 11884659b24SMichael Zeller 11984659b24SMichael Zeller struct hda_softc { 12084659b24SMichael Zeller struct pci_devinst *pci_dev; 12184659b24SMichael Zeller uint32_t regs[HDA_LAST_OFFSET]; 12284659b24SMichael Zeller 12384659b24SMichael Zeller uint8_t lintr; 12484659b24SMichael Zeller uint8_t rirb_cnt; 12584659b24SMichael Zeller uint64_t wall_clock_start; 12684659b24SMichael Zeller 12784659b24SMichael Zeller struct hda_codec_cmd_ctl corb; 12884659b24SMichael Zeller struct hda_codec_cmd_ctl rirb; 12984659b24SMichael Zeller 13084659b24SMichael Zeller uint8_t codecs_no; 13184659b24SMichael Zeller struct hda_codec_inst *codecs[HDA_CODEC_MAX]; 13284659b24SMichael Zeller 13384659b24SMichael Zeller /* Base Address of the DMA Position Buffer */ 13484659b24SMichael Zeller void *dma_pib_vaddr; 13584659b24SMichael Zeller 13684659b24SMichael Zeller struct hda_stream_desc streams[HDA_IOSS_NO]; 13784659b24SMichael Zeller /* 2 tables for output and input */ 13884659b24SMichael Zeller uint8_t stream_map[2][HDA_STREAM_TAGS_CNT]; 13984659b24SMichael Zeller }; 14084659b24SMichael Zeller 14184659b24SMichael Zeller /* 14284659b24SMichael Zeller * HDA module function declarations 14384659b24SMichael Zeller */ 14484659b24SMichael Zeller static inline void hda_set_reg_by_offset(struct hda_softc *sc, uint32_t offset, 14584659b24SMichael Zeller uint32_t value); 14684659b24SMichael Zeller static inline uint32_t hda_get_reg_by_offset(struct hda_softc *sc, 14784659b24SMichael Zeller uint32_t offset); 14884659b24SMichael Zeller static inline void hda_set_field_by_offset(struct hda_softc *sc, 14984659b24SMichael Zeller uint32_t offset, uint32_t mask, uint32_t value); 15084659b24SMichael Zeller 1512b948146SAndy Fiddaman static struct hda_softc *hda_init(nvlist_t *nvl); 15284659b24SMichael Zeller static void hda_update_intr(struct hda_softc *sc); 15384659b24SMichael Zeller static void hda_response_interrupt(struct hda_softc *sc); 15484659b24SMichael Zeller static int hda_codec_constructor(struct hda_softc *sc, 1552b948146SAndy Fiddaman struct hda_codec_class *codec, const char *play, const char *rec); 15684659b24SMichael Zeller static struct hda_codec_class *hda_find_codec_class(const char *name); 15784659b24SMichael Zeller 15884659b24SMichael Zeller static int hda_send_command(struct hda_softc *sc, uint32_t verb); 15984659b24SMichael Zeller static int hda_notify_codecs(struct hda_softc *sc, uint8_t run, 16084659b24SMichael Zeller uint8_t stream, uint8_t dir); 16184659b24SMichael Zeller static void hda_reset(struct hda_softc *sc); 16284659b24SMichael Zeller static void hda_reset_regs(struct hda_softc *sc); 16384659b24SMichael Zeller static void hda_stream_reset(struct hda_softc *sc, uint8_t stream_ind); 16484659b24SMichael Zeller static int hda_stream_start(struct hda_softc *sc, uint8_t stream_ind); 16584659b24SMichael Zeller static int hda_stream_stop(struct hda_softc *sc, uint8_t stream_ind); 16684659b24SMichael Zeller static uint32_t hda_read(struct hda_softc *sc, uint32_t offset); 16784659b24SMichael Zeller static int hda_write(struct hda_softc *sc, uint32_t offset, uint8_t size, 16884659b24SMichael Zeller uint32_t value); 16984659b24SMichael Zeller 17084659b24SMichael Zeller static inline void hda_print_cmd_ctl_data(struct hda_codec_cmd_ctl *p); 17184659b24SMichael Zeller static int hda_corb_start(struct hda_softc *sc); 17284659b24SMichael Zeller static int hda_corb_run(struct hda_softc *sc); 17384659b24SMichael Zeller static int hda_rirb_start(struct hda_softc *sc); 17484659b24SMichael Zeller 17584659b24SMichael Zeller static void *hda_dma_get_vaddr(struct hda_softc *sc, uint64_t dma_paddr, 17684659b24SMichael Zeller size_t len); 17784659b24SMichael Zeller static void hda_dma_st_dword(void *dma_vaddr, uint32_t data); 17884659b24SMichael Zeller static uint32_t hda_dma_ld_dword(void *dma_vaddr); 17984659b24SMichael Zeller 18084659b24SMichael Zeller static inline uint8_t hda_get_stream_by_offsets(uint32_t offset, 18184659b24SMichael Zeller uint8_t reg_offset); 18284659b24SMichael Zeller static inline uint32_t hda_get_offset_stream(uint8_t stream_ind); 18384659b24SMichael Zeller 18484659b24SMichael Zeller static void hda_set_gctl(struct hda_softc *sc, uint32_t offset, uint32_t old); 18584659b24SMichael Zeller static void hda_set_statests(struct hda_softc *sc, uint32_t offset, 18684659b24SMichael Zeller uint32_t old); 18784659b24SMichael Zeller static void hda_set_corbwp(struct hda_softc *sc, uint32_t offset, uint32_t old); 18884659b24SMichael Zeller static void hda_set_corbctl(struct hda_softc *sc, uint32_t offset, 18984659b24SMichael Zeller uint32_t old); 19084659b24SMichael Zeller static void hda_set_rirbctl(struct hda_softc *sc, uint32_t offset, 19184659b24SMichael Zeller uint32_t old); 19284659b24SMichael Zeller static void hda_set_rirbsts(struct hda_softc *sc, uint32_t offset, 19384659b24SMichael Zeller uint32_t old); 19484659b24SMichael Zeller static void hda_set_dpiblbase(struct hda_softc *sc, uint32_t offset, 19584659b24SMichael Zeller uint32_t old); 19684659b24SMichael Zeller static void hda_set_sdctl(struct hda_softc *sc, uint32_t offset, uint32_t old); 19784659b24SMichael Zeller static void hda_set_sdctl2(struct hda_softc *sc, uint32_t offset, uint32_t old); 19884659b24SMichael Zeller static void hda_set_sdsts(struct hda_softc *sc, uint32_t offset, uint32_t old); 19984659b24SMichael Zeller 20084659b24SMichael Zeller static int hda_signal_state_change(struct hda_codec_inst *hci); 20184659b24SMichael Zeller static int hda_response(struct hda_codec_inst *hci, uint32_t response, 20284659b24SMichael Zeller uint8_t unsol); 20384659b24SMichael Zeller static int hda_transfer(struct hda_codec_inst *hci, uint8_t stream, 204*59d65d31SAndy Fiddaman uint8_t dir, uint8_t *buf, size_t count); 20584659b24SMichael Zeller 20684659b24SMichael Zeller static void hda_set_pib(struct hda_softc *sc, uint8_t stream_ind, uint32_t pib); 20784659b24SMichael Zeller static uint64_t hda_get_clock_ns(void); 20884659b24SMichael Zeller 20984659b24SMichael Zeller /* 21084659b24SMichael Zeller * PCI HDA function declarations 21184659b24SMichael Zeller */ 2122b948146SAndy Fiddaman static int pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl); 213*59d65d31SAndy Fiddaman static void pci_hda_write(struct vmctx *ctx, struct pci_devinst *pi, 21484659b24SMichael Zeller int baridx, uint64_t offset, int size, uint64_t value); 215*59d65d31SAndy Fiddaman static uint64_t pci_hda_read(struct vmctx *ctx, struct pci_devinst *pi, 21684659b24SMichael Zeller int baridx, uint64_t offset, int size); 21784659b24SMichael Zeller /* 21884659b24SMichael Zeller * HDA global data 21984659b24SMichael Zeller */ 22084659b24SMichael Zeller 22184659b24SMichael Zeller static const hda_set_reg_handler hda_set_reg_table[] = { 22284659b24SMichael Zeller [HDAC_GCTL] = hda_set_gctl, 22384659b24SMichael Zeller [HDAC_STATESTS] = hda_set_statests, 22484659b24SMichael Zeller [HDAC_CORBWP] = hda_set_corbwp, 22584659b24SMichael Zeller [HDAC_CORBCTL] = hda_set_corbctl, 22684659b24SMichael Zeller [HDAC_RIRBCTL] = hda_set_rirbctl, 22784659b24SMichael Zeller [HDAC_RIRBSTS] = hda_set_rirbsts, 22884659b24SMichael Zeller [HDAC_DPIBLBASE] = hda_set_dpiblbase, 22984659b24SMichael Zeller 23084659b24SMichael Zeller #define HDAC_ISTREAM(n, iss, oss) \ 23184659b24SMichael Zeller [_HDAC_ISDCTL(n, iss, oss)] = hda_set_sdctl, \ 23284659b24SMichael Zeller [_HDAC_ISDCTL(n, iss, oss) + 2] = hda_set_sdctl2, \ 23384659b24SMichael Zeller [_HDAC_ISDSTS(n, iss, oss)] = hda_set_sdsts, \ 23484659b24SMichael Zeller 23584659b24SMichael Zeller #define HDAC_OSTREAM(n, iss, oss) \ 23684659b24SMichael Zeller [_HDAC_OSDCTL(n, iss, oss)] = hda_set_sdctl, \ 23784659b24SMichael Zeller [_HDAC_OSDCTL(n, iss, oss) + 2] = hda_set_sdctl2, \ 23884659b24SMichael Zeller [_HDAC_OSDSTS(n, iss, oss)] = hda_set_sdsts, \ 23984659b24SMichael Zeller 24084659b24SMichael Zeller HDAC_ISTREAM(0, HDA_ISS_NO, HDA_OSS_NO) 24184659b24SMichael Zeller HDAC_ISTREAM(1, HDA_ISS_NO, HDA_OSS_NO) 24284659b24SMichael Zeller HDAC_ISTREAM(2, HDA_ISS_NO, HDA_OSS_NO) 24384659b24SMichael Zeller HDAC_ISTREAM(3, HDA_ISS_NO, HDA_OSS_NO) 24484659b24SMichael Zeller 24584659b24SMichael Zeller HDAC_OSTREAM(0, HDA_ISS_NO, HDA_OSS_NO) 24684659b24SMichael Zeller HDAC_OSTREAM(1, HDA_ISS_NO, HDA_OSS_NO) 24784659b24SMichael Zeller HDAC_OSTREAM(2, HDA_ISS_NO, HDA_OSS_NO) 24884659b24SMichael Zeller HDAC_OSTREAM(3, HDA_ISS_NO, HDA_OSS_NO) 24984659b24SMichael Zeller 25084659b24SMichael Zeller [HDA_SET_REG_TABLE_SZ] = NULL, 25184659b24SMichael Zeller }; 25284659b24SMichael Zeller 25384659b24SMichael Zeller static const uint16_t hda_corb_sizes[] = { 25484659b24SMichael Zeller [HDAC_CORBSIZE_CORBSIZE_2] = 2, 25584659b24SMichael Zeller [HDAC_CORBSIZE_CORBSIZE_16] = 16, 25684659b24SMichael Zeller [HDAC_CORBSIZE_CORBSIZE_256] = 256, 25784659b24SMichael Zeller [HDAC_CORBSIZE_CORBSIZE_MASK] = 0, 25884659b24SMichael Zeller }; 25984659b24SMichael Zeller 26084659b24SMichael Zeller static const uint16_t hda_rirb_sizes[] = { 26184659b24SMichael Zeller [HDAC_RIRBSIZE_RIRBSIZE_2] = 2, 26284659b24SMichael Zeller [HDAC_RIRBSIZE_RIRBSIZE_16] = 16, 26384659b24SMichael Zeller [HDAC_RIRBSIZE_RIRBSIZE_256] = 256, 26484659b24SMichael Zeller [HDAC_RIRBSIZE_RIRBSIZE_MASK] = 0, 26584659b24SMichael Zeller }; 26684659b24SMichael Zeller 267*59d65d31SAndy Fiddaman static const struct hda_ops hops = { 26884659b24SMichael Zeller .signal = hda_signal_state_change, 26984659b24SMichael Zeller .response = hda_response, 27084659b24SMichael Zeller .transfer = hda_transfer, 27184659b24SMichael Zeller }; 27284659b24SMichael Zeller 2734f3f3e9aSAndy Fiddaman static const struct pci_devemu pci_de_hda = { 27484659b24SMichael Zeller .pe_emu = "hda", 27584659b24SMichael Zeller .pe_init = pci_hda_init, 27684659b24SMichael Zeller .pe_barwrite = pci_hda_write, 27784659b24SMichael Zeller .pe_barread = pci_hda_read 27884659b24SMichael Zeller }; 27984659b24SMichael Zeller PCI_EMUL_SET(pci_de_hda); 28084659b24SMichael Zeller 28184659b24SMichael Zeller SET_DECLARE(hda_codec_class_set, struct hda_codec_class); 28284659b24SMichael Zeller 28384659b24SMichael Zeller #if DEBUG_HDA == 1 28484659b24SMichael Zeller FILE *dbg; 28584659b24SMichael Zeller #endif 28684659b24SMichael Zeller 28784659b24SMichael Zeller /* 28884659b24SMichael Zeller * HDA module function definitions 28984659b24SMichael Zeller */ 29084659b24SMichael Zeller 29184659b24SMichael Zeller static inline void 29284659b24SMichael Zeller hda_set_reg_by_offset(struct hda_softc *sc, uint32_t offset, uint32_t value) 29384659b24SMichael Zeller { 29484659b24SMichael Zeller assert(offset < HDA_LAST_OFFSET); 29584659b24SMichael Zeller sc->regs[offset] = value; 29684659b24SMichael Zeller } 29784659b24SMichael Zeller 29884659b24SMichael Zeller static inline uint32_t 29984659b24SMichael Zeller hda_get_reg_by_offset(struct hda_softc *sc, uint32_t offset) 30084659b24SMichael Zeller { 30184659b24SMichael Zeller assert(offset < HDA_LAST_OFFSET); 30284659b24SMichael Zeller return sc->regs[offset]; 30384659b24SMichael Zeller } 30484659b24SMichael Zeller 30584659b24SMichael Zeller static inline void 30684659b24SMichael Zeller hda_set_field_by_offset(struct hda_softc *sc, uint32_t offset, 30784659b24SMichael Zeller uint32_t mask, uint32_t value) 30884659b24SMichael Zeller { 30984659b24SMichael Zeller uint32_t reg_value = 0; 31084659b24SMichael Zeller 31184659b24SMichael Zeller reg_value = hda_get_reg_by_offset(sc, offset); 31284659b24SMichael Zeller 31384659b24SMichael Zeller reg_value &= ~mask; 31484659b24SMichael Zeller reg_value |= (value & mask); 31584659b24SMichael Zeller 31684659b24SMichael Zeller hda_set_reg_by_offset(sc, offset, reg_value); 31784659b24SMichael Zeller } 31884659b24SMichael Zeller 31984659b24SMichael Zeller static struct hda_softc * 3202b948146SAndy Fiddaman hda_init(nvlist_t *nvl) 32184659b24SMichael Zeller { 32284659b24SMichael Zeller struct hda_softc *sc = NULL; 32384659b24SMichael Zeller struct hda_codec_class *codec = NULL; 3242b948146SAndy Fiddaman const char *value; 3252b948146SAndy Fiddaman char *play; 3262b948146SAndy Fiddaman char *rec; 3272b948146SAndy Fiddaman int err; 32884659b24SMichael Zeller 32984659b24SMichael Zeller #if DEBUG_HDA == 1 33084659b24SMichael Zeller dbg = fopen("/tmp/bhyve_hda.log", "w+"); 33184659b24SMichael Zeller #endif 33284659b24SMichael Zeller 33384659b24SMichael Zeller sc = calloc(1, sizeof(*sc)); 33484659b24SMichael Zeller if (!sc) 33584659b24SMichael Zeller return (NULL); 33684659b24SMichael Zeller 33784659b24SMichael Zeller hda_reset_regs(sc); 33884659b24SMichael Zeller 33984659b24SMichael Zeller /* 3402b948146SAndy Fiddaman * TODO search all configured codecs 34184659b24SMichael Zeller * For now we play with one single codec 34284659b24SMichael Zeller */ 34384659b24SMichael Zeller codec = hda_find_codec_class("hda_codec"); 34484659b24SMichael Zeller if (codec) { 3452b948146SAndy Fiddaman value = get_config_value_node(nvl, "play"); 3462b948146SAndy Fiddaman if (value == NULL) 3472b948146SAndy Fiddaman play = NULL; 3482b948146SAndy Fiddaman else 3492b948146SAndy Fiddaman play = strdup(value); 3502b948146SAndy Fiddaman value = get_config_value_node(nvl, "rec"); 3512b948146SAndy Fiddaman if (value == NULL) 3522b948146SAndy Fiddaman rec = NULL; 3532b948146SAndy Fiddaman else 3542b948146SAndy Fiddaman rec = strdup(value); 355154972afSPatrick Mooney DPRINTF("play: %s rec: %s", play, rec); 3562b948146SAndy Fiddaman if (play != NULL || rec != NULL) { 3572b948146SAndy Fiddaman err = hda_codec_constructor(sc, codec, play, rec); 35884659b24SMichael Zeller assert(!err); 35984659b24SMichael Zeller } 3602b948146SAndy Fiddaman free(play); 3612b948146SAndy Fiddaman free(rec); 36284659b24SMichael Zeller } 36384659b24SMichael Zeller 36484659b24SMichael Zeller return (sc); 36584659b24SMichael Zeller } 36684659b24SMichael Zeller 36784659b24SMichael Zeller static void 36884659b24SMichael Zeller hda_update_intr(struct hda_softc *sc) 36984659b24SMichael Zeller { 37084659b24SMichael Zeller struct pci_devinst *pi = sc->pci_dev; 37184659b24SMichael Zeller uint32_t intctl = hda_get_reg_by_offset(sc, HDAC_INTCTL); 37284659b24SMichael Zeller uint32_t intsts = 0; 37384659b24SMichael Zeller uint32_t sdsts = 0; 37484659b24SMichael Zeller uint32_t rirbsts = 0; 37584659b24SMichael Zeller uint32_t wakeen = 0; 37684659b24SMichael Zeller uint32_t statests = 0; 37784659b24SMichael Zeller uint32_t off = 0; 37884659b24SMichael Zeller int i; 37984659b24SMichael Zeller 38084659b24SMichael Zeller /* update the CIS bits */ 38184659b24SMichael Zeller rirbsts = hda_get_reg_by_offset(sc, HDAC_RIRBSTS); 38284659b24SMichael Zeller if (rirbsts & (HDAC_RIRBSTS_RINTFL | HDAC_RIRBSTS_RIRBOIS)) 38384659b24SMichael Zeller intsts |= HDAC_INTSTS_CIS; 38484659b24SMichael Zeller 38584659b24SMichael Zeller wakeen = hda_get_reg_by_offset(sc, HDAC_WAKEEN); 38684659b24SMichael Zeller statests = hda_get_reg_by_offset(sc, HDAC_STATESTS); 38784659b24SMichael Zeller if (statests & wakeen) 38884659b24SMichael Zeller intsts |= HDAC_INTSTS_CIS; 38984659b24SMichael Zeller 39084659b24SMichael Zeller /* update the SIS bits */ 39184659b24SMichael Zeller for (i = 0; i < HDA_IOSS_NO; i++) { 39284659b24SMichael Zeller off = hda_get_offset_stream(i); 39384659b24SMichael Zeller sdsts = hda_get_reg_by_offset(sc, off + HDAC_SDSTS); 39484659b24SMichael Zeller if (sdsts & HDAC_SDSTS_BCIS) 39584659b24SMichael Zeller intsts |= (1 << i); 39684659b24SMichael Zeller } 39784659b24SMichael Zeller 39884659b24SMichael Zeller /* update the GIS bit */ 39984659b24SMichael Zeller if (intsts) 40084659b24SMichael Zeller intsts |= HDAC_INTSTS_GIS; 40184659b24SMichael Zeller 40284659b24SMichael Zeller hda_set_reg_by_offset(sc, HDAC_INTSTS, intsts); 40384659b24SMichael Zeller 40484659b24SMichael Zeller if ((intctl & HDAC_INTCTL_GIE) && ((intsts & \ 40584659b24SMichael Zeller ~HDAC_INTSTS_GIS) & intctl)) { 40684659b24SMichael Zeller if (!sc->lintr) { 40784659b24SMichael Zeller pci_lintr_assert(pi); 40884659b24SMichael Zeller sc->lintr = 1; 40984659b24SMichael Zeller } 41084659b24SMichael Zeller } else { 41184659b24SMichael Zeller if (sc->lintr) { 41284659b24SMichael Zeller pci_lintr_deassert(pi); 41384659b24SMichael Zeller sc->lintr = 0; 41484659b24SMichael Zeller } 41584659b24SMichael Zeller } 41684659b24SMichael Zeller } 41784659b24SMichael Zeller 41884659b24SMichael Zeller static void 41984659b24SMichael Zeller hda_response_interrupt(struct hda_softc *sc) 42084659b24SMichael Zeller { 42184659b24SMichael Zeller uint8_t rirbctl = hda_get_reg_by_offset(sc, HDAC_RIRBCTL); 42284659b24SMichael Zeller 42384659b24SMichael Zeller if ((rirbctl & HDAC_RIRBCTL_RINTCTL) && sc->rirb_cnt) { 42484659b24SMichael Zeller sc->rirb_cnt = 0; 42584659b24SMichael Zeller hda_set_field_by_offset(sc, HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL, 42684659b24SMichael Zeller HDAC_RIRBSTS_RINTFL); 42784659b24SMichael Zeller hda_update_intr(sc); 42884659b24SMichael Zeller } 42984659b24SMichael Zeller } 43084659b24SMichael Zeller 43184659b24SMichael Zeller static int 43284659b24SMichael Zeller hda_codec_constructor(struct hda_softc *sc, struct hda_codec_class *codec, 4332b948146SAndy Fiddaman const char *play, const char *rec) 43484659b24SMichael Zeller { 43584659b24SMichael Zeller struct hda_codec_inst *hci = NULL; 43684659b24SMichael Zeller 43784659b24SMichael Zeller if (sc->codecs_no >= HDA_CODEC_MAX) 43884659b24SMichael Zeller return (-1); 43984659b24SMichael Zeller 44084659b24SMichael Zeller hci = calloc(1, sizeof(struct hda_codec_inst)); 44184659b24SMichael Zeller if (!hci) 44284659b24SMichael Zeller return (-1); 44384659b24SMichael Zeller 44484659b24SMichael Zeller hci->hda = sc; 44584659b24SMichael Zeller hci->hops = &hops; 44684659b24SMichael Zeller hci->cad = sc->codecs_no; 44784659b24SMichael Zeller hci->codec = codec; 44884659b24SMichael Zeller 44984659b24SMichael Zeller sc->codecs[sc->codecs_no++] = hci; 45084659b24SMichael Zeller 45184659b24SMichael Zeller if (!codec->init) { 452154972afSPatrick Mooney DPRINTF("This codec does not implement the init function"); 45384659b24SMichael Zeller return (-1); 45484659b24SMichael Zeller } 45584659b24SMichael Zeller 4562b948146SAndy Fiddaman return (codec->init(hci, play, rec)); 45784659b24SMichael Zeller } 45884659b24SMichael Zeller 45984659b24SMichael Zeller static struct hda_codec_class * 46084659b24SMichael Zeller hda_find_codec_class(const char *name) 46184659b24SMichael Zeller { 46284659b24SMichael Zeller struct hda_codec_class **pdpp = NULL, *pdp = NULL; 46384659b24SMichael Zeller 46484659b24SMichael Zeller SET_FOREACH(pdpp, hda_codec_class_set) { 46584659b24SMichael Zeller pdp = *pdpp; 46684659b24SMichael Zeller if (!strcmp(pdp->name, name)) { 46784659b24SMichael Zeller return (pdp); 46884659b24SMichael Zeller } 46984659b24SMichael Zeller } 47084659b24SMichael Zeller 47184659b24SMichael Zeller return (NULL); 47284659b24SMichael Zeller } 47384659b24SMichael Zeller 47484659b24SMichael Zeller static int 47584659b24SMichael Zeller hda_send_command(struct hda_softc *sc, uint32_t verb) 47684659b24SMichael Zeller { 47784659b24SMichael Zeller struct hda_codec_inst *hci = NULL; 47884659b24SMichael Zeller struct hda_codec_class *codec = NULL; 47984659b24SMichael Zeller uint8_t cad = (verb >> HDA_CMD_CAD_SHIFT) & 0x0f; 48084659b24SMichael Zeller 48184659b24SMichael Zeller hci = sc->codecs[cad]; 48284659b24SMichael Zeller if (!hci) 48384659b24SMichael Zeller return (-1); 48484659b24SMichael Zeller 485154972afSPatrick Mooney DPRINTF("cad: 0x%x verb: 0x%x", cad, verb); 48684659b24SMichael Zeller 48784659b24SMichael Zeller codec = hci->codec; 48884659b24SMichael Zeller assert(codec); 48984659b24SMichael Zeller 49084659b24SMichael Zeller if (!codec->command) { 491154972afSPatrick Mooney DPRINTF("This codec does not implement the command function"); 49284659b24SMichael Zeller return (-1); 49384659b24SMichael Zeller } 49484659b24SMichael Zeller 49584659b24SMichael Zeller return (codec->command(hci, verb)); 49684659b24SMichael Zeller } 49784659b24SMichael Zeller 49884659b24SMichael Zeller static int 49984659b24SMichael Zeller hda_notify_codecs(struct hda_softc *sc, uint8_t run, uint8_t stream, 50084659b24SMichael Zeller uint8_t dir) 50184659b24SMichael Zeller { 50284659b24SMichael Zeller struct hda_codec_inst *hci = NULL; 50384659b24SMichael Zeller struct hda_codec_class *codec = NULL; 50484659b24SMichael Zeller int err; 50584659b24SMichael Zeller int i; 50684659b24SMichael Zeller 50784659b24SMichael Zeller /* Notify each codec */ 50884659b24SMichael Zeller for (i = 0; i < sc->codecs_no; i++) { 50984659b24SMichael Zeller hci = sc->codecs[i]; 51084659b24SMichael Zeller assert(hci); 51184659b24SMichael Zeller 51284659b24SMichael Zeller codec = hci->codec; 51384659b24SMichael Zeller assert(codec); 51484659b24SMichael Zeller 51584659b24SMichael Zeller if (codec->notify) { 51684659b24SMichael Zeller err = codec->notify(hci, run, stream, dir); 51784659b24SMichael Zeller if (!err) 51884659b24SMichael Zeller break; 51984659b24SMichael Zeller } 52084659b24SMichael Zeller } 52184659b24SMichael Zeller 52284659b24SMichael Zeller return (i == sc->codecs_no ? (-1) : 0); 52384659b24SMichael Zeller } 52484659b24SMichael Zeller 52584659b24SMichael Zeller static void 52684659b24SMichael Zeller hda_reset(struct hda_softc *sc) 52784659b24SMichael Zeller { 52884659b24SMichael Zeller int i; 52984659b24SMichael Zeller struct hda_codec_inst *hci = NULL; 53084659b24SMichael Zeller struct hda_codec_class *codec = NULL; 53184659b24SMichael Zeller 53284659b24SMichael Zeller hda_reset_regs(sc); 53384659b24SMichael Zeller 53484659b24SMichael Zeller /* Reset each codec */ 53584659b24SMichael Zeller for (i = 0; i < sc->codecs_no; i++) { 53684659b24SMichael Zeller hci = sc->codecs[i]; 53784659b24SMichael Zeller assert(hci); 53884659b24SMichael Zeller 53984659b24SMichael Zeller codec = hci->codec; 54084659b24SMichael Zeller assert(codec); 54184659b24SMichael Zeller 54284659b24SMichael Zeller if (codec->reset) 54384659b24SMichael Zeller codec->reset(hci); 54484659b24SMichael Zeller } 54584659b24SMichael Zeller 54684659b24SMichael Zeller sc->wall_clock_start = hda_get_clock_ns(); 54784659b24SMichael Zeller } 54884659b24SMichael Zeller 54984659b24SMichael Zeller static void 55084659b24SMichael Zeller hda_reset_regs(struct hda_softc *sc) 55184659b24SMichael Zeller { 55284659b24SMichael Zeller uint32_t off = 0; 55384659b24SMichael Zeller uint8_t i; 55484659b24SMichael Zeller 555154972afSPatrick Mooney DPRINTF("Reset the HDA controller registers ..."); 55684659b24SMichael Zeller 55784659b24SMichael Zeller memset(sc->regs, 0, sizeof(sc->regs)); 55884659b24SMichael Zeller 55984659b24SMichael Zeller hda_set_reg_by_offset(sc, HDAC_GCAP, 56084659b24SMichael Zeller HDAC_GCAP_64OK | 56184659b24SMichael Zeller (HDA_ISS_NO << HDAC_GCAP_ISS_SHIFT) | 56284659b24SMichael Zeller (HDA_OSS_NO << HDAC_GCAP_OSS_SHIFT)); 56384659b24SMichael Zeller hda_set_reg_by_offset(sc, HDAC_VMAJ, 0x01); 56484659b24SMichael Zeller hda_set_reg_by_offset(sc, HDAC_OUTPAY, 0x3c); 56584659b24SMichael Zeller hda_set_reg_by_offset(sc, HDAC_INPAY, 0x1d); 56684659b24SMichael Zeller hda_set_reg_by_offset(sc, HDAC_CORBSIZE, 56784659b24SMichael Zeller HDAC_CORBSIZE_CORBSZCAP_256 | HDAC_CORBSIZE_CORBSIZE_256); 56884659b24SMichael Zeller hda_set_reg_by_offset(sc, HDAC_RIRBSIZE, 56984659b24SMichael Zeller HDAC_RIRBSIZE_RIRBSZCAP_256 | HDAC_RIRBSIZE_RIRBSIZE_256); 57084659b24SMichael Zeller 57184659b24SMichael Zeller for (i = 0; i < HDA_IOSS_NO; i++) { 57284659b24SMichael Zeller off = hda_get_offset_stream(i); 57384659b24SMichael Zeller hda_set_reg_by_offset(sc, off + HDAC_SDFIFOS, HDA_FIFO_SIZE); 57484659b24SMichael Zeller } 57584659b24SMichael Zeller } 57684659b24SMichael Zeller 57784659b24SMichael Zeller static void 57884659b24SMichael Zeller hda_stream_reset(struct hda_softc *sc, uint8_t stream_ind) 57984659b24SMichael Zeller { 58084659b24SMichael Zeller struct hda_stream_desc *st = &sc->streams[stream_ind]; 58184659b24SMichael Zeller uint32_t off = hda_get_offset_stream(stream_ind); 58284659b24SMichael Zeller 583154972afSPatrick Mooney DPRINTF("Reset the HDA stream: 0x%x", stream_ind); 58484659b24SMichael Zeller 58584659b24SMichael Zeller /* Reset the Stream Descriptor registers */ 58684659b24SMichael Zeller memset(sc->regs + HDA_STREAM_REGS_BASE + off, 0, HDA_STREAM_REGS_LEN); 58784659b24SMichael Zeller 58884659b24SMichael Zeller /* Reset the Stream Descriptor */ 58984659b24SMichael Zeller memset(st, 0, sizeof(*st)); 59084659b24SMichael Zeller 59184659b24SMichael Zeller hda_set_field_by_offset(sc, off + HDAC_SDSTS, 59284659b24SMichael Zeller HDAC_SDSTS_FIFORDY, HDAC_SDSTS_FIFORDY); 59384659b24SMichael Zeller hda_set_field_by_offset(sc, off + HDAC_SDCTL0, 59484659b24SMichael Zeller HDAC_SDCTL_SRST, HDAC_SDCTL_SRST); 59584659b24SMichael Zeller } 59684659b24SMichael Zeller 59784659b24SMichael Zeller static int 59884659b24SMichael Zeller hda_stream_start(struct hda_softc *sc, uint8_t stream_ind) 59984659b24SMichael Zeller { 60084659b24SMichael Zeller struct hda_stream_desc *st = &sc->streams[stream_ind]; 60184659b24SMichael Zeller struct hda_bdle_desc *bdle_desc = NULL; 60284659b24SMichael Zeller struct hda_bdle *bdle = NULL; 60384659b24SMichael Zeller uint32_t lvi = 0; 60484659b24SMichael Zeller uint32_t bdl_cnt = 0; 60584659b24SMichael Zeller uint64_t bdpl = 0; 60684659b24SMichael Zeller uint64_t bdpu = 0; 60784659b24SMichael Zeller uint64_t bdl_paddr = 0; 60884659b24SMichael Zeller void *bdl_vaddr = NULL; 60984659b24SMichael Zeller uint32_t bdle_sz = 0; 61084659b24SMichael Zeller uint64_t bdle_addrl = 0; 61184659b24SMichael Zeller uint64_t bdle_addrh = 0; 61284659b24SMichael Zeller uint64_t bdle_paddr = 0; 61384659b24SMichael Zeller void *bdle_vaddr = NULL; 61484659b24SMichael Zeller uint32_t off = hda_get_offset_stream(stream_ind); 61584659b24SMichael Zeller uint32_t sdctl = 0; 61684659b24SMichael Zeller uint8_t strm = 0; 61784659b24SMichael Zeller uint8_t dir = 0; 61884659b24SMichael Zeller 61984659b24SMichael Zeller assert(!st->run); 62084659b24SMichael Zeller 62184659b24SMichael Zeller lvi = hda_get_reg_by_offset(sc, off + HDAC_SDLVI); 62284659b24SMichael Zeller bdpl = hda_get_reg_by_offset(sc, off + HDAC_SDBDPL); 62384659b24SMichael Zeller bdpu = hda_get_reg_by_offset(sc, off + HDAC_SDBDPU); 62484659b24SMichael Zeller 62584659b24SMichael Zeller bdl_cnt = lvi + 1; 62684659b24SMichael Zeller assert(bdl_cnt <= HDA_BDL_MAX_LEN); 62784659b24SMichael Zeller 62884659b24SMichael Zeller bdl_paddr = bdpl | (bdpu << 32); 62984659b24SMichael Zeller bdl_vaddr = hda_dma_get_vaddr(sc, bdl_paddr, 63084659b24SMichael Zeller HDA_BDL_ENTRY_LEN * bdl_cnt); 63184659b24SMichael Zeller if (!bdl_vaddr) { 632154972afSPatrick Mooney DPRINTF("Fail to get the guest virtual address"); 63384659b24SMichael Zeller return (-1); 63484659b24SMichael Zeller } 63584659b24SMichael Zeller 636154972afSPatrick Mooney DPRINTF("stream: 0x%x bdl_cnt: 0x%x bdl_paddr: 0x%lx", 63784659b24SMichael Zeller stream_ind, bdl_cnt, bdl_paddr); 63884659b24SMichael Zeller 63984659b24SMichael Zeller st->bdl_cnt = bdl_cnt; 64084659b24SMichael Zeller 64184659b24SMichael Zeller bdle = (struct hda_bdle *)bdl_vaddr; 642*59d65d31SAndy Fiddaman for (size_t i = 0; i < bdl_cnt; i++, bdle++) { 64384659b24SMichael Zeller bdle_sz = bdle->len; 64484659b24SMichael Zeller assert(!(bdle_sz % HDA_DMA_ACCESS_LEN)); 64584659b24SMichael Zeller 64684659b24SMichael Zeller bdle_addrl = bdle->addrl; 64784659b24SMichael Zeller bdle_addrh = bdle->addrh; 64884659b24SMichael Zeller 64984659b24SMichael Zeller bdle_paddr = bdle_addrl | (bdle_addrh << 32); 65084659b24SMichael Zeller bdle_vaddr = hda_dma_get_vaddr(sc, bdle_paddr, bdle_sz); 65184659b24SMichael Zeller if (!bdle_vaddr) { 652154972afSPatrick Mooney DPRINTF("Fail to get the guest virtual address"); 65384659b24SMichael Zeller return (-1); 65484659b24SMichael Zeller } 65584659b24SMichael Zeller 65684659b24SMichael Zeller bdle_desc = &st->bdl[i]; 65784659b24SMichael Zeller bdle_desc->addr = bdle_vaddr; 65884659b24SMichael Zeller bdle_desc->len = bdle_sz; 65984659b24SMichael Zeller bdle_desc->ioc = bdle->ioc; 66084659b24SMichael Zeller 661*59d65d31SAndy Fiddaman DPRINTF("bdle: 0x%zx bdle_sz: 0x%x", i, bdle_sz); 66284659b24SMichael Zeller } 66384659b24SMichael Zeller 66484659b24SMichael Zeller sdctl = hda_get_reg_by_offset(sc, off + HDAC_SDCTL0); 66584659b24SMichael Zeller strm = (sdctl >> 20) & 0x0f; 66684659b24SMichael Zeller dir = stream_ind >= HDA_ISS_NO; 66784659b24SMichael Zeller 668154972afSPatrick Mooney DPRINTF("strm: 0x%x, dir: 0x%x", strm, dir); 66984659b24SMichael Zeller 67084659b24SMichael Zeller sc->stream_map[dir][strm] = stream_ind; 67184659b24SMichael Zeller st->stream = strm; 67284659b24SMichael Zeller st->dir = dir; 67384659b24SMichael Zeller st->bp = 0; 67484659b24SMichael Zeller st->be = 0; 67584659b24SMichael Zeller 67684659b24SMichael Zeller hda_set_pib(sc, stream_ind, 0); 67784659b24SMichael Zeller 67884659b24SMichael Zeller st->run = 1; 67984659b24SMichael Zeller 68084659b24SMichael Zeller hda_notify_codecs(sc, 1, strm, dir); 68184659b24SMichael Zeller 68284659b24SMichael Zeller return (0); 68384659b24SMichael Zeller } 68484659b24SMichael Zeller 68584659b24SMichael Zeller static int 68684659b24SMichael Zeller hda_stream_stop(struct hda_softc *sc, uint8_t stream_ind) 68784659b24SMichael Zeller { 68884659b24SMichael Zeller struct hda_stream_desc *st = &sc->streams[stream_ind]; 68984659b24SMichael Zeller uint8_t strm = st->stream; 69084659b24SMichael Zeller uint8_t dir = st->dir; 69184659b24SMichael Zeller 692154972afSPatrick Mooney DPRINTF("stream: 0x%x, strm: 0x%x, dir: 0x%x", stream_ind, strm, dir); 69384659b24SMichael Zeller 69484659b24SMichael Zeller st->run = 0; 69584659b24SMichael Zeller 69684659b24SMichael Zeller hda_notify_codecs(sc, 0, strm, dir); 69784659b24SMichael Zeller 69884659b24SMichael Zeller return (0); 69984659b24SMichael Zeller } 70084659b24SMichael Zeller 70184659b24SMichael Zeller static uint32_t 70284659b24SMichael Zeller hda_read(struct hda_softc *sc, uint32_t offset) 70384659b24SMichael Zeller { 70484659b24SMichael Zeller if (offset == HDAC_WALCLK) 70584659b24SMichael Zeller return (24 * (hda_get_clock_ns() - \ 70684659b24SMichael Zeller sc->wall_clock_start) / 1000); 70784659b24SMichael Zeller 70884659b24SMichael Zeller return (hda_get_reg_by_offset(sc, offset)); 70984659b24SMichael Zeller } 71084659b24SMichael Zeller 71184659b24SMichael Zeller static int 71284659b24SMichael Zeller hda_write(struct hda_softc *sc, uint32_t offset, uint8_t size, uint32_t value) 71384659b24SMichael Zeller { 71484659b24SMichael Zeller uint32_t old = hda_get_reg_by_offset(sc, offset); 71584659b24SMichael Zeller uint32_t masks[] = {0x00000000, 0x000000ff, 0x0000ffff, 71684659b24SMichael Zeller 0x00ffffff, 0xffffffff}; 71784659b24SMichael Zeller hda_set_reg_handler set_reg_handler = hda_set_reg_table[offset]; 71884659b24SMichael Zeller 71984659b24SMichael Zeller hda_set_field_by_offset(sc, offset, masks[size], value); 72084659b24SMichael Zeller 72184659b24SMichael Zeller if (set_reg_handler) 72284659b24SMichael Zeller set_reg_handler(sc, offset, old); 72384659b24SMichael Zeller 72484659b24SMichael Zeller return (0); 72584659b24SMichael Zeller } 72684659b24SMichael Zeller 72784659b24SMichael Zeller static inline void 72884659b24SMichael Zeller hda_print_cmd_ctl_data(struct hda_codec_cmd_ctl *p) 72984659b24SMichael Zeller { 73084659b24SMichael Zeller #if DEBUG_HDA == 1 7314f3f3e9aSAndy Fiddaman const char *name = p->name; 73284659b24SMichael Zeller #endif 733154972afSPatrick Mooney DPRINTF("%s size: %d", name, p->size); 734154972afSPatrick Mooney DPRINTF("%s dma_vaddr: %p", name, p->dma_vaddr); 735154972afSPatrick Mooney DPRINTF("%s wp: 0x%x", name, p->wp); 736154972afSPatrick Mooney DPRINTF("%s rp: 0x%x", name, p->rp); 73784659b24SMichael Zeller } 73884659b24SMichael Zeller 73984659b24SMichael Zeller static int 74084659b24SMichael Zeller hda_corb_start(struct hda_softc *sc) 74184659b24SMichael Zeller { 74284659b24SMichael Zeller struct hda_codec_cmd_ctl *corb = &sc->corb; 74384659b24SMichael Zeller uint8_t corbsize = 0; 74484659b24SMichael Zeller uint64_t corblbase = 0; 74584659b24SMichael Zeller uint64_t corbubase = 0; 74684659b24SMichael Zeller uint64_t corbpaddr = 0; 74784659b24SMichael Zeller 74884659b24SMichael Zeller corb->name = "CORB"; 74984659b24SMichael Zeller 75084659b24SMichael Zeller corbsize = hda_get_reg_by_offset(sc, HDAC_CORBSIZE) & \ 75184659b24SMichael Zeller HDAC_CORBSIZE_CORBSIZE_MASK; 75284659b24SMichael Zeller corb->size = hda_corb_sizes[corbsize]; 75384659b24SMichael Zeller 75484659b24SMichael Zeller if (!corb->size) { 755154972afSPatrick Mooney DPRINTF("Invalid corb size"); 75684659b24SMichael Zeller return (-1); 75784659b24SMichael Zeller } 75884659b24SMichael Zeller 75984659b24SMichael Zeller corblbase = hda_get_reg_by_offset(sc, HDAC_CORBLBASE); 76084659b24SMichael Zeller corbubase = hda_get_reg_by_offset(sc, HDAC_CORBUBASE); 76184659b24SMichael Zeller 76284659b24SMichael Zeller corbpaddr = corblbase | (corbubase << 32); 763154972afSPatrick Mooney DPRINTF("CORB dma_paddr: %p", (void *)corbpaddr); 76484659b24SMichael Zeller 76584659b24SMichael Zeller corb->dma_vaddr = hda_dma_get_vaddr(sc, corbpaddr, 76684659b24SMichael Zeller HDA_CORB_ENTRY_LEN * corb->size); 76784659b24SMichael Zeller if (!corb->dma_vaddr) { 768154972afSPatrick Mooney DPRINTF("Fail to get the guest virtual address"); 76984659b24SMichael Zeller return (-1); 77084659b24SMichael Zeller } 77184659b24SMichael Zeller 77284659b24SMichael Zeller corb->wp = hda_get_reg_by_offset(sc, HDAC_CORBWP); 77384659b24SMichael Zeller corb->rp = hda_get_reg_by_offset(sc, HDAC_CORBRP); 77484659b24SMichael Zeller 77584659b24SMichael Zeller corb->run = 1; 77684659b24SMichael Zeller 77784659b24SMichael Zeller hda_print_cmd_ctl_data(corb); 77884659b24SMichael Zeller 77984659b24SMichael Zeller return (0); 78084659b24SMichael Zeller } 78184659b24SMichael Zeller 78284659b24SMichael Zeller static int 78384659b24SMichael Zeller hda_corb_run(struct hda_softc *sc) 78484659b24SMichael Zeller { 78584659b24SMichael Zeller struct hda_codec_cmd_ctl *corb = &sc->corb; 78684659b24SMichael Zeller uint32_t verb = 0; 78784659b24SMichael Zeller int err; 78884659b24SMichael Zeller 78984659b24SMichael Zeller corb->wp = hda_get_reg_by_offset(sc, HDAC_CORBWP); 79084659b24SMichael Zeller 79184659b24SMichael Zeller while (corb->rp != corb->wp && corb->run) { 79284659b24SMichael Zeller corb->rp++; 79384659b24SMichael Zeller corb->rp %= corb->size; 79484659b24SMichael Zeller 795*59d65d31SAndy Fiddaman verb = hda_dma_ld_dword((uint8_t *)corb->dma_vaddr + 79684659b24SMichael Zeller HDA_CORB_ENTRY_LEN * corb->rp); 79784659b24SMichael Zeller 79884659b24SMichael Zeller err = hda_send_command(sc, verb); 79984659b24SMichael Zeller assert(!err); 80084659b24SMichael Zeller } 80184659b24SMichael Zeller 80284659b24SMichael Zeller hda_set_reg_by_offset(sc, HDAC_CORBRP, corb->rp); 80384659b24SMichael Zeller 80484659b24SMichael Zeller if (corb->run) 80584659b24SMichael Zeller hda_response_interrupt(sc); 80684659b24SMichael Zeller 80784659b24SMichael Zeller return (0); 80884659b24SMichael Zeller } 80984659b24SMichael Zeller 81084659b24SMichael Zeller static int 81184659b24SMichael Zeller hda_rirb_start(struct hda_softc *sc) 81284659b24SMichael Zeller { 81384659b24SMichael Zeller struct hda_codec_cmd_ctl *rirb = &sc->rirb; 81484659b24SMichael Zeller uint8_t rirbsize = 0; 81584659b24SMichael Zeller uint64_t rirblbase = 0; 81684659b24SMichael Zeller uint64_t rirbubase = 0; 81784659b24SMichael Zeller uint64_t rirbpaddr = 0; 81884659b24SMichael Zeller 81984659b24SMichael Zeller rirb->name = "RIRB"; 82084659b24SMichael Zeller 82184659b24SMichael Zeller rirbsize = hda_get_reg_by_offset(sc, HDAC_RIRBSIZE) & \ 82284659b24SMichael Zeller HDAC_RIRBSIZE_RIRBSIZE_MASK; 82384659b24SMichael Zeller rirb->size = hda_rirb_sizes[rirbsize]; 82484659b24SMichael Zeller 82584659b24SMichael Zeller if (!rirb->size) { 826154972afSPatrick Mooney DPRINTF("Invalid rirb size"); 82784659b24SMichael Zeller return (-1); 82884659b24SMichael Zeller } 82984659b24SMichael Zeller 83084659b24SMichael Zeller rirblbase = hda_get_reg_by_offset(sc, HDAC_RIRBLBASE); 83184659b24SMichael Zeller rirbubase = hda_get_reg_by_offset(sc, HDAC_RIRBUBASE); 83284659b24SMichael Zeller 83384659b24SMichael Zeller rirbpaddr = rirblbase | (rirbubase << 32); 834154972afSPatrick Mooney DPRINTF("RIRB dma_paddr: %p", (void *)rirbpaddr); 83584659b24SMichael Zeller 83684659b24SMichael Zeller rirb->dma_vaddr = hda_dma_get_vaddr(sc, rirbpaddr, 83784659b24SMichael Zeller HDA_RIRB_ENTRY_LEN * rirb->size); 83884659b24SMichael Zeller if (!rirb->dma_vaddr) { 839154972afSPatrick Mooney DPRINTF("Fail to get the guest virtual address"); 84084659b24SMichael Zeller return (-1); 84184659b24SMichael Zeller } 84284659b24SMichael Zeller 84384659b24SMichael Zeller rirb->wp = hda_get_reg_by_offset(sc, HDAC_RIRBWP); 84484659b24SMichael Zeller rirb->rp = 0x0000; 84584659b24SMichael Zeller 84684659b24SMichael Zeller rirb->run = 1; 84784659b24SMichael Zeller 84884659b24SMichael Zeller hda_print_cmd_ctl_data(rirb); 84984659b24SMichael Zeller 85084659b24SMichael Zeller return (0); 85184659b24SMichael Zeller } 85284659b24SMichael Zeller 85384659b24SMichael Zeller static void * 85484659b24SMichael Zeller hda_dma_get_vaddr(struct hda_softc *sc, uint64_t dma_paddr, size_t len) 85584659b24SMichael Zeller { 85684659b24SMichael Zeller struct pci_devinst *pi = sc->pci_dev; 85784659b24SMichael Zeller 85884659b24SMichael Zeller assert(pi); 85984659b24SMichael Zeller 86084659b24SMichael Zeller return (paddr_guest2host(pi->pi_vmctx, (uintptr_t)dma_paddr, len)); 86184659b24SMichael Zeller } 86284659b24SMichael Zeller 86384659b24SMichael Zeller static void 86484659b24SMichael Zeller hda_dma_st_dword(void *dma_vaddr, uint32_t data) 86584659b24SMichael Zeller { 86684659b24SMichael Zeller *(uint32_t*)dma_vaddr = data; 86784659b24SMichael Zeller } 86884659b24SMichael Zeller 86984659b24SMichael Zeller static uint32_t 87084659b24SMichael Zeller hda_dma_ld_dword(void *dma_vaddr) 87184659b24SMichael Zeller { 87284659b24SMichael Zeller return (*(uint32_t*)dma_vaddr); 87384659b24SMichael Zeller } 87484659b24SMichael Zeller 87584659b24SMichael Zeller static inline uint8_t 87684659b24SMichael Zeller hda_get_stream_by_offsets(uint32_t offset, uint8_t reg_offset) 87784659b24SMichael Zeller { 87884659b24SMichael Zeller uint8_t stream_ind = (offset - reg_offset) >> 5; 87984659b24SMichael Zeller 88084659b24SMichael Zeller assert(stream_ind < HDA_IOSS_NO); 88184659b24SMichael Zeller 88284659b24SMichael Zeller return (stream_ind); 88384659b24SMichael Zeller } 88484659b24SMichael Zeller 88584659b24SMichael Zeller static inline uint32_t 88684659b24SMichael Zeller hda_get_offset_stream(uint8_t stream_ind) 88784659b24SMichael Zeller { 88884659b24SMichael Zeller return (stream_ind << 5); 88984659b24SMichael Zeller } 89084659b24SMichael Zeller 89184659b24SMichael Zeller static void 892*59d65d31SAndy Fiddaman hda_set_gctl(struct hda_softc *sc, uint32_t offset, uint32_t old __unused) 89384659b24SMichael Zeller { 89484659b24SMichael Zeller uint32_t value = hda_get_reg_by_offset(sc, offset); 89584659b24SMichael Zeller 89684659b24SMichael Zeller if (!(value & HDAC_GCTL_CRST)) { 89784659b24SMichael Zeller hda_reset(sc); 89884659b24SMichael Zeller } 89984659b24SMichael Zeller } 90084659b24SMichael Zeller 90184659b24SMichael Zeller static void 90284659b24SMichael Zeller hda_set_statests(struct hda_softc *sc, uint32_t offset, uint32_t old) 90384659b24SMichael Zeller { 90484659b24SMichael Zeller uint32_t value = hda_get_reg_by_offset(sc, offset); 90584659b24SMichael Zeller 90684659b24SMichael Zeller hda_set_reg_by_offset(sc, offset, old); 90784659b24SMichael Zeller 90884659b24SMichael Zeller /* clear the corresponding bits written by the software (guest) */ 90984659b24SMichael Zeller hda_set_field_by_offset(sc, offset, value & HDA_STATESTS_IRQ_MASK, 0); 91084659b24SMichael Zeller 91184659b24SMichael Zeller hda_update_intr(sc); 91284659b24SMichael Zeller } 91384659b24SMichael Zeller 91484659b24SMichael Zeller static void 915*59d65d31SAndy Fiddaman hda_set_corbwp(struct hda_softc *sc, uint32_t offset __unused, 916*59d65d31SAndy Fiddaman uint32_t old __unused) 91784659b24SMichael Zeller { 91884659b24SMichael Zeller hda_corb_run(sc); 91984659b24SMichael Zeller } 92084659b24SMichael Zeller 92184659b24SMichael Zeller static void 92284659b24SMichael Zeller hda_set_corbctl(struct hda_softc *sc, uint32_t offset, uint32_t old) 92384659b24SMichael Zeller { 92484659b24SMichael Zeller uint32_t value = hda_get_reg_by_offset(sc, offset); 92584659b24SMichael Zeller int err; 92684659b24SMichael Zeller struct hda_codec_cmd_ctl *corb = NULL; 92784659b24SMichael Zeller 92884659b24SMichael Zeller if (value & HDAC_CORBCTL_CORBRUN) { 92984659b24SMichael Zeller if (!(old & HDAC_CORBCTL_CORBRUN)) { 93084659b24SMichael Zeller err = hda_corb_start(sc); 93184659b24SMichael Zeller assert(!err); 93284659b24SMichael Zeller } 93384659b24SMichael Zeller } else { 93484659b24SMichael Zeller corb = &sc->corb; 93584659b24SMichael Zeller memset(corb, 0, sizeof(*corb)); 93684659b24SMichael Zeller } 93784659b24SMichael Zeller 93884659b24SMichael Zeller hda_corb_run(sc); 93984659b24SMichael Zeller } 94084659b24SMichael Zeller 94184659b24SMichael Zeller static void 942*59d65d31SAndy Fiddaman hda_set_rirbctl(struct hda_softc *sc, uint32_t offset, uint32_t old __unused) 94384659b24SMichael Zeller { 94484659b24SMichael Zeller uint32_t value = hda_get_reg_by_offset(sc, offset); 94584659b24SMichael Zeller int err; 94684659b24SMichael Zeller struct hda_codec_cmd_ctl *rirb = NULL; 94784659b24SMichael Zeller 94884659b24SMichael Zeller if (value & HDAC_RIRBCTL_RIRBDMAEN) { 94984659b24SMichael Zeller err = hda_rirb_start(sc); 95084659b24SMichael Zeller assert(!err); 95184659b24SMichael Zeller } else { 95284659b24SMichael Zeller rirb = &sc->rirb; 95384659b24SMichael Zeller memset(rirb, 0, sizeof(*rirb)); 95484659b24SMichael Zeller } 95584659b24SMichael Zeller } 95684659b24SMichael Zeller 95784659b24SMichael Zeller static void 95884659b24SMichael Zeller hda_set_rirbsts(struct hda_softc *sc, uint32_t offset, uint32_t old) 95984659b24SMichael Zeller { 96084659b24SMichael Zeller uint32_t value = hda_get_reg_by_offset(sc, offset); 96184659b24SMichael Zeller 96284659b24SMichael Zeller hda_set_reg_by_offset(sc, offset, old); 96384659b24SMichael Zeller 96484659b24SMichael Zeller /* clear the corresponding bits written by the software (guest) */ 96584659b24SMichael Zeller hda_set_field_by_offset(sc, offset, value & HDA_RIRBSTS_IRQ_MASK, 0); 96684659b24SMichael Zeller 96784659b24SMichael Zeller hda_update_intr(sc); 96884659b24SMichael Zeller } 96984659b24SMichael Zeller 97084659b24SMichael Zeller static void 97184659b24SMichael Zeller hda_set_dpiblbase(struct hda_softc *sc, uint32_t offset, uint32_t old) 97284659b24SMichael Zeller { 97384659b24SMichael Zeller uint32_t value = hda_get_reg_by_offset(sc, offset); 97484659b24SMichael Zeller uint64_t dpiblbase = 0; 97584659b24SMichael Zeller uint64_t dpibubase = 0; 97684659b24SMichael Zeller uint64_t dpibpaddr = 0; 97784659b24SMichael Zeller 97884659b24SMichael Zeller if ((value & HDAC_DPLBASE_DPLBASE_DMAPBE) != (old & \ 97984659b24SMichael Zeller HDAC_DPLBASE_DPLBASE_DMAPBE)) { 98084659b24SMichael Zeller if (value & HDAC_DPLBASE_DPLBASE_DMAPBE) { 98184659b24SMichael Zeller dpiblbase = value & HDAC_DPLBASE_DPLBASE_MASK; 98284659b24SMichael Zeller dpibubase = hda_get_reg_by_offset(sc, HDAC_DPIBUBASE); 98384659b24SMichael Zeller 98484659b24SMichael Zeller dpibpaddr = dpiblbase | (dpibubase << 32); 985154972afSPatrick Mooney DPRINTF("DMA Position In Buffer dma_paddr: %p", 98684659b24SMichael Zeller (void *)dpibpaddr); 98784659b24SMichael Zeller 98884659b24SMichael Zeller sc->dma_pib_vaddr = hda_dma_get_vaddr(sc, dpibpaddr, 98984659b24SMichael Zeller HDA_DMA_PIB_ENTRY_LEN * HDA_IOSS_NO); 99084659b24SMichael Zeller if (!sc->dma_pib_vaddr) { 99184659b24SMichael Zeller DPRINTF("Fail to get the guest \ 992154972afSPatrick Mooney virtual address"); 99384659b24SMichael Zeller assert(0); 99484659b24SMichael Zeller } 99584659b24SMichael Zeller } else { 996154972afSPatrick Mooney DPRINTF("DMA Position In Buffer Reset"); 99784659b24SMichael Zeller sc->dma_pib_vaddr = NULL; 99884659b24SMichael Zeller } 99984659b24SMichael Zeller } 100084659b24SMichael Zeller } 100184659b24SMichael Zeller 100284659b24SMichael Zeller static void 100384659b24SMichael Zeller hda_set_sdctl(struct hda_softc *sc, uint32_t offset, uint32_t old) 100484659b24SMichael Zeller { 100584659b24SMichael Zeller uint8_t stream_ind = hda_get_stream_by_offsets(offset, HDAC_SDCTL0); 100684659b24SMichael Zeller uint32_t value = hda_get_reg_by_offset(sc, offset); 100784659b24SMichael Zeller int err; 100884659b24SMichael Zeller 1009154972afSPatrick Mooney DPRINTF("stream_ind: 0x%x old: 0x%x value: 0x%x", 101084659b24SMichael Zeller stream_ind, old, value); 101184659b24SMichael Zeller 101284659b24SMichael Zeller if (value & HDAC_SDCTL_SRST) { 101384659b24SMichael Zeller hda_stream_reset(sc, stream_ind); 101484659b24SMichael Zeller } 101584659b24SMichael Zeller 101684659b24SMichael Zeller if ((value & HDAC_SDCTL_RUN) != (old & HDAC_SDCTL_RUN)) { 101784659b24SMichael Zeller if (value & HDAC_SDCTL_RUN) { 101884659b24SMichael Zeller err = hda_stream_start(sc, stream_ind); 101984659b24SMichael Zeller assert(!err); 102084659b24SMichael Zeller } else { 102184659b24SMichael Zeller err = hda_stream_stop(sc, stream_ind); 102284659b24SMichael Zeller assert(!err); 102384659b24SMichael Zeller } 102484659b24SMichael Zeller } 102584659b24SMichael Zeller } 102684659b24SMichael Zeller 102784659b24SMichael Zeller static void 1028*59d65d31SAndy Fiddaman hda_set_sdctl2(struct hda_softc *sc, uint32_t offset, uint32_t old __unused) 102984659b24SMichael Zeller { 103084659b24SMichael Zeller uint32_t value = hda_get_reg_by_offset(sc, offset); 103184659b24SMichael Zeller 103284659b24SMichael Zeller hda_set_field_by_offset(sc, offset - 2, 0x00ff0000, value << 16); 103384659b24SMichael Zeller } 103484659b24SMichael Zeller 103584659b24SMichael Zeller static void 103684659b24SMichael Zeller hda_set_sdsts(struct hda_softc *sc, uint32_t offset, uint32_t old) 103784659b24SMichael Zeller { 103884659b24SMichael Zeller uint32_t value = hda_get_reg_by_offset(sc, offset); 103984659b24SMichael Zeller 104084659b24SMichael Zeller hda_set_reg_by_offset(sc, offset, old); 104184659b24SMichael Zeller 104284659b24SMichael Zeller /* clear the corresponding bits written by the software (guest) */ 104384659b24SMichael Zeller hda_set_field_by_offset(sc, offset, value & HDA_SDSTS_IRQ_MASK, 0); 104484659b24SMichael Zeller 104584659b24SMichael Zeller hda_update_intr(sc); 104684659b24SMichael Zeller } 104784659b24SMichael Zeller 104884659b24SMichael Zeller static int 104984659b24SMichael Zeller hda_signal_state_change(struct hda_codec_inst *hci) 105084659b24SMichael Zeller { 105184659b24SMichael Zeller struct hda_softc *sc = NULL; 105284659b24SMichael Zeller uint32_t sdiwake = 0; 105384659b24SMichael Zeller 105484659b24SMichael Zeller assert(hci); 105584659b24SMichael Zeller assert(hci->hda); 105684659b24SMichael Zeller 1057154972afSPatrick Mooney DPRINTF("cad: 0x%x", hci->cad); 105884659b24SMichael Zeller 105984659b24SMichael Zeller sc = hci->hda; 106084659b24SMichael Zeller sdiwake = 1 << hci->cad; 106184659b24SMichael Zeller 106284659b24SMichael Zeller hda_set_field_by_offset(sc, HDAC_STATESTS, sdiwake, sdiwake); 106384659b24SMichael Zeller hda_update_intr(sc); 106484659b24SMichael Zeller 106584659b24SMichael Zeller return (0); 106684659b24SMichael Zeller } 106784659b24SMichael Zeller 106884659b24SMichael Zeller static int 106984659b24SMichael Zeller hda_response(struct hda_codec_inst *hci, uint32_t response, uint8_t unsol) 107084659b24SMichael Zeller { 107184659b24SMichael Zeller struct hda_softc *sc = NULL; 107284659b24SMichael Zeller struct hda_codec_cmd_ctl *rirb = NULL; 107384659b24SMichael Zeller uint32_t response_ex = 0; 107484659b24SMichael Zeller uint8_t rintcnt = 0; 107584659b24SMichael Zeller 107684659b24SMichael Zeller assert(hci); 107784659b24SMichael Zeller assert(hci->cad <= HDA_CODEC_MAX); 107884659b24SMichael Zeller 107984659b24SMichael Zeller response_ex = hci->cad | unsol; 108084659b24SMichael Zeller 108184659b24SMichael Zeller sc = hci->hda; 108284659b24SMichael Zeller assert(sc); 108384659b24SMichael Zeller 108484659b24SMichael Zeller rirb = &sc->rirb; 108584659b24SMichael Zeller 108684659b24SMichael Zeller if (rirb->run) { 108784659b24SMichael Zeller rirb->wp++; 108884659b24SMichael Zeller rirb->wp %= rirb->size; 108984659b24SMichael Zeller 1090*59d65d31SAndy Fiddaman hda_dma_st_dword((uint8_t *)rirb->dma_vaddr + 1091*59d65d31SAndy Fiddaman HDA_RIRB_ENTRY_LEN * rirb->wp, response); 1092*59d65d31SAndy Fiddaman hda_dma_st_dword((uint8_t *)rirb->dma_vaddr + 1093*59d65d31SAndy Fiddaman HDA_RIRB_ENTRY_LEN * rirb->wp + 0x04, response_ex); 109484659b24SMichael Zeller 109584659b24SMichael Zeller hda_set_reg_by_offset(sc, HDAC_RIRBWP, rirb->wp); 109684659b24SMichael Zeller 109784659b24SMichael Zeller sc->rirb_cnt++; 109884659b24SMichael Zeller } 109984659b24SMichael Zeller 110084659b24SMichael Zeller rintcnt = hda_get_reg_by_offset(sc, HDAC_RINTCNT); 110184659b24SMichael Zeller if (sc->rirb_cnt == rintcnt) 110284659b24SMichael Zeller hda_response_interrupt(sc); 110384659b24SMichael Zeller 110484659b24SMichael Zeller return (0); 110584659b24SMichael Zeller } 110684659b24SMichael Zeller 110784659b24SMichael Zeller static int 110884659b24SMichael Zeller hda_transfer(struct hda_codec_inst *hci, uint8_t stream, uint8_t dir, 1109*59d65d31SAndy Fiddaman uint8_t *buf, size_t count) 111084659b24SMichael Zeller { 111184659b24SMichael Zeller struct hda_softc *sc = NULL; 111284659b24SMichael Zeller struct hda_stream_desc *st = NULL; 111384659b24SMichael Zeller struct hda_bdle_desc *bdl = NULL; 111484659b24SMichael Zeller struct hda_bdle_desc *bdle_desc = NULL; 111584659b24SMichael Zeller uint8_t stream_ind = 0; 111684659b24SMichael Zeller uint32_t lpib = 0; 111784659b24SMichael Zeller uint32_t off = 0; 111884659b24SMichael Zeller size_t left = 0; 111984659b24SMichael Zeller uint8_t irq = 0; 112084659b24SMichael Zeller 112184659b24SMichael Zeller assert(hci); 112284659b24SMichael Zeller assert(hci->hda); 112384659b24SMichael Zeller assert(buf); 112484659b24SMichael Zeller assert(!(count % HDA_DMA_ACCESS_LEN)); 112584659b24SMichael Zeller 112684659b24SMichael Zeller if (!stream) { 1127154972afSPatrick Mooney DPRINTF("Invalid stream"); 112884659b24SMichael Zeller return (-1); 112984659b24SMichael Zeller } 113084659b24SMichael Zeller 113184659b24SMichael Zeller sc = hci->hda; 113284659b24SMichael Zeller 113384659b24SMichael Zeller assert(stream < HDA_STREAM_TAGS_CNT); 113484659b24SMichael Zeller stream_ind = sc->stream_map[dir][stream]; 113584659b24SMichael Zeller 113684659b24SMichael Zeller if (!dir) 113784659b24SMichael Zeller assert(stream_ind < HDA_ISS_NO); 113884659b24SMichael Zeller else 113984659b24SMichael Zeller assert(stream_ind >= HDA_ISS_NO && stream_ind < HDA_IOSS_NO); 114084659b24SMichael Zeller 114184659b24SMichael Zeller st = &sc->streams[stream_ind]; 114284659b24SMichael Zeller if (!st->run) { 1143154972afSPatrick Mooney DPRINTF("Stream 0x%x stopped", stream); 114484659b24SMichael Zeller return (-1); 114584659b24SMichael Zeller } 114684659b24SMichael Zeller 114784659b24SMichael Zeller assert(st->stream == stream); 114884659b24SMichael Zeller 114984659b24SMichael Zeller off = hda_get_offset_stream(stream_ind); 115084659b24SMichael Zeller 115184659b24SMichael Zeller lpib = hda_get_reg_by_offset(sc, off + HDAC_SDLPIB); 115284659b24SMichael Zeller 115384659b24SMichael Zeller bdl = st->bdl; 115484659b24SMichael Zeller 115584659b24SMichael Zeller assert(st->be < st->bdl_cnt); 115684659b24SMichael Zeller assert(st->bp < bdl[st->be].len); 115784659b24SMichael Zeller 115884659b24SMichael Zeller left = count; 115984659b24SMichael Zeller while (left) { 116084659b24SMichael Zeller bdle_desc = &bdl[st->be]; 116184659b24SMichael Zeller 116284659b24SMichael Zeller if (dir) 1163*59d65d31SAndy Fiddaman *(uint32_t *)buf = hda_dma_ld_dword( 1164*59d65d31SAndy Fiddaman (uint8_t *)bdle_desc->addr + st->bp); 116584659b24SMichael Zeller else 1166*59d65d31SAndy Fiddaman hda_dma_st_dword((uint8_t *)bdle_desc->addr + 1167*59d65d31SAndy Fiddaman st->bp, *(uint32_t *)buf); 116884659b24SMichael Zeller 116984659b24SMichael Zeller buf += HDA_DMA_ACCESS_LEN; 117084659b24SMichael Zeller st->bp += HDA_DMA_ACCESS_LEN; 117184659b24SMichael Zeller lpib += HDA_DMA_ACCESS_LEN; 117284659b24SMichael Zeller left -= HDA_DMA_ACCESS_LEN; 117384659b24SMichael Zeller 117484659b24SMichael Zeller if (st->bp == bdle_desc->len) { 117584659b24SMichael Zeller st->bp = 0; 117684659b24SMichael Zeller if (bdle_desc->ioc) 117784659b24SMichael Zeller irq = 1; 117884659b24SMichael Zeller st->be++; 117984659b24SMichael Zeller if (st->be == st->bdl_cnt) { 118084659b24SMichael Zeller st->be = 0; 118184659b24SMichael Zeller lpib = 0; 118284659b24SMichael Zeller } 118384659b24SMichael Zeller bdle_desc = &bdl[st->be]; 118484659b24SMichael Zeller } 118584659b24SMichael Zeller } 118684659b24SMichael Zeller 118784659b24SMichael Zeller hda_set_pib(sc, stream_ind, lpib); 118884659b24SMichael Zeller 118984659b24SMichael Zeller if (irq) { 119084659b24SMichael Zeller hda_set_field_by_offset(sc, off + HDAC_SDSTS, 119184659b24SMichael Zeller HDAC_SDSTS_BCIS, HDAC_SDSTS_BCIS); 119284659b24SMichael Zeller hda_update_intr(sc); 119384659b24SMichael Zeller } 119484659b24SMichael Zeller 119584659b24SMichael Zeller return (0); 119684659b24SMichael Zeller } 119784659b24SMichael Zeller 119884659b24SMichael Zeller static void 119984659b24SMichael Zeller hda_set_pib(struct hda_softc *sc, uint8_t stream_ind, uint32_t pib) 120084659b24SMichael Zeller { 120184659b24SMichael Zeller uint32_t off = hda_get_offset_stream(stream_ind); 120284659b24SMichael Zeller 120384659b24SMichael Zeller hda_set_reg_by_offset(sc, off + HDAC_SDLPIB, pib); 120484659b24SMichael Zeller /* LPIB Alias */ 120584659b24SMichael Zeller hda_set_reg_by_offset(sc, 0x2000 + off + HDAC_SDLPIB, pib); 120684659b24SMichael Zeller if (sc->dma_pib_vaddr) 1207*59d65d31SAndy Fiddaman *(uint32_t *)((uint8_t *)sc->dma_pib_vaddr + stream_ind * 120884659b24SMichael Zeller HDA_DMA_PIB_ENTRY_LEN) = pib; 120984659b24SMichael Zeller } 121084659b24SMichael Zeller 121184659b24SMichael Zeller static uint64_t hda_get_clock_ns(void) 121284659b24SMichael Zeller { 121384659b24SMichael Zeller struct timespec ts; 121484659b24SMichael Zeller int err; 121584659b24SMichael Zeller 121684659b24SMichael Zeller err = clock_gettime(CLOCK_MONOTONIC, &ts); 121784659b24SMichael Zeller assert(!err); 121884659b24SMichael Zeller 121984659b24SMichael Zeller return (ts.tv_sec * 1000000000LL + ts.tv_nsec); 122084659b24SMichael Zeller } 122184659b24SMichael Zeller 122284659b24SMichael Zeller /* 122384659b24SMichael Zeller * PCI HDA function definitions 122484659b24SMichael Zeller */ 122584659b24SMichael Zeller static int 12262b948146SAndy Fiddaman pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) 122784659b24SMichael Zeller { 122884659b24SMichael Zeller struct hda_softc *sc = NULL; 122984659b24SMichael Zeller 123084659b24SMichael Zeller assert(ctx != NULL); 123184659b24SMichael Zeller assert(pi != NULL); 123284659b24SMichael Zeller 123384659b24SMichael Zeller pci_set_cfgdata16(pi, PCIR_VENDOR, INTEL_VENDORID); 123484659b24SMichael Zeller pci_set_cfgdata16(pi, PCIR_DEVICE, HDA_INTEL_82801G); 123584659b24SMichael Zeller 123684659b24SMichael Zeller pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_MULTIMEDIA_HDA); 123784659b24SMichael Zeller pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_MULTIMEDIA); 123884659b24SMichael Zeller 123984659b24SMichael Zeller /* select the Intel HDA mode */ 124084659b24SMichael Zeller pci_set_cfgdata8(pi, PCIR_HDCTL, 0x01); 124184659b24SMichael Zeller 124284659b24SMichael Zeller /* allocate one BAR register for the Memory address offsets */ 124384659b24SMichael Zeller pci_emul_alloc_bar(pi, 0, PCIBAR_MEM32, HDA_LAST_OFFSET); 124484659b24SMichael Zeller 124584659b24SMichael Zeller /* allocate an IRQ pin for our slot */ 124684659b24SMichael Zeller pci_lintr_request(pi); 124784659b24SMichael Zeller 12482b948146SAndy Fiddaman sc = hda_init(nvl); 124984659b24SMichael Zeller if (!sc) 125084659b24SMichael Zeller return (-1); 125184659b24SMichael Zeller 125284659b24SMichael Zeller sc->pci_dev = pi; 125384659b24SMichael Zeller pi->pi_arg = sc; 125484659b24SMichael Zeller 125584659b24SMichael Zeller return (0); 125684659b24SMichael Zeller } 125784659b24SMichael Zeller 125884659b24SMichael Zeller static void 1259*59d65d31SAndy Fiddaman pci_hda_write(struct vmctx *ctx __unused, 1260*59d65d31SAndy Fiddaman struct pci_devinst *pi, int baridx, uint64_t offset, int size, 1261*59d65d31SAndy Fiddaman uint64_t value) 126284659b24SMichael Zeller { 126384659b24SMichael Zeller struct hda_softc *sc = pi->pi_arg; 126484659b24SMichael Zeller int err; 126584659b24SMichael Zeller 126684659b24SMichael Zeller assert(sc); 126784659b24SMichael Zeller assert(baridx == 0); 126884659b24SMichael Zeller assert(size <= 4); 126984659b24SMichael Zeller 1270154972afSPatrick Mooney DPRINTF("offset: 0x%lx value: 0x%lx", offset, value); 127184659b24SMichael Zeller 127284659b24SMichael Zeller err = hda_write(sc, offset, size, value); 127384659b24SMichael Zeller assert(!err); 127484659b24SMichael Zeller } 127584659b24SMichael Zeller 127684659b24SMichael Zeller static uint64_t 1277*59d65d31SAndy Fiddaman pci_hda_read(struct vmctx *ctx __unused, 1278*59d65d31SAndy Fiddaman struct pci_devinst *pi, int baridx, uint64_t offset, int size) 127984659b24SMichael Zeller { 128084659b24SMichael Zeller struct hda_softc *sc = pi->pi_arg; 128184659b24SMichael Zeller uint64_t value = 0; 128284659b24SMichael Zeller 128384659b24SMichael Zeller assert(sc); 128484659b24SMichael Zeller assert(baridx == 0); 128584659b24SMichael Zeller assert(size <= 4); 128684659b24SMichael Zeller 128784659b24SMichael Zeller value = hda_read(sc, offset); 128884659b24SMichael Zeller 1289154972afSPatrick Mooney DPRINTF("offset: 0x%lx value: 0x%lx", offset, value); 129084659b24SMichael Zeller 129184659b24SMichael Zeller return (value); 129284659b24SMichael Zeller } 1293