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 @@
11 # SPDX-License-Identifier: GPL-2.0-only
22
33 snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \
4− topology.o path.o pcm.o
4+ topology.o path.o pcm.o board_selection.o
55 snd-soc-avs-objs += cldma.o
66
77 snd-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
310310 unsigned long *tdms);
311311 int avs_hda_platform_register(struct avs_dev *adev, const char *name);
312312
313+int avs_register_all_boards(struct avs_dev *adev);
314+void avs_unregister_all_boards(struct avs_dev *adev);
315+
313316 /* Firmware tracing helpers */
314317
315318 unsigned 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+
21+static bool i2s_test;
22+module_param(i2s_test, bool, 0444);
23+MODULE_PARM_DESC(i2s_test, "Probe I2S test-board and skip all other I2S boards");
24+
25+static 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+
35+static 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+
45+static 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 */
67+static 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+
103+static 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+
143+static 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+
180+static 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+
192+static 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+
238+struct 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 */
247+static 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+
255+static 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 */
267+static void board_pdev_unregister(void *data)
268+{
269+ platform_device_unregister(data);
270+}
271+
272+static 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+
319+static 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+
360+static 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+
411+static 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+
451+static 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+
476+int 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+
498+void 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