1 /* $NetBSD: hdaudio_pci.c,v 1.5 2016/12/16 11:34:52 nonaka 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.5 2016/12/16 11:34:52 nonaka 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 static int hdaudio_pci_match(device_t, cfdata_t, void *); 65 static void hdaudio_pci_attach(device_t, device_t, void *); 66 static int hdaudio_pci_detach(device_t, int); 67 static int hdaudio_pci_rescan(device_t, const char *, const int *); 68 static void hdaudio_pci_childdet(device_t, device_t); 69 70 static int hdaudio_pci_intr(void *); 71 static void hdaudio_pci_reinit(struct hdaudio_pci_softc *); 72 73 /* power management */ 74 static bool hdaudio_pci_resume(device_t, const pmf_qual_t *); 75 76 CFATTACH_DECL2_NEW( 77 hdaudio_pci, 78 sizeof(struct hdaudio_pci_softc), 79 hdaudio_pci_match, 80 hdaudio_pci_attach, 81 hdaudio_pci_detach, 82 NULL, 83 hdaudio_pci_rescan, 84 hdaudio_pci_childdet 85 ); 86 87 /* 88 * NetBSD autoconfiguration 89 */ 90 91 static int 92 hdaudio_pci_match(device_t parent, cfdata_t match, void *opaque) 93 { 94 struct pci_attach_args *pa = opaque; 95 96 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_MULTIMEDIA) 97 return 0; 98 if (PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_MULTIMEDIA_HDAUDIO) 99 return 0; 100 101 return 10; 102 } 103 104 static void 105 hdaudio_pci_attach(device_t parent, device_t self, void *opaque) 106 { 107 struct hdaudio_pci_softc *sc = device_private(self); 108 struct pci_attach_args *pa = opaque; 109 const char *intrstr; 110 pcireg_t csr; 111 int err; 112 char intrbuf[PCI_INTRSTR_LEN]; 113 114 aprint_naive("\n"); 115 aprint_normal(": HD Audio Controller\n"); 116 117 sc->sc_pc = pa->pa_pc; 118 sc->sc_tag = pa->pa_tag; 119 sc->sc_id = pa->pa_id; 120 121 sc->sc_hdaudio.sc_subsystem = pci_conf_read(sc->sc_pc, sc->sc_tag, 122 PCI_SUBSYS_ID_REG); 123 124 /* Enable busmastering and MMIO access */ 125 csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG); 126 csr |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_BACKTOBACK_ENABLE; 127 pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, csr); 128 129 /* Map MMIO registers */ 130 err = pci_mapreg_map(pa, HDAUDIO_PCI_AZBARL, PCI_MAPREG_TYPE_MEM, 0, 131 &sc->sc_hdaudio.sc_memt, 132 &sc->sc_hdaudio.sc_memh, 133 &sc->sc_hdaudio.sc_membase, 134 &sc->sc_hdaudio.sc_memsize); 135 if (err) { 136 aprint_error_dev(self, "couldn't map mmio space\n"); 137 return; 138 } 139 sc->sc_hdaudio.sc_memvalid = true; 140 sc->sc_hdaudio.sc_dmat = pa->pa_dmat; 141 142 /* Map interrupt and establish handler */ 143 if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0)) { 144 aprint_error_dev(self, "couldn't map interrupt\n"); 145 return; 146 } 147 intrstr = pci_intr_string(pa->pa_pc, sc->sc_pihp[0], intrbuf, 148 sizeof(intrbuf)); 149 sc->sc_ih = pci_intr_establish(pa->pa_pc, sc->sc_pihp[0], IPL_AUDIO, 150 hdaudio_pci_intr, sc); 151 if (sc->sc_ih == NULL) { 152 aprint_error_dev(self, "couldn't establish interrupt"); 153 if (intrstr) 154 aprint_error(" at %s", intrstr); 155 aprint_error("\n"); 156 return; 157 } 158 aprint_normal_dev(self, "interrupting at %s\n", intrstr); 159 160 if (!pmf_device_register(self, NULL, hdaudio_pci_resume)) 161 aprint_error_dev(self, "couldn't establish power handler\n"); 162 163 hdaudio_pci_reinit(sc); 164 165 /* Attach bus-independent HD audio layer */ 166 if (hdaudio_attach(self, &sc->sc_hdaudio)) { 167 pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 168 pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); 169 sc->sc_ih = NULL; 170 bus_space_unmap(sc->sc_hdaudio.sc_memt, 171 sc->sc_hdaudio.sc_memh, 172 sc->sc_hdaudio.sc_memsize); 173 sc->sc_hdaudio.sc_memvalid = false; 174 csr = pci_conf_read(sc->sc_pc, sc->sc_tag, 175 PCI_COMMAND_STATUS_REG); 176 csr &= ~(PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_BACKTOBACK_ENABLE); 177 pci_conf_write(sc->sc_pc, sc->sc_tag, 178 PCI_COMMAND_STATUS_REG, csr); 179 pmf_device_deregister(self); 180 } 181 } 182 183 static int 184 hdaudio_pci_rescan(device_t self, const char *ifattr, const int *locs) 185 { 186 struct hdaudio_pci_softc *sc = device_private(self); 187 188 return hdaudio_rescan(&sc->sc_hdaudio, ifattr, locs); 189 } 190 191 void 192 hdaudio_pci_childdet(device_t self, device_t child) 193 { 194 struct hdaudio_pci_softc *sc = device_private(self); 195 196 hdaudio_childdet(&sc->sc_hdaudio, child); 197 } 198 199 static int 200 hdaudio_pci_detach(device_t self, int flags) 201 { 202 struct hdaudio_pci_softc *sc = device_private(self); 203 pcireg_t csr; 204 205 hdaudio_detach(&sc->sc_hdaudio, flags); 206 207 if (sc->sc_ih != NULL) { 208 pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 209 pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); 210 sc->sc_ih = NULL; 211 } 212 if (sc->sc_hdaudio.sc_memvalid == true) { 213 bus_space_unmap(sc->sc_hdaudio.sc_memt, 214 sc->sc_hdaudio.sc_memh, 215 sc->sc_hdaudio.sc_memsize); 216 sc->sc_hdaudio.sc_memvalid = false; 217 } 218 219 /* Disable busmastering and MMIO access */ 220 csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG); 221 csr &= ~(PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_BACKTOBACK_ENABLE); 222 pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, csr); 223 224 pmf_device_deregister(self); 225 226 return 0; 227 } 228 229 static int 230 hdaudio_pci_intr(void *opaque) 231 { 232 struct hdaudio_pci_softc *sc = opaque; 233 234 return hdaudio_intr(&sc->sc_hdaudio); 235 } 236 237 238 static void 239 hdaudio_pci_reinit(struct hdaudio_pci_softc *sc) 240 { 241 pcireg_t val; 242 243 /* stops playback static */ 244 val = pci_conf_read(sc->sc_pc, sc->sc_tag, HDAUDIO_PCI_TCSEL); 245 val &= ~7; 246 val |= 0; 247 pci_conf_write(sc->sc_pc, sc->sc_tag, HDAUDIO_PCI_TCSEL, val); 248 249 switch (PCI_VENDOR(sc->sc_id)) { 250 case PCI_VENDOR_NVIDIA: 251 /* enable snooping */ 252 val = pci_conf_read(sc->sc_pc, sc->sc_tag, 253 HDAUDIO_NV_REG_SNOOP); 254 val &= ~HDAUDIO_NV_SNOOP_MASK; 255 val |= HDAUDIO_NV_SNOOP_ENABLE; 256 pci_conf_write(sc->sc_pc, sc->sc_tag, 257 HDAUDIO_NV_REG_SNOOP, val); 258 break; 259 } 260 } 261 262 static bool 263 hdaudio_pci_resume(device_t self, const pmf_qual_t *qual) 264 { 265 struct hdaudio_pci_softc *sc = device_private(self); 266 267 hdaudio_pci_reinit(sc); 268 return hdaudio_resume(&sc->sc_hdaudio); 269 } 270 271 MODULE(MODULE_CLASS_DRIVER, hdaudio_pci, "hdaudio"); 272 273 #ifdef _MODULE 274 #include "ioconf.c" 275 #endif 276 277 static int 278 hdaudio_pci_modcmd(modcmd_t cmd, void *opaque) 279 { 280 int error = 0; 281 282 switch (cmd) { 283 case MODULE_CMD_INIT: 284 #ifdef _MODULE 285 error = config_init_component(cfdriver_ioconf_hdaudio_pci, 286 cfattach_ioconf_hdaudio_pci, cfdata_ioconf_hdaudio_pci); 287 #endif 288 return error; 289 case MODULE_CMD_FINI: 290 #ifdef _MODULE 291 error = config_fini_component(cfdriver_ioconf_hdaudio_pci, 292 cfattach_ioconf_hdaudio_pci, cfdata_ioconf_hdaudio_pci); 293 #endif 294 return error; 295 default: 296 return ENOTTY; 297 } 298 } 299