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