1/* $NetBSD: hdaudio_pci.c,v 1.13 2022/09/13 11:47:54 msaitoh Exp $ */ 2 3/* 4 * Copyright (c) 2009 Precedence Technologies Ltd <support@precedence.co.uk> 5 * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca> 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Precedence Technologies Ltd 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32/* 33 * Intel High Definition Audio (Revision 1.0a) device driver. 34 */ 35 36#include <sys/cdefs.h> 37__KERNEL_RCSID(0, "$NetBSD: hdaudio_pci.c,v 1.13 2022/09/13 11:47:54 msaitoh Exp $"); 38 39#include <sys/types.h> 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/device.h> 43#include <sys/conf.h> 44#include <sys/bus.h> 45#include <sys/intr.h> 46#include <sys/module.h> 47 48#include <dev/pci/pcidevs.h> 49#include <dev/pci/pcivar.h> 50 51#include <dev/hdaudio/hdaudioreg.h> 52#include <dev/hdaudio/hdaudiovar.h> 53#include <dev/pci/hdaudio_pci.h> 54 55struct hdaudio_pci_softc { 56 struct hdaudio_softc sc_hdaudio; /* must be first */ 57 pcitag_t sc_tag; 58 pci_chipset_tag_t sc_pc; 59 void *sc_ih; 60 pcireg_t sc_id; 61 pci_intr_handle_t *sc_pihp; 62}; 63 64#define HDAUDIO_PCI_IS_INTEL(sc) \ 65 (PCI_VENDOR(sc->sc_id) == PCI_VENDOR_INTEL) 66#define HDAUDIO_PCI_IS_NVIDIA(sc) \ 67 (PCI_VENDOR(sc->sc_id) == PCI_VENDOR_NVIDIA) 68 69static int hdaudio_pci_match(device_t, cfdata_t, void *); 70static void hdaudio_pci_attach(device_t, device_t, void *); 71static int hdaudio_pci_detach(device_t, int); 72static int hdaudio_pci_rescan(device_t, const char *, const int *); 73static void hdaudio_pci_childdet(device_t, device_t); 74 75static int hdaudio_pci_intr(void *); 76static void hdaudio_pci_init(struct hdaudio_pci_softc *); 77 78/* power management */ 79static bool hdaudio_pci_resume(device_t, const pmf_qual_t *); 80 81CFATTACH_DECL2_NEW( 82 hdaudio_pci, 83 sizeof(struct hdaudio_pci_softc), 84 hdaudio_pci_match, 85 hdaudio_pci_attach, 86 hdaudio_pci_detach, 87 NULL, 88 hdaudio_pci_rescan, 89 hdaudio_pci_childdet 90); 91 92/* Some devices' sublcass is not PCI_SUBCLASS_MULTIMEDIA_HDAUDIO. */ 93static const struct device_compatible_entry compat_data[] = { 94 { .id = PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_2HS_U_HDA) }, 95 { .id = PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_3HS_U_HDA) }, 96 { .id = PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_4HS_H_CAVS) }, 97 { .id = PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_5HS_LP_HDA) }, 98 { .id = PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6HS_LP_HDA) }, 99 { .id = PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_JSL_CAVS) }, 100 101 PCI_COMPAT_EOL 102}; 103 104/* 105 * NetBSD autoconfiguration 106 */ 107 108static int 109hdaudio_pci_match(device_t parent, cfdata_t match, void *opaque) 110{ 111 struct pci_attach_args *pa = opaque; 112 113 if ((PCI_CLASS(pa->pa_class) == PCI_CLASS_MULTIMEDIA) && 114 (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MULTIMEDIA_HDAUDIO)) 115 return 10; 116 if (pci_compatible_match(pa, compat_data) != 0) 117 return 10; 118 119 return 0; 120} 121 122static void 123hdaudio_pci_attach(device_t parent, device_t self, void *opaque) 124{ 125 struct hdaudio_pci_softc *sc = device_private(self); 126 struct pci_attach_args *pa = opaque; 127 const char *intrstr; 128 pcireg_t csr, maptype; 129 int err, reg; 130 char intrbuf[PCI_INTRSTR_LEN]; 131 132 aprint_naive("\n"); 133 aprint_normal(": HD Audio Controller\n"); 134 135 sc->sc_pc = pa->pa_pc; 136 sc->sc_tag = pa->pa_tag; 137 sc->sc_id = pa->pa_id; 138 139 sc->sc_hdaudio.sc_subsystem = pci_conf_read(sc->sc_pc, sc->sc_tag, 140 PCI_SUBSYS_ID_REG); 141 142 /* Enable busmastering and MMIO access */ 143 csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG); 144 csr |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_BACKTOBACK_ENABLE; 145 pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, csr); 146 147 /* Map MMIO registers */ 148 reg = PCI_BAR0; 149 maptype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, reg); 150 err = pci_mapreg_map(pa, reg, maptype, 0, 151 &sc->sc_hdaudio.sc_memt, 152 &sc->sc_hdaudio.sc_memh, 153 &sc->sc_hdaudio.sc_membase, 154 &sc->sc_hdaudio.sc_memsize); 155 if (err) { 156 aprint_error_dev(self, "couldn't map mmio space\n"); 157 return; 158 } 159 sc->sc_hdaudio.sc_memvalid = true; 160 if (pci_dma64_available(pa)) 161 sc->sc_hdaudio.sc_dmat = pa->pa_dmat64; 162 else 163 sc->sc_hdaudio.sc_dmat = pa->pa_dmat; 164 165 /* Map interrupt and establish handler */ 166 if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0)) { 167 aprint_error_dev(self, "couldn't map interrupt\n"); 168 return; 169 } 170 intrstr = pci_intr_string(pa->pa_pc, sc->sc_pihp[0], intrbuf, 171 sizeof(intrbuf)); 172 sc->sc_ih = pci_intr_establish_xname(pa->pa_pc, sc->sc_pihp[0], 173 IPL_AUDIO, hdaudio_pci_intr, sc, device_xname(self)); 174 if (sc->sc_ih == NULL) { 175 aprint_error_dev(self, "couldn't establish interrupt"); 176 if (intrstr) 177 aprint_error(" at %s", intrstr); 178 aprint_error("\n"); 179 return; 180 } 181 aprint_normal_dev(self, "interrupting at %s\n", intrstr); 182 183 hdaudio_pci_init(sc); 184 185 /* Attach bus-independent HD audio layer */ 186 if (hdaudio_attach(self, &sc->sc_hdaudio)) { 187 pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 188 pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); 189 sc->sc_ih = NULL; 190 bus_space_unmap(sc->sc_hdaudio.sc_memt, 191 sc->sc_hdaudio.sc_memh, 192 sc->sc_hdaudio.sc_memsize); 193 sc->sc_hdaudio.sc_memvalid = false; 194 csr = pci_conf_read(sc->sc_pc, sc->sc_tag, 195 PCI_COMMAND_STATUS_REG); 196 csr &= ~(PCI_COMMAND_MASTER_ENABLE | 197 PCI_COMMAND_BACKTOBACK_ENABLE); 198 pci_conf_write(sc->sc_pc, sc->sc_tag, 199 PCI_COMMAND_STATUS_REG, csr); 200 201 if (!pmf_device_register(self, NULL, NULL)) { 202 aprint_error_dev(self, 203 "couldn't establish power handler\n"); 204 } 205 } else if (!pmf_device_register(self, NULL, hdaudio_pci_resume)) { 206 aprint_error_dev(self, "couldn't establish power handler\n"); 207 } 208} 209 210static int 211hdaudio_pci_rescan(device_t self, const char *ifattr, const int *locs) 212{ 213 struct hdaudio_pci_softc *sc = device_private(self); 214 215 return hdaudio_rescan(&sc->sc_hdaudio, ifattr, locs); 216} 217 218void 219hdaudio_pci_childdet(device_t self, device_t child) 220{ 221 struct hdaudio_pci_softc *sc = device_private(self); 222 223 hdaudio_childdet(&sc->sc_hdaudio, child); 224} 225 226static int 227hdaudio_pci_detach(device_t self, int flags) 228{ 229 struct hdaudio_pci_softc *sc = device_private(self); 230 pcireg_t csr; 231 232 hdaudio_detach(&sc->sc_hdaudio, flags); 233 234 if (sc->sc_ih != NULL) { 235 pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 236 pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); 237 sc->sc_ih = NULL; 238 } 239 if (sc->sc_hdaudio.sc_memvalid == true) { 240 bus_space_unmap(sc->sc_hdaudio.sc_memt, 241 sc->sc_hdaudio.sc_memh, 242 sc->sc_hdaudio.sc_memsize); 243 sc->sc_hdaudio.sc_memvalid = false; 244 } 245 246 /* Disable busmastering and MMIO access */ 247 csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG); 248 csr &= ~(PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_BACKTOBACK_ENABLE); 249 pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, csr); 250 251 pmf_device_deregister(self); 252 253 return 0; 254} 255 256static int 257hdaudio_pci_intr(void *opaque) 258{ 259 struct hdaudio_pci_softc *sc = opaque; 260 261 return hdaudio_intr(&sc->sc_hdaudio); 262} 263 264static void 265hdaudio_pci_init(struct hdaudio_pci_softc *sc) 266{ 267 pcireg_t val; 268 269 if (HDAUDIO_PCI_IS_INTEL(sc)) { 270 /* 271 * ICH: Set traffic class for input/output/buf descriptors 272 * to TC0. For PCH without a TCSEL register, PGCTL is in 273 * the same location and clearing these bits is harmless. 274 */ 275 val = pci_conf_read(sc->sc_pc, sc->sc_tag, 276 HDAUDIO_INTEL_REG_ICH_TCSEL); 277 val &= ~HDAUDIO_INTEL_ICH_TCSEL_MASK; 278 val |= HDAUDIO_INTEL_ICH_TCSEL_TC0; 279 pci_conf_write(sc->sc_pc, sc->sc_tag, 280 HDAUDIO_INTEL_REG_ICH_TCSEL, val); 281 282 /* 283 * PCH: Disable dynamic clock gating logic. Implementations 284 * without a CGCTL register do not appear to have anything 285 * else in its place. 286 */ 287 val = pci_conf_read(sc->sc_pc, sc->sc_tag, 288 HDAUDIO_INTEL_REG_PCH_CGCTL); 289 val &= ~HDAUDIO_INTEL_PCH_CGCTL_MISCBDCGE; 290 pci_conf_write(sc->sc_pc, sc->sc_tag, 291 HDAUDIO_INTEL_REG_PCH_CGCTL, val); 292 293 /* ICH/PCH: Enable snooping. */ 294 val = pci_conf_read(sc->sc_pc, sc->sc_tag, 295 HDAUDIO_INTEL_REG_PCH_DEVC); 296 val &= ~HDAUDIO_INTEL_PCH_DEVC_NSNPEN; 297 pci_conf_write(sc->sc_pc, sc->sc_tag, 298 HDAUDIO_INTEL_REG_PCH_DEVC, val); 299 } 300 301 if (HDAUDIO_PCI_IS_NVIDIA(sc)) { 302 /* Enable snooping. */ 303 val = pci_conf_read(sc->sc_pc, sc->sc_tag, 304 HDAUDIO_NV_REG_SNOOP); 305 val &= ~HDAUDIO_NV_SNOOP_MASK; 306 val |= HDAUDIO_NV_SNOOP_ENABLE; 307 pci_conf_write(sc->sc_pc, sc->sc_tag, 308 HDAUDIO_NV_REG_SNOOP, val); 309 } 310} 311 312static bool 313hdaudio_pci_resume(device_t self, const pmf_qual_t *qual) 314{ 315 struct hdaudio_pci_softc *sc = device_private(self); 316 317 hdaudio_pci_init(sc); 318 319 return hdaudio_resume(&sc->sc_hdaudio); 320} 321 322MODULE(MODULE_CLASS_DRIVER, hdaudio_pci, "pci,hdaudio,audio"); 323 324#ifdef _MODULE 325/* 326 * XXX Don't allow ioconf.c to redefine the "struct cfdriver hdaudio_cd" 327 * XXX it will be defined in the common hdaudio module 328 */ 329 330#undef CFDRIVER_DECL 331#define CFDRIVER_DECL(name, class, attr) /* nothing */ 332#include "ioconf.c" 333#endif 334 335static int 336hdaudio_pci_modcmd(modcmd_t cmd, void *opaque) 337{ 338#ifdef _MODULE 339 /* 340 * We ignore the cfdriver_vec[] that ioconf provides, since 341 * the cfdrivers are attached already. 342 */ 343 static struct cfdriver * const no_cfdriver_vec[] = { NULL }; 344#endif 345 int error = 0; 346 347 switch (cmd) { 348 case MODULE_CMD_INIT: 349#ifdef _MODULE 350 error = config_init_component(no_cfdriver_vec, 351 cfattach_ioconf_hdaudio_pci, cfdata_ioconf_hdaudio_pci); 352#endif 353 return error; 354 case MODULE_CMD_FINI: 355#ifdef _MODULE 356 error = config_fini_component(no_cfdriver_vec, 357 cfattach_ioconf_hdaudio_pci, cfdata_ioconf_hdaudio_pci); 358#endif 359 return error; 360 default: 361 return ENOTTY; 362 } 363} 364