History

ASoC: Intel: avs: Machine board registration

AVS driver operates with granular audio card division in mind. Super-card approach (e.g.: I2S, DMIC and HDA DAIs combined) is deprecated in favour of individual cards - one per each device. This provides necessary dynamism, especially for configurations with number of codecs present and makes it easier to survive auxiliary devices failures - one card failing to probe does not prevent others from succeeding. All boards spawned by AVS are unregistered on ->remove(). This includes dummy codecs such as DMIC. As all machine boards found in sound/soc/intel/boards are irreversibly tied to 'super-card' approach, new boards are going to be introduced. This temporarily increases number of boards available under /intel directory until skylake-driver becomes deprecated and removed.

Cezary Rojewski committed 4 years ago

Commit beed9831 parent 25b552f3 files · +505 −1Browse files

Unified · Split

3 files
  1. sound/soc/intel/avs/Makefile +1 −1
  2. sound/soc/intel/avs/avs.h +3 −0
  3. sound/soc/intel/avs/board_selection.c +501 −0
sound/soc/intel/avs/Makefile+1−1
@@ -1,7 +1,7 @@
1# SPDX-License-Identifier: GPL-2.0-only1# SPDX-License-Identifier: GPL-2.0-only
2 2
3snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \3snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \
4 topology.o path.o pcm.o4 topology.o path.o pcm.o board_selection.o
5snd-soc-avs-objs += cldma.o5snd-soc-avs-objs += cldma.o
6 6
7snd-soc-avs-objs += trace.o7snd-soc-avs-objs += trace.o
sound/soc/intel/avs/avs.h+3−0
@@ -310,6 +310,9 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l · 309 unmodified lines
310 unsigned long *tdms);310 unsigned long *tdms);
311int avs_hda_platform_register(struct avs_dev *adev, const char *name);311int avs_hda_platform_register(struct avs_dev *adev, const char *name);
312 312
313int avs_register_all_boards(struct avs_dev *adev);
314void avs_unregister_all_boards(struct avs_dev *adev);
315
313/* Firmware tracing helpers */316/* Firmware tracing helpers */
314 317
315unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,318unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,
sound/soc/intel/avs/board_selection.c+501−0
@@ -0,0 +1,501 @@
1// SPDX-License-Identifier: GPL-2.0-only
2//
3// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
4//
5// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
6// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
7//
8
9#include <linux/acpi.h>
10#include <linux/module.h>
11#include <linux/dmi.h>
12#include <linux/pci.h>
13#include <linux/platform_device.h>
14#include <sound/hda_codec.h>
15#include <sound/hda_register.h>
16#include <sound/intel-nhlt.h>
17#include <sound/soc-acpi.h>
18#include <sound/soc-component.h>
19#include "avs.h"
20
21static bool i2s_test;
22module_param(i2s_test, bool, 0444);
23MODULE_PARM_DESC(i2s_test, "Probe I2S test-board and skip all other I2S boards");
24
25static const struct dmi_system_id kbl_dmi_table[] = {
26 {
27 .matches = {
28 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
29 DMI_MATCH(DMI_BOARD_NAME, "Skylake Y LPDDR3 RVP3"),
30 },
31 },
32 {}
33};
34
35static const struct dmi_system_id kblr_dmi_table[] = {
36 {
37 .matches = {
38 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
39 DMI_MATCH(DMI_BOARD_NAME, "Kabylake R DDR4 RVP"),
40 },
41 },
42 {}
43};
44
45static struct snd_soc_acpi_mach *dmi_match_quirk(void *arg)
46{
47 struct snd_soc_acpi_mach *mach = arg;
48 const struct dmi_system_id *dmi_id;
49 struct dmi_system_id *dmi_table;
50
51 if (mach->quirk_data == NULL)
52 return mach;
53
54 dmi_table = (struct dmi_system_id *)mach->quirk_data;
55
56 dmi_id = dmi_first_match(dmi_table);
57 if (!dmi_id)
58 return NULL;
59
60 return mach;
61}
62
63#define AVS_SSP(x) (BIT(x))
64#define AVS_SSP_RANGE(a, b) (GENMASK(b, a))
65
66/* supported I2S board codec configurations */
67static struct snd_soc_acpi_mach avs_skl_i2s_machines[] = {
68 {
69 .id = "INT343A",
70 .drv_name = "avs_rt286",
71 .mach_params = {
72 .i2s_link_mask = AVS_SSP(0),
73 },
74 .tplg_filename = "rt286-tplg.bin",
75 },
76 {
77 .id = "10508825",
78 .drv_name = "avs_nau8825",
79 .mach_params = {
80 .i2s_link_mask = AVS_SSP(1),
81 },
82 .tplg_filename = "nau8825-tplg.bin",
83 },
84 {
85 .id = "INT343B",
86 .drv_name = "avs_ssm4567",
87 .mach_params = {
88 .i2s_link_mask = AVS_SSP(0),
89 },
90 .tplg_filename = "ssm4567-tplg.bin",
91 },
92 {
93 .id = "MX98357A",
94 .drv_name = "avs_max98357a",
95 .mach_params = {
96 .i2s_link_mask = AVS_SSP(0),
97 },
98 .tplg_filename = "max98357a-tplg.bin",
99 },
100 {},
101};
102
103static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
104 {
105 .id = "INT343A",
106 .drv_name = "avs_rt286",
107 .mach_params = {
108 .i2s_link_mask = AVS_SSP(0),
109 },
110 .quirk_data = &kbl_dmi_table,
111 .machine_quirk = dmi_match_quirk,
112 .tplg_filename = "rt286-tplg.bin",
113 },
114 {
115 .id = "INT343A",
116 .drv_name = "avs_rt298",
117 .mach_params = {
118 .i2s_link_mask = AVS_SSP(0),
119 },
120 .quirk_data = &kblr_dmi_table,
121 .machine_quirk = dmi_match_quirk,
122 .tplg_filename = "rt298-tplg.bin",
123 },
124 {
125 .id = "MX98373",
126 .drv_name = "avs_max98373",
127 .mach_params = {
128 .i2s_link_mask = AVS_SSP(0),
129 },
130 .tplg_filename = "max98373-tplg.bin",
131 },
132 {
133 .id = "DLGS7219",
134 .drv_name = "avs_da7219",
135 .mach_params = {
136 .i2s_link_mask = AVS_SSP(1),
137 },
138 .tplg_filename = "da7219-tplg.bin",
139 },
140 {},
141};
142
143static struct snd_soc_acpi_mach avs_apl_i2s_machines[] = {
144 {
145 .id = "INT343A",
146 .drv_name = "avs_rt298",
147 .mach_params = {
148 .i2s_link_mask = AVS_SSP(5),
149 },
150 .tplg_filename = "rt298-tplg.bin",
151 },
152 {
153 .id = "INT34C3",
154 .drv_name = "avs_tdf8532",
155 .mach_params = {
156 .i2s_link_mask = AVS_SSP_RANGE(0, 5),
157 },
158 .pdata = (unsigned long[]){ 0, 0, 0x14, 0, 0, 0 }, /* SSP2 TDMs */
159 .tplg_filename = "tdf8532-tplg.bin",
160 },
161 {
162 .id = "MX98357A",
163 .drv_name = "avs_max98357a",
164 .mach_params = {
165 .i2s_link_mask = AVS_SSP(5),
166 },
167 .tplg_filename = "max98357a-tplg.bin",
168 },
169 {
170 .id = "DLGS7219",
171 .drv_name = "avs_da7219",
172 .mach_params = {
173 .i2s_link_mask = AVS_SSP(1),
174 },
175 .tplg_filename = "da7219-tplg.bin",
176 },
177 {},
178};
179
180static struct snd_soc_acpi_mach avs_gml_i2s_machines[] = {
181 {
182 .id = "INT343A",
183 .drv_name = "avs_rt298",
184 .mach_params = {
185 .i2s_link_mask = AVS_SSP(2),
186 },
187 .tplg_filename = "rt298-tplg.bin",
188 },
189 {},
190};
191
192static struct snd_soc_acpi_mach avs_test_i2s_machines[] = {
193 {
194 .drv_name = "avs_i2s_test",
195 .mach_params = {
196 .i2s_link_mask = AVS_SSP(0),
197 },
198 .tplg_filename = "i2s-test-tplg.bin",
199 },
200 {
201 .drv_name = "avs_i2s_test",
202 .mach_params = {
203 .i2s_link_mask = AVS_SSP(1),
204 },
205 .tplg_filename = "i2s-test-tplg.bin",
206 },
207 {
208 .drv_name = "avs_i2s_test",
209 .mach_params = {
210 .i2s_link_mask = AVS_SSP(2),
211 },
212 .tplg_filename = "i2s-test-tplg.bin",
213 },
214 {
215 .drv_name = "avs_i2s_test",
216 .mach_params = {
217 .i2s_link_mask = AVS_SSP(3),
218 },
219 .tplg_filename = "i2s-test-tplg.bin",
220 },
221 {
222 .drv_name = "avs_i2s_test",
223 .mach_params = {
224 .i2s_link_mask = AVS_SSP(4),
225 },
226 .tplg_filename = "i2s-test-tplg.bin",
227 },
228 {
229 .drv_name = "avs_i2s_test",
230 .mach_params = {
231 .i2s_link_mask = AVS_SSP(5),
232 },
233 .tplg_filename = "i2s-test-tplg.bin",
234 },
235 /* no NULL terminator, as we depend on ARRAY SIZE due to .id == NULL */
236};
237
238struct avs_acpi_boards {
239 int id;
240 struct snd_soc_acpi_mach *machs;
241};
242
243#define AVS_MACH_ENTRY(_id, _mach) \
244 { .id = (_id), .machs = (_mach), }
245
246/* supported I2S boards per platform */
247static const struct avs_acpi_boards i2s_boards[] = {
248 AVS_MACH_ENTRY(0x9d70, avs_skl_i2s_machines), /* SKL */
249 AVS_MACH_ENTRY(0x9d71, avs_kbl_i2s_machines), /* KBL */
250 AVS_MACH_ENTRY(0x5a98, avs_apl_i2s_machines), /* APL */
251 AVS_MACH_ENTRY(0x3198, avs_gml_i2s_machines), /* GML */
252 {},
253};
254
255static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev)
256{
257 int id, i;
258
259 id = adev->base.pci->device;
260 for (i = 0; i < ARRAY_SIZE(i2s_boards); i++)
261 if (i2s_boards[i].id == id)
262 return &i2s_boards[i];
263 return NULL;
264}
265
266/* platform devices owned by AVS audio are removed with this hook */
267static void board_pdev_unregister(void *data)
268{
269 platform_device_unregister(data);
270}
271
272static int avs_register_dmic_board(struct avs_dev *adev)
273{
274 struct platform_device *codec, *board;
275 struct snd_soc_acpi_mach mach = {{0}};
276 int ret;
277
278 if (!adev->nhlt ||
279 !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_DMIC)) {
280 dev_dbg(adev->dev, "no DMIC endpoints present\n");
281 return 0;
282 }
283
284 codec = platform_device_register_simple("dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
285 if (IS_ERR(codec)) {
286 dev_err(adev->dev, "dmic codec register failed\n");
287 return PTR_ERR(codec);
288 }
289
290 ret = devm_add_action(adev->dev, board_pdev_unregister, codec);
291 if (ret < 0) {
292 platform_device_unregister(codec);
293 return ret;
294 }
295
296 ret = avs_dmic_platform_register(adev, "dmic-platform");
297 if (ret < 0)
298 return ret;
299
300 mach.tplg_filename = "dmic-tplg.bin";
301 mach.mach_params.platform = "dmic-platform";
302
303 board = platform_device_register_data(NULL, "avs_dmic", PLATFORM_DEVID_NONE,
304 (const void *)&mach, sizeof(mach));
305 if (IS_ERR(board)) {
306 dev_err(adev->dev, "dmic board register failed\n");
307 return PTR_ERR(board);
308 }
309
310 ret = devm_add_action(adev->dev, board_pdev_unregister, board);
311 if (ret < 0) {
312 platform_device_unregister(board);
313 return ret;
314 }
315
316 return 0;
317}
318
319static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
320{
321 struct platform_device *board;
322 int num_ssps;
323 char *name;
324 int ret;
325
326 num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
327 if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
328 dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
329 num_ssps, mach->drv_name, __fls(mach->mach_params.i2s_link_mask));
330 return -ENODEV;
331 }
332
333 name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name,
334 mach->mach_params.i2s_link_mask);
335 if (!name)
336 return -ENOMEM;
337
338 ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, mach->pdata);
339 if (ret < 0)
340 return ret;
341
342 mach->mach_params.platform = name;
343
344 board = platform_device_register_data(NULL, mach->drv_name, mach->mach_params.i2s_link_mask,
345 (const void *)mach, sizeof(*mach));
346 if (IS_ERR(board)) {
347 dev_err(adev->dev, "ssp board register failed\n");
348 return PTR_ERR(board);
349 }
350
351 ret = devm_add_action(adev->dev, board_pdev_unregister, board);
352 if (ret < 0) {
353 platform_device_unregister(board);
354 return ret;
355 }
356
357 return 0;
358}
359
360static int avs_register_i2s_boards(struct avs_dev *adev)
361{
362 const struct avs_acpi_boards *boards;
363 struct snd_soc_acpi_mach *mach;
364 int ret;
365
366 if (!adev->nhlt || !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_SSP)) {
367 dev_dbg(adev->dev, "no I2S endpoints present\n");
368 return 0;
369 }
370
371 if (i2s_test) {
372 int i, num_ssps;
373
374 num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
375 /* constrain just in case FW says there can be more SSPs than possible */
376 num_ssps = min_t(int, ARRAY_SIZE(avs_test_i2s_machines), num_ssps);
377
378 mach = avs_test_i2s_machines;
379
380 for (i = 0; i < num_ssps; i++) {
381 ret = avs_register_i2s_board(adev, &mach[i]);
382 if (ret < 0)
383 dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name,
384 ret);
385 }
386 return 0;
387 }
388
389 boards = avs_get_i2s_boards(adev);
390 if (!boards) {
391 dev_dbg(adev->dev, "no I2S endpoints supported\n");
392 return 0;
393 }
394
395 for (mach = boards->machs; mach->id[0]; mach++) {
396 if (!acpi_dev_present(mach->id, NULL, -1))
397 continue;
398
399 if (mach->machine_quirk)
400 if (!mach->machine_quirk(mach))
401 continue;
402
403 ret = avs_register_i2s_board(adev, mach);
404 if (ret < 0)
405 dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret);
406 }
407
408 return 0;
409}
410
411static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec)
412{
413 struct snd_soc_acpi_mach mach = {{0}};
414 struct platform_device *board;
415 struct hdac_device *hdev = &codec->core;
416 char *pname;
417 int ret, id;
418
419 pname = devm_kasprintf(adev->dev, GFP_KERNEL, "%s-platform", dev_name(&hdev->dev));
420 if (!pname)
421 return -ENOMEM;
422
423 ret = avs_hda_platform_register(adev, pname);
424 if (ret < 0)
425 return ret;
426
427 mach.pdata = codec;
428 mach.mach_params.platform = pname;
429 mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin",
430 hdev->vendor_id);
431 if (!mach.tplg_filename)
432 return -ENOMEM;
433
434 id = adev->base.core.idx * HDA_MAX_CODECS + hdev->addr;
435 board = platform_device_register_data(NULL, "avs_hdaudio", id, (const void *)&mach,
436 sizeof(mach));
437 if (IS_ERR(board)) {
438 dev_err(adev->dev, "hda board register failed\n");
439 return PTR_ERR(board);
440 }
441
442 ret = devm_add_action(adev->dev, board_pdev_unregister, board);
443 if (ret < 0) {
444 platform_device_unregister(board);
445 return ret;
446 }
447
448 return 0;
449}
450
451static int avs_register_hda_boards(struct avs_dev *adev)
452{
453 struct hdac_bus *bus = &adev->base.core;
454 struct hdac_device *hdev;
455 int ret;
456
457 if (!bus->num_codecs) {
458 dev_dbg(adev->dev, "no HDA endpoints present\n");
459 return 0;
460 }
461
462 list_for_each_entry(hdev, &bus->codec_list, list) {
463 struct hda_codec *codec;
464
465 codec = dev_to_hda_codec(&hdev->dev);
466
467 ret = avs_register_hda_board(adev, codec);
468 if (ret < 0)
469 dev_warn(adev->dev, "register hda-%08x failed: %d\n",
470 codec->core.vendor_id, ret);
471 }
472
473 return 0;
474}
475
476int avs_register_all_boards(struct avs_dev *adev)
477{
478 int ret;
479
480 ret = avs_register_dmic_board(adev);
481 if (ret < 0)
482 dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
483 ret);
484
485 ret = avs_register_i2s_boards(adev);
486 if (ret < 0)
487 dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n",
488 ret);
489
490 ret = avs_register_hda_boards(adev);
491 if (ret < 0)
492 dev_warn(adev->dev, "enumerate HDA endpoints failed: %d\n",
493 ret);
494
495 return 0;
496}
497
498void avs_unregister_all_boards(struct avs_dev *adev)
499{
500 snd_soc_unregister_component(adev->dev);
501}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t