11f0387f7SAriff Abdullah /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
41f0387f7SAriff Abdullah * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca>
51f0387f7SAriff Abdullah * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org>
67c6b05d2SAlexander Motin * Copyright (c) 2008-2012 Alexander Motin <mav@FreeBSD.org>
71f0387f7SAriff Abdullah * All rights reserved.
81f0387f7SAriff Abdullah *
91f0387f7SAriff Abdullah * Redistribution and use in source and binary forms, with or without
101f0387f7SAriff Abdullah * modification, are permitted provided that the following conditions
111f0387f7SAriff Abdullah * are met:
121f0387f7SAriff Abdullah * 1. Redistributions of source code must retain the above copyright
131f0387f7SAriff Abdullah * notice, this list of conditions and the following disclaimer.
141f0387f7SAriff Abdullah * 2. Redistributions in binary form must reproduce the above copyright
151f0387f7SAriff Abdullah * notice, this list of conditions and the following disclaimer in the
161f0387f7SAriff Abdullah * documentation and/or other materials provided with the distribution.
171f0387f7SAriff Abdullah *
181f0387f7SAriff Abdullah * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
191f0387f7SAriff Abdullah * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
201f0387f7SAriff Abdullah * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
211f0387f7SAriff Abdullah * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
221f0387f7SAriff Abdullah * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
231f0387f7SAriff Abdullah * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
241f0387f7SAriff Abdullah * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
251f0387f7SAriff Abdullah * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
261f0387f7SAriff Abdullah * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
271f0387f7SAriff Abdullah * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
281f0387f7SAriff Abdullah * SUCH DAMAGE.
291f0387f7SAriff Abdullah */
301f0387f7SAriff Abdullah
311f0387f7SAriff Abdullah /*
327c6b05d2SAlexander Motin * Intel High Definition Audio (Controller) driver for FreeBSD.
331f0387f7SAriff Abdullah */
341f0387f7SAriff Abdullah
3590da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS
3690da2b28SAriff Abdullah #include "opt_snd.h"
3790da2b28SAriff Abdullah #endif
3890da2b28SAriff Abdullah
391f0387f7SAriff Abdullah #include <dev/sound/pcm/sound.h>
401f0387f7SAriff Abdullah #include <dev/pci/pcireg.h>
411f0387f7SAriff Abdullah #include <dev/pci/pcivar.h>
421f0387f7SAriff Abdullah
43e5ad83a7SAriff Abdullah #include <sys/ctype.h>
442a9ee5fcSJustin Hibbits #include <sys/endian.h>
45e5ad83a7SAriff Abdullah #include <sys/taskqueue.h>
46e5ad83a7SAriff Abdullah
471f0387f7SAriff Abdullah #include <dev/sound/pci/hda/hdac_private.h>
481f0387f7SAriff Abdullah #include <dev/sound/pci/hda/hdac_reg.h>
491f0387f7SAriff Abdullah #include <dev/sound/pci/hda/hda_reg.h>
501f0387f7SAriff Abdullah #include <dev/sound/pci/hda/hdac.h>
511f0387f7SAriff Abdullah
525409d3eeSAlexander Motin #define HDA_DRV_TEST_REV "20120126_0002"
531f0387f7SAriff Abdullah
541f0387f7SAriff Abdullah #define hdac_lock(sc) snd_mtxlock((sc)->lock)
551f0387f7SAriff Abdullah #define hdac_unlock(sc) snd_mtxunlock((sc)->lock)
568d999aa8SAriff Abdullah #define hdac_lockassert(sc) snd_mtxassert((sc)->lock)
571f0387f7SAriff Abdullah
587c6b05d2SAlexander Motin #define HDAC_QUIRK_64BIT (1 << 0)
597c6b05d2SAlexander Motin #define HDAC_QUIRK_DMAPOS (1 << 1)
607c6b05d2SAlexander Motin #define HDAC_QUIRK_MSI (1 << 2)
61e5ad83a7SAriff Abdullah
628d999aa8SAriff Abdullah static const struct {
63abe917adSMarius Strobl const char *key;
648d999aa8SAriff Abdullah uint32_t value;
658d999aa8SAriff Abdullah } hdac_quirks_tab[] = {
665c96a7b2SAndriy Gapon { "64bit", HDAC_QUIRK_64BIT },
677c6b05d2SAlexander Motin { "dmapos", HDAC_QUIRK_DMAPOS },
687c6b05d2SAlexander Motin { "msi", HDAC_QUIRK_MSI },
698d999aa8SAriff Abdullah };
701f0387f7SAriff Abdullah
717c6b05d2SAlexander Motin MALLOC_DEFINE(M_HDAC, "hdac", "HDA Controller");
72edce9c99SAlexander Motin
731f0387f7SAriff Abdullah static const struct {
741f0387f7SAriff Abdullah uint32_t model;
75abe917adSMarius Strobl const char *desc;
767c6b05d2SAlexander Motin char quirks_on;
777c6b05d2SAlexander Motin char quirks_off;
781f0387f7SAriff Abdullah } hdac_devices[] = {
79c9b3a5a0SAlexander Motin { HDA_INTEL_OAK, "Intel Oaktrail", 0, 0 },
80fc68af79SAlexander Motin { HDA_INTEL_CMLKLP, "Intel Comet Lake-LP", 0, 0 },
81fc68af79SAlexander Motin { HDA_INTEL_CMLKH, "Intel Comet Lake-H", 0, 0 },
82c9b3a5a0SAlexander Motin { HDA_INTEL_BAY, "Intel BayTrail", 0, 0 },
83c9b3a5a0SAlexander Motin { HDA_INTEL_HSW1, "Intel Haswell", 0, 0 },
84c9b3a5a0SAlexander Motin { HDA_INTEL_HSW2, "Intel Haswell", 0, 0 },
85c9b3a5a0SAlexander Motin { HDA_INTEL_HSW3, "Intel Haswell", 0, 0 },
86420827daSRui Paulo { HDA_INTEL_BDW1, "Intel Broadwell", 0, 0 },
87420827daSRui Paulo { HDA_INTEL_BDW2, "Intel Broadwell", 0, 0 },
88fc68af79SAlexander Motin { HDA_INTEL_BXTNT, "Intel Broxton-T", 0, 0 },
897c6b05d2SAlexander Motin { HDA_INTEL_CPT, "Intel Cougar Point", 0, 0 },
907c6b05d2SAlexander Motin { HDA_INTEL_PATSBURG,"Intel Patsburg", 0, 0 },
917c6b05d2SAlexander Motin { HDA_INTEL_PPT1, "Intel Panther Point", 0, 0 },
92fc68af79SAlexander Motin { HDA_INTEL_BR, "Intel Braswell", 0, 0 },
939e81697fSJack F Vogel { HDA_INTEL_LPT1, "Intel Lynx Point", 0, 0 },
949e81697fSJack F Vogel { HDA_INTEL_LPT2, "Intel Lynx Point", 0, 0 },
95e67f3becSAlexander Motin { HDA_INTEL_WCPT, "Intel Wildcat Point", 0, 0 },
96c9b3a5a0SAlexander Motin { HDA_INTEL_WELLS1, "Intel Wellsburg", 0, 0 },
97c9b3a5a0SAlexander Motin { HDA_INTEL_WELLS2, "Intel Wellsburg", 0, 0 },
98c9b3a5a0SAlexander Motin { HDA_INTEL_LPTLP1, "Intel Lynx Point-LP", 0, 0 },
99c9b3a5a0SAlexander Motin { HDA_INTEL_LPTLP2, "Intel Lynx Point-LP", 0, 0 },
10071733a50SAlexander Motin { HDA_INTEL_SRPTLP, "Intel Sunrise Point-LP", 0, 0 },
101ce829184SAlexander Motin { HDA_INTEL_KBLKLP, "Intel Kaby Lake-LP", 0, 0 },
10271733a50SAlexander Motin { HDA_INTEL_SRPT, "Intel Sunrise Point", 0, 0 },
103ce829184SAlexander Motin { HDA_INTEL_KBLK, "Intel Kaby Lake", 0, 0 },
104ce829184SAlexander Motin { HDA_INTEL_KBLKH, "Intel Kaby Lake-H", 0, 0 },
105ce829184SAlexander Motin { HDA_INTEL_CFLK, "Intel Coffee Lake", 0, 0 },
106fc68af79SAlexander Motin { HDA_INTEL_CMLKS, "Intel Comet Lake-S", 0, 0 },
107c314e2afSOleksandr Tymoshenko { HDA_INTEL_CNLK, "Intel Cannon Lake", 0, 0 },
108a6c2525cSScott Long { HDA_INTEL_ICLK, "Intel Ice Lake", 0, 0 },
10935228417SScott Long { HDA_INTEL_TGLK, "Intel Tiger Lake", 0, 0 },
110fb1028dcSAdam Retter { HDA_INTEL_TGLKH, "Intel Tiger Lake-H", 0, 0 },
111a6c2525cSScott Long { HDA_INTEL_GMLK, "Intel Gemini Lake", 0, 0 },
112dc238358SAlexander Motin { HDA_INTEL_ALLK, "Intel Alder Lake", 0, 0 },
11322ecfc58SNeel Chauhan { HDA_INTEL_ALLKM, "Intel Alder Lake-M", 0, 0 },
11422ecfc58SNeel Chauhan { HDA_INTEL_ALLKN, "Intel Alder Lake-N", 0, 0 },
11522ecfc58SNeel Chauhan { HDA_INTEL_ALLKP1, "Intel Alder Lake-P", 0, 0 },
11622ecfc58SNeel Chauhan { HDA_INTEL_ALLKP2, "Intel Alder Lake-P", 0, 0 },
11722ecfc58SNeel Chauhan { HDA_INTEL_ALLKPS, "Intel Alder Lake-PS", 0, 0 },
11822ecfc58SNeel Chauhan { HDA_INTEL_RPTLK1, "Intel Raptor Lake-P", 0, 0 },
11922ecfc58SNeel Chauhan { HDA_INTEL_RPTLK2, "Intel Raptor Lake-P", 0, 0 },
1201dd1a696SMichael Zhilin { HDA_INTEL_MTL, "Intel Meteor Lake-P", 0, 0 },
1211dd1a696SMichael Zhilin { HDA_INTEL_ARLS, "Intel Arrow Lake-S", 0, 0 },
1221dd1a696SMichael Zhilin { HDA_INTEL_ARL, "Intel Arrow Lake", 0, 0 },
1231dd1a696SMichael Zhilin { HDA_INTEL_LNLP, "Intel Lunar Lake-P", 0, 0 },
1247c6b05d2SAlexander Motin { HDA_INTEL_82801F, "Intel 82801F", 0, 0 },
1257c6b05d2SAlexander Motin { HDA_INTEL_63XXESB, "Intel 631x/632xESB", 0, 0 },
1267c6b05d2SAlexander Motin { HDA_INTEL_82801G, "Intel 82801G", 0, 0 },
1277c6b05d2SAlexander Motin { HDA_INTEL_82801H, "Intel 82801H", 0, 0 },
1287c6b05d2SAlexander Motin { HDA_INTEL_82801I, "Intel 82801I", 0, 0 },
129fc68af79SAlexander Motin { HDA_INTEL_JLK, "Intel Jasper Lake", 0, 0 },
1307c6b05d2SAlexander Motin { HDA_INTEL_82801JI, "Intel 82801JI", 0, 0 },
1317c6b05d2SAlexander Motin { HDA_INTEL_82801JD, "Intel 82801JD", 0, 0 },
1326750c3d0SAlexander Motin { HDA_INTEL_PCH, "Intel Ibex Peak", 0, 0 },
1336750c3d0SAlexander Motin { HDA_INTEL_PCH2, "Intel Ibex Peak", 0, 0 },
134fc68af79SAlexander Motin { HDA_INTEL_ELLK, "Intel Elkhart Lake", 0, 0 },
135fc68af79SAlexander Motin { HDA_INTEL_JLK2, "Intel Jasper Lake", 0, 0 },
136fc68af79SAlexander Motin { HDA_INTEL_BXTNP, "Intel Broxton-P", 0, 0 },
1377c6b05d2SAlexander Motin { HDA_INTEL_SCH, "Intel SCH", 0, 0 },
1387c6b05d2SAlexander Motin { HDA_NVIDIA_MCP51, "NVIDIA MCP51", 0, HDAC_QUIRK_MSI },
1397c6b05d2SAlexander Motin { HDA_NVIDIA_MCP55, "NVIDIA MCP55", 0, HDAC_QUIRK_MSI },
1407c6b05d2SAlexander Motin { HDA_NVIDIA_MCP61_1, "NVIDIA MCP61", 0, 0 },
1417c6b05d2SAlexander Motin { HDA_NVIDIA_MCP61_2, "NVIDIA MCP61", 0, 0 },
1427c6b05d2SAlexander Motin { HDA_NVIDIA_MCP65_1, "NVIDIA MCP65", 0, 0 },
1437c6b05d2SAlexander Motin { HDA_NVIDIA_MCP65_2, "NVIDIA MCP65", 0, 0 },
1447c6b05d2SAlexander Motin { HDA_NVIDIA_MCP67_1, "NVIDIA MCP67", 0, 0 },
1457c6b05d2SAlexander Motin { HDA_NVIDIA_MCP67_2, "NVIDIA MCP67", 0, 0 },
1467c6b05d2SAlexander Motin { HDA_NVIDIA_MCP73_1, "NVIDIA MCP73", 0, 0 },
1477c6b05d2SAlexander Motin { HDA_NVIDIA_MCP73_2, "NVIDIA MCP73", 0, 0 },
1487c6b05d2SAlexander Motin { HDA_NVIDIA_MCP78_1, "NVIDIA MCP78", 0, HDAC_QUIRK_64BIT },
1497c6b05d2SAlexander Motin { HDA_NVIDIA_MCP78_2, "NVIDIA MCP78", 0, HDAC_QUIRK_64BIT },
1507c6b05d2SAlexander Motin { HDA_NVIDIA_MCP78_3, "NVIDIA MCP78", 0, HDAC_QUIRK_64BIT },
1517c6b05d2SAlexander Motin { HDA_NVIDIA_MCP78_4, "NVIDIA MCP78", 0, HDAC_QUIRK_64BIT },
1527c6b05d2SAlexander Motin { HDA_NVIDIA_MCP79_1, "NVIDIA MCP79", 0, 0 },
1537c6b05d2SAlexander Motin { HDA_NVIDIA_MCP79_2, "NVIDIA MCP79", 0, 0 },
1547c6b05d2SAlexander Motin { HDA_NVIDIA_MCP79_3, "NVIDIA MCP79", 0, 0 },
1557c6b05d2SAlexander Motin { HDA_NVIDIA_MCP79_4, "NVIDIA MCP79", 0, 0 },
1567c6b05d2SAlexander Motin { HDA_NVIDIA_MCP89_1, "NVIDIA MCP89", 0, 0 },
1577c6b05d2SAlexander Motin { HDA_NVIDIA_MCP89_2, "NVIDIA MCP89", 0, 0 },
1587c6b05d2SAlexander Motin { HDA_NVIDIA_MCP89_3, "NVIDIA MCP89", 0, 0 },
1597c6b05d2SAlexander Motin { HDA_NVIDIA_MCP89_4, "NVIDIA MCP89", 0, 0 },
1605bcd25deSAlexander Motin { HDA_NVIDIA_0BE2, "NVIDIA (0x0be2)", 0, HDAC_QUIRK_MSI },
1615bcd25deSAlexander Motin { HDA_NVIDIA_0BE3, "NVIDIA (0x0be3)", 0, HDAC_QUIRK_MSI },
1625bcd25deSAlexander Motin { HDA_NVIDIA_0BE4, "NVIDIA (0x0be4)", 0, HDAC_QUIRK_MSI },
16388addcbeSAlexander Motin { HDA_NVIDIA_GT100, "NVIDIA GT100", 0, HDAC_QUIRK_MSI },
16488addcbeSAlexander Motin { HDA_NVIDIA_GT104, "NVIDIA GT104", 0, HDAC_QUIRK_MSI },
16588addcbeSAlexander Motin { HDA_NVIDIA_GT106, "NVIDIA GT106", 0, HDAC_QUIRK_MSI },
16688addcbeSAlexander Motin { HDA_NVIDIA_GT108, "NVIDIA GT108", 0, HDAC_QUIRK_MSI },
16788addcbeSAlexander Motin { HDA_NVIDIA_GT116, "NVIDIA GT116", 0, HDAC_QUIRK_MSI },
16888addcbeSAlexander Motin { HDA_NVIDIA_GF119, "NVIDIA GF119", 0, 0 },
16988addcbeSAlexander Motin { HDA_NVIDIA_GF110_1, "NVIDIA GF110", 0, HDAC_QUIRK_MSI },
17088addcbeSAlexander Motin { HDA_NVIDIA_GF110_2, "NVIDIA GF110", 0, HDAC_QUIRK_MSI },
1717c6b05d2SAlexander Motin { HDA_ATI_SB450, "ATI SB450", 0, 0 },
1727c6b05d2SAlexander Motin { HDA_ATI_SB600, "ATI SB600", 0, 0 },
1737c6b05d2SAlexander Motin { HDA_ATI_RS600, "ATI RS600", 0, 0 },
1747c6b05d2SAlexander Motin { HDA_ATI_RS690, "ATI RS690", 0, 0 },
1757c6b05d2SAlexander Motin { HDA_ATI_RS780, "ATI RS780", 0, 0 },
17698d59d2eSAlexander Motin { HDA_ATI_RS880, "ATI RS880", 0, 0 },
1777c6b05d2SAlexander Motin { HDA_ATI_R600, "ATI R600", 0, 0 },
1787c6b05d2SAlexander Motin { HDA_ATI_RV610, "ATI RV610", 0, 0 },
1797c6b05d2SAlexander Motin { HDA_ATI_RV620, "ATI RV620", 0, 0 },
1807c6b05d2SAlexander Motin { HDA_ATI_RV630, "ATI RV630", 0, 0 },
1817c6b05d2SAlexander Motin { HDA_ATI_RV635, "ATI RV635", 0, 0 },
1827c6b05d2SAlexander Motin { HDA_ATI_RV710, "ATI RV710", 0, 0 },
1837c6b05d2SAlexander Motin { HDA_ATI_RV730, "ATI RV730", 0, 0 },
1847c6b05d2SAlexander Motin { HDA_ATI_RV740, "ATI RV740", 0, 0 },
1857c6b05d2SAlexander Motin { HDA_ATI_RV770, "ATI RV770", 0, 0 },
1867d0ec9ddSAlexander Motin { HDA_ATI_RV810, "ATI RV810", 0, 0 },
1877d0ec9ddSAlexander Motin { HDA_ATI_RV830, "ATI RV830", 0, 0 },
1887d0ec9ddSAlexander Motin { HDA_ATI_RV840, "ATI RV840", 0, 0 },
1897d0ec9ddSAlexander Motin { HDA_ATI_RV870, "ATI RV870", 0, 0 },
1907d0ec9ddSAlexander Motin { HDA_ATI_RV910, "ATI RV910", 0, 0 },
1917d0ec9ddSAlexander Motin { HDA_ATI_RV930, "ATI RV930", 0, 0 },
1927d0ec9ddSAlexander Motin { HDA_ATI_RV940, "ATI RV940", 0, 0 },
1937d0ec9ddSAlexander Motin { HDA_ATI_RV970, "ATI RV970", 0, 0 },
1947d0ec9ddSAlexander Motin { HDA_ATI_R1000, "ATI R1000", 0, 0 },
1954cc4b5e2SDmitry Luhtionov { HDA_ATI_OLAND, "ATI Oland", 0, 0 },
19698d59d2eSAlexander Motin { HDA_ATI_KABINI, "ATI Kabini", 0, 0 },
19798d59d2eSAlexander Motin { HDA_ATI_TRINITY, "ATI Trinity", 0, 0 },
198fc68af79SAlexander Motin { HDA_AMD_X370, "AMD X370", 0, 0 },
199fc68af79SAlexander Motin { HDA_AMD_X570, "AMD X570", 0, 0 },
200fc68af79SAlexander Motin { HDA_AMD_STONEY, "AMD Stoney", 0, 0 },
201fc68af79SAlexander Motin { HDA_AMD_RAVEN, "AMD Raven", 0, 0 },
20215e01a35SAlexander Motin { HDA_AMD_HUDSON2, "AMD Hudson-2", 0, 0 },
2037c6b05d2SAlexander Motin { HDA_RDC_M3010, "RDC M3010", 0, 0 },
2047c6b05d2SAlexander Motin { HDA_VIA_VT82XX, "VIA VT8251/8237A",0, 0 },
2052a31a06bSAlexander Motin { HDA_VMWARE, "VMware", 0, 0 },
206af6a86ebSAlexander Motin { HDA_SIS_966, "SiS 966/968", 0, 0 },
2077c6b05d2SAlexander Motin { HDA_ULI_M5461, "ULI M5461", 0, 0 },
20889189224SGleb Smirnoff { HDA_CREATIVE_SB1570, "Creative SB Audigy FX", 0, HDAC_QUIRK_64BIT },
2091f0387f7SAriff Abdullah /* Unknown */
2105bcd25deSAlexander Motin { HDA_INTEL_ALL, "Intel", 0, 0 },
2115bcd25deSAlexander Motin { HDA_NVIDIA_ALL, "NVIDIA", 0, 0 },
2125bcd25deSAlexander Motin { HDA_ATI_ALL, "ATI", 0, 0 },
21315e01a35SAlexander Motin { HDA_AMD_ALL, "AMD", 0, 0 },
214eeec68eaSAlexander Motin { HDA_CREATIVE_ALL, "Creative", 0, 0 },
2155bcd25deSAlexander Motin { HDA_VIA_ALL, "VIA", 0, 0 },
2162a31a06bSAlexander Motin { HDA_VMWARE_ALL, "VMware", 0, 0 },
2175bcd25deSAlexander Motin { HDA_SIS_ALL, "SiS", 0, 0 },
2185bcd25deSAlexander Motin { HDA_ULI_ALL, "ULI", 0, 0 },
2191f0387f7SAriff Abdullah };
2201f0387f7SAriff Abdullah
2211f0387f7SAriff Abdullah static const struct {
22271e3af01SAriff Abdullah uint16_t vendor;
22371e3af01SAriff Abdullah uint8_t reg;
22471e3af01SAriff Abdullah uint8_t mask;
22571e3af01SAriff Abdullah uint8_t enable;
22671e3af01SAriff Abdullah } hdac_pcie_snoop[] = {
22771e3af01SAriff Abdullah { INTEL_VENDORID, 0x00, 0x00, 0x00 },
22871e3af01SAriff Abdullah { ATI_VENDORID, 0x42, 0xf8, 0x02 },
229317cb280SAndriy Gapon { AMD_VENDORID, 0x42, 0xf8, 0x02 },
23071e3af01SAriff Abdullah { NVIDIA_VENDORID, 0x4e, 0xf0, 0x0f },
23171e3af01SAriff Abdullah };
23271e3af01SAriff Abdullah
2331f0387f7SAriff Abdullah /****************************************************************************
2341f0387f7SAriff Abdullah * Function prototypes
2351f0387f7SAriff Abdullah ****************************************************************************/
2361f0387f7SAriff Abdullah static void hdac_intr_handler(void *);
237258ba4c0SEd Maste static int hdac_reset(struct hdac_softc *, bool);
2381f0387f7SAriff Abdullah static int hdac_get_capabilities(struct hdac_softc *);
2391f0387f7SAriff Abdullah static void hdac_dma_cb(void *, bus_dma_segment_t *, int, int);
2401f0387f7SAriff Abdullah static int hdac_dma_alloc(struct hdac_softc *,
2411f0387f7SAriff Abdullah struct hdac_dma *, bus_size_t);
24271e3af01SAriff Abdullah static void hdac_dma_free(struct hdac_softc *, struct hdac_dma *);
2431f0387f7SAriff Abdullah static int hdac_mem_alloc(struct hdac_softc *);
2441f0387f7SAriff Abdullah static void hdac_mem_free(struct hdac_softc *);
2451f0387f7SAriff Abdullah static int hdac_irq_alloc(struct hdac_softc *);
2461f0387f7SAriff Abdullah static void hdac_irq_free(struct hdac_softc *);
2471f0387f7SAriff Abdullah static void hdac_corb_init(struct hdac_softc *);
2481f0387f7SAriff Abdullah static void hdac_rirb_init(struct hdac_softc *);
2491f0387f7SAriff Abdullah static void hdac_corb_start(struct hdac_softc *);
2501f0387f7SAriff Abdullah static void hdac_rirb_start(struct hdac_softc *);
2511f0387f7SAriff Abdullah
2521f0387f7SAriff Abdullah static void hdac_attach2(void *);
2531f0387f7SAriff Abdullah
2547c6b05d2SAlexander Motin static uint32_t hdac_send_command(struct hdac_softc *, nid_t, uint32_t);
2551f0387f7SAriff Abdullah
2561f0387f7SAriff Abdullah static int hdac_probe(device_t);
2571f0387f7SAriff Abdullah static int hdac_attach(device_t);
2581f0387f7SAriff Abdullah static int hdac_detach(device_t);
259859159d1SAlexander Motin static int hdac_suspend(device_t);
260859159d1SAlexander Motin static int hdac_resume(device_t);
2611f0387f7SAriff Abdullah
262a580b31aSAriff Abdullah static int hdac_rirb_flush(struct hdac_softc *sc);
263a580b31aSAriff Abdullah static int hdac_unsolq_flush(struct hdac_softc *sc);
264a580b31aSAriff Abdullah
2657c6b05d2SAlexander Motin /* This function surely going to make its way into upper level someday. */
2661f0387f7SAriff Abdullah static void
hdac_config_fetch(struct hdac_softc * sc,uint32_t * on,uint32_t * off)2677c6b05d2SAlexander Motin hdac_config_fetch(struct hdac_softc *sc, uint32_t *on, uint32_t *off)
2681f0387f7SAriff Abdullah {
2697c6b05d2SAlexander Motin const char *res = NULL;
2707c6b05d2SAlexander Motin int i = 0, j, k, len, inv;
2711f0387f7SAriff Abdullah
2727c6b05d2SAlexander Motin if (resource_string_value(device_get_name(sc->dev),
2737c6b05d2SAlexander Motin device_get_unit(sc->dev), "config", &res) != 0)
2741f0387f7SAriff Abdullah return;
2757c6b05d2SAlexander Motin if (!(res != NULL && strlen(res) > 0))
2767c6b05d2SAlexander Motin return;
2778d999aa8SAriff Abdullah HDA_BOOTVERBOSE(
2787c6b05d2SAlexander Motin device_printf(sc->dev, "Config options:");
2791f0387f7SAriff Abdullah );
2807c6b05d2SAlexander Motin for (;;) {
2817c6b05d2SAlexander Motin while (res[i] != '\0' &&
2827c6b05d2SAlexander Motin (res[i] == ',' || isspace(res[i]) != 0))
2837c6b05d2SAlexander Motin i++;
2847c6b05d2SAlexander Motin if (res[i] == '\0') {
2857c6b05d2SAlexander Motin HDA_BOOTVERBOSE(
2867c6b05d2SAlexander Motin printf("\n");
2877c6b05d2SAlexander Motin );
2887c6b05d2SAlexander Motin return;
2891f0387f7SAriff Abdullah }
2907c6b05d2SAlexander Motin j = i;
2917c6b05d2SAlexander Motin while (res[j] != '\0' &&
2927c6b05d2SAlexander Motin !(res[j] == ',' || isspace(res[j]) != 0))
2937c6b05d2SAlexander Motin j++;
2947c6b05d2SAlexander Motin len = j - i;
2957c6b05d2SAlexander Motin if (len > 2 && strncmp(res + i, "no", 2) == 0)
2967c6b05d2SAlexander Motin inv = 2;
297859159d1SAlexander Motin else
2987c6b05d2SAlexander Motin inv = 0;
299abe917adSMarius Strobl for (k = 0; len > inv && k < nitems(hdac_quirks_tab); k++) {
3007c6b05d2SAlexander Motin if (strncmp(res + i + inv,
3017c6b05d2SAlexander Motin hdac_quirks_tab[k].key, len - inv) != 0)
30271e3af01SAriff Abdullah continue;
3037c6b05d2SAlexander Motin if (len - inv != strlen(hdac_quirks_tab[k].key))
304859159d1SAlexander Motin continue;
305859159d1SAlexander Motin HDA_BOOTVERBOSE(
3067c6b05d2SAlexander Motin printf(" %s%s", (inv != 0) ? "no" : "",
3077c6b05d2SAlexander Motin hdac_quirks_tab[k].key);
308859159d1SAlexander Motin );
3097c6b05d2SAlexander Motin if (inv == 0) {
3107c6b05d2SAlexander Motin *on |= hdac_quirks_tab[k].value;
3115c96a7b2SAndriy Gapon *off &= ~hdac_quirks_tab[k].value;
3127c6b05d2SAlexander Motin } else if (inv != 0) {
3137c6b05d2SAlexander Motin *off |= hdac_quirks_tab[k].value;
3145c96a7b2SAndriy Gapon *on &= ~hdac_quirks_tab[k].value;
315859159d1SAlexander Motin }
3161f0387f7SAriff Abdullah break;
3171f0387f7SAriff Abdullah }
3187c6b05d2SAlexander Motin i = j;
319859159d1SAlexander Motin }
3201f0387f7SAriff Abdullah }
3211f0387f7SAriff Abdullah
3221f0387f7SAriff Abdullah static void
hdac_one_intr(struct hdac_softc * sc,uint32_t intsts)3234c7d1ab0SAndriy Gapon hdac_one_intr(struct hdac_softc *sc, uint32_t intsts)
3241f0387f7SAriff Abdullah {
3257c6b05d2SAlexander Motin device_t dev;
3261f0387f7SAriff Abdullah uint8_t rirbsts;
327859159d1SAlexander Motin int i;
3281f0387f7SAriff Abdullah
3291f0387f7SAriff Abdullah /* Was this a controller interrupt? */
3307c6b05d2SAlexander Motin if (intsts & HDAC_INTSTS_CIS) {
33143022083SAndriy Gapon /*
33243022083SAndriy Gapon * Placeholder: if we ever enable any bits in HDAC_WAKEEN, then
33343022083SAndriy Gapon * we will need to check and clear HDAC_STATESTS.
33443022083SAndriy Gapon * That event is used to report codec status changes such as
33543022083SAndriy Gapon * a reset or a wake-up event.
33643022083SAndriy Gapon */
33743022083SAndriy Gapon /*
33843022083SAndriy Gapon * Placeholder: if we ever enable HDAC_CORBCTL_CMEIE, then we
33943022083SAndriy Gapon * will need to check and clear HDAC_CORBSTS_CMEI in
34043022083SAndriy Gapon * HDAC_CORBSTS.
34143022083SAndriy Gapon * That event is used to report CORB memory errors.
34243022083SAndriy Gapon */
34343022083SAndriy Gapon /*
34443022083SAndriy Gapon * Placeholder: if we ever enable HDAC_RIRBCTL_RIRBOIC, then we
34543022083SAndriy Gapon * will need to check and clear HDAC_RIRBSTS_RIRBOIS in
34643022083SAndriy Gapon * HDAC_RIRBSTS.
34743022083SAndriy Gapon * That event is used to report response FIFO overruns.
34843022083SAndriy Gapon */
34943022083SAndriy Gapon
3501f0387f7SAriff Abdullah /* Get as many responses that we can */
35143022083SAndriy Gapon rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
3527c6b05d2SAlexander Motin while (rirbsts & HDAC_RIRBSTS_RINTFL) {
353a580b31aSAriff Abdullah HDAC_WRITE_1(&sc->mem,
354a580b31aSAriff Abdullah HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL);
3557c6b05d2SAlexander Motin hdac_rirb_flush(sc);
3561f0387f7SAriff Abdullah rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
3571f0387f7SAriff Abdullah }
3587c6b05d2SAlexander Motin if (sc->unsolq_rp != sc->unsolq_wp)
3597c6b05d2SAlexander Motin taskqueue_enqueue(taskqueue_thread, &sc->unsolq_task);
3601f0387f7SAriff Abdullah }
361a580b31aSAriff Abdullah
3628d999aa8SAriff Abdullah if (intsts & HDAC_INTSTS_SIS_MASK) {
3637c6b05d2SAlexander Motin for (i = 0; i < sc->num_ss; i++) {
3647c6b05d2SAlexander Motin if ((intsts & (1 << i)) == 0)
3657c6b05d2SAlexander Motin continue;
3667c6b05d2SAlexander Motin HDAC_WRITE_1(&sc->mem, (i << 5) + HDAC_SDSTS,
3677c6b05d2SAlexander Motin HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS);
3687c6b05d2SAlexander Motin if ((dev = sc->streams[i].dev) != NULL) {
3697c6b05d2SAlexander Motin HDAC_STREAM_INTR(dev,
3707c6b05d2SAlexander Motin sc->streams[i].dir, sc->streams[i].stream);
371859159d1SAlexander Motin }
3727c6b05d2SAlexander Motin }
3731f0387f7SAriff Abdullah }
3744c7d1ab0SAndriy Gapon }
3751f0387f7SAriff Abdullah
3764c7d1ab0SAndriy Gapon /****************************************************************************
3774c7d1ab0SAndriy Gapon * void hdac_intr_handler(void *)
3784c7d1ab0SAndriy Gapon *
3794c7d1ab0SAndriy Gapon * Interrupt handler. Processes interrupts received from the hdac.
3804c7d1ab0SAndriy Gapon ****************************************************************************/
3814c7d1ab0SAndriy Gapon static void
hdac_intr_handler(void * context)3824c7d1ab0SAndriy Gapon hdac_intr_handler(void *context)
3834c7d1ab0SAndriy Gapon {
3844c7d1ab0SAndriy Gapon struct hdac_softc *sc;
3854c7d1ab0SAndriy Gapon uint32_t intsts;
3864c7d1ab0SAndriy Gapon
3874c7d1ab0SAndriy Gapon sc = (struct hdac_softc *)context;
3884c7d1ab0SAndriy Gapon
3894c7d1ab0SAndriy Gapon /*
3904c7d1ab0SAndriy Gapon * Loop until HDAC_INTSTS_GIS gets clear.
3914c7d1ab0SAndriy Gapon * It is plausible that hardware interrupts a host only when GIS goes
3924c7d1ab0SAndriy Gapon * from zero to one. GIS is formed by OR-ing multiple hardware
3934c7d1ab0SAndriy Gapon * statuses, so it's possible that a previously cleared status gets set
3944c7d1ab0SAndriy Gapon * again while another status has not been cleared yet. Thus, there
3954c7d1ab0SAndriy Gapon * will be no new interrupt as GIS always stayed set. If we don't
3964c7d1ab0SAndriy Gapon * re-examine GIS then we can leave it set and never get an interrupt
3974c7d1ab0SAndriy Gapon * again.
3984c7d1ab0SAndriy Gapon */
3994c7d1ab0SAndriy Gapon hdac_lock(sc);
400077564cfSMark Johnston intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS);
401077564cfSMark Johnston while (intsts != 0xffffffff && (intsts & HDAC_INTSTS_GIS) != 0) {
4024c7d1ab0SAndriy Gapon hdac_one_intr(sc, intsts);
4034c7d1ab0SAndriy Gapon intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS);
4044c7d1ab0SAndriy Gapon }
405077564cfSMark Johnston hdac_unlock(sc);
4067c6b05d2SAlexander Motin }
4077c6b05d2SAlexander Motin
4087c6b05d2SAlexander Motin static void
hdac_poll_callback(void * arg)4097c6b05d2SAlexander Motin hdac_poll_callback(void *arg)
4107c6b05d2SAlexander Motin {
4117c6b05d2SAlexander Motin struct hdac_softc *sc = arg;
4127c6b05d2SAlexander Motin
4137c6b05d2SAlexander Motin if (sc == NULL)
4147c6b05d2SAlexander Motin return;
4157c6b05d2SAlexander Motin
4167c6b05d2SAlexander Motin hdac_lock(sc);
4177c6b05d2SAlexander Motin if (sc->polling == 0) {
4187c6b05d2SAlexander Motin hdac_unlock(sc);
4197c6b05d2SAlexander Motin return;
4207c6b05d2SAlexander Motin }
421944a6408SEd Maste callout_reset(&sc->poll_callout, sc->poll_ival, hdac_poll_callback, sc);
4221f0387f7SAriff Abdullah hdac_unlock(sc);
423a580b31aSAriff Abdullah
4247c6b05d2SAlexander Motin hdac_intr_handler(sc);
4251f0387f7SAriff Abdullah }
4261f0387f7SAriff Abdullah
4271f0387f7SAriff Abdullah /****************************************************************************
428258ba4c0SEd Maste * int hdac_reset(hdac_softc *, bool)
4291f0387f7SAriff Abdullah *
4301f0387f7SAriff Abdullah * Reset the hdac to a quiescent and known state.
4311f0387f7SAriff Abdullah ****************************************************************************/
4321f0387f7SAriff Abdullah static int
hdac_reset(struct hdac_softc * sc,bool wakeup)433258ba4c0SEd Maste hdac_reset(struct hdac_softc *sc, bool wakeup)
4341f0387f7SAriff Abdullah {
4351f0387f7SAriff Abdullah uint32_t gctl;
4361f0387f7SAriff Abdullah int count, i;
4371f0387f7SAriff Abdullah
4381f0387f7SAriff Abdullah /*
4391f0387f7SAriff Abdullah * Stop all Streams DMA engine
4401f0387f7SAriff Abdullah */
4411f0387f7SAriff Abdullah for (i = 0; i < sc->num_iss; i++)
4421f0387f7SAriff Abdullah HDAC_WRITE_4(&sc->mem, HDAC_ISDCTL(sc, i), 0x0);
4431f0387f7SAriff Abdullah for (i = 0; i < sc->num_oss; i++)
4441f0387f7SAriff Abdullah HDAC_WRITE_4(&sc->mem, HDAC_OSDCTL(sc, i), 0x0);
4451f0387f7SAriff Abdullah for (i = 0; i < sc->num_bss; i++)
4461f0387f7SAriff Abdullah HDAC_WRITE_4(&sc->mem, HDAC_BSDCTL(sc, i), 0x0);
4471f0387f7SAriff Abdullah
4481f0387f7SAriff Abdullah /*
44971e3af01SAriff Abdullah * Stop Control DMA engines.
4501f0387f7SAriff Abdullah */
4511f0387f7SAriff Abdullah HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, 0x0);
4521f0387f7SAriff Abdullah HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, 0x0);
4531f0387f7SAriff Abdullah
4541f0387f7SAriff Abdullah /*
45571e3af01SAriff Abdullah * Reset DMA position buffer.
45671e3af01SAriff Abdullah */
45771e3af01SAriff Abdullah HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE, 0x0);
45871e3af01SAriff Abdullah HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, 0x0);
45971e3af01SAriff Abdullah
46071e3af01SAriff Abdullah /*
4611f0387f7SAriff Abdullah * Reset the controller. The reset must remain asserted for
4621f0387f7SAriff Abdullah * a minimum of 100us.
4631f0387f7SAriff Abdullah */
4641f0387f7SAriff Abdullah gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
4651f0387f7SAriff Abdullah HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl & ~HDAC_GCTL_CRST);
4661f0387f7SAriff Abdullah count = 10000;
4671f0387f7SAriff Abdullah do {
4681f0387f7SAriff Abdullah gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
4691f0387f7SAriff Abdullah if (!(gctl & HDAC_GCTL_CRST))
4701f0387f7SAriff Abdullah break;
4711f0387f7SAriff Abdullah DELAY(10);
4721f0387f7SAriff Abdullah } while (--count);
4731f0387f7SAriff Abdullah if (gctl & HDAC_GCTL_CRST) {
4741f0387f7SAriff Abdullah device_printf(sc->dev, "Unable to put hdac in reset\n");
4751f0387f7SAriff Abdullah return (ENXIO);
4761f0387f7SAriff Abdullah }
477859159d1SAlexander Motin
478859159d1SAlexander Motin /* If wakeup is not requested - leave the controller in reset state. */
479859159d1SAlexander Motin if (!wakeup)
480859159d1SAlexander Motin return (0);
481859159d1SAlexander Motin
4821f0387f7SAriff Abdullah DELAY(100);
4831f0387f7SAriff Abdullah gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
4841f0387f7SAriff Abdullah HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_CRST);
4851f0387f7SAriff Abdullah count = 10000;
4861f0387f7SAriff Abdullah do {
4871f0387f7SAriff Abdullah gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
4888d999aa8SAriff Abdullah if (gctl & HDAC_GCTL_CRST)
4891f0387f7SAriff Abdullah break;
4901f0387f7SAriff Abdullah DELAY(10);
4911f0387f7SAriff Abdullah } while (--count);
4921f0387f7SAriff Abdullah if (!(gctl & HDAC_GCTL_CRST)) {
4931f0387f7SAriff Abdullah device_printf(sc->dev, "Device stuck in reset\n");
4941f0387f7SAriff Abdullah return (ENXIO);
4951f0387f7SAriff Abdullah }
4961f0387f7SAriff Abdullah
4971f0387f7SAriff Abdullah /*
4981f0387f7SAriff Abdullah * Wait for codecs to finish their own reset sequence. The delay here
499e41841f0SEd Maste * must be at least 521us (HDA 1.0a section 4.3 Codec Discovery).
5001f0387f7SAriff Abdullah */
5011f0387f7SAriff Abdullah DELAY(1000);
5021f0387f7SAriff Abdullah
5031f0387f7SAriff Abdullah return (0);
5041f0387f7SAriff Abdullah }
5051f0387f7SAriff Abdullah
5061f0387f7SAriff Abdullah /****************************************************************************
5071f0387f7SAriff Abdullah * int hdac_get_capabilities(struct hdac_softc *);
5081f0387f7SAriff Abdullah *
5091f0387f7SAriff Abdullah * Retreive the general capabilities of the hdac;
5101f0387f7SAriff Abdullah * Number of Input Streams
5111f0387f7SAriff Abdullah * Number of Output Streams
5121f0387f7SAriff Abdullah * Number of bidirectional Streams
5131f0387f7SAriff Abdullah * 64bit ready
5141f0387f7SAriff Abdullah * CORB and RIRB sizes
5151f0387f7SAriff Abdullah ****************************************************************************/
5161f0387f7SAriff Abdullah static int
hdac_get_capabilities(struct hdac_softc * sc)5171f0387f7SAriff Abdullah hdac_get_capabilities(struct hdac_softc *sc)
5181f0387f7SAriff Abdullah {
5191f0387f7SAriff Abdullah uint16_t gcap;
5201f0387f7SAriff Abdullah uint8_t corbsize, rirbsize;
5211f0387f7SAriff Abdullah
5221f0387f7SAriff Abdullah gcap = HDAC_READ_2(&sc->mem, HDAC_GCAP);
5231f0387f7SAriff Abdullah sc->num_iss = HDAC_GCAP_ISS(gcap);
5241f0387f7SAriff Abdullah sc->num_oss = HDAC_GCAP_OSS(gcap);
5251f0387f7SAriff Abdullah sc->num_bss = HDAC_GCAP_BSS(gcap);
5267c6b05d2SAlexander Motin sc->num_ss = sc->num_iss + sc->num_oss + sc->num_bss;
52746681d6eSAlexander Motin sc->num_sdo = HDAC_GCAP_NSDO(gcap);
5287c6b05d2SAlexander Motin sc->support_64bit = (gcap & HDAC_GCAP_64OK) != 0;
5297c6b05d2SAlexander Motin if (sc->quirks_on & HDAC_QUIRK_64BIT)
5307c6b05d2SAlexander Motin sc->support_64bit = 1;
5317c6b05d2SAlexander Motin else if (sc->quirks_off & HDAC_QUIRK_64BIT)
5327c6b05d2SAlexander Motin sc->support_64bit = 0;
5331f0387f7SAriff Abdullah
5341f0387f7SAriff Abdullah corbsize = HDAC_READ_1(&sc->mem, HDAC_CORBSIZE);
5351f0387f7SAriff Abdullah if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_256) ==
5361f0387f7SAriff Abdullah HDAC_CORBSIZE_CORBSZCAP_256)
5371f0387f7SAriff Abdullah sc->corb_size = 256;
5381f0387f7SAriff Abdullah else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_16) ==
5391f0387f7SAriff Abdullah HDAC_CORBSIZE_CORBSZCAP_16)
5401f0387f7SAriff Abdullah sc->corb_size = 16;
5411f0387f7SAriff Abdullah else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_2) ==
5421f0387f7SAriff Abdullah HDAC_CORBSIZE_CORBSZCAP_2)
5431f0387f7SAriff Abdullah sc->corb_size = 2;
5441f0387f7SAriff Abdullah else {
5451f0387f7SAriff Abdullah device_printf(sc->dev, "%s: Invalid corb size (%x)\n",
5461f0387f7SAriff Abdullah __func__, corbsize);
5471f0387f7SAriff Abdullah return (ENXIO);
5481f0387f7SAriff Abdullah }
5491f0387f7SAriff Abdullah
5501f0387f7SAriff Abdullah rirbsize = HDAC_READ_1(&sc->mem, HDAC_RIRBSIZE);
5511f0387f7SAriff Abdullah if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_256) ==
5521f0387f7SAriff Abdullah HDAC_RIRBSIZE_RIRBSZCAP_256)
5531f0387f7SAriff Abdullah sc->rirb_size = 256;
5541f0387f7SAriff Abdullah else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_16) ==
5551f0387f7SAriff Abdullah HDAC_RIRBSIZE_RIRBSZCAP_16)
5561f0387f7SAriff Abdullah sc->rirb_size = 16;
5571f0387f7SAriff Abdullah else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_2) ==
5581f0387f7SAriff Abdullah HDAC_RIRBSIZE_RIRBSZCAP_2)
5591f0387f7SAriff Abdullah sc->rirb_size = 2;
5601f0387f7SAriff Abdullah else {
5611f0387f7SAriff Abdullah device_printf(sc->dev, "%s: Invalid rirb size (%x)\n",
5621f0387f7SAriff Abdullah __func__, rirbsize);
5631f0387f7SAriff Abdullah return (ENXIO);
5641f0387f7SAriff Abdullah }
5651f0387f7SAriff Abdullah
56646681d6eSAlexander Motin HDA_BOOTVERBOSE(
56746681d6eSAlexander Motin device_printf(sc->dev, "Caps: OSS %d, ISS %d, BSS %d, "
56846681d6eSAlexander Motin "NSDO %d%s, CORB %d, RIRB %d\n",
56946681d6eSAlexander Motin sc->num_oss, sc->num_iss, sc->num_bss, 1 << sc->num_sdo,
57046681d6eSAlexander Motin sc->support_64bit ? ", 64bit" : "",
57146681d6eSAlexander Motin sc->corb_size, sc->rirb_size);
572859159d1SAlexander Motin );
573859159d1SAlexander Motin
5741f0387f7SAriff Abdullah return (0);
5751f0387f7SAriff Abdullah }
5761f0387f7SAriff Abdullah
5771f0387f7SAriff Abdullah /****************************************************************************
5781f0387f7SAriff Abdullah * void hdac_dma_cb
5791f0387f7SAriff Abdullah *
5801f0387f7SAriff Abdullah * This function is called by bus_dmamap_load when the mapping has been
5811f0387f7SAriff Abdullah * established. We just record the physical address of the mapping into
5821f0387f7SAriff Abdullah * the struct hdac_dma passed in.
5831f0387f7SAriff Abdullah ****************************************************************************/
5841f0387f7SAriff Abdullah static void
hdac_dma_cb(void * callback_arg,bus_dma_segment_t * segs,int nseg,int error)5851f0387f7SAriff Abdullah hdac_dma_cb(void *callback_arg, bus_dma_segment_t *segs, int nseg, int error)
5861f0387f7SAriff Abdullah {
5871f0387f7SAriff Abdullah struct hdac_dma *dma;
5881f0387f7SAriff Abdullah
5891f0387f7SAriff Abdullah if (error == 0) {
5901f0387f7SAriff Abdullah dma = (struct hdac_dma *)callback_arg;
5911f0387f7SAriff Abdullah dma->dma_paddr = segs[0].ds_addr;
5921f0387f7SAriff Abdullah }
5931f0387f7SAriff Abdullah }
5941f0387f7SAriff Abdullah
5951f0387f7SAriff Abdullah /****************************************************************************
5961f0387f7SAriff Abdullah * int hdac_dma_alloc
5971f0387f7SAriff Abdullah *
5981f0387f7SAriff Abdullah * This function allocate and setup a dma region (struct hdac_dma).
5991f0387f7SAriff Abdullah * It must be freed by a corresponding hdac_dma_free.
6001f0387f7SAriff Abdullah ****************************************************************************/
6011f0387f7SAriff Abdullah static int
hdac_dma_alloc(struct hdac_softc * sc,struct hdac_dma * dma,bus_size_t size)6021f0387f7SAriff Abdullah hdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size)
6031f0387f7SAriff Abdullah {
60471e3af01SAriff Abdullah bus_size_t roundsz;
6051f0387f7SAriff Abdullah int result;
6061f0387f7SAriff Abdullah
6077c6b05d2SAlexander Motin roundsz = roundup2(size, HDA_DMA_ALIGNMENT);
6081f0387f7SAriff Abdullah bzero(dma, sizeof(*dma));
6091f0387f7SAriff Abdullah
6101f0387f7SAriff Abdullah /*
6111f0387f7SAriff Abdullah * Create a DMA tag
6121f0387f7SAriff Abdullah */
6138380c28eSAlexander Motin result = bus_dma_tag_create(
6148380c28eSAlexander Motin bus_get_dma_tag(sc->dev), /* parent */
6157c6b05d2SAlexander Motin HDA_DMA_ALIGNMENT, /* alignment */
6161f0387f7SAriff Abdullah 0, /* boundary */
6178380c28eSAlexander Motin (sc->support_64bit) ? BUS_SPACE_MAXADDR :
6188380c28eSAlexander Motin BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
6191f0387f7SAriff Abdullah BUS_SPACE_MAXADDR, /* highaddr */
6201f0387f7SAriff Abdullah NULL, /* filtfunc */
6211f0387f7SAriff Abdullah NULL, /* fistfuncarg */
62271e3af01SAriff Abdullah roundsz, /* maxsize */
6231f0387f7SAriff Abdullah 1, /* nsegments */
62471e3af01SAriff Abdullah roundsz, /* maxsegsz */
6251f0387f7SAriff Abdullah 0, /* flags */
6261f0387f7SAriff Abdullah NULL, /* lockfunc */
6271f0387f7SAriff Abdullah NULL, /* lockfuncarg */
6281f0387f7SAriff Abdullah &dma->dma_tag); /* dmat */
6291f0387f7SAriff Abdullah if (result != 0) {
630bdafaf0aSJustin Hibbits device_printf(sc->dev, "%s: bus_dma_tag_create failed (%d)\n",
6311f0387f7SAriff Abdullah __func__, result);
632703c934aSAriff Abdullah goto hdac_dma_alloc_fail;
6331f0387f7SAriff Abdullah }
6341f0387f7SAriff Abdullah
6351f0387f7SAriff Abdullah /*
6361f0387f7SAriff Abdullah * Allocate DMA memory
6371f0387f7SAriff Abdullah */
6381f0387f7SAriff Abdullah result = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr,
63971e3af01SAriff Abdullah BUS_DMA_NOWAIT | BUS_DMA_ZERO |
64080a79189SJustin Hibbits ((sc->flags & HDAC_F_DMA_NOCACHE) ? BUS_DMA_NOCACHE :
64180a79189SJustin Hibbits BUS_DMA_COHERENT),
6420937dd1eSAriff Abdullah &dma->dma_map);
6431f0387f7SAriff Abdullah if (result != 0) {
644bdafaf0aSJustin Hibbits device_printf(sc->dev, "%s: bus_dmamem_alloc failed (%d)\n",
6451f0387f7SAriff Abdullah __func__, result);
646703c934aSAriff Abdullah goto hdac_dma_alloc_fail;
6471f0387f7SAriff Abdullah }
6481f0387f7SAriff Abdullah
64971e3af01SAriff Abdullah dma->dma_size = roundsz;
65071e3af01SAriff Abdullah
6511f0387f7SAriff Abdullah /*
6521f0387f7SAriff Abdullah * Map the memory
6531f0387f7SAriff Abdullah */
6541f0387f7SAriff Abdullah result = bus_dmamap_load(dma->dma_tag, dma->dma_map,
65571e3af01SAriff Abdullah (void *)dma->dma_vaddr, roundsz, hdac_dma_cb, (void *)dma, 0);
6561f0387f7SAriff Abdullah if (result != 0 || dma->dma_paddr == 0) {
657703c934aSAriff Abdullah if (result == 0)
658703c934aSAriff Abdullah result = ENOMEM;
659bdafaf0aSJustin Hibbits device_printf(sc->dev, "%s: bus_dmamem_load failed (%d)\n",
6601f0387f7SAriff Abdullah __func__, result);
661703c934aSAriff Abdullah goto hdac_dma_alloc_fail;
6621f0387f7SAriff Abdullah }
66371e3af01SAriff Abdullah
6644d423c80SAlexander Motin HDA_BOOTHVERBOSE(
66571e3af01SAriff Abdullah device_printf(sc->dev, "%s: size=%ju -> roundsz=%ju\n",
66671e3af01SAriff Abdullah __func__, (uintmax_t)size, (uintmax_t)roundsz);
66771e3af01SAriff Abdullah );
6681f0387f7SAriff Abdullah
6691f0387f7SAriff Abdullah return (0);
67071e3af01SAriff Abdullah
671703c934aSAriff Abdullah hdac_dma_alloc_fail:
67271e3af01SAriff Abdullah hdac_dma_free(sc, dma);
673703c934aSAriff Abdullah
6741f0387f7SAriff Abdullah return (result);
6751f0387f7SAriff Abdullah }
6761f0387f7SAriff Abdullah
6771f0387f7SAriff Abdullah /****************************************************************************
67871e3af01SAriff Abdullah * void hdac_dma_free(struct hdac_softc *, struct hdac_dma *)
6791f0387f7SAriff Abdullah *
680944a6408SEd Maste * Free a struct hdac_dma that has been previously allocated via the
6811f0387f7SAriff Abdullah * hdac_dma_alloc function.
6821f0387f7SAriff Abdullah ****************************************************************************/
6831f0387f7SAriff Abdullah static void
hdac_dma_free(struct hdac_softc * sc,struct hdac_dma * dma)68471e3af01SAriff Abdullah hdac_dma_free(struct hdac_softc *sc, struct hdac_dma *dma)
6851f0387f7SAriff Abdullah {
68686843ea8SJohn Baldwin if (dma->dma_paddr != 0) {
6871f0387f7SAriff Abdullah /* Flush caches */
6881f0387f7SAriff Abdullah bus_dmamap_sync(dma->dma_tag, dma->dma_map,
6891f0387f7SAriff Abdullah BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
6901f0387f7SAriff Abdullah bus_dmamap_unload(dma->dma_tag, dma->dma_map);
69186843ea8SJohn Baldwin dma->dma_paddr = 0;
6921f0387f7SAriff Abdullah }
693703c934aSAriff Abdullah if (dma->dma_vaddr != NULL) {
694703c934aSAriff Abdullah bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
695703c934aSAriff Abdullah dma->dma_vaddr = NULL;
696703c934aSAriff Abdullah }
697703c934aSAriff Abdullah if (dma->dma_tag != NULL) {
698703c934aSAriff Abdullah bus_dma_tag_destroy(dma->dma_tag);
699703c934aSAriff Abdullah dma->dma_tag = NULL;
700703c934aSAriff Abdullah }
701703c934aSAriff Abdullah dma->dma_size = 0;
7021f0387f7SAriff Abdullah }
7031f0387f7SAriff Abdullah
7041f0387f7SAriff Abdullah /****************************************************************************
7051f0387f7SAriff Abdullah * int hdac_mem_alloc(struct hdac_softc *)
7061f0387f7SAriff Abdullah *
7071f0387f7SAriff Abdullah * Allocate all the bus resources necessary to speak with the physical
7081f0387f7SAriff Abdullah * controller.
7091f0387f7SAriff Abdullah ****************************************************************************/
7101f0387f7SAriff Abdullah static int
hdac_mem_alloc(struct hdac_softc * sc)7111f0387f7SAriff Abdullah hdac_mem_alloc(struct hdac_softc *sc)
7121f0387f7SAriff Abdullah {
7131f0387f7SAriff Abdullah struct hdac_mem *mem;
7141f0387f7SAriff Abdullah
7151f0387f7SAriff Abdullah mem = &sc->mem;
7161f0387f7SAriff Abdullah mem->mem_rid = PCIR_BAR(0);
7171f0387f7SAriff Abdullah mem->mem_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
7181f0387f7SAriff Abdullah &mem->mem_rid, RF_ACTIVE);
7191f0387f7SAriff Abdullah if (mem->mem_res == NULL) {
7201f0387f7SAriff Abdullah device_printf(sc->dev,
7211f0387f7SAriff Abdullah "%s: Unable to allocate memory resource\n", __func__);
7221f0387f7SAriff Abdullah return (ENOMEM);
7231f0387f7SAriff Abdullah }
7241f0387f7SAriff Abdullah mem->mem_tag = rman_get_bustag(mem->mem_res);
7251f0387f7SAriff Abdullah mem->mem_handle = rman_get_bushandle(mem->mem_res);
7261f0387f7SAriff Abdullah
7271f0387f7SAriff Abdullah return (0);
7281f0387f7SAriff Abdullah }
7291f0387f7SAriff Abdullah
7301f0387f7SAriff Abdullah /****************************************************************************
7311f0387f7SAriff Abdullah * void hdac_mem_free(struct hdac_softc *)
7321f0387f7SAriff Abdullah *
7331f0387f7SAriff Abdullah * Free up resources previously allocated by hdac_mem_alloc.
7341f0387f7SAriff Abdullah ****************************************************************************/
7351f0387f7SAriff Abdullah static void
hdac_mem_free(struct hdac_softc * sc)7361f0387f7SAriff Abdullah hdac_mem_free(struct hdac_softc *sc)
7371f0387f7SAriff Abdullah {
7381f0387f7SAriff Abdullah struct hdac_mem *mem;
7391f0387f7SAriff Abdullah
7401f0387f7SAriff Abdullah mem = &sc->mem;
7411f0387f7SAriff Abdullah if (mem->mem_res != NULL)
7421f0387f7SAriff Abdullah bus_release_resource(sc->dev, SYS_RES_MEMORY, mem->mem_rid,
7431f0387f7SAriff Abdullah mem->mem_res);
744a580b31aSAriff Abdullah mem->mem_res = NULL;
7451f0387f7SAriff Abdullah }
7461f0387f7SAriff Abdullah
7471f0387f7SAriff Abdullah /****************************************************************************
7481f0387f7SAriff Abdullah * int hdac_irq_alloc(struct hdac_softc *)
7491f0387f7SAriff Abdullah *
7501f0387f7SAriff Abdullah * Allocate and setup the resources necessary for interrupt handling.
7511f0387f7SAriff Abdullah ****************************************************************************/
7521f0387f7SAriff Abdullah static int
hdac_irq_alloc(struct hdac_softc * sc)7531f0387f7SAriff Abdullah hdac_irq_alloc(struct hdac_softc *sc)
7541f0387f7SAriff Abdullah {
7551f0387f7SAriff Abdullah struct hdac_irq *irq;
7561f0387f7SAriff Abdullah int result;
7571f0387f7SAriff Abdullah
7581f0387f7SAriff Abdullah irq = &sc->irq;
7591f0387f7SAriff Abdullah irq->irq_rid = 0x0;
7600937dd1eSAriff Abdullah
7617c6b05d2SAlexander Motin if ((sc->quirks_off & HDAC_QUIRK_MSI) == 0 &&
7620937dd1eSAriff Abdullah (result = pci_msi_count(sc->dev)) == 1 &&
7630937dd1eSAriff Abdullah pci_alloc_msi(sc->dev, &result) == 0)
7640937dd1eSAriff Abdullah irq->irq_rid = 0x1;
7650937dd1eSAriff Abdullah
7661f0387f7SAriff Abdullah irq->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
7671f0387f7SAriff Abdullah &irq->irq_rid, RF_SHAREABLE | RF_ACTIVE);
7681f0387f7SAriff Abdullah if (irq->irq_res == NULL) {
7691f0387f7SAriff Abdullah device_printf(sc->dev, "%s: Unable to allocate irq\n",
7701f0387f7SAriff Abdullah __func__);
771703c934aSAriff Abdullah goto hdac_irq_alloc_fail;
7721f0387f7SAriff Abdullah }
773859159d1SAlexander Motin result = bus_setup_intr(sc->dev, irq->irq_res, INTR_MPSAFE | INTR_TYPE_AV,
774859159d1SAlexander Motin NULL, hdac_intr_handler, sc, &irq->irq_handle);
7751f0387f7SAriff Abdullah if (result != 0) {
7761f0387f7SAriff Abdullah device_printf(sc->dev,
777bdafaf0aSJustin Hibbits "%s: Unable to setup interrupt handler (%d)\n",
7781f0387f7SAriff Abdullah __func__, result);
779703c934aSAriff Abdullah goto hdac_irq_alloc_fail;
7801f0387f7SAriff Abdullah }
7811f0387f7SAriff Abdullah
7821f0387f7SAriff Abdullah return (0);
7831f0387f7SAriff Abdullah
784703c934aSAriff Abdullah hdac_irq_alloc_fail:
785a580b31aSAriff Abdullah hdac_irq_free(sc);
786a580b31aSAriff Abdullah
7871f0387f7SAriff Abdullah return (ENXIO);
7881f0387f7SAriff Abdullah }
7891f0387f7SAriff Abdullah
7901f0387f7SAriff Abdullah /****************************************************************************
7911f0387f7SAriff Abdullah * void hdac_irq_free(struct hdac_softc *)
7921f0387f7SAriff Abdullah *
7931f0387f7SAriff Abdullah * Free up resources previously allocated by hdac_irq_alloc.
7941f0387f7SAriff Abdullah ****************************************************************************/
7951f0387f7SAriff Abdullah static void
hdac_irq_free(struct hdac_softc * sc)7961f0387f7SAriff Abdullah hdac_irq_free(struct hdac_softc *sc)
7971f0387f7SAriff Abdullah {
7981f0387f7SAriff Abdullah struct hdac_irq *irq;
7991f0387f7SAriff Abdullah
8001f0387f7SAriff Abdullah irq = &sc->irq;
801a580b31aSAriff Abdullah if (irq->irq_res != NULL && irq->irq_handle != NULL)
8021f0387f7SAriff Abdullah bus_teardown_intr(sc->dev, irq->irq_res, irq->irq_handle);
8031f0387f7SAriff Abdullah if (irq->irq_res != NULL)
8041f0387f7SAriff Abdullah bus_release_resource(sc->dev, SYS_RES_IRQ, irq->irq_rid,
8051f0387f7SAriff Abdullah irq->irq_res);
8068f740c4bSAlexander Motin if (irq->irq_rid == 0x1)
8070937dd1eSAriff Abdullah pci_release_msi(sc->dev);
808a580b31aSAriff Abdullah irq->irq_handle = NULL;
809a580b31aSAriff Abdullah irq->irq_res = NULL;
8100937dd1eSAriff Abdullah irq->irq_rid = 0x0;
8111f0387f7SAriff Abdullah }
8121f0387f7SAriff Abdullah
8131f0387f7SAriff Abdullah /****************************************************************************
8141f0387f7SAriff Abdullah * void hdac_corb_init(struct hdac_softc *)
8151f0387f7SAriff Abdullah *
8161f0387f7SAriff Abdullah * Initialize the corb registers for operations but do not start it up yet.
8171f0387f7SAriff Abdullah * The CORB engine must not be running when this function is called.
8181f0387f7SAriff Abdullah ****************************************************************************/
8191f0387f7SAriff Abdullah static void
hdac_corb_init(struct hdac_softc * sc)8201f0387f7SAriff Abdullah hdac_corb_init(struct hdac_softc *sc)
8211f0387f7SAriff Abdullah {
8221f0387f7SAriff Abdullah uint8_t corbsize;
8231f0387f7SAriff Abdullah uint64_t corbpaddr;
8241f0387f7SAriff Abdullah
8251f0387f7SAriff Abdullah /* Setup the CORB size. */
8261f0387f7SAriff Abdullah switch (sc->corb_size) {
8271f0387f7SAriff Abdullah case 256:
8281f0387f7SAriff Abdullah corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_256);
8291f0387f7SAriff Abdullah break;
8301f0387f7SAriff Abdullah case 16:
8311f0387f7SAriff Abdullah corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_16);
8321f0387f7SAriff Abdullah break;
8331f0387f7SAriff Abdullah case 2:
8341f0387f7SAriff Abdullah corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_2);
8351f0387f7SAriff Abdullah break;
8361f0387f7SAriff Abdullah default:
8371f0387f7SAriff Abdullah panic("%s: Invalid CORB size (%x)\n", __func__, sc->corb_size);
8381f0387f7SAriff Abdullah }
8391f0387f7SAriff Abdullah HDAC_WRITE_1(&sc->mem, HDAC_CORBSIZE, corbsize);
8401f0387f7SAriff Abdullah
8411f0387f7SAriff Abdullah /* Setup the CORB Address in the hdac */
8421f0387f7SAriff Abdullah corbpaddr = (uint64_t)sc->corb_dma.dma_paddr;
8431f0387f7SAriff Abdullah HDAC_WRITE_4(&sc->mem, HDAC_CORBLBASE, (uint32_t)corbpaddr);
8441f0387f7SAriff Abdullah HDAC_WRITE_4(&sc->mem, HDAC_CORBUBASE, (uint32_t)(corbpaddr >> 32));
8451f0387f7SAriff Abdullah
8461f0387f7SAriff Abdullah /* Set the WP and RP */
8471f0387f7SAriff Abdullah sc->corb_wp = 0;
8481f0387f7SAriff Abdullah HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
8491f0387f7SAriff Abdullah HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, HDAC_CORBRP_CORBRPRST);
8501f0387f7SAriff Abdullah /*
8511f0387f7SAriff Abdullah * The HDA specification indicates that the CORBRPRST bit will always
8521f0387f7SAriff Abdullah * read as zero. Unfortunately, it seems that at least the 82801G
8531f0387f7SAriff Abdullah * doesn't reset the bit to zero, which stalls the corb engine.
8541f0387f7SAriff Abdullah * manually reset the bit to zero before continuing.
8551f0387f7SAriff Abdullah */
8561f0387f7SAriff Abdullah HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, 0x0);
8571f0387f7SAriff Abdullah
8581f0387f7SAriff Abdullah /* Enable CORB error reporting */
8591f0387f7SAriff Abdullah #if 0
8601f0387f7SAriff Abdullah HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, HDAC_CORBCTL_CMEIE);
8611f0387f7SAriff Abdullah #endif
8621f0387f7SAriff Abdullah }
8631f0387f7SAriff Abdullah
8641f0387f7SAriff Abdullah /****************************************************************************
8651f0387f7SAriff Abdullah * void hdac_rirb_init(struct hdac_softc *)
8661f0387f7SAriff Abdullah *
8671f0387f7SAriff Abdullah * Initialize the rirb registers for operations but do not start it up yet.
8681f0387f7SAriff Abdullah * The RIRB engine must not be running when this function is called.
8691f0387f7SAriff Abdullah ****************************************************************************/
8701f0387f7SAriff Abdullah static void
hdac_rirb_init(struct hdac_softc * sc)8711f0387f7SAriff Abdullah hdac_rirb_init(struct hdac_softc *sc)
8721f0387f7SAriff Abdullah {
8731f0387f7SAriff Abdullah uint8_t rirbsize;
8741f0387f7SAriff Abdullah uint64_t rirbpaddr;
8751f0387f7SAriff Abdullah
8761f0387f7SAriff Abdullah /* Setup the RIRB size. */
8771f0387f7SAriff Abdullah switch (sc->rirb_size) {
8781f0387f7SAriff Abdullah case 256:
8791f0387f7SAriff Abdullah rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_256);
8801f0387f7SAriff Abdullah break;
8811f0387f7SAriff Abdullah case 16:
8821f0387f7SAriff Abdullah rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_16);
8831f0387f7SAriff Abdullah break;
8841f0387f7SAriff Abdullah case 2:
8851f0387f7SAriff Abdullah rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_2);
8861f0387f7SAriff Abdullah break;
8871f0387f7SAriff Abdullah default:
8881f0387f7SAriff Abdullah panic("%s: Invalid RIRB size (%x)\n", __func__, sc->rirb_size);
8891f0387f7SAriff Abdullah }
8901f0387f7SAriff Abdullah HDAC_WRITE_1(&sc->mem, HDAC_RIRBSIZE, rirbsize);
8911f0387f7SAriff Abdullah
8921f0387f7SAriff Abdullah /* Setup the RIRB Address in the hdac */
8931f0387f7SAriff Abdullah rirbpaddr = (uint64_t)sc->rirb_dma.dma_paddr;
8941f0387f7SAriff Abdullah HDAC_WRITE_4(&sc->mem, HDAC_RIRBLBASE, (uint32_t)rirbpaddr);
8951f0387f7SAriff Abdullah HDAC_WRITE_4(&sc->mem, HDAC_RIRBUBASE, (uint32_t)(rirbpaddr >> 32));
8961f0387f7SAriff Abdullah
8971f0387f7SAriff Abdullah /* Setup the WP and RP */
8981f0387f7SAriff Abdullah sc->rirb_rp = 0;
8991f0387f7SAriff Abdullah HDAC_WRITE_2(&sc->mem, HDAC_RIRBWP, HDAC_RIRBWP_RIRBWPRST);
9001f0387f7SAriff Abdullah
9011f0387f7SAriff Abdullah /* Setup the interrupt threshold */
9021f0387f7SAriff Abdullah HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, sc->rirb_size / 2);
9031f0387f7SAriff Abdullah
9041f0387f7SAriff Abdullah /* Enable Overrun and response received reporting */
9051f0387f7SAriff Abdullah #if 0
9061f0387f7SAriff Abdullah HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL,
9071f0387f7SAriff Abdullah HDAC_RIRBCTL_RIRBOIC | HDAC_RIRBCTL_RINTCTL);
9081f0387f7SAriff Abdullah #else
9091f0387f7SAriff Abdullah HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, HDAC_RIRBCTL_RINTCTL);
9101f0387f7SAriff Abdullah #endif
9111f0387f7SAriff Abdullah
9121f0387f7SAriff Abdullah /*
9131f0387f7SAriff Abdullah * Make sure that the Host CPU cache doesn't contain any dirty
9141f0387f7SAriff Abdullah * cache lines that falls in the rirb. If I understood correctly, it
9151f0387f7SAriff Abdullah * should be sufficient to do this only once as the rirb is purely
9161f0387f7SAriff Abdullah * read-only from now on.
9171f0387f7SAriff Abdullah */
9181f0387f7SAriff Abdullah bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
9191f0387f7SAriff Abdullah BUS_DMASYNC_PREREAD);
9201f0387f7SAriff Abdullah }
9211f0387f7SAriff Abdullah
9221f0387f7SAriff Abdullah /****************************************************************************
9231f0387f7SAriff Abdullah * void hdac_corb_start(hdac_softc *)
9241f0387f7SAriff Abdullah *
9251f0387f7SAriff Abdullah * Startup the corb DMA engine
9261f0387f7SAriff Abdullah ****************************************************************************/
9271f0387f7SAriff Abdullah static void
hdac_corb_start(struct hdac_softc * sc)9281f0387f7SAriff Abdullah hdac_corb_start(struct hdac_softc *sc)
9291f0387f7SAriff Abdullah {
9301f0387f7SAriff Abdullah uint32_t corbctl;
9311f0387f7SAriff Abdullah
9321f0387f7SAriff Abdullah corbctl = HDAC_READ_1(&sc->mem, HDAC_CORBCTL);
9331f0387f7SAriff Abdullah corbctl |= HDAC_CORBCTL_CORBRUN;
9341f0387f7SAriff Abdullah HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, corbctl);
9351f0387f7SAriff Abdullah }
9361f0387f7SAriff Abdullah
9371f0387f7SAriff Abdullah /****************************************************************************
9381f0387f7SAriff Abdullah * void hdac_rirb_start(hdac_softc *)
9391f0387f7SAriff Abdullah *
9401f0387f7SAriff Abdullah * Startup the rirb DMA engine
9411f0387f7SAriff Abdullah ****************************************************************************/
9421f0387f7SAriff Abdullah static void
hdac_rirb_start(struct hdac_softc * sc)9431f0387f7SAriff Abdullah hdac_rirb_start(struct hdac_softc *sc)
9441f0387f7SAriff Abdullah {
9451f0387f7SAriff Abdullah uint32_t rirbctl;
9461f0387f7SAriff Abdullah
9471f0387f7SAriff Abdullah rirbctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL);
9481f0387f7SAriff Abdullah rirbctl |= HDAC_RIRBCTL_RIRBDMAEN;
9491f0387f7SAriff Abdullah HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, rirbctl);
9501f0387f7SAriff Abdullah }
9511f0387f7SAriff Abdullah
952a580b31aSAriff Abdullah static int
hdac_rirb_flush(struct hdac_softc * sc)953a580b31aSAriff Abdullah hdac_rirb_flush(struct hdac_softc *sc)
954a580b31aSAriff Abdullah {
955a580b31aSAriff Abdullah struct hdac_rirb *rirb_base, *rirb;
956a580b31aSAriff Abdullah nid_t cad;
9572a9ee5fcSJustin Hibbits uint32_t resp, resp_ex;
958a580b31aSAriff Abdullah uint8_t rirbwp;
959e5ad83a7SAriff Abdullah int ret;
960a580b31aSAriff Abdullah
961a580b31aSAriff Abdullah rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
962a580b31aSAriff Abdullah rirbwp = HDAC_READ_1(&sc->mem, HDAC_RIRBWP);
963a580b31aSAriff Abdullah bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
964a580b31aSAriff Abdullah BUS_DMASYNC_POSTREAD);
965a580b31aSAriff Abdullah
966e5ad83a7SAriff Abdullah ret = 0;
967a580b31aSAriff Abdullah while (sc->rirb_rp != rirbwp) {
968a580b31aSAriff Abdullah sc->rirb_rp++;
969a580b31aSAriff Abdullah sc->rirb_rp %= sc->rirb_size;
970a580b31aSAriff Abdullah rirb = &rirb_base[sc->rirb_rp];
9712a9ee5fcSJustin Hibbits resp = le32toh(rirb->response);
9722a9ee5fcSJustin Hibbits resp_ex = le32toh(rirb->response_ex);
9732a9ee5fcSJustin Hibbits cad = HDAC_RIRB_RESPONSE_EX_SDATA_IN(resp_ex);
9742a9ee5fcSJustin Hibbits if (resp_ex & HDAC_RIRB_RESPONSE_EX_UNSOLICITED) {
9757c6b05d2SAlexander Motin sc->unsolq[sc->unsolq_wp++] = resp;
976a580b31aSAriff Abdullah sc->unsolq_wp %= HDAC_UNSOLQ_MAX;
9777c6b05d2SAlexander Motin sc->unsolq[sc->unsolq_wp++] = cad;
9787c6b05d2SAlexander Motin sc->unsolq_wp %= HDAC_UNSOLQ_MAX;
9797c6b05d2SAlexander Motin } else if (sc->codecs[cad].pending <= 0) {
9807c6b05d2SAlexander Motin device_printf(sc->dev, "Unexpected unsolicited "
9817c6b05d2SAlexander Motin "response from address %d: %08x\n", cad, resp);
9827c6b05d2SAlexander Motin } else {
9837c6b05d2SAlexander Motin sc->codecs[cad].response = resp;
9847c6b05d2SAlexander Motin sc->codecs[cad].pending--;
9857c6b05d2SAlexander Motin }
986a580b31aSAriff Abdullah ret++;
987a580b31aSAriff Abdullah }
98880a79189SJustin Hibbits
98980a79189SJustin Hibbits bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
99080a79189SJustin Hibbits BUS_DMASYNC_PREREAD);
991a580b31aSAriff Abdullah return (ret);
992a580b31aSAriff Abdullah }
993a580b31aSAriff Abdullah
994a580b31aSAriff Abdullah static int
hdac_unsolq_flush(struct hdac_softc * sc)995a580b31aSAriff Abdullah hdac_unsolq_flush(struct hdac_softc *sc)
996a580b31aSAriff Abdullah {
9977c6b05d2SAlexander Motin device_t child;
998a580b31aSAriff Abdullah nid_t cad;
9997c6b05d2SAlexander Motin uint32_t resp;
1000a580b31aSAriff Abdullah int ret = 0;
1001a580b31aSAriff Abdullah
1002a580b31aSAriff Abdullah if (sc->unsolq_st == HDAC_UNSOLQ_READY) {
1003a580b31aSAriff Abdullah sc->unsolq_st = HDAC_UNSOLQ_BUSY;
1004a580b31aSAriff Abdullah while (sc->unsolq_rp != sc->unsolq_wp) {
10057c6b05d2SAlexander Motin resp = sc->unsolq[sc->unsolq_rp++];
1006a580b31aSAriff Abdullah sc->unsolq_rp %= HDAC_UNSOLQ_MAX;
10077c6b05d2SAlexander Motin cad = sc->unsolq[sc->unsolq_rp++];
10087c6b05d2SAlexander Motin sc->unsolq_rp %= HDAC_UNSOLQ_MAX;
1009cd3d0f8cSAlexander Motin if ((child = sc->codecs[cad].dev) != NULL &&
1010cd3d0f8cSAlexander Motin device_is_attached(child))
10117c6b05d2SAlexander Motin HDAC_UNSOL_INTR(child, resp);
1012a580b31aSAriff Abdullah ret++;
1013a580b31aSAriff Abdullah }
1014a580b31aSAriff Abdullah sc->unsolq_st = HDAC_UNSOLQ_READY;
1015a580b31aSAriff Abdullah }
1016a580b31aSAriff Abdullah
1017a580b31aSAriff Abdullah return (ret);
1018a580b31aSAriff Abdullah }
1019a580b31aSAriff Abdullah
10201f0387f7SAriff Abdullah /****************************************************************************
1021a449a1ebSEd Maste * uint32_t hdac_send_command
10221f0387f7SAriff Abdullah *
10231f0387f7SAriff Abdullah * Wrapper function that sends only one command to a given codec
10241f0387f7SAriff Abdullah ****************************************************************************/
10251f0387f7SAriff Abdullah static uint32_t
hdac_send_command(struct hdac_softc * sc,nid_t cad,uint32_t verb)10267c6b05d2SAlexander Motin hdac_send_command(struct hdac_softc *sc, nid_t cad, uint32_t verb)
10271f0387f7SAriff Abdullah {
10287c6b05d2SAlexander Motin int timeout;
10297c6b05d2SAlexander Motin uint32_t *corb;
10301f0387f7SAriff Abdullah
1031f6448524SEd Maste hdac_lockassert(sc);
10327c6b05d2SAlexander Motin verb &= ~HDA_CMD_CAD_MASK;
10337c6b05d2SAlexander Motin verb |= ((uint32_t)cad) << HDA_CMD_CAD_SHIFT;
10347c6b05d2SAlexander Motin sc->codecs[cad].response = HDA_INVALID;
10351f0387f7SAriff Abdullah
10367c6b05d2SAlexander Motin sc->codecs[cad].pending++;
10377c6b05d2SAlexander Motin sc->corb_wp++;
10387c6b05d2SAlexander Motin sc->corb_wp %= sc->corb_size;
10391f0387f7SAriff Abdullah corb = (uint32_t *)sc->corb_dma.dma_vaddr;
10401f0387f7SAriff Abdullah bus_dmamap_sync(sc->corb_dma.dma_tag,
10411f0387f7SAriff Abdullah sc->corb_dma.dma_map, BUS_DMASYNC_PREWRITE);
10422a9ee5fcSJustin Hibbits corb[sc->corb_wp] = htole32(verb);
10431f0387f7SAriff Abdullah bus_dmamap_sync(sc->corb_dma.dma_tag,
10441f0387f7SAriff Abdullah sc->corb_dma.dma_map, BUS_DMASYNC_POSTWRITE);
10451f0387f7SAriff Abdullah HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
10461f0387f7SAriff Abdullah
10477c6b05d2SAlexander Motin timeout = 10000;
10487c6b05d2SAlexander Motin do {
10497c6b05d2SAlexander Motin if (hdac_rirb_flush(sc) == 0)
10501f0387f7SAriff Abdullah DELAY(10);
10517c6b05d2SAlexander Motin } while (sc->codecs[cad].pending != 0 && --timeout);
10521f0387f7SAriff Abdullah
10537c6b05d2SAlexander Motin if (sc->codecs[cad].pending != 0) {
10548fe63c2aSEd Maste device_printf(sc->dev, "Command 0x%08x timeout on address %d\n",
10558fe63c2aSEd Maste verb, cad);
10567c6b05d2SAlexander Motin sc->codecs[cad].pending = 0;
10571f0387f7SAriff Abdullah }
10581f0387f7SAriff Abdullah
10597c6b05d2SAlexander Motin if (sc->unsolq_rp != sc->unsolq_wp)
10607c6b05d2SAlexander Motin taskqueue_enqueue(taskqueue_thread, &sc->unsolq_task);
10617c6b05d2SAlexander Motin return (sc->codecs[cad].response);
10627c6b05d2SAlexander Motin }
10631f0387f7SAriff Abdullah
10641f0387f7SAriff Abdullah /****************************************************************************
10651f0387f7SAriff Abdullah * Device Methods
10661f0387f7SAriff Abdullah ****************************************************************************/
10671f0387f7SAriff Abdullah
10681f0387f7SAriff Abdullah /****************************************************************************
10691f0387f7SAriff Abdullah * int hdac_probe(device_t)
10701f0387f7SAriff Abdullah *
10711f0387f7SAriff Abdullah * Probe for the presence of an hdac. If none is found, check for a generic
10721f0387f7SAriff Abdullah * match using the subclass of the device.
10731f0387f7SAriff Abdullah ****************************************************************************/
10741f0387f7SAriff Abdullah static int
hdac_probe(device_t dev)10751f0387f7SAriff Abdullah hdac_probe(device_t dev)
10761f0387f7SAriff Abdullah {
10771f0387f7SAriff Abdullah int i, result;
10780b414ccaSAriff Abdullah uint32_t model;
10790b414ccaSAriff Abdullah uint16_t class, subclass;
10801f0387f7SAriff Abdullah char desc[64];
10811f0387f7SAriff Abdullah
10821f0387f7SAriff Abdullah model = (uint32_t)pci_get_device(dev) << 16;
10831f0387f7SAriff Abdullah model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
10841f0387f7SAriff Abdullah class = pci_get_class(dev);
10851f0387f7SAriff Abdullah subclass = pci_get_subclass(dev);
10861f0387f7SAriff Abdullah
10871f0387f7SAriff Abdullah bzero(desc, sizeof(desc));
10881f0387f7SAriff Abdullah result = ENXIO;
1089abe917adSMarius Strobl for (i = 0; i < nitems(hdac_devices); i++) {
10901f0387f7SAriff Abdullah if (hdac_devices[i].model == model) {
10911f0387f7SAriff Abdullah strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
10921f0387f7SAriff Abdullah result = BUS_PROBE_DEFAULT;
10931f0387f7SAriff Abdullah break;
10941f0387f7SAriff Abdullah }
10950b414ccaSAriff Abdullah if (HDA_DEV_MATCH(hdac_devices[i].model, model) &&
10961f0387f7SAriff Abdullah class == PCIC_MULTIMEDIA &&
10971f0387f7SAriff Abdullah subclass == PCIS_MULTIMEDIA_HDA) {
1098944a6408SEd Maste snprintf(desc, sizeof(desc), "%s (0x%04x)",
10995bcd25deSAlexander Motin hdac_devices[i].desc, pci_get_device(dev));
11001f0387f7SAriff Abdullah result = BUS_PROBE_GENERIC;
11011f0387f7SAriff Abdullah break;
11021f0387f7SAriff Abdullah }
11031f0387f7SAriff Abdullah }
11041f0387f7SAriff Abdullah if (result == ENXIO && class == PCIC_MULTIMEDIA &&
11051f0387f7SAriff Abdullah subclass == PCIS_MULTIMEDIA_HDA) {
11065bcd25deSAlexander Motin snprintf(desc, sizeof(desc), "Generic (0x%08x)", model);
11071f0387f7SAriff Abdullah result = BUS_PROBE_GENERIC;
11081f0387f7SAriff Abdullah }
1109f7d3d0a4SChristos Margiolis if (result != ENXIO)
1110f7d3d0a4SChristos Margiolis device_set_descf(dev, "%s HDA Controller", desc);
11111f0387f7SAriff Abdullah
11121f0387f7SAriff Abdullah return (result);
11131f0387f7SAriff Abdullah }
11141f0387f7SAriff Abdullah
1115e5ad83a7SAriff Abdullah static void
hdac_unsolq_task(void * context,int pending)1116e5ad83a7SAriff Abdullah hdac_unsolq_task(void *context, int pending)
1117e5ad83a7SAriff Abdullah {
1118e5ad83a7SAriff Abdullah struct hdac_softc *sc;
1119e5ad83a7SAriff Abdullah
1120e5ad83a7SAriff Abdullah sc = (struct hdac_softc *)context;
1121e5ad83a7SAriff Abdullah
1122e5ad83a7SAriff Abdullah hdac_lock(sc);
1123e5ad83a7SAriff Abdullah hdac_unsolq_flush(sc);
1124e5ad83a7SAriff Abdullah hdac_unlock(sc);
1125e5ad83a7SAriff Abdullah }
1126e5ad83a7SAriff Abdullah
11271f0387f7SAriff Abdullah /****************************************************************************
11281f0387f7SAriff Abdullah * int hdac_attach(device_t)
11291f0387f7SAriff Abdullah *
11301f0387f7SAriff Abdullah * Attach the device into the kernel. Interrupts usually won't be enabled
11311f0387f7SAriff Abdullah * when this function is called. Setup everything that doesn't require
11321f0387f7SAriff Abdullah * interrupts and defer probing of codecs until interrupts are enabled.
11331f0387f7SAriff Abdullah ****************************************************************************/
11341f0387f7SAriff Abdullah static int
hdac_attach(device_t dev)11351f0387f7SAriff Abdullah hdac_attach(device_t dev)
11361f0387f7SAriff Abdullah {
11371f0387f7SAriff Abdullah struct hdac_softc *sc;
11381f0387f7SAriff Abdullah int result;
1139edce9c99SAlexander Motin int i, devid = -1;
1140edce9c99SAlexander Motin uint32_t model;
1141edce9c99SAlexander Motin uint16_t class, subclass;
114271e3af01SAriff Abdullah uint16_t vendor;
114371e3af01SAriff Abdullah uint8_t v;
11441f0387f7SAriff Abdullah
11457c6b05d2SAlexander Motin sc = device_get_softc(dev);
1146d2c60314SJoel Dahl HDA_BOOTVERBOSE(
1147ed228e40SAlexander Motin device_printf(dev, "PCI card vendor: 0x%04x, device: 0x%04x\n",
1148ed228e40SAlexander Motin pci_get_subvendor(dev), pci_get_subdevice(dev));
1149d2c60314SJoel Dahl device_printf(dev, "HDA Driver Revision: %s\n",
1150d2c60314SJoel Dahl HDA_DRV_TEST_REV);
1151d2c60314SJoel Dahl );
1152859159d1SAlexander Motin
1153edce9c99SAlexander Motin model = (uint32_t)pci_get_device(dev) << 16;
1154edce9c99SAlexander Motin model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
1155edce9c99SAlexander Motin class = pci_get_class(dev);
1156edce9c99SAlexander Motin subclass = pci_get_subclass(dev);
1157edce9c99SAlexander Motin
1158abe917adSMarius Strobl for (i = 0; i < nitems(hdac_devices); i++) {
1159edce9c99SAlexander Motin if (hdac_devices[i].model == model) {
1160edce9c99SAlexander Motin devid = i;
1161edce9c99SAlexander Motin break;
1162edce9c99SAlexander Motin }
1163edce9c99SAlexander Motin if (HDA_DEV_MATCH(hdac_devices[i].model, model) &&
1164edce9c99SAlexander Motin class == PCIC_MULTIMEDIA &&
1165edce9c99SAlexander Motin subclass == PCIS_MULTIMEDIA_HDA) {
1166edce9c99SAlexander Motin devid = i;
1167edce9c99SAlexander Motin break;
1168edce9c99SAlexander Motin }
1169edce9c99SAlexander Motin }
1170edce9c99SAlexander Motin
11717c6b05d2SAlexander Motin sc->lock = snd_mtxcreate(device_get_nameunit(dev), "HDA driver mutex");
11721f0387f7SAriff Abdullah sc->dev = dev;
1173e5ad83a7SAriff Abdullah TASK_INIT(&sc->unsolq_task, 0, hdac_unsolq_task, sc);
1174fd90e2edSJung-uk Kim callout_init(&sc->poll_callout, 1);
11757c6b05d2SAlexander Motin for (i = 0; i < HDAC_CODEC_MAX; i++)
11767c6b05d2SAlexander Motin sc->codecs[i].dev = NULL;
11777c6b05d2SAlexander Motin if (devid >= 0) {
11787c6b05d2SAlexander Motin sc->quirks_on = hdac_devices[devid].quirks_on;
11797c6b05d2SAlexander Motin sc->quirks_off = hdac_devices[devid].quirks_off;
11807c6b05d2SAlexander Motin } else {
11817c6b05d2SAlexander Motin sc->quirks_on = 0;
11827c6b05d2SAlexander Motin sc->quirks_off = 0;
11837c6b05d2SAlexander Motin }
11847c6b05d2SAlexander Motin if (resource_int_value(device_get_name(dev),
11857c6b05d2SAlexander Motin device_get_unit(dev), "msi", &i) == 0) {
11867c6b05d2SAlexander Motin if (i == 0)
11877c6b05d2SAlexander Motin sc->quirks_off |= HDAC_QUIRK_MSI;
11887c6b05d2SAlexander Motin else {
11897c6b05d2SAlexander Motin sc->quirks_on |= HDAC_QUIRK_MSI;
11907c6b05d2SAlexander Motin sc->quirks_off |= ~HDAC_QUIRK_MSI;
11917c6b05d2SAlexander Motin }
11927c6b05d2SAlexander Motin }
11937c6b05d2SAlexander Motin hdac_config_fetch(sc, &sc->quirks_on, &sc->quirks_off);
11947c6b05d2SAlexander Motin HDA_BOOTVERBOSE(
11957c6b05d2SAlexander Motin device_printf(sc->dev,
11967c6b05d2SAlexander Motin "Config options: on=0x%08x off=0x%08x\n",
11977c6b05d2SAlexander Motin sc->quirks_on, sc->quirks_off);
11987c6b05d2SAlexander Motin );
11997c6b05d2SAlexander Motin sc->poll_ival = hz;
120071e3af01SAriff Abdullah if (resource_int_value(device_get_name(dev),
120171e3af01SAriff Abdullah device_get_unit(dev), "polling", &i) == 0 && i != 0)
1202a580b31aSAriff Abdullah sc->polling = 1;
1203a580b31aSAriff Abdullah else
1204a580b31aSAriff Abdullah sc->polling = 0;
1205a580b31aSAriff Abdullah
12061f0387f7SAriff Abdullah pci_enable_busmaster(dev);
12071f0387f7SAriff Abdullah
12087c6b05d2SAlexander Motin vendor = pci_get_vendor(dev);
120971e3af01SAriff Abdullah if (vendor == INTEL_VENDORID) {
121071e3af01SAriff Abdullah /* TCSEL -> TC0 */
121171e3af01SAriff Abdullah v = pci_read_config(dev, 0x44, 1);
121271e3af01SAriff Abdullah pci_write_config(dev, 0x44, v & 0xf8, 1);
12134d423c80SAlexander Motin HDA_BOOTHVERBOSE(
121471e3af01SAriff Abdullah device_printf(dev, "TCSEL: 0x%02d -> 0x%02d\n", v,
121571e3af01SAriff Abdullah pci_read_config(dev, 0x44, 1));
121671e3af01SAriff Abdullah );
121771e3af01SAriff Abdullah }
121871e3af01SAriff Abdullah
121971e3af01SAriff Abdullah #if defined(__i386__) || defined(__amd64__)
12200937dd1eSAriff Abdullah sc->flags |= HDAC_F_DMA_NOCACHE;
122171e3af01SAriff Abdullah
122271e3af01SAriff Abdullah if (resource_int_value(device_get_name(dev),
122371e3af01SAriff Abdullah device_get_unit(dev), "snoop", &i) == 0 && i != 0) {
122471e3af01SAriff Abdullah #else
12250937dd1eSAriff Abdullah sc->flags &= ~HDAC_F_DMA_NOCACHE;
122671e3af01SAriff Abdullah #endif
122771e3af01SAriff Abdullah /*
122871e3af01SAriff Abdullah * Try to enable PCIe snoop to avoid messing around with
122971e3af01SAriff Abdullah * uncacheable DMA attribute. Since PCIe snoop register
123071e3af01SAriff Abdullah * config is pretty much vendor specific, there are no
123171e3af01SAriff Abdullah * general solutions on how to enable it, forcing us (even
123271e3af01SAriff Abdullah * Microsoft) to enable uncacheable or write combined DMA
123371e3af01SAriff Abdullah * by default.
123471e3af01SAriff Abdullah *
123571e3af01SAriff Abdullah * http://msdn2.microsoft.com/en-us/library/ms790324.aspx
123671e3af01SAriff Abdullah */
1237abe917adSMarius Strobl for (i = 0; i < nitems(hdac_pcie_snoop); i++) {
123871e3af01SAriff Abdullah if (hdac_pcie_snoop[i].vendor != vendor)
123971e3af01SAriff Abdullah continue;
12400937dd1eSAriff Abdullah sc->flags &= ~HDAC_F_DMA_NOCACHE;
124171e3af01SAriff Abdullah if (hdac_pcie_snoop[i].reg == 0x00)
124271e3af01SAriff Abdullah break;
124371e3af01SAriff Abdullah v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1);
124471e3af01SAriff Abdullah if ((v & hdac_pcie_snoop[i].enable) ==
124571e3af01SAriff Abdullah hdac_pcie_snoop[i].enable)
124671e3af01SAriff Abdullah break;
124771e3af01SAriff Abdullah v &= hdac_pcie_snoop[i].mask;
124871e3af01SAriff Abdullah v |= hdac_pcie_snoop[i].enable;
124971e3af01SAriff Abdullah pci_write_config(dev, hdac_pcie_snoop[i].reg, v, 1);
125071e3af01SAriff Abdullah v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1);
125171e3af01SAriff Abdullah if ((v & hdac_pcie_snoop[i].enable) !=
125271e3af01SAriff Abdullah hdac_pcie_snoop[i].enable) {
125371e3af01SAriff Abdullah HDA_BOOTVERBOSE(
125471e3af01SAriff Abdullah device_printf(dev,
125571e3af01SAriff Abdullah "WARNING: Failed to enable PCIe "
125671e3af01SAriff Abdullah "snoop!\n");
125771e3af01SAriff Abdullah );
125871e3af01SAriff Abdullah #if defined(__i386__) || defined(__amd64__)
12590937dd1eSAriff Abdullah sc->flags |= HDAC_F_DMA_NOCACHE;
126071e3af01SAriff Abdullah #endif
126171e3af01SAriff Abdullah }
126271e3af01SAriff Abdullah break;
126371e3af01SAriff Abdullah }
126471e3af01SAriff Abdullah #if defined(__i386__) || defined(__amd64__)
126571e3af01SAriff Abdullah }
126671e3af01SAriff Abdullah #endif
126771e3af01SAriff Abdullah
12684d423c80SAlexander Motin HDA_BOOTHVERBOSE(
126971e3af01SAriff Abdullah device_printf(dev, "DMA Coherency: %s / vendor=0x%04x\n",
12700937dd1eSAriff Abdullah (sc->flags & HDAC_F_DMA_NOCACHE) ?
12710937dd1eSAriff Abdullah "Uncacheable" : "PCIe snoop", vendor);
127271e3af01SAriff Abdullah );
127371e3af01SAriff Abdullah
12741f0387f7SAriff Abdullah /* Allocate resources */
12751f0387f7SAriff Abdullah result = hdac_mem_alloc(sc);
12761f0387f7SAriff Abdullah if (result != 0)
12778d999aa8SAriff Abdullah goto hdac_attach_fail;
12781f0387f7SAriff Abdullah
12791f0387f7SAriff Abdullah /* Get Capabilities */
12801f0387f7SAriff Abdullah result = hdac_get_capabilities(sc);
12811f0387f7SAriff Abdullah if (result != 0)
12828d999aa8SAriff Abdullah goto hdac_attach_fail;
12831f0387f7SAriff Abdullah
12847c6b05d2SAlexander Motin /* Allocate CORB, RIRB, POS and BDLs dma memory */
12851f0387f7SAriff Abdullah result = hdac_dma_alloc(sc, &sc->corb_dma,
12861f0387f7SAriff Abdullah sc->corb_size * sizeof(uint32_t));
12871f0387f7SAriff Abdullah if (result != 0)
12888d999aa8SAriff Abdullah goto hdac_attach_fail;
12891f0387f7SAriff Abdullah result = hdac_dma_alloc(sc, &sc->rirb_dma,
12901f0387f7SAriff Abdullah sc->rirb_size * sizeof(struct hdac_rirb));
12911f0387f7SAriff Abdullah if (result != 0)
12928d999aa8SAriff Abdullah goto hdac_attach_fail;
12937c6b05d2SAlexander Motin sc->streams = malloc(sizeof(struct hdac_stream) * sc->num_ss,
12947c6b05d2SAlexander Motin M_HDAC, M_ZERO | M_WAITOK);
12957c6b05d2SAlexander Motin for (i = 0; i < sc->num_ss; i++) {
12967c6b05d2SAlexander Motin result = hdac_dma_alloc(sc, &sc->streams[i].bdl,
12977c6b05d2SAlexander Motin sizeof(struct hdac_bdle) * HDA_BDL_MAX);
12987c6b05d2SAlexander Motin if (result != 0)
12997c6b05d2SAlexander Motin goto hdac_attach_fail;
13007c6b05d2SAlexander Motin }
13017c6b05d2SAlexander Motin if (sc->quirks_on & HDAC_QUIRK_DMAPOS) {
13027c6b05d2SAlexander Motin if (hdac_dma_alloc(sc, &sc->pos_dma, (sc->num_ss) * 8) != 0) {
13037c6b05d2SAlexander Motin HDA_BOOTVERBOSE(
13047c6b05d2SAlexander Motin device_printf(dev, "Failed to "
13057c6b05d2SAlexander Motin "allocate DMA pos buffer "
13067c6b05d2SAlexander Motin "(non-fatal)\n");
13077c6b05d2SAlexander Motin );
13087c6b05d2SAlexander Motin } else {
13097c6b05d2SAlexander Motin uint64_t addr = sc->pos_dma.dma_paddr;
13107c6b05d2SAlexander Motin
13117c6b05d2SAlexander Motin HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, addr >> 32);
13127c6b05d2SAlexander Motin HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE,
13137c6b05d2SAlexander Motin (addr & HDAC_DPLBASE_DPLBASE_MASK) |
13147c6b05d2SAlexander Motin HDAC_DPLBASE_DPLBASE_DMAPBE);
13157c6b05d2SAlexander Motin }
13167c6b05d2SAlexander Motin }
13171f0387f7SAriff Abdullah
13188380c28eSAlexander Motin result = bus_dma_tag_create(
13198380c28eSAlexander Motin bus_get_dma_tag(sc->dev), /* parent */
13207c6b05d2SAlexander Motin HDA_DMA_ALIGNMENT, /* alignment */
13218380c28eSAlexander Motin 0, /* boundary */
13228380c28eSAlexander Motin (sc->support_64bit) ? BUS_SPACE_MAXADDR :
13238380c28eSAlexander Motin BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
13248380c28eSAlexander Motin BUS_SPACE_MAXADDR, /* highaddr */
13258380c28eSAlexander Motin NULL, /* filtfunc */
13268380c28eSAlexander Motin NULL, /* fistfuncarg */
13278380c28eSAlexander Motin HDA_BUFSZ_MAX, /* maxsize */
13288380c28eSAlexander Motin 1, /* nsegments */
13298380c28eSAlexander Motin HDA_BUFSZ_MAX, /* maxsegsz */
13308380c28eSAlexander Motin 0, /* flags */
13318380c28eSAlexander Motin NULL, /* lockfunc */
13328380c28eSAlexander Motin NULL, /* lockfuncarg */
13338380c28eSAlexander Motin &sc->chan_dmat); /* dmat */
13348380c28eSAlexander Motin if (result != 0) {
1335bdafaf0aSJustin Hibbits device_printf(dev, "%s: bus_dma_tag_create failed (%d)\n",
13368380c28eSAlexander Motin __func__, result);
13378380c28eSAlexander Motin goto hdac_attach_fail;
13388380c28eSAlexander Motin }
13398380c28eSAlexander Motin
13401f0387f7SAriff Abdullah /* Quiesce everything */
13414d423c80SAlexander Motin HDA_BOOTHVERBOSE(
1342859159d1SAlexander Motin device_printf(dev, "Reset controller...\n");
1343859159d1SAlexander Motin );
1344258ba4c0SEd Maste hdac_reset(sc, true);
13451f0387f7SAriff Abdullah
13461f0387f7SAriff Abdullah /* Initialize the CORB and RIRB */
13471f0387f7SAriff Abdullah hdac_corb_init(sc);
13481f0387f7SAriff Abdullah hdac_rirb_init(sc);
13491f0387f7SAriff Abdullah
1350015daf52SMark Johnston result = hdac_irq_alloc(sc);
1351015daf52SMark Johnston if (result != 0)
1352015daf52SMark Johnston goto hdac_attach_fail;
1353015daf52SMark Johnston
13541f0387f7SAriff Abdullah /* Defer remaining of initialization until interrupts are enabled */
13551f0387f7SAriff Abdullah sc->intrhook.ich_func = hdac_attach2;
13561f0387f7SAriff Abdullah sc->intrhook.ich_arg = (void *)sc;
13571f0387f7SAriff Abdullah if (cold == 0 || config_intrhook_establish(&sc->intrhook) != 0) {
13581f0387f7SAriff Abdullah sc->intrhook.ich_func = NULL;
13591f0387f7SAriff Abdullah hdac_attach2((void *)sc);
13601f0387f7SAriff Abdullah }
13611f0387f7SAriff Abdullah
13621f0387f7SAriff Abdullah return (0);
13631f0387f7SAriff Abdullah
13648d999aa8SAriff Abdullah hdac_attach_fail:
13651f0387f7SAriff Abdullah hdac_irq_free(sc);
1366cf40916bSJustin Hibbits if (sc->streams != NULL)
13677c6b05d2SAlexander Motin for (i = 0; i < sc->num_ss; i++)
13687c6b05d2SAlexander Motin hdac_dma_free(sc, &sc->streams[i].bdl);
13697c6b05d2SAlexander Motin free(sc->streams, M_HDAC);
137071e3af01SAriff Abdullah hdac_dma_free(sc, &sc->rirb_dma);
137171e3af01SAriff Abdullah hdac_dma_free(sc, &sc->corb_dma);
13721f0387f7SAriff Abdullah hdac_mem_free(sc);
13731f0387f7SAriff Abdullah snd_mtxfree(sc->lock);
13741f0387f7SAriff Abdullah
13751f0387f7SAriff Abdullah return (ENXIO);
13761f0387f7SAriff Abdullah }
13771f0387f7SAriff Abdullah
1378859159d1SAlexander Motin static int
sysctl_hdac_pindump(SYSCTL_HANDLER_ARGS)13797c6b05d2SAlexander Motin sysctl_hdac_pindump(SYSCTL_HANDLER_ARGS)
1380859159d1SAlexander Motin {
13817c6b05d2SAlexander Motin struct hdac_softc *sc;
13827c6b05d2SAlexander Motin device_t *devlist;
13837c6b05d2SAlexander Motin device_t dev;
13847c6b05d2SAlexander Motin int devcount, i, err, val;
1385859159d1SAlexander Motin
13867c6b05d2SAlexander Motin dev = oidp->oid_arg1;
13877c6b05d2SAlexander Motin sc = device_get_softc(dev);
13888d999aa8SAriff Abdullah if (sc == NULL)
13897c6b05d2SAlexander Motin return (EINVAL);
13907c6b05d2SAlexander Motin val = 0;
13917c6b05d2SAlexander Motin err = sysctl_handle_int(oidp, &val, 0, req);
13927c6b05d2SAlexander Motin if (err != 0 || req->newptr == NULL || val == 0)
13937c6b05d2SAlexander Motin return (err);
13948d999aa8SAriff Abdullah
13957c6b05d2SAlexander Motin /* XXX: Temporary. For debugging. */
13967c6b05d2SAlexander Motin if (val == 100) {
13977c6b05d2SAlexander Motin hdac_suspend(dev);
13987c6b05d2SAlexander Motin return (0);
13997c6b05d2SAlexander Motin } else if (val == 101) {
14007c6b05d2SAlexander Motin hdac_resume(dev);
14017c6b05d2SAlexander Motin return (0);
14027c6b05d2SAlexander Motin }
14037c6b05d2SAlexander Motin
140496e500a3SWarner Losh bus_topo_lock();
140596e500a3SWarner Losh
140696e500a3SWarner Losh if ((err = device_get_children(dev, &devlist, &devcount)) != 0) {
140796e500a3SWarner Losh bus_topo_unlock();
14087c6b05d2SAlexander Motin return (err);
140996e500a3SWarner Losh }
141096e500a3SWarner Losh
14118d999aa8SAriff Abdullah hdac_lock(sc);
14127c6b05d2SAlexander Motin for (i = 0; i < devcount; i++)
14137c6b05d2SAlexander Motin HDAC_PINDUMP(devlist[i]);
14148d999aa8SAriff Abdullah hdac_unlock(sc);
141596e500a3SWarner Losh
141696e500a3SWarner Losh bus_topo_unlock();
141796e500a3SWarner Losh
14187c6b05d2SAlexander Motin free(devlist, M_TEMP);
14197c6b05d2SAlexander Motin return (0);
14208d999aa8SAriff Abdullah }
14218d999aa8SAriff Abdullah
14227c6b05d2SAlexander Motin static int
hdac_mdata_rate(uint16_t fmt)14236fa8e691SAlexander Motin hdac_mdata_rate(uint16_t fmt)
14248d999aa8SAriff Abdullah {
14256fa8e691SAlexander Motin static const int mbits[8] = { 8, 16, 32, 32, 32, 32, 32, 32 };
14266fa8e691SAlexander Motin int rate, bits;
14278d999aa8SAriff Abdullah
14287c6b05d2SAlexander Motin if (fmt & (1 << 14))
14297c6b05d2SAlexander Motin rate = 44100;
14308d999aa8SAriff Abdullah else
14317c6b05d2SAlexander Motin rate = 48000;
14327c6b05d2SAlexander Motin rate *= ((fmt >> 11) & 0x07) + 1;
14337c6b05d2SAlexander Motin rate /= ((fmt >> 8) & 0x07) + 1;
14346fa8e691SAlexander Motin bits = mbits[(fmt >> 4) & 0x03];
14356fa8e691SAlexander Motin bits *= (fmt & 0x0f) + 1;
14366fa8e691SAlexander Motin return (rate * bits);
14376fa8e691SAlexander Motin }
14386fa8e691SAlexander Motin
14396fa8e691SAlexander Motin static int
hdac_bdata_rate(uint16_t fmt,int output)14406fa8e691SAlexander Motin hdac_bdata_rate(uint16_t fmt, int output)
14416fa8e691SAlexander Motin {
14426fa8e691SAlexander Motin static const int bbits[8] = { 8, 16, 20, 24, 32, 32, 32, 32 };
14436fa8e691SAlexander Motin int rate, bits;
14446fa8e691SAlexander Motin
14456fa8e691SAlexander Motin rate = 48000;
14466fa8e691SAlexander Motin rate *= ((fmt >> 11) & 0x07) + 1;
14476fa8e691SAlexander Motin bits = bbits[(fmt >> 4) & 0x03];
14486fa8e691SAlexander Motin bits *= (fmt & 0x0f) + 1;
14496fa8e691SAlexander Motin if (!output)
14506fa8e691SAlexander Motin bits = ((bits + 7) & ~0x07) + 10;
14516fa8e691SAlexander Motin return (rate * bits);
14527c6b05d2SAlexander Motin }
14537c6b05d2SAlexander Motin
14547c6b05d2SAlexander Motin static void
hdac_poll_reinit(struct hdac_softc * sc)14557c6b05d2SAlexander Motin hdac_poll_reinit(struct hdac_softc *sc)
14567c6b05d2SAlexander Motin {
14577c6b05d2SAlexander Motin int i, pollticks, min = 1000000;
14587c6b05d2SAlexander Motin struct hdac_stream *s;
14597c6b05d2SAlexander Motin
14607c6b05d2SAlexander Motin if (sc->polling == 0)
14617c6b05d2SAlexander Motin return;
14627c6b05d2SAlexander Motin if (sc->unsol_registered > 0)
14637c6b05d2SAlexander Motin min = hz / 2;
14647c6b05d2SAlexander Motin for (i = 0; i < sc->num_ss; i++) {
14657c6b05d2SAlexander Motin s = &sc->streams[i];
14667c6b05d2SAlexander Motin if (s->running == 0)
14678d999aa8SAriff Abdullah continue;
14687c6b05d2SAlexander Motin pollticks = ((uint64_t)hz * s->blksz) /
14696fa8e691SAlexander Motin (hdac_mdata_rate(s->format) / 8);
14707c6b05d2SAlexander Motin pollticks >>= 1;
14717c6b05d2SAlexander Motin if (pollticks > hz)
14727c6b05d2SAlexander Motin pollticks = hz;
1473f30cf558SKonstantin Belousov if (pollticks < 1)
14747c6b05d2SAlexander Motin pollticks = 1;
14757c6b05d2SAlexander Motin if (min > pollticks)
14767c6b05d2SAlexander Motin min = pollticks;
14778d999aa8SAriff Abdullah }
14787c6b05d2SAlexander Motin sc->poll_ival = min;
14797c6b05d2SAlexander Motin if (min == 1000000)
14807c6b05d2SAlexander Motin callout_stop(&sc->poll_callout);
14817c6b05d2SAlexander Motin else
14827c6b05d2SAlexander Motin callout_reset(&sc->poll_callout, 1, hdac_poll_callback, sc);
14838d999aa8SAriff Abdullah }
14848d999aa8SAriff Abdullah
1485a580b31aSAriff Abdullah static int
sysctl_hdac_polling(SYSCTL_HANDLER_ARGS)1486a580b31aSAriff Abdullah sysctl_hdac_polling(SYSCTL_HANDLER_ARGS)
1487a580b31aSAriff Abdullah {
1488a580b31aSAriff Abdullah struct hdac_softc *sc;
1489a580b31aSAriff Abdullah device_t dev;
1490a580b31aSAriff Abdullah uint32_t ctl;
1491a580b31aSAriff Abdullah int err, val;
1492a580b31aSAriff Abdullah
1493a580b31aSAriff Abdullah dev = oidp->oid_arg1;
1494859159d1SAlexander Motin sc = device_get_softc(dev);
1495859159d1SAlexander Motin if (sc == NULL)
1496a580b31aSAriff Abdullah return (EINVAL);
1497a580b31aSAriff Abdullah hdac_lock(sc);
1498a580b31aSAriff Abdullah val = sc->polling;
1499a580b31aSAriff Abdullah hdac_unlock(sc);
1500041b706bSDavid Malone err = sysctl_handle_int(oidp, &val, 0, req);
1501a580b31aSAriff Abdullah
150271e3af01SAriff Abdullah if (err != 0 || req->newptr == NULL)
1503a580b31aSAriff Abdullah return (err);
1504a580b31aSAriff Abdullah if (val < 0 || val > 1)
1505a580b31aSAriff Abdullah return (EINVAL);
1506a580b31aSAriff Abdullah
1507a580b31aSAriff Abdullah hdac_lock(sc);
1508a580b31aSAriff Abdullah if (val != sc->polling) {
1509859159d1SAlexander Motin if (val == 0) {
15107c6b05d2SAlexander Motin callout_stop(&sc->poll_callout);
151171e3af01SAriff Abdullah hdac_unlock(sc);
15127c6b05d2SAlexander Motin callout_drain(&sc->poll_callout);
151371e3af01SAriff Abdullah hdac_lock(sc);
1514a580b31aSAriff Abdullah sc->polling = 0;
1515859159d1SAlexander Motin ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
1516859159d1SAlexander Motin ctl |= HDAC_INTCTL_GIE;
1517859159d1SAlexander Motin HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
1518a580b31aSAriff Abdullah } else {
1519859159d1SAlexander Motin ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
1520859159d1SAlexander Motin ctl &= ~HDAC_INTCTL_GIE;
1521859159d1SAlexander Motin HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
1522a580b31aSAriff Abdullah sc->polling = 1;
1523859159d1SAlexander Motin hdac_poll_reinit(sc);
1524a580b31aSAriff Abdullah }
1525a580b31aSAriff Abdullah }
1526a580b31aSAriff Abdullah hdac_unlock(sc);
1527a580b31aSAriff Abdullah
1528a580b31aSAriff Abdullah return (err);
1529a580b31aSAriff Abdullah }
153071e3af01SAriff Abdullah
15318d999aa8SAriff Abdullah static void
hdac_attach2(void * arg)15321f0387f7SAriff Abdullah hdac_attach2(void *arg)
15331f0387f7SAriff Abdullah {
15341f0387f7SAriff Abdullah struct hdac_softc *sc;
15357c6b05d2SAlexander Motin device_t child;
15367c6b05d2SAlexander Motin uint32_t vendorid, revisionid;
15377c6b05d2SAlexander Motin int i;
15387c6b05d2SAlexander Motin uint16_t statests;
15391f0387f7SAriff Abdullah
15401f0387f7SAriff Abdullah sc = (struct hdac_softc *)arg;
15411f0387f7SAriff Abdullah
15421f0387f7SAriff Abdullah hdac_lock(sc);
15431f0387f7SAriff Abdullah
15441f0387f7SAriff Abdullah /* Remove ourselves from the config hooks */
15451f0387f7SAriff Abdullah if (sc->intrhook.ich_func != NULL) {
15461f0387f7SAriff Abdullah config_intrhook_disestablish(&sc->intrhook);
15471f0387f7SAriff Abdullah sc->intrhook.ich_func = NULL;
15481f0387f7SAriff Abdullah }
15491f0387f7SAriff Abdullah
15504d423c80SAlexander Motin HDA_BOOTHVERBOSE(
1551859159d1SAlexander Motin device_printf(sc->dev, "Starting CORB Engine...\n");
15521f0387f7SAriff Abdullah );
15531f0387f7SAriff Abdullah hdac_corb_start(sc);
15544d423c80SAlexander Motin HDA_BOOTHVERBOSE(
1555859159d1SAlexander Motin device_printf(sc->dev, "Starting RIRB Engine...\n");
15561f0387f7SAriff Abdullah );
15571f0387f7SAriff Abdullah hdac_rirb_start(sc);
155843022083SAndriy Gapon
155943022083SAndriy Gapon /*
156043022083SAndriy Gapon * Clear HDAC_WAKEEN as at present we have no use for SDI wake
156143022083SAndriy Gapon * (status change) interrupts. The documentation says that we
156243022083SAndriy Gapon * should not make any assumptions about the state of this register
156343022083SAndriy Gapon * and set it explicitly.
156443022083SAndriy Gapon * NB: this needs to be done before the interrupt is enabled as
156543022083SAndriy Gapon * the handler does not expect this interrupt source.
156643022083SAndriy Gapon */
156743022083SAndriy Gapon HDAC_WRITE_2(&sc->mem, HDAC_WAKEEN, 0);
156843022083SAndriy Gapon
156943022083SAndriy Gapon /*
157043022083SAndriy Gapon * Read and clear post-reset SDI wake status.
157143022083SAndriy Gapon * Each set bit corresponds to a codec that came out of reset.
157243022083SAndriy Gapon */
157343022083SAndriy Gapon statests = HDAC_READ_2(&sc->mem, HDAC_STATESTS);
157443022083SAndriy Gapon HDAC_WRITE_2(&sc->mem, HDAC_STATESTS, statests);
157543022083SAndriy Gapon
15764d423c80SAlexander Motin HDA_BOOTHVERBOSE(
15771f0387f7SAriff Abdullah device_printf(sc->dev,
1578859159d1SAlexander Motin "Enabling controller interrupt...\n");
15791f0387f7SAriff Abdullah );
15808d999aa8SAriff Abdullah HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) |
15818d999aa8SAriff Abdullah HDAC_GCTL_UNSOL);
1582859159d1SAlexander Motin if (sc->polling == 0) {
1583859159d1SAlexander Motin HDAC_WRITE_4(&sc->mem, HDAC_INTCTL,
1584859159d1SAlexander Motin HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
1585859159d1SAlexander Motin }
15861f0387f7SAriff Abdullah DELAY(1000);
15871f0387f7SAriff Abdullah
15884d423c80SAlexander Motin HDA_BOOTHVERBOSE(
15897c6b05d2SAlexander Motin device_printf(sc->dev, "Scanning HDA codecs ...\n");
15901f0387f7SAriff Abdullah );
1591859159d1SAlexander Motin hdac_unlock(sc);
15927c6b05d2SAlexander Motin for (i = 0; i < HDAC_CODEC_MAX; i++) {
15937c6b05d2SAlexander Motin if (HDAC_STATESTS_SDIWAKE(statests, i)) {
15947c6b05d2SAlexander Motin HDA_BOOTHVERBOSE(
15957c6b05d2SAlexander Motin device_printf(sc->dev,
15967c6b05d2SAlexander Motin "Found CODEC at address %d\n", i);
15971f0387f7SAriff Abdullah );
15987c6b05d2SAlexander Motin hdac_lock(sc);
15997c6b05d2SAlexander Motin vendorid = hdac_send_command(sc, i,
16007c6b05d2SAlexander Motin HDA_CMD_GET_PARAMETER(0, 0x0, HDA_PARAM_VENDOR_ID));
16017c6b05d2SAlexander Motin revisionid = hdac_send_command(sc, i,
16027c6b05d2SAlexander Motin HDA_CMD_GET_PARAMETER(0, 0x0, HDA_PARAM_REVISION_ID));
16037c6b05d2SAlexander Motin hdac_unlock(sc);
16047c6b05d2SAlexander Motin if (vendorid == HDA_INVALID &&
16057c6b05d2SAlexander Motin revisionid == HDA_INVALID) {
16067c6b05d2SAlexander Motin device_printf(sc->dev,
1607b75e561aSEd Maste "CODEC at address %d not responding!\n", i);
16087c6b05d2SAlexander Motin continue;
16097c6b05d2SAlexander Motin }
16107c6b05d2SAlexander Motin sc->codecs[i].vendor_id =
16117c6b05d2SAlexander Motin HDA_PARAM_VENDOR_ID_VENDOR_ID(vendorid);
16127c6b05d2SAlexander Motin sc->codecs[i].device_id =
16137c6b05d2SAlexander Motin HDA_PARAM_VENDOR_ID_DEVICE_ID(vendorid);
16147c6b05d2SAlexander Motin sc->codecs[i].revision_id =
16157c6b05d2SAlexander Motin HDA_PARAM_REVISION_ID_REVISION_ID(revisionid);
16167c6b05d2SAlexander Motin sc->codecs[i].stepping_id =
16177c6b05d2SAlexander Motin HDA_PARAM_REVISION_ID_STEPPING_ID(revisionid);
16185b56413dSWarner Losh child = device_add_child(sc->dev, "hdacc", DEVICE_UNIT_ANY);
16197c6b05d2SAlexander Motin if (child == NULL) {
16207c6b05d2SAlexander Motin device_printf(sc->dev,
16217c6b05d2SAlexander Motin "Failed to add CODEC device\n");
16227c6b05d2SAlexander Motin continue;
16237c6b05d2SAlexander Motin }
16247c6b05d2SAlexander Motin device_set_ivars(child, (void *)(intptr_t)i);
16257c6b05d2SAlexander Motin sc->codecs[i].dev = child;
16267c6b05d2SAlexander Motin }
16277c6b05d2SAlexander Motin }
162818250ec6SJohn Baldwin bus_attach_children(sc->dev);
1629859159d1SAlexander Motin
1630859159d1SAlexander Motin SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
1631859159d1SAlexander Motin SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
163296e500a3SWarner Losh "pindump", CTLTYPE_INT | CTLFLAG_RW, sc->dev,
16337029da5cSPawel Biernacki sizeof(sc->dev), sysctl_hdac_pindump, "I", "Dump pin states/data");
16347c6b05d2SAlexander Motin SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
16357c6b05d2SAlexander Motin SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
163696e500a3SWarner Losh "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev,
16377029da5cSPawel Biernacki sizeof(sc->dev), sysctl_hdac_polling, "I", "Enable polling mode");
1638859159d1SAlexander Motin }
1639859159d1SAlexander Motin
1640859159d1SAlexander Motin /****************************************************************************
1641859159d1SAlexander Motin * int hdac_suspend(device_t)
1642859159d1SAlexander Motin *
1643859159d1SAlexander Motin * Suspend and power down HDA bus and codecs.
1644859159d1SAlexander Motin ****************************************************************************/
1645859159d1SAlexander Motin static int
hdac_suspend(device_t dev)1646859159d1SAlexander Motin hdac_suspend(device_t dev)
1647859159d1SAlexander Motin {
16487c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
1649859159d1SAlexander Motin
16504d423c80SAlexander Motin HDA_BOOTHVERBOSE(
1651859159d1SAlexander Motin device_printf(dev, "Suspend...\n");
1652859159d1SAlexander Motin );
16537c6b05d2SAlexander Motin bus_generic_suspend(dev);
1654859159d1SAlexander Motin
1655a580b31aSAriff Abdullah hdac_lock(sc);
16564d423c80SAlexander Motin HDA_BOOTHVERBOSE(
1657859159d1SAlexander Motin device_printf(dev, "Reset controller...\n");
1658859159d1SAlexander Motin );
165916b8ad64SAlexander Motin callout_stop(&sc->poll_callout);
1660258ba4c0SEd Maste hdac_reset(sc, false);
1661859159d1SAlexander Motin hdac_unlock(sc);
166216b8ad64SAlexander Motin callout_drain(&sc->poll_callout);
1663859159d1SAlexander Motin taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
16644d423c80SAlexander Motin HDA_BOOTHVERBOSE(
1665859159d1SAlexander Motin device_printf(dev, "Suspend done\n");
1666859159d1SAlexander Motin );
1667859159d1SAlexander Motin return (0);
1668859159d1SAlexander Motin }
1669859159d1SAlexander Motin
1670859159d1SAlexander Motin /****************************************************************************
1671859159d1SAlexander Motin * int hdac_resume(device_t)
1672859159d1SAlexander Motin *
1673859159d1SAlexander Motin * Powerup and restore HDA bus and codecs state.
1674859159d1SAlexander Motin ****************************************************************************/
1675859159d1SAlexander Motin static int
hdac_resume(device_t dev)1676859159d1SAlexander Motin hdac_resume(device_t dev)
1677859159d1SAlexander Motin {
16787c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
16797c6b05d2SAlexander Motin int error;
1680859159d1SAlexander Motin
16814d423c80SAlexander Motin HDA_BOOTHVERBOSE(
1682859159d1SAlexander Motin device_printf(dev, "Resume...\n");
1683859159d1SAlexander Motin );
1684859159d1SAlexander Motin hdac_lock(sc);
1685859159d1SAlexander Motin
1686859159d1SAlexander Motin /* Quiesce everything */
16874d423c80SAlexander Motin HDA_BOOTHVERBOSE(
1688859159d1SAlexander Motin device_printf(dev, "Reset controller...\n");
1689859159d1SAlexander Motin );
1690258ba4c0SEd Maste hdac_reset(sc, true);
1691859159d1SAlexander Motin
1692859159d1SAlexander Motin /* Initialize the CORB and RIRB */
1693859159d1SAlexander Motin hdac_corb_init(sc);
1694859159d1SAlexander Motin hdac_rirb_init(sc);
1695859159d1SAlexander Motin
16964d423c80SAlexander Motin HDA_BOOTHVERBOSE(
1697859159d1SAlexander Motin device_printf(dev, "Starting CORB Engine...\n");
1698859159d1SAlexander Motin );
1699859159d1SAlexander Motin hdac_corb_start(sc);
17004d423c80SAlexander Motin HDA_BOOTHVERBOSE(
1701859159d1SAlexander Motin device_printf(dev, "Starting RIRB Engine...\n");
1702859159d1SAlexander Motin );
1703859159d1SAlexander Motin hdac_rirb_start(sc);
170443022083SAndriy Gapon
170543022083SAndriy Gapon /*
170643022083SAndriy Gapon * Clear HDAC_WAKEEN as at present we have no use for SDI wake
170743022083SAndriy Gapon * (status change) events. The documentation says that we should
170843022083SAndriy Gapon * not make any assumptions about the state of this register and
170943022083SAndriy Gapon * set it explicitly.
171043022083SAndriy Gapon * Also, clear HDAC_STATESTS.
171143022083SAndriy Gapon * NB: this needs to be done before the interrupt is enabled as
171243022083SAndriy Gapon * the handler does not expect this interrupt source.
171343022083SAndriy Gapon */
171443022083SAndriy Gapon HDAC_WRITE_2(&sc->mem, HDAC_WAKEEN, 0);
171543022083SAndriy Gapon HDAC_WRITE_2(&sc->mem, HDAC_STATESTS, HDAC_STATESTS_SDIWAKE_MASK);
171643022083SAndriy Gapon
17174d423c80SAlexander Motin HDA_BOOTHVERBOSE(
17187c6b05d2SAlexander Motin device_printf(dev, "Enabling controller interrupt...\n");
1719859159d1SAlexander Motin );
1720859159d1SAlexander Motin HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) |
1721859159d1SAlexander Motin HDAC_GCTL_UNSOL);
17227c6b05d2SAlexander Motin HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
1723859159d1SAlexander Motin DELAY(1000);
172416b8ad64SAlexander Motin hdac_poll_reinit(sc);
1725859159d1SAlexander Motin hdac_unlock(sc);
1726859159d1SAlexander Motin
17277c6b05d2SAlexander Motin error = bus_generic_resume(dev);
17284d423c80SAlexander Motin HDA_BOOTHVERBOSE(
1729859159d1SAlexander Motin device_printf(dev, "Resume done\n");
1730859159d1SAlexander Motin );
17317c6b05d2SAlexander Motin return (error);
1732859159d1SAlexander Motin }
17337c6b05d2SAlexander Motin
17341f0387f7SAriff Abdullah /****************************************************************************
17351f0387f7SAriff Abdullah * int hdac_detach(device_t)
17361f0387f7SAriff Abdullah *
17371f0387f7SAriff Abdullah * Detach and free up resources utilized by the hdac device.
17381f0387f7SAriff Abdullah ****************************************************************************/
17391f0387f7SAriff Abdullah static int
hdac_detach(device_t dev)17401f0387f7SAriff Abdullah hdac_detach(device_t dev)
17411f0387f7SAriff Abdullah {
17427c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
1743*11a91178SJohn Baldwin int i, error;
17441f0387f7SAriff Abdullah
1745*11a91178SJohn Baldwin error = bus_generic_detach(dev);
1746*11a91178SJohn Baldwin if (error != 0)
1747e3ae9f65SAlexander Motin return (error);
17481f0387f7SAriff Abdullah
17497c6b05d2SAlexander Motin hdac_lock(sc);
1750258ba4c0SEd Maste hdac_reset(sc, false);
17517c6b05d2SAlexander Motin hdac_unlock(sc);
17527c6b05d2SAlexander Motin taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
17537c6b05d2SAlexander Motin hdac_irq_free(sc);
17541f0387f7SAriff Abdullah
17557c6b05d2SAlexander Motin for (i = 0; i < sc->num_ss; i++)
17567c6b05d2SAlexander Motin hdac_dma_free(sc, &sc->streams[i].bdl);
17577c6b05d2SAlexander Motin free(sc->streams, M_HDAC);
17587c6b05d2SAlexander Motin hdac_dma_free(sc, &sc->pos_dma);
17597c6b05d2SAlexander Motin hdac_dma_free(sc, &sc->rirb_dma);
17607c6b05d2SAlexander Motin hdac_dma_free(sc, &sc->corb_dma);
17617c6b05d2SAlexander Motin if (sc->chan_dmat != NULL) {
17627c6b05d2SAlexander Motin bus_dma_tag_destroy(sc->chan_dmat);
17637c6b05d2SAlexander Motin sc->chan_dmat = NULL;
17647c6b05d2SAlexander Motin }
17657c6b05d2SAlexander Motin hdac_mem_free(sc);
17667c6b05d2SAlexander Motin snd_mtxfree(sc->lock);
17671f0387f7SAriff Abdullah return (0);
17681f0387f7SAriff Abdullah }
17691f0387f7SAriff Abdullah
17707c6b05d2SAlexander Motin static bus_dma_tag_t
hdac_get_dma_tag(device_t dev,device_t child)17717c6b05d2SAlexander Motin hdac_get_dma_tag(device_t dev, device_t child)
17727c6b05d2SAlexander Motin {
17737c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
17747c6b05d2SAlexander Motin
17757c6b05d2SAlexander Motin return (sc->chan_dmat);
17767c6b05d2SAlexander Motin }
17777c6b05d2SAlexander Motin
17785ce33ccfSAlexander Motin static int
hdac_print_child(device_t dev,device_t child)17795ce33ccfSAlexander Motin hdac_print_child(device_t dev, device_t child)
17805ce33ccfSAlexander Motin {
17815ce33ccfSAlexander Motin int retval;
17825ce33ccfSAlexander Motin
17835ce33ccfSAlexander Motin retval = bus_print_child_header(dev, child);
1784944a6408SEd Maste retval += printf(" at cad %d", (int)(intptr_t)device_get_ivars(child));
17855ce33ccfSAlexander Motin retval += bus_print_child_footer(dev, child);
17865ce33ccfSAlexander Motin
17875ce33ccfSAlexander Motin return (retval);
17885ce33ccfSAlexander Motin }
17895ce33ccfSAlexander Motin
17907c6b05d2SAlexander Motin static int
hdac_child_location(device_t dev,device_t child,struct sbuf * sb)1791ddfc9c4cSWarner Losh hdac_child_location(device_t dev, device_t child, struct sbuf *sb)
17927c6b05d2SAlexander Motin {
17937c6b05d2SAlexander Motin
1794ddfc9c4cSWarner Losh sbuf_printf(sb, "cad=%d", (int)(intptr_t)device_get_ivars(child));
17957c6b05d2SAlexander Motin return (0);
17967c6b05d2SAlexander Motin }
17977c6b05d2SAlexander Motin
17987c6b05d2SAlexander Motin static int
hdac_child_pnpinfo_method(device_t dev,device_t child,struct sbuf * sb)1799ddfc9c4cSWarner Losh hdac_child_pnpinfo_method(device_t dev, device_t child, struct sbuf *sb)
18007c6b05d2SAlexander Motin {
18017c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
18027c6b05d2SAlexander Motin nid_t cad = (uintptr_t)device_get_ivars(child);
18037c6b05d2SAlexander Motin
1804ddfc9c4cSWarner Losh sbuf_printf(sb,
1805944a6408SEd Maste "vendor=0x%04x device=0x%04x revision=0x%02x stepping=0x%02x",
18067c6b05d2SAlexander Motin sc->codecs[cad].vendor_id, sc->codecs[cad].device_id,
18077c6b05d2SAlexander Motin sc->codecs[cad].revision_id, sc->codecs[cad].stepping_id);
18087c6b05d2SAlexander Motin return (0);
18097c6b05d2SAlexander Motin }
18107c6b05d2SAlexander Motin
18117c6b05d2SAlexander Motin static int
hdac_read_ivar(device_t dev,device_t child,int which,uintptr_t * result)18127c6b05d2SAlexander Motin hdac_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
18137c6b05d2SAlexander Motin {
18147c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
18157c6b05d2SAlexander Motin nid_t cad = (uintptr_t)device_get_ivars(child);
18167c6b05d2SAlexander Motin
18177c6b05d2SAlexander Motin switch (which) {
18187c6b05d2SAlexander Motin case HDA_IVAR_CODEC_ID:
18197c6b05d2SAlexander Motin *result = cad;
18207c6b05d2SAlexander Motin break;
18217c6b05d2SAlexander Motin case HDA_IVAR_VENDOR_ID:
18227c6b05d2SAlexander Motin *result = sc->codecs[cad].vendor_id;
18237c6b05d2SAlexander Motin break;
18247c6b05d2SAlexander Motin case HDA_IVAR_DEVICE_ID:
18257c6b05d2SAlexander Motin *result = sc->codecs[cad].device_id;
18267c6b05d2SAlexander Motin break;
18277c6b05d2SAlexander Motin case HDA_IVAR_REVISION_ID:
18287c6b05d2SAlexander Motin *result = sc->codecs[cad].revision_id;
18297c6b05d2SAlexander Motin break;
18307c6b05d2SAlexander Motin case HDA_IVAR_STEPPING_ID:
18317c6b05d2SAlexander Motin *result = sc->codecs[cad].stepping_id;
18327c6b05d2SAlexander Motin break;
18337c6b05d2SAlexander Motin case HDA_IVAR_SUBVENDOR_ID:
18347c6b05d2SAlexander Motin *result = pci_get_subvendor(dev);
18357c6b05d2SAlexander Motin break;
18367c6b05d2SAlexander Motin case HDA_IVAR_SUBDEVICE_ID:
18377c6b05d2SAlexander Motin *result = pci_get_subdevice(dev);
18387c6b05d2SAlexander Motin break;
18397c6b05d2SAlexander Motin case HDA_IVAR_DMA_NOCACHE:
18407c6b05d2SAlexander Motin *result = (sc->flags & HDAC_F_DMA_NOCACHE) != 0;
18417c6b05d2SAlexander Motin break;
18424642c8c5SMichal Meloun case HDA_IVAR_STRIPES_MASK:
18434642c8c5SMichal Meloun *result = (1 << (1 << sc->num_sdo)) - 1;
18444642c8c5SMichal Meloun break;
18457c6b05d2SAlexander Motin default:
18467c6b05d2SAlexander Motin return (ENOENT);
18477c6b05d2SAlexander Motin }
18487c6b05d2SAlexander Motin return (0);
18497c6b05d2SAlexander Motin }
18507c6b05d2SAlexander Motin
18517c6b05d2SAlexander Motin static struct mtx *
hdac_get_mtx(device_t dev,device_t child)18527c6b05d2SAlexander Motin hdac_get_mtx(device_t dev, device_t child)
18537c6b05d2SAlexander Motin {
18547c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
18557c6b05d2SAlexander Motin
18567c6b05d2SAlexander Motin return (sc->lock);
18577c6b05d2SAlexander Motin }
18587c6b05d2SAlexander Motin
18597c6b05d2SAlexander Motin static uint32_t
hdac_codec_command(device_t dev,device_t child,uint32_t verb)18607c6b05d2SAlexander Motin hdac_codec_command(device_t dev, device_t child, uint32_t verb)
18617c6b05d2SAlexander Motin {
18627c6b05d2SAlexander Motin
18637c6b05d2SAlexander Motin return (hdac_send_command(device_get_softc(dev),
18647c6b05d2SAlexander Motin (intptr_t)device_get_ivars(child), verb));
18657c6b05d2SAlexander Motin }
18667c6b05d2SAlexander Motin
18677c6b05d2SAlexander Motin static int
hdac_find_stream(struct hdac_softc * sc,int dir,int stream)18687c6b05d2SAlexander Motin hdac_find_stream(struct hdac_softc *sc, int dir, int stream)
18697c6b05d2SAlexander Motin {
18707c6b05d2SAlexander Motin int i, ss;
18717c6b05d2SAlexander Motin
18727c6b05d2SAlexander Motin ss = -1;
18733228add8SAlexander Motin /* Allocate ISS/OSS first. */
18747c6b05d2SAlexander Motin if (dir == 0) {
18757c6b05d2SAlexander Motin for (i = 0; i < sc->num_iss; i++) {
18767c6b05d2SAlexander Motin if (sc->streams[i].stream == stream) {
18777c6b05d2SAlexander Motin ss = i;
18787c6b05d2SAlexander Motin break;
18797c6b05d2SAlexander Motin }
18807c6b05d2SAlexander Motin }
18817c6b05d2SAlexander Motin } else {
18827c6b05d2SAlexander Motin for (i = 0; i < sc->num_oss; i++) {
18837c6b05d2SAlexander Motin if (sc->streams[i + sc->num_iss].stream == stream) {
18847c6b05d2SAlexander Motin ss = i + sc->num_iss;
18857c6b05d2SAlexander Motin break;
18867c6b05d2SAlexander Motin }
18877c6b05d2SAlexander Motin }
18887c6b05d2SAlexander Motin }
18897c6b05d2SAlexander Motin /* Fallback to BSS. */
18907c6b05d2SAlexander Motin if (ss == -1) {
18917c6b05d2SAlexander Motin for (i = 0; i < sc->num_bss; i++) {
18927c6b05d2SAlexander Motin if (sc->streams[i + sc->num_iss + sc->num_oss].stream
18937c6b05d2SAlexander Motin == stream) {
18947c6b05d2SAlexander Motin ss = i + sc->num_iss + sc->num_oss;
18957c6b05d2SAlexander Motin break;
18967c6b05d2SAlexander Motin }
18977c6b05d2SAlexander Motin }
18987c6b05d2SAlexander Motin }
18997c6b05d2SAlexander Motin return (ss);
19007c6b05d2SAlexander Motin }
19017c6b05d2SAlexander Motin
19027c6b05d2SAlexander Motin static int
hdac_stream_alloc(device_t dev,device_t child,int dir,int format,int stripe,uint32_t ** dmapos)19036fa8e691SAlexander Motin hdac_stream_alloc(device_t dev, device_t child, int dir, int format, int stripe,
19047c6b05d2SAlexander Motin uint32_t **dmapos)
19057c6b05d2SAlexander Motin {
19067c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
19076fa8e691SAlexander Motin nid_t cad = (uintptr_t)device_get_ivars(child);
19086fa8e691SAlexander Motin int stream, ss, bw, maxbw, prevbw;
19097c6b05d2SAlexander Motin
19107c6b05d2SAlexander Motin /* Look for empty stream. */
19117c6b05d2SAlexander Motin ss = hdac_find_stream(sc, dir, 0);
19127c6b05d2SAlexander Motin
19137c6b05d2SAlexander Motin /* Return if found nothing. */
19147c6b05d2SAlexander Motin if (ss < 0)
19157c6b05d2SAlexander Motin return (0);
19167c6b05d2SAlexander Motin
19176fa8e691SAlexander Motin /* Check bus bandwidth. */
19186fa8e691SAlexander Motin bw = hdac_bdata_rate(format, dir);
19196fa8e691SAlexander Motin if (dir == 1) {
19206fa8e691SAlexander Motin bw *= 1 << (sc->num_sdo - stripe);
19216fa8e691SAlexander Motin prevbw = sc->sdo_bw_used;
19226fa8e691SAlexander Motin maxbw = 48000 * 960 * (1 << sc->num_sdo);
19236fa8e691SAlexander Motin } else {
19246fa8e691SAlexander Motin prevbw = sc->codecs[cad].sdi_bw_used;
19256fa8e691SAlexander Motin maxbw = 48000 * 464;
19266fa8e691SAlexander Motin }
19276fa8e691SAlexander Motin HDA_BOOTHVERBOSE(
19286fa8e691SAlexander Motin device_printf(dev, "%dKbps of %dKbps bandwidth used%s\n",
19296fa8e691SAlexander Motin (bw + prevbw) / 1000, maxbw / 1000,
19306fa8e691SAlexander Motin bw + prevbw > maxbw ? " -- OVERFLOW!" : "");
19316fa8e691SAlexander Motin );
19326fa8e691SAlexander Motin if (bw + prevbw > maxbw)
19336fa8e691SAlexander Motin return (0);
19346fa8e691SAlexander Motin if (dir == 1)
19356fa8e691SAlexander Motin sc->sdo_bw_used += bw;
19366fa8e691SAlexander Motin else
19376fa8e691SAlexander Motin sc->codecs[cad].sdi_bw_used += bw;
19386fa8e691SAlexander Motin
19397c6b05d2SAlexander Motin /* Allocate stream number */
19407c6b05d2SAlexander Motin if (ss >= sc->num_iss + sc->num_oss)
19413228add8SAlexander Motin stream = 15 - (ss - sc->num_iss - sc->num_oss);
19427c6b05d2SAlexander Motin else if (ss >= sc->num_iss)
19437c6b05d2SAlexander Motin stream = ss - sc->num_iss + 1;
19447c6b05d2SAlexander Motin else
19457c6b05d2SAlexander Motin stream = ss + 1;
19467c6b05d2SAlexander Motin
19477c6b05d2SAlexander Motin sc->streams[ss].dev = child;
19487c6b05d2SAlexander Motin sc->streams[ss].dir = dir;
19497c6b05d2SAlexander Motin sc->streams[ss].stream = stream;
19506fa8e691SAlexander Motin sc->streams[ss].bw = bw;
19517c6b05d2SAlexander Motin sc->streams[ss].format = format;
19526fa8e691SAlexander Motin sc->streams[ss].stripe = stripe;
19537c6b05d2SAlexander Motin if (dmapos != NULL) {
19547c6b05d2SAlexander Motin if (sc->pos_dma.dma_vaddr != NULL)
19557c6b05d2SAlexander Motin *dmapos = (uint32_t *)(sc->pos_dma.dma_vaddr + ss * 8);
19567c6b05d2SAlexander Motin else
19577c6b05d2SAlexander Motin *dmapos = NULL;
19587c6b05d2SAlexander Motin }
19597c6b05d2SAlexander Motin return (stream);
19607c6b05d2SAlexander Motin }
19617c6b05d2SAlexander Motin
19627c6b05d2SAlexander Motin static void
hdac_stream_free(device_t dev,device_t child,int dir,int stream)19637c6b05d2SAlexander Motin hdac_stream_free(device_t dev, device_t child, int dir, int stream)
19647c6b05d2SAlexander Motin {
19657c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
19666fa8e691SAlexander Motin nid_t cad = (uintptr_t)device_get_ivars(child);
19677c6b05d2SAlexander Motin int ss;
19687c6b05d2SAlexander Motin
19697c6b05d2SAlexander Motin ss = hdac_find_stream(sc, dir, stream);
19707c6b05d2SAlexander Motin KASSERT(ss >= 0,
19717c6b05d2SAlexander Motin ("Free for not allocated stream (%d/%d)\n", dir, stream));
19726fa8e691SAlexander Motin if (dir == 1)
19736fa8e691SAlexander Motin sc->sdo_bw_used -= sc->streams[ss].bw;
19746fa8e691SAlexander Motin else
19756fa8e691SAlexander Motin sc->codecs[cad].sdi_bw_used -= sc->streams[ss].bw;
19767c6b05d2SAlexander Motin sc->streams[ss].stream = 0;
19777c6b05d2SAlexander Motin sc->streams[ss].dev = NULL;
19787c6b05d2SAlexander Motin }
19797c6b05d2SAlexander Motin
19807c6b05d2SAlexander Motin static int
hdac_stream_start(device_t dev,device_t child,int dir,int stream,bus_addr_t buf,int blksz,int blkcnt)1981944a6408SEd Maste hdac_stream_start(device_t dev, device_t child, int dir, int stream,
1982944a6408SEd Maste bus_addr_t buf, int blksz, int blkcnt)
19837c6b05d2SAlexander Motin {
19847c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
19857c6b05d2SAlexander Motin struct hdac_bdle *bdle;
19867c6b05d2SAlexander Motin uint64_t addr;
19877c6b05d2SAlexander Motin int i, ss, off;
19887c6b05d2SAlexander Motin uint32_t ctl;
19897c6b05d2SAlexander Motin
19907c6b05d2SAlexander Motin ss = hdac_find_stream(sc, dir, stream);
19917c6b05d2SAlexander Motin KASSERT(ss >= 0,
19927c6b05d2SAlexander Motin ("Start for not allocated stream (%d/%d)\n", dir, stream));
19937c6b05d2SAlexander Motin
19947c6b05d2SAlexander Motin addr = (uint64_t)buf;
19957c6b05d2SAlexander Motin bdle = (struct hdac_bdle *)sc->streams[ss].bdl.dma_vaddr;
19967c6b05d2SAlexander Motin for (i = 0; i < blkcnt; i++, bdle++) {
1997212de33eSJustin Hibbits bdle->addrl = htole32((uint32_t)addr);
1998212de33eSJustin Hibbits bdle->addrh = htole32((uint32_t)(addr >> 32));
1999212de33eSJustin Hibbits bdle->len = htole32(blksz);
2000212de33eSJustin Hibbits bdle->ioc = htole32(1);
20017c6b05d2SAlexander Motin addr += blksz;
20027c6b05d2SAlexander Motin }
20037c6b05d2SAlexander Motin
200480a79189SJustin Hibbits bus_dmamap_sync(sc->streams[ss].bdl.dma_tag,
200580a79189SJustin Hibbits sc->streams[ss].bdl.dma_map, BUS_DMASYNC_PREWRITE);
200680a79189SJustin Hibbits
20077c6b05d2SAlexander Motin off = ss << 5;
20087c6b05d2SAlexander Motin HDAC_WRITE_4(&sc->mem, off + HDAC_SDCBL, blksz * blkcnt);
20097c6b05d2SAlexander Motin HDAC_WRITE_2(&sc->mem, off + HDAC_SDLVI, blkcnt - 1);
20107c6b05d2SAlexander Motin addr = sc->streams[ss].bdl.dma_paddr;
20117c6b05d2SAlexander Motin HDAC_WRITE_4(&sc->mem, off + HDAC_SDBDPL, (uint32_t)addr);
20127c6b05d2SAlexander Motin HDAC_WRITE_4(&sc->mem, off + HDAC_SDBDPU, (uint32_t)(addr >> 32));
20137c6b05d2SAlexander Motin
20147c6b05d2SAlexander Motin ctl = HDAC_READ_1(&sc->mem, off + HDAC_SDCTL2);
20157c6b05d2SAlexander Motin if (dir)
20167c6b05d2SAlexander Motin ctl |= HDAC_SDCTL2_DIR;
20177c6b05d2SAlexander Motin else
20187c6b05d2SAlexander Motin ctl &= ~HDAC_SDCTL2_DIR;
20197c6b05d2SAlexander Motin ctl &= ~HDAC_SDCTL2_STRM_MASK;
20207c6b05d2SAlexander Motin ctl |= stream << HDAC_SDCTL2_STRM_SHIFT;
20216fa8e691SAlexander Motin ctl &= ~HDAC_SDCTL2_STRIPE_MASK;
20226fa8e691SAlexander Motin ctl |= sc->streams[ss].stripe << HDAC_SDCTL2_STRIPE_SHIFT;
20237c6b05d2SAlexander Motin HDAC_WRITE_1(&sc->mem, off + HDAC_SDCTL2, ctl);
20247c6b05d2SAlexander Motin
20257c6b05d2SAlexander Motin HDAC_WRITE_2(&sc->mem, off + HDAC_SDFMT, sc->streams[ss].format);
20267c6b05d2SAlexander Motin
20277c6b05d2SAlexander Motin ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
20287c6b05d2SAlexander Motin ctl |= 1 << ss;
20297c6b05d2SAlexander Motin HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
20307c6b05d2SAlexander Motin
2031c6c4eaa8SAlexander Motin HDAC_WRITE_1(&sc->mem, off + HDAC_SDSTS,
2032c6c4eaa8SAlexander Motin HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS);
20337c6b05d2SAlexander Motin ctl = HDAC_READ_1(&sc->mem, off + HDAC_SDCTL0);
20347c6b05d2SAlexander Motin ctl |= HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
20357c6b05d2SAlexander Motin HDAC_SDCTL_RUN;
20367c6b05d2SAlexander Motin HDAC_WRITE_1(&sc->mem, off + HDAC_SDCTL0, ctl);
20377c6b05d2SAlexander Motin
20387c6b05d2SAlexander Motin sc->streams[ss].blksz = blksz;
20397c6b05d2SAlexander Motin sc->streams[ss].running = 1;
20407c6b05d2SAlexander Motin hdac_poll_reinit(sc);
20417c6b05d2SAlexander Motin return (0);
20427c6b05d2SAlexander Motin }
20437c6b05d2SAlexander Motin
20447c6b05d2SAlexander Motin static void
hdac_stream_stop(device_t dev,device_t child,int dir,int stream)20457c6b05d2SAlexander Motin hdac_stream_stop(device_t dev, device_t child, int dir, int stream)
20467c6b05d2SAlexander Motin {
20477c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
20487c6b05d2SAlexander Motin int ss, off;
20497c6b05d2SAlexander Motin uint32_t ctl;
20507c6b05d2SAlexander Motin
20517c6b05d2SAlexander Motin ss = hdac_find_stream(sc, dir, stream);
20527c6b05d2SAlexander Motin KASSERT(ss >= 0,
20537c6b05d2SAlexander Motin ("Stop for not allocated stream (%d/%d)\n", dir, stream));
20547c6b05d2SAlexander Motin
205580a79189SJustin Hibbits bus_dmamap_sync(sc->streams[ss].bdl.dma_tag,
205680a79189SJustin Hibbits sc->streams[ss].bdl.dma_map, BUS_DMASYNC_POSTWRITE);
205780a79189SJustin Hibbits
20587c6b05d2SAlexander Motin off = ss << 5;
20597c6b05d2SAlexander Motin ctl = HDAC_READ_1(&sc->mem, off + HDAC_SDCTL0);
20607c6b05d2SAlexander Motin ctl &= ~(HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
20617c6b05d2SAlexander Motin HDAC_SDCTL_RUN);
20627c6b05d2SAlexander Motin HDAC_WRITE_1(&sc->mem, off + HDAC_SDCTL0, ctl);
20637c6b05d2SAlexander Motin
20647c6b05d2SAlexander Motin ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
20657c6b05d2SAlexander Motin ctl &= ~(1 << ss);
20667c6b05d2SAlexander Motin HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
20677c6b05d2SAlexander Motin
20687c6b05d2SAlexander Motin sc->streams[ss].running = 0;
20697c6b05d2SAlexander Motin hdac_poll_reinit(sc);
20707c6b05d2SAlexander Motin }
20717c6b05d2SAlexander Motin
20727c6b05d2SAlexander Motin static void
hdac_stream_reset(device_t dev,device_t child,int dir,int stream)20737c6b05d2SAlexander Motin hdac_stream_reset(device_t dev, device_t child, int dir, int stream)
20747c6b05d2SAlexander Motin {
20757c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
20767c6b05d2SAlexander Motin int timeout = 1000;
20777c6b05d2SAlexander Motin int to = timeout;
20787c6b05d2SAlexander Motin int ss, off;
20797c6b05d2SAlexander Motin uint32_t ctl;
20807c6b05d2SAlexander Motin
20817c6b05d2SAlexander Motin ss = hdac_find_stream(sc, dir, stream);
20827c6b05d2SAlexander Motin KASSERT(ss >= 0,
20837c6b05d2SAlexander Motin ("Reset for not allocated stream (%d/%d)\n", dir, stream));
20847c6b05d2SAlexander Motin
20857c6b05d2SAlexander Motin off = ss << 5;
20867c6b05d2SAlexander Motin ctl = HDAC_READ_1(&sc->mem, off + HDAC_SDCTL0);
20877c6b05d2SAlexander Motin ctl |= HDAC_SDCTL_SRST;
20887c6b05d2SAlexander Motin HDAC_WRITE_1(&sc->mem, off + HDAC_SDCTL0, ctl);
20897c6b05d2SAlexander Motin do {
20907c6b05d2SAlexander Motin ctl = HDAC_READ_1(&sc->mem, off + HDAC_SDCTL0);
20917c6b05d2SAlexander Motin if (ctl & HDAC_SDCTL_SRST)
20927c6b05d2SAlexander Motin break;
20937c6b05d2SAlexander Motin DELAY(10);
20947c6b05d2SAlexander Motin } while (--to);
20957c6b05d2SAlexander Motin if (!(ctl & HDAC_SDCTL_SRST))
20967c6b05d2SAlexander Motin device_printf(dev, "Reset setting timeout\n");
20977c6b05d2SAlexander Motin ctl &= ~HDAC_SDCTL_SRST;
20987c6b05d2SAlexander Motin HDAC_WRITE_1(&sc->mem, off + HDAC_SDCTL0, ctl);
20997c6b05d2SAlexander Motin to = timeout;
21007c6b05d2SAlexander Motin do {
21017c6b05d2SAlexander Motin ctl = HDAC_READ_1(&sc->mem, off + HDAC_SDCTL0);
21027c6b05d2SAlexander Motin if (!(ctl & HDAC_SDCTL_SRST))
21037c6b05d2SAlexander Motin break;
21047c6b05d2SAlexander Motin DELAY(10);
21057c6b05d2SAlexander Motin } while (--to);
21067c6b05d2SAlexander Motin if (ctl & HDAC_SDCTL_SRST)
21077c6b05d2SAlexander Motin device_printf(dev, "Reset timeout!\n");
21087c6b05d2SAlexander Motin }
21097c6b05d2SAlexander Motin
21107c6b05d2SAlexander Motin static uint32_t
hdac_stream_getptr(device_t dev,device_t child,int dir,int stream)21117c6b05d2SAlexander Motin hdac_stream_getptr(device_t dev, device_t child, int dir, int stream)
21127c6b05d2SAlexander Motin {
21137c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
21147c6b05d2SAlexander Motin int ss, off;
21157c6b05d2SAlexander Motin
21167c6b05d2SAlexander Motin ss = hdac_find_stream(sc, dir, stream);
21177c6b05d2SAlexander Motin KASSERT(ss >= 0,
21187c6b05d2SAlexander Motin ("Reset for not allocated stream (%d/%d)\n", dir, stream));
21197c6b05d2SAlexander Motin
21207c6b05d2SAlexander Motin off = ss << 5;
21217c6b05d2SAlexander Motin return (HDAC_READ_4(&sc->mem, off + HDAC_SDLPIB));
21227c6b05d2SAlexander Motin }
21237c6b05d2SAlexander Motin
21247c6b05d2SAlexander Motin static int
hdac_unsol_alloc(device_t dev,device_t child,int tag)21257c6b05d2SAlexander Motin hdac_unsol_alloc(device_t dev, device_t child, int tag)
21267c6b05d2SAlexander Motin {
21277c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
21287c6b05d2SAlexander Motin
21297c6b05d2SAlexander Motin sc->unsol_registered++;
21307c6b05d2SAlexander Motin hdac_poll_reinit(sc);
21317c6b05d2SAlexander Motin return (tag);
21327c6b05d2SAlexander Motin }
21337c6b05d2SAlexander Motin
21347c6b05d2SAlexander Motin static void
hdac_unsol_free(device_t dev,device_t child,int tag)21357c6b05d2SAlexander Motin hdac_unsol_free(device_t dev, device_t child, int tag)
21367c6b05d2SAlexander Motin {
21377c6b05d2SAlexander Motin struct hdac_softc *sc = device_get_softc(dev);
21387c6b05d2SAlexander Motin
21397c6b05d2SAlexander Motin sc->unsol_registered--;
21407c6b05d2SAlexander Motin hdac_poll_reinit(sc);
21417c6b05d2SAlexander Motin }
21427c6b05d2SAlexander Motin
21431f0387f7SAriff Abdullah static device_method_t hdac_methods[] = {
21441f0387f7SAriff Abdullah /* device interface */
21451f0387f7SAriff Abdullah DEVMETHOD(device_probe, hdac_probe),
21461f0387f7SAriff Abdullah DEVMETHOD(device_attach, hdac_attach),
21471f0387f7SAriff Abdullah DEVMETHOD(device_detach, hdac_detach),
2148859159d1SAlexander Motin DEVMETHOD(device_suspend, hdac_suspend),
2149859159d1SAlexander Motin DEVMETHOD(device_resume, hdac_resume),
21505ce33ccfSAlexander Motin /* Bus interface */
21517c6b05d2SAlexander Motin DEVMETHOD(bus_get_dma_tag, hdac_get_dma_tag),
21525ce33ccfSAlexander Motin DEVMETHOD(bus_print_child, hdac_print_child),
2153ddfc9c4cSWarner Losh DEVMETHOD(bus_child_location, hdac_child_location),
2154ddfc9c4cSWarner Losh DEVMETHOD(bus_child_pnpinfo, hdac_child_pnpinfo_method),
21557c6b05d2SAlexander Motin DEVMETHOD(bus_read_ivar, hdac_read_ivar),
21567c6b05d2SAlexander Motin DEVMETHOD(hdac_get_mtx, hdac_get_mtx),
21577c6b05d2SAlexander Motin DEVMETHOD(hdac_codec_command, hdac_codec_command),
21587c6b05d2SAlexander Motin DEVMETHOD(hdac_stream_alloc, hdac_stream_alloc),
21597c6b05d2SAlexander Motin DEVMETHOD(hdac_stream_free, hdac_stream_free),
21607c6b05d2SAlexander Motin DEVMETHOD(hdac_stream_start, hdac_stream_start),
21617c6b05d2SAlexander Motin DEVMETHOD(hdac_stream_stop, hdac_stream_stop),
21627c6b05d2SAlexander Motin DEVMETHOD(hdac_stream_reset, hdac_stream_reset),
21637c6b05d2SAlexander Motin DEVMETHOD(hdac_stream_getptr, hdac_stream_getptr),
21647c6b05d2SAlexander Motin DEVMETHOD(hdac_unsol_alloc, hdac_unsol_alloc),
21657c6b05d2SAlexander Motin DEVMETHOD(hdac_unsol_free, hdac_unsol_free),
2166abe917adSMarius Strobl DEVMETHOD_END
21671f0387f7SAriff Abdullah };
21681f0387f7SAriff Abdullah
21691f0387f7SAriff Abdullah static driver_t hdac_driver = {
2170859159d1SAlexander Motin "hdac",
21711f0387f7SAriff Abdullah hdac_methods,
2172859159d1SAlexander Motin sizeof(struct hdac_softc),
2173859159d1SAlexander Motin };
2174859159d1SAlexander Motin
21753390adfeSJohn Baldwin DRIVER_MODULE(snd_hda, pci, hdac_driver, NULL, NULL);
2176