1 | /* |
2 | * Common code to disable/enable mixer emulation at run time |
3 | * |
4 | * Copyright (C) 2013 Red Hat, Inc. |
5 | * |
6 | * Written by Bandan Das <bsd@redhat.com> |
7 | * with important bits picked up from hda-codec.c |
8 | * |
9 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License as |
11 | * published by the Free Software Foundation; either version 2 or |
12 | * (at your option) version 3 of the License. |
13 | * |
14 | * This program is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | * GNU General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
21 | */ |
22 | |
23 | /* |
24 | * HDA codec descriptions |
25 | */ |
26 | |
27 | #ifdef HDA_MIXER |
28 | #define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x12) |
29 | #define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x22) |
30 | #define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x32) |
31 | #define QEMU_HDA_AMP_CAPS \ |
32 | (AC_AMPCAP_MUTE | \ |
33 | (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT) | \ |
34 | (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) | \ |
35 | (3 << AC_AMPCAP_STEP_SIZE_SHIFT)) |
36 | #else |
37 | #define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x11) |
38 | #define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x21) |
39 | #define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x31) |
40 | #define QEMU_HDA_AMP_CAPS QEMU_HDA_AMP_NONE |
41 | #endif |
42 | |
43 | |
44 | /* common: audio output widget */ |
45 | static const desc_param glue(common_params_audio_dac_, PARAM)[] = { |
46 | { |
47 | .id = AC_PAR_AUDIO_WIDGET_CAP, |
48 | .val = ((AC_WID_AUD_OUT << AC_WCAP_TYPE_SHIFT) | |
49 | AC_WCAP_FORMAT_OVRD | |
50 | AC_WCAP_AMP_OVRD | |
51 | AC_WCAP_OUT_AMP | |
52 | AC_WCAP_STEREO), |
53 | },{ |
54 | .id = AC_PAR_PCM, |
55 | .val = QEMU_HDA_PCM_FORMATS, |
56 | },{ |
57 | .id = AC_PAR_STREAM, |
58 | .val = AC_SUPFMT_PCM, |
59 | },{ |
60 | .id = AC_PAR_AMP_IN_CAP, |
61 | .val = QEMU_HDA_AMP_NONE, |
62 | },{ |
63 | .id = AC_PAR_AMP_OUT_CAP, |
64 | .val = QEMU_HDA_AMP_CAPS, |
65 | }, |
66 | }; |
67 | |
68 | /* common: audio input widget */ |
69 | static const desc_param glue(common_params_audio_adc_, PARAM)[] = { |
70 | { |
71 | .id = AC_PAR_AUDIO_WIDGET_CAP, |
72 | .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) | |
73 | AC_WCAP_CONN_LIST | |
74 | AC_WCAP_FORMAT_OVRD | |
75 | AC_WCAP_AMP_OVRD | |
76 | AC_WCAP_IN_AMP | |
77 | AC_WCAP_STEREO), |
78 | },{ |
79 | .id = AC_PAR_CONNLIST_LEN, |
80 | .val = 1, |
81 | },{ |
82 | .id = AC_PAR_PCM, |
83 | .val = QEMU_HDA_PCM_FORMATS, |
84 | },{ |
85 | .id = AC_PAR_STREAM, |
86 | .val = AC_SUPFMT_PCM, |
87 | },{ |
88 | .id = AC_PAR_AMP_IN_CAP, |
89 | .val = QEMU_HDA_AMP_CAPS, |
90 | },{ |
91 | .id = AC_PAR_AMP_OUT_CAP, |
92 | .val = QEMU_HDA_AMP_NONE, |
93 | }, |
94 | }; |
95 | |
96 | /* common: pin widget (line-out) */ |
97 | static const desc_param glue(common_params_audio_lineout_, PARAM)[] = { |
98 | { |
99 | .id = AC_PAR_AUDIO_WIDGET_CAP, |
100 | .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) | |
101 | AC_WCAP_CONN_LIST | |
102 | AC_WCAP_STEREO), |
103 | },{ |
104 | .id = AC_PAR_PIN_CAP, |
105 | .val = AC_PINCAP_OUT, |
106 | },{ |
107 | .id = AC_PAR_CONNLIST_LEN, |
108 | .val = 1, |
109 | },{ |
110 | .id = AC_PAR_AMP_IN_CAP, |
111 | .val = QEMU_HDA_AMP_NONE, |
112 | },{ |
113 | .id = AC_PAR_AMP_OUT_CAP, |
114 | .val = QEMU_HDA_AMP_NONE, |
115 | }, |
116 | }; |
117 | |
118 | /* common: pin widget (line-in) */ |
119 | static const desc_param glue(common_params_audio_linein_, PARAM)[] = { |
120 | { |
121 | .id = AC_PAR_AUDIO_WIDGET_CAP, |
122 | .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) | |
123 | AC_WCAP_STEREO), |
124 | },{ |
125 | .id = AC_PAR_PIN_CAP, |
126 | .val = AC_PINCAP_IN, |
127 | },{ |
128 | .id = AC_PAR_AMP_IN_CAP, |
129 | .val = QEMU_HDA_AMP_NONE, |
130 | },{ |
131 | .id = AC_PAR_AMP_OUT_CAP, |
132 | .val = QEMU_HDA_AMP_NONE, |
133 | }, |
134 | }; |
135 | |
136 | /* output: root node */ |
137 | static const desc_param glue(output_params_root_, PARAM)[] = { |
138 | { |
139 | .id = AC_PAR_VENDOR_ID, |
140 | .val = QEMU_HDA_ID_OUTPUT, |
141 | },{ |
142 | .id = AC_PAR_SUBSYSTEM_ID, |
143 | .val = QEMU_HDA_ID_OUTPUT, |
144 | },{ |
145 | .id = AC_PAR_REV_ID, |
146 | .val = 0x00100101, |
147 | },{ |
148 | .id = AC_PAR_NODE_COUNT, |
149 | .val = 0x00010001, |
150 | }, |
151 | }; |
152 | |
153 | /* output: audio function */ |
154 | static const desc_param glue(output_params_audio_func_, PARAM)[] = { |
155 | { |
156 | .id = AC_PAR_FUNCTION_TYPE, |
157 | .val = AC_GRP_AUDIO_FUNCTION, |
158 | },{ |
159 | .id = AC_PAR_SUBSYSTEM_ID, |
160 | .val = QEMU_HDA_ID_OUTPUT, |
161 | },{ |
162 | .id = AC_PAR_NODE_COUNT, |
163 | .val = 0x00020002, |
164 | },{ |
165 | .id = AC_PAR_PCM, |
166 | .val = QEMU_HDA_PCM_FORMATS, |
167 | },{ |
168 | .id = AC_PAR_STREAM, |
169 | .val = AC_SUPFMT_PCM, |
170 | },{ |
171 | .id = AC_PAR_AMP_IN_CAP, |
172 | .val = QEMU_HDA_AMP_NONE, |
173 | },{ |
174 | .id = AC_PAR_AMP_OUT_CAP, |
175 | .val = QEMU_HDA_AMP_NONE, |
176 | },{ |
177 | .id = AC_PAR_GPIO_CAP, |
178 | .val = 0, |
179 | },{ |
180 | .id = AC_PAR_AUDIO_FG_CAP, |
181 | .val = 0x00000808, |
182 | },{ |
183 | .id = AC_PAR_POWER_STATE, |
184 | .val = 0, |
185 | }, |
186 | }; |
187 | |
188 | /* output: nodes */ |
189 | static const desc_node glue(output_nodes_, PARAM)[] = { |
190 | { |
191 | .nid = AC_NODE_ROOT, |
192 | .name = "root" , |
193 | .params = glue(output_params_root_, PARAM), |
194 | .nparams = ARRAY_SIZE(glue(output_params_root_, PARAM)), |
195 | },{ |
196 | .nid = 1, |
197 | .name = "func" , |
198 | .params = glue(output_params_audio_func_, PARAM), |
199 | .nparams = ARRAY_SIZE(glue(output_params_audio_func_, PARAM)), |
200 | },{ |
201 | .nid = 2, |
202 | .name = "dac" , |
203 | .params = glue(common_params_audio_dac_, PARAM), |
204 | .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)), |
205 | .stindex = 0, |
206 | },{ |
207 | .nid = 3, |
208 | .name = "out" , |
209 | .params = glue(common_params_audio_lineout_, PARAM), |
210 | .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)), |
211 | .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | |
212 | (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) | |
213 | (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | |
214 | (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) | |
215 | 0x10), |
216 | .pinctl = AC_PINCTL_OUT_EN, |
217 | .conn = (uint32_t[]) { 2 }, |
218 | } |
219 | }; |
220 | |
221 | /* output: codec */ |
222 | static const desc_codec glue(output_, PARAM) = { |
223 | .name = "output" , |
224 | .iid = QEMU_HDA_ID_OUTPUT, |
225 | .nodes = glue(output_nodes_, PARAM), |
226 | .nnodes = ARRAY_SIZE(glue(output_nodes_, PARAM)), |
227 | }; |
228 | |
229 | /* duplex: root node */ |
230 | static const desc_param glue(duplex_params_root_, PARAM)[] = { |
231 | { |
232 | .id = AC_PAR_VENDOR_ID, |
233 | .val = QEMU_HDA_ID_DUPLEX, |
234 | },{ |
235 | .id = AC_PAR_SUBSYSTEM_ID, |
236 | .val = QEMU_HDA_ID_DUPLEX, |
237 | },{ |
238 | .id = AC_PAR_REV_ID, |
239 | .val = 0x00100101, |
240 | },{ |
241 | .id = AC_PAR_NODE_COUNT, |
242 | .val = 0x00010001, |
243 | }, |
244 | }; |
245 | |
246 | /* duplex: audio function */ |
247 | static const desc_param glue(duplex_params_audio_func_, PARAM)[] = { |
248 | { |
249 | .id = AC_PAR_FUNCTION_TYPE, |
250 | .val = AC_GRP_AUDIO_FUNCTION, |
251 | },{ |
252 | .id = AC_PAR_SUBSYSTEM_ID, |
253 | .val = QEMU_HDA_ID_DUPLEX, |
254 | },{ |
255 | .id = AC_PAR_NODE_COUNT, |
256 | .val = 0x00020004, |
257 | },{ |
258 | .id = AC_PAR_PCM, |
259 | .val = QEMU_HDA_PCM_FORMATS, |
260 | },{ |
261 | .id = AC_PAR_STREAM, |
262 | .val = AC_SUPFMT_PCM, |
263 | },{ |
264 | .id = AC_PAR_AMP_IN_CAP, |
265 | .val = QEMU_HDA_AMP_NONE, |
266 | },{ |
267 | .id = AC_PAR_AMP_OUT_CAP, |
268 | .val = QEMU_HDA_AMP_NONE, |
269 | },{ |
270 | .id = AC_PAR_GPIO_CAP, |
271 | .val = 0, |
272 | },{ |
273 | .id = AC_PAR_AUDIO_FG_CAP, |
274 | .val = 0x00000808, |
275 | },{ |
276 | .id = AC_PAR_POWER_STATE, |
277 | .val = 0, |
278 | }, |
279 | }; |
280 | |
281 | /* duplex: nodes */ |
282 | static const desc_node glue(duplex_nodes_, PARAM)[] = { |
283 | { |
284 | .nid = AC_NODE_ROOT, |
285 | .name = "root" , |
286 | .params = glue(duplex_params_root_, PARAM), |
287 | .nparams = ARRAY_SIZE(glue(duplex_params_root_, PARAM)), |
288 | },{ |
289 | .nid = 1, |
290 | .name = "func" , |
291 | .params = glue(duplex_params_audio_func_, PARAM), |
292 | .nparams = ARRAY_SIZE(glue(duplex_params_audio_func_, PARAM)), |
293 | },{ |
294 | .nid = 2, |
295 | .name = "dac" , |
296 | .params = glue(common_params_audio_dac_, PARAM), |
297 | .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)), |
298 | .stindex = 0, |
299 | },{ |
300 | .nid = 3, |
301 | .name = "out" , |
302 | .params = glue(common_params_audio_lineout_, PARAM), |
303 | .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)), |
304 | .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | |
305 | (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) | |
306 | (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | |
307 | (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) | |
308 | 0x10), |
309 | .pinctl = AC_PINCTL_OUT_EN, |
310 | .conn = (uint32_t[]) { 2 }, |
311 | },{ |
312 | .nid = 4, |
313 | .name = "adc" , |
314 | .params = glue(common_params_audio_adc_, PARAM), |
315 | .nparams = ARRAY_SIZE(glue(common_params_audio_adc_, PARAM)), |
316 | .stindex = 1, |
317 | .conn = (uint32_t[]) { 5 }, |
318 | },{ |
319 | .nid = 5, |
320 | .name = "in" , |
321 | .params = glue(common_params_audio_linein_, PARAM), |
322 | .nparams = ARRAY_SIZE(glue(common_params_audio_linein_, PARAM)), |
323 | .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | |
324 | (AC_JACK_LINE_IN << AC_DEFCFG_DEVICE_SHIFT) | |
325 | (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | |
326 | (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) | |
327 | 0x20), |
328 | .pinctl = AC_PINCTL_IN_EN, |
329 | } |
330 | }; |
331 | |
332 | /* duplex: codec */ |
333 | static const desc_codec glue(duplex_, PARAM) = { |
334 | .name = "duplex" , |
335 | .iid = QEMU_HDA_ID_DUPLEX, |
336 | .nodes = glue(duplex_nodes_, PARAM), |
337 | .nnodes = ARRAY_SIZE(glue(duplex_nodes_, PARAM)), |
338 | }; |
339 | |
340 | /* micro: root node */ |
341 | static const desc_param glue(micro_params_root_, PARAM)[] = { |
342 | { |
343 | .id = AC_PAR_VENDOR_ID, |
344 | .val = QEMU_HDA_ID_MICRO, |
345 | },{ |
346 | .id = AC_PAR_SUBSYSTEM_ID, |
347 | .val = QEMU_HDA_ID_MICRO, |
348 | },{ |
349 | .id = AC_PAR_REV_ID, |
350 | .val = 0x00100101, |
351 | },{ |
352 | .id = AC_PAR_NODE_COUNT, |
353 | .val = 0x00010001, |
354 | }, |
355 | }; |
356 | |
357 | /* micro: audio function */ |
358 | static const desc_param glue(micro_params_audio_func_, PARAM)[] = { |
359 | { |
360 | .id = AC_PAR_FUNCTION_TYPE, |
361 | .val = AC_GRP_AUDIO_FUNCTION, |
362 | },{ |
363 | .id = AC_PAR_SUBSYSTEM_ID, |
364 | .val = QEMU_HDA_ID_MICRO, |
365 | },{ |
366 | .id = AC_PAR_NODE_COUNT, |
367 | .val = 0x00020004, |
368 | },{ |
369 | .id = AC_PAR_PCM, |
370 | .val = QEMU_HDA_PCM_FORMATS, |
371 | },{ |
372 | .id = AC_PAR_STREAM, |
373 | .val = AC_SUPFMT_PCM, |
374 | },{ |
375 | .id = AC_PAR_AMP_IN_CAP, |
376 | .val = QEMU_HDA_AMP_NONE, |
377 | },{ |
378 | .id = AC_PAR_AMP_OUT_CAP, |
379 | .val = QEMU_HDA_AMP_NONE, |
380 | },{ |
381 | .id = AC_PAR_GPIO_CAP, |
382 | .val = 0, |
383 | },{ |
384 | .id = AC_PAR_AUDIO_FG_CAP, |
385 | .val = 0x00000808, |
386 | },{ |
387 | .id = AC_PAR_POWER_STATE, |
388 | .val = 0, |
389 | }, |
390 | }; |
391 | |
392 | /* micro: nodes */ |
393 | static const desc_node glue(micro_nodes_, PARAM)[] = { |
394 | { |
395 | .nid = AC_NODE_ROOT, |
396 | .name = "root" , |
397 | .params = glue(micro_params_root_, PARAM), |
398 | .nparams = ARRAY_SIZE(glue(micro_params_root_, PARAM)), |
399 | },{ |
400 | .nid = 1, |
401 | .name = "func" , |
402 | .params = glue(micro_params_audio_func_, PARAM), |
403 | .nparams = ARRAY_SIZE(glue(micro_params_audio_func_, PARAM)), |
404 | },{ |
405 | .nid = 2, |
406 | .name = "dac" , |
407 | .params = glue(common_params_audio_dac_, PARAM), |
408 | .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)), |
409 | .stindex = 0, |
410 | },{ |
411 | .nid = 3, |
412 | .name = "out" , |
413 | .params = glue(common_params_audio_lineout_, PARAM), |
414 | .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)), |
415 | .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | |
416 | (AC_JACK_SPEAKER << AC_DEFCFG_DEVICE_SHIFT) | |
417 | (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | |
418 | (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) | |
419 | 0x10), |
420 | .pinctl = AC_PINCTL_OUT_EN, |
421 | .conn = (uint32_t[]) { 2 }, |
422 | },{ |
423 | .nid = 4, |
424 | .name = "adc" , |
425 | .params = glue(common_params_audio_adc_, PARAM), |
426 | .nparams = ARRAY_SIZE(glue(common_params_audio_adc_, PARAM)), |
427 | .stindex = 1, |
428 | .conn = (uint32_t[]) { 5 }, |
429 | },{ |
430 | .nid = 5, |
431 | .name = "in" , |
432 | .params = glue(common_params_audio_linein_, PARAM), |
433 | .nparams = ARRAY_SIZE(glue(common_params_audio_linein_, PARAM)), |
434 | .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | |
435 | (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT) | |
436 | (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | |
437 | (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) | |
438 | 0x20), |
439 | .pinctl = AC_PINCTL_IN_EN, |
440 | } |
441 | }; |
442 | |
443 | /* micro: codec */ |
444 | static const desc_codec glue(micro_, PARAM) = { |
445 | .name = "micro" , |
446 | .iid = QEMU_HDA_ID_MICRO, |
447 | .nodes = glue(micro_nodes_, PARAM), |
448 | .nnodes = ARRAY_SIZE(glue(micro_nodes_, PARAM)), |
449 | }; |
450 | |
451 | #undef PARAM |
452 | #undef HDA_MIXER |
453 | #undef QEMU_HDA_ID_OUTPUT |
454 | #undef QEMU_HDA_ID_DUPLEX |
455 | #undef QEMU_HDA_ID_MICRO |
456 | #undef QEMU_HDA_AMP_CAPS |
457 | |