1 /* $NetBSD: hdaudio_pci.c,v 1.12 2022/03/21 09:12:09 jmcneill 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.12 2022/03/21 09:12:09 jmcneill 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 55 struct 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 69 static int hdaudio_pci_match(device_t, cfdata_t, void *); 70 static void hdaudio_pci_attach(device_t, device_t, void *); 71 static int hdaudio_pci_detach(device_t, int); 72 static int hdaudio_pci_rescan(device_t, const char *, const int *); 73 static void hdaudio_pci_childdet(device_t, device_t); 74 75 static int hdaudio_pci_intr(void *); 76 static void hdaudio_pci_init(struct hdaudio_pci_softc *); 77 78 /* power management */ 79 static bool hdaudio_pci_resume(device_t, const pmf_qual_t *); 80 81 CFATTACH_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. */ 93 static 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_JSL_CAVS) }, 99 100 PCI_COMPAT_EOL 101 }; 102 103 /* 104 * NetBSD autoconfiguration 105 */ 106 107 static int 108 hdaudio_pci_match(device_t parent, cfdata_t match, void *opaque) 109 { 110 struct pci_attach_args *pa = opaque; 111 112 if ((PCI_CLASS(pa->pa_class) == PCI_CLASS_MULTIMEDIA) && 113 (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MULTIMEDIA_HDAUDIO)) 114 return 10; 115 if (pci_compatible_match(pa, compat_data) != 0) 116 return 10; 117 118 return 0; 119 } 120 121 static void 122 hdaudio_pci_attach(device_t parent, device_t self, void *opaque) 123 { 124 struct hdaudio_pci_softc *sc = device_private(self); 125 struct pci_attach_args *pa = opaque; 126 const char *intrstr; 127 pcireg_t csr, maptype; 128 int err, reg; 129 char intrbuf[PCI_INTRSTR_LEN]; 130 131 aprint_naive("\n"); 132 aprint_normal(": HD Audio Controller\n"); 133 134 sc->sc_pc = pa->pa_pc; 135 sc->sc_tag = pa->pa_tag; 136 sc->sc_id = pa->pa_id; 137 138 sc->sc_hdaudio.sc_subsystem = pci_conf_read(sc->sc_pc, sc->sc_tag, 139 PCI_SUBSYS_ID_REG); 140 141 /* Enable busmastering and MMIO access */ 142 csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG); 143 csr |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_BACKTOBACK_ENABLE; 144 pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, csr); 145 146 /* Map MMIO registers */ 147 reg = PCI_BAR0; 148 maptype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, reg); 149 err = pci_mapreg_map(pa, reg, maptype, 0, 150 &sc->sc_hdaudio.sc_memt, 151 &sc->sc_hdaudio.sc_memh, 152 &sc->sc_hdaudio.sc_membase, 153 &sc->sc_hdaudio.sc_memsize); 154 if (err) { 155 aprint_error_dev(self, "couldn't map mmio space\n"); 156 return; 157 } 158 sc->sc_hdaudio.sc_memvalid = true; 159 if (pci_dma64_available(pa)) 160 sc->sc_hdaudio.sc_dmat = pa->pa_dmat64; 161 else 162 sc->sc_hdaudio.sc_dmat = pa->pa_dmat; 163 164 /* Map interrupt and establish handler */ 165 if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0)) { 166 aprint_error_dev(self, "couldn't map interrupt\n"); 167 return; 168 } 169 intrstr = pci_intr_string(pa->pa_pc, sc->sc_pihp[0], intrbuf, 170 sizeof(intrbuf)); 171 sc->sc_ih = pci_intr_establish_xname(pa->pa_pc, sc->sc_pihp[0], 172 IPL_AUDIO, hdaudio_pci_intr, sc, device_xname(self)); 173 if (sc->sc_ih == NULL) { 174 aprint_error_dev(self, "couldn't establish interrupt"); 175 if (intrstr) 176 aprint_error(" at %s", intrstr); 177 aprint_error("\n"); 178 return; 179 } 180 aprint_normal_dev(self, "interrupting at %s\n", intrstr); 181 182 hdaudio_pci_init(sc); 183 184 /* Attach bus-independent HD audio layer */ 185 if (hdaudio_attach(self, &sc->sc_hdaudio)) { 186 pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 187 pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); 188 sc->sc_ih = NULL; 189 bus_space_unmap(sc->sc_hdaudio.sc_memt, 190 sc->sc_hdaudio.sc_memh, 191 sc->sc_hdaudio.sc_memsize); 192 sc->sc_hdaudio.sc_memvalid = false; 193 csr = pci_conf_read(sc->sc_pc, sc->sc_tag, 194 PCI_COMMAND_STATUS_REG); 195 csr &= ~(PCI_COMMAND_MASTER_ENABLE | 196 PCI_COMMAND_BACKTOBACK_ENABLE); 197 pci_conf_write(sc->sc_pc, sc->sc_tag, 198 PCI_COMMAND_STATUS_REG, csr); 199 200 if (!pmf_device_register(self, NULL, NULL)) { 201 aprint_error_dev(self, 202 "couldn't establish power handler\n"); 203 } 204 } else if (!pmf_device_register(self, NULL, hdaudio_pci_resume)) { 205 aprint_error_dev(self, "couldn't establish power handler\n"); 206 } 207 } 208 209 static int 210 hdaudio_pci_rescan(device_t self, const char *ifattr, const int *locs) 211 { 212 struct hdaudio_pci_softc *sc = device_private(self); 213 214 return hdaudio_rescan(&sc->sc_hdaudio, ifattr, locs); 215 } 216 217 void 218 hdaudio_pci_childdet(device_t self, device_t child) 219 { 220 struct hdaudio_pci_softc *sc = device_private(self); 221 222 hdaudio_childdet(&sc->sc_hdaudio, child); 223 } 224 225 static int 226 hdaudio_pci_detach(device_t self, int flags) 227 { 228 struct hdaudio_pci_softc *sc = device_private(self); 229 pcireg_t csr; 230 231 hdaudio_detach(&sc->sc_hdaudio, flags); 232 233 if (sc->sc_ih != NULL) { 234 pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 235 pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); 236 sc->sc_ih = NULL; 237 } 238 if (sc->sc_hdaudio.sc_memvalid == true) { 239 bus_space_unmap(sc->sc_hdaudio.sc_memt, 240 sc->sc_hdaudio.sc_memh, 241 sc->sc_hdaudio.sc_memsize); 242 sc->sc_hdaudio.sc_memvalid = false; 243 } 244 245 /* Disable busmastering and MMIO access */ 246 csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG); 247 csr &= ~(PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_BACKTOBACK_ENABLE); 248 pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, csr); 249 250 pmf_device_deregister(self); 251 252 return 0; 253 } 254 255 static int 256 hdaudio_pci_intr(void *opaque) 257 { 258 struct hdaudio_pci_softc *sc = opaque; 259 260 return hdaudio_intr(&sc->sc_hdaudio); 261 } 262 263 static void 264 hdaudio_pci_init(struct hdaudio_pci_softc *sc) 265 { 266 pcireg_t val; 267 268 if (HDAUDIO_PCI_IS_INTEL(sc)) { 269 /* 270 * ICH: Set traffic class for input/output/buf descriptors 271 * to TC0. For PCH without a TCSEL register, PGCTL is in 272 * the same location and clearing these bits is harmless. 273 */ 274 val = pci_conf_read(sc->sc_pc, sc->sc_tag, 275 HDAUDIO_INTEL_REG_ICH_TCSEL); 276 val &= ~HDAUDIO_INTEL_ICH_TCSEL_MASK; 277 val |= HDAUDIO_INTEL_ICH_TCSEL_TC0; 278 pci_conf_write(sc->sc_pc, sc->sc_tag, 279 HDAUDIO_INTEL_REG_ICH_TCSEL, val); 280 281 /* 282 * PCH: Disable dynamic clock gating logic. Implementations 283 * without a CGCTL register do not appear to have anything 284 * else in its place. 285 */ 286 val = pci_conf_read(sc->sc_pc, sc->sc_tag, 287 HDAUDIO_INTEL_REG_PCH_CGCTL); 288 val &= ~HDAUDIO_INTEL_PCH_CGCTL_MISCBDCGE; 289 pci_conf_write(sc->sc_pc, sc->sc_tag, 290 HDAUDIO_INTEL_REG_PCH_CGCTL, val); 291 292 /* ICH/PCH: Enable snooping. */ 293 val = pci_conf_read(sc->sc_pc, sc->sc_tag, 294 HDAUDIO_INTEL_REG_PCH_DEVC); 295 val &= ~HDAUDIO_INTEL_PCH_DEVC_NSNPEN; 296 pci_conf_write(sc->sc_pc, sc->sc_tag, 297 HDAUDIO_INTEL_REG_PCH_DEVC, val); 298 } 299 300 if (HDAUDIO_PCI_IS_NVIDIA(sc)) { 301 /* Enable snooping. */ 302 val = pci_conf_read(sc->sc_pc, sc->sc_tag, 303 HDAUDIO_NV_REG_SNOOP); 304 val &= ~HDAUDIO_NV_SNOOP_MASK; 305 val |= HDAUDIO_NV_SNOOP_ENABLE; 306 pci_conf_write(sc->sc_pc, sc->sc_tag, 307 HDAUDIO_NV_REG_SNOOP, val); 308 } 309 } 310 311 static bool 312 hdaudio_pci_resume(device_t self, const pmf_qual_t *qual) 313 { 314 struct hdaudio_pci_softc *sc = device_private(self); 315 316 hdaudio_pci_init(sc); 317 318 return hdaudio_resume(&sc->sc_hdaudio); 319 } 320 321 MODULE(MODULE_CLASS_DRIVER, hdaudio_pci, "pci,hdaudio,audio"); 322 323 #ifdef _MODULE 324 /* 325 * XXX Don't allow ioconf.c to redefine the "struct cfdriver hdaudio_cd" 326 * XXX it will be defined in the common hdaudio module 327 */ 328 329 #undef CFDRIVER_DECL 330 #define CFDRIVER_DECL(name, class, attr) /* nothing */ 331 #include "ioconf.c" 332 #endif 333 334 static int 335 hdaudio_pci_modcmd(modcmd_t cmd, void *opaque) 336 { 337 #ifdef _MODULE 338 /* 339 * We ignore the cfdriver_vec[] that ioconf provides, since 340 * the cfdrivers are attached already. 341 */ 342 static struct cfdriver * const no_cfdriver_vec[] = { NULL }; 343 #endif 344 int error = 0; 345 346 switch (cmd) { 347 case MODULE_CMD_INIT: 348 #ifdef _MODULE 349 error = config_init_component(no_cfdriver_vec, 350 cfattach_ioconf_hdaudio_pci, cfdata_ioconf_hdaudio_pci); 351 #endif 352 return error; 353 case MODULE_CMD_FINI: 354 #ifdef _MODULE 355 error = config_fini_component(no_cfdriver_vec, 356 cfattach_ioconf_hdaudio_pci, cfdata_ioconf_hdaudio_pci); 357 #endif 358 return error; 359 default: 360 return ENOTTY; 361 } 362 } 363