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