xref: /netbsd-src/sys/dev/pci/hdaudio_pci.c (revision dd3ee07da436799d8de85f3055253118b76bf345)
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@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.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