xref: /freebsd/sys/dev/sound/pci/hda/hdac.c (revision 11a9117871e6037ae7b8011b243939322efce569)
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