hdaudio_pci.c revision 1.7.2.2 1 /* $NetBSD: hdaudio_pci.c,v 1.7.2.2 2018/09/23 17:22:51 martin Exp $ */
2
3 /*
4 * Copyright (c) 2009 Precedence Technologies Ltd <support (at) precedence.co.uk>
5 * Copyright (c) 2009 Jared D. McNeill <jmcneill (at) 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.7.2.2 2018/09/23 17:22:51 martin 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, maptype;
111 int err, reg;
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 reg = HDAUDIO_PCI_AZBARL;
131 maptype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, reg);
132 err = pci_mapreg_map(pa, reg, maptype, 0,
133 &sc->sc_hdaudio.sc_memt,
134 &sc->sc_hdaudio.sc_memh,
135 &sc->sc_hdaudio.sc_membase,
136 &sc->sc_hdaudio.sc_memsize);
137 if (err) {
138 aprint_error_dev(self, "couldn't map mmio space\n");
139 return;
140 }
141 sc->sc_hdaudio.sc_memvalid = true;
142 if (pci_dma64_available(pa))
143 sc->sc_hdaudio.sc_dmat = pa->pa_dmat64;
144 else
145 sc->sc_hdaudio.sc_dmat = pa->pa_dmat;
146
147 /* Map interrupt and establish handler */
148 if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0)) {
149 aprint_error_dev(self, "couldn't map interrupt\n");
150 return;
151 }
152 intrstr = pci_intr_string(pa->pa_pc, sc->sc_pihp[0], intrbuf,
153 sizeof(intrbuf));
154 sc->sc_ih = pci_intr_establish_xname(pa->pa_pc, sc->sc_pihp[0],
155 IPL_AUDIO, hdaudio_pci_intr, sc, device_xname(self));
156 if (sc->sc_ih == NULL) {
157 aprint_error_dev(self, "couldn't establish interrupt");
158 if (intrstr)
159 aprint_error(" at %s", intrstr);
160 aprint_error("\n");
161 return;
162 }
163 aprint_normal_dev(self, "interrupting at %s\n", intrstr);
164
165 hdaudio_pci_reinit(sc);
166
167 /* Attach bus-independent HD audio layer */
168 if (hdaudio_attach(self, &sc->sc_hdaudio)) {
169 pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
170 pci_intr_release(sc->sc_pc, sc->sc_pihp, 1);
171 sc->sc_ih = NULL;
172 bus_space_unmap(sc->sc_hdaudio.sc_memt,
173 sc->sc_hdaudio.sc_memh,
174 sc->sc_hdaudio.sc_memsize);
175 sc->sc_hdaudio.sc_memvalid = false;
176 csr = pci_conf_read(sc->sc_pc, sc->sc_tag,
177 PCI_COMMAND_STATUS_REG);
178 csr &= ~(PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_BACKTOBACK_ENABLE);
179 pci_conf_write(sc->sc_pc, sc->sc_tag,
180 PCI_COMMAND_STATUS_REG, csr);
181
182 if (!pmf_device_register(self, NULL, NULL))
183 aprint_error_dev(self, "couldn't establish power handler\n");
184 }
185 else if (!pmf_device_register(self, NULL, hdaudio_pci_resume))
186 aprint_error_dev(self, "couldn't establish power handler\n");
187 }
188
189 static int
190 hdaudio_pci_rescan(device_t self, const char *ifattr, const int *locs)
191 {
192 struct hdaudio_pci_softc *sc = device_private(self);
193
194 return hdaudio_rescan(&sc->sc_hdaudio, ifattr, locs);
195 }
196
197 void
198 hdaudio_pci_childdet(device_t self, device_t child)
199 {
200 struct hdaudio_pci_softc *sc = device_private(self);
201
202 hdaudio_childdet(&sc->sc_hdaudio, child);
203 }
204
205 static int
206 hdaudio_pci_detach(device_t self, int flags)
207 {
208 struct hdaudio_pci_softc *sc = device_private(self);
209 pcireg_t csr;
210
211 hdaudio_detach(&sc->sc_hdaudio, flags);
212
213 if (sc->sc_ih != NULL) {
214 pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
215 pci_intr_release(sc->sc_pc, sc->sc_pihp, 1);
216 sc->sc_ih = NULL;
217 }
218 if (sc->sc_hdaudio.sc_memvalid == true) {
219 bus_space_unmap(sc->sc_hdaudio.sc_memt,
220 sc->sc_hdaudio.sc_memh,
221 sc->sc_hdaudio.sc_memsize);
222 sc->sc_hdaudio.sc_memvalid = false;
223 }
224
225 /* Disable busmastering and MMIO access */
226 csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG);
227 csr &= ~(PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_BACKTOBACK_ENABLE);
228 pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, csr);
229
230 pmf_device_deregister(self);
231
232 return 0;
233 }
234
235 static int
236 hdaudio_pci_intr(void *opaque)
237 {
238 struct hdaudio_pci_softc *sc = opaque;
239
240 return hdaudio_intr(&sc->sc_hdaudio);
241 }
242
243
244 static void
245 hdaudio_pci_reinit(struct hdaudio_pci_softc *sc)
246 {
247 pcireg_t val;
248
249 /* stops playback static */
250 val = pci_conf_read(sc->sc_pc, sc->sc_tag, HDAUDIO_PCI_TCSEL);
251 val &= ~7;
252 val |= 0;
253 pci_conf_write(sc->sc_pc, sc->sc_tag, HDAUDIO_PCI_TCSEL, val);
254
255 switch (PCI_VENDOR(sc->sc_id)) {
256 case PCI_VENDOR_NVIDIA:
257 /* enable snooping */
258 val = pci_conf_read(sc->sc_pc, sc->sc_tag,
259 HDAUDIO_NV_REG_SNOOP);
260 val &= ~HDAUDIO_NV_SNOOP_MASK;
261 val |= HDAUDIO_NV_SNOOP_ENABLE;
262 pci_conf_write(sc->sc_pc, sc->sc_tag,
263 HDAUDIO_NV_REG_SNOOP, val);
264 break;
265 }
266 }
267
268 static bool
269 hdaudio_pci_resume(device_t self, const pmf_qual_t *qual)
270 {
271 struct hdaudio_pci_softc *sc = device_private(self);
272
273 hdaudio_pci_reinit(sc);
274 return hdaudio_resume(&sc->sc_hdaudio);
275 }
276
277 MODULE(MODULE_CLASS_DRIVER, hdaudio_pci, "pci,hdaudio,audio");
278
279 #ifdef _MODULE
280 /*
281 * XXX Don't allow ioconf.c to redefine the "struct cfdriver hdaudio_cd"
282 * XXX it will be defined in the common hdaudio module
283 */
284
285 #undef CFDRIVER_DECL
286 #define CFDRIVER_DECL(name, class, attr) /* nothing */
287 #include "ioconf.c"
288 #endif
289
290 static int
291 hdaudio_pci_modcmd(modcmd_t cmd, void *opaque)
292 {
293 #ifdef _MODULE
294 /*
295 * We ignore the cfdriver_vec[] that ioconf provides, since
296 * the cfdrivers are attached already.
297 */
298 static struct cfdriver * const no_cfdriver_vec[] = { NULL };
299 #endif
300 int error = 0;
301
302 switch (cmd) {
303 case MODULE_CMD_INIT:
304 #ifdef _MODULE
305 error = config_init_component(no_cfdriver_vec,
306 cfattach_ioconf_hdaudio_pci, cfdata_ioconf_hdaudio_pci);
307 #endif
308 return error;
309 case MODULE_CMD_FINI:
310 #ifdef _MODULE
311 error = config_fini_component(no_cfdriver_vec,
312 cfattach_ioconf_hdaudio_pci, cfdata_ioconf_hdaudio_pci);
313 #endif
314 return error;
315 default:
316 return ENOTTY;
317 }
318 }
319