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