hdaudio_pci.c revision 1.12 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 (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.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