Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/intel/avs/board_selection.c
29270 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
//
3
// Copyright(c) 2021-2022 Intel Corporation
4
//
5
// Authors: Cezary Rojewski <[email protected]>
6
// Amadeusz Slawinski <[email protected]>
7
//
8
9
#include <linux/acpi.h>
10
#include <linux/module.h>
11
#include <linux/dmi.h>
12
#include <linux/pci.h>
13
#include <acpi/nhlt.h>
14
#include <linux/platform_device.h>
15
#include <sound/hda_codec.h>
16
#include <sound/hda_register.h>
17
#include <sound/soc-acpi.h>
18
#include <sound/soc-component.h>
19
#include "avs.h"
20
#include "debug.h"
21
#include "pcm.h"
22
#include "utils.h"
23
24
static char *i2s_test;
25
module_param(i2s_test, charp, 0444);
26
MODULE_PARM_DESC(i2s_test, "Use I2S test-board instead of ACPI, i2s_test=ssp0tdm,ssp1tdm,... 0 to ignore port");
27
28
bool obsolete_card_names = IS_ENABLED(CONFIG_SND_SOC_INTEL_AVS_CARDNAME_OBSOLETE);
29
module_param_named(obsolete_card_names, obsolete_card_names, bool, 0444);
30
MODULE_PARM_DESC(obsolete_card_names, "Use obsolete card names 0=no, 1=yes");
31
32
static const struct dmi_system_id kbl_dmi_table[] = {
33
{
34
.matches = {
35
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
36
DMI_MATCH(DMI_BOARD_NAME, "Skylake Y LPDDR3 RVP3"),
37
},
38
},
39
{
40
.matches = {
41
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
42
DMI_MATCH(DMI_BOARD_NAME, "AmberLake Y"),
43
},
44
},
45
{}
46
};
47
48
static const struct dmi_system_id kblr_dmi_table[] = {
49
{
50
.matches = {
51
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
52
DMI_MATCH(DMI_BOARD_NAME, "Kabylake R DDR4 RVP"),
53
},
54
},
55
{}
56
};
57
58
static struct snd_soc_acpi_mach *dmi_match_quirk(void *arg)
59
{
60
struct snd_soc_acpi_mach *mach = arg;
61
struct dmi_system_id *dmi_table;
62
63
dmi_table = (struct dmi_system_id *)mach->quirk_data;
64
65
if (!dmi_table || dmi_first_match(dmi_table))
66
return mach;
67
return NULL;
68
}
69
70
#define AVS_SSP(x) (BIT(x))
71
#define AVS_SSP_RANGE(a, b) (GENMASK(b, a))
72
73
/* supported I2S board codec configurations */
74
static struct snd_soc_acpi_mach avs_skl_i2s_machines[] = {
75
{
76
.id = "INT343A",
77
.drv_name = "avs_rt286",
78
.mach_params = {
79
.i2s_link_mask = AVS_SSP(0),
80
},
81
.tplg_filename = "rt286-tplg.bin",
82
},
83
{
84
.id = "10508825",
85
.drv_name = "avs_nau8825",
86
.mach_params = {
87
.i2s_link_mask = AVS_SSP(1),
88
},
89
.tplg_filename = "nau8825-tplg.bin",
90
},
91
{
92
.id = "INT343B",
93
.drv_name = "avs_ssm4567",
94
.mach_params = {
95
.i2s_link_mask = AVS_SSP(0),
96
},
97
.tplg_filename = "ssm4567-tplg.bin",
98
},
99
{
100
.id = "MX98357A",
101
.drv_name = "avs_max98357a",
102
.mach_params = {
103
.i2s_link_mask = AVS_SSP(0),
104
},
105
.tplg_filename = "max98357a-tplg.bin",
106
},
107
{},
108
};
109
110
static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
111
{
112
.id = "INT343A",
113
.drv_name = "avs_rt286",
114
.mach_params = {
115
.i2s_link_mask = AVS_SSP(0),
116
},
117
.quirk_data = &kbl_dmi_table,
118
.machine_quirk = dmi_match_quirk,
119
.tplg_filename = "rt286-tplg.bin",
120
},
121
{
122
.id = "INT343A",
123
.drv_name = "avs_rt298",
124
.mach_params = {
125
.i2s_link_mask = AVS_SSP(0),
126
},
127
.quirk_data = &kblr_dmi_table,
128
.machine_quirk = dmi_match_quirk,
129
.tplg_filename = "rt298-tplg.bin",
130
},
131
{
132
.id = "MX98927",
133
.drv_name = "avs_max98927",
134
.mach_params = {
135
.i2s_link_mask = AVS_SSP(0),
136
},
137
.tplg_filename = "max98927-tplg.bin",
138
},
139
{
140
.id = "10EC5514",
141
.drv_name = "avs_rt5514",
142
.mach_params = {
143
.i2s_link_mask = AVS_SSP(0),
144
},
145
.pdata = (struct avs_mach_pdata[]){ { .tdms = (unsigned long[]){ 0x2 } } },
146
.tplg_filename = "rt5514-tplg.bin",
147
},
148
{
149
.id = "10EC5663",
150
.drv_name = "avs_rt5663",
151
.mach_params = {
152
.i2s_link_mask = AVS_SSP(1),
153
},
154
.tplg_filename = "rt5663-tplg.bin",
155
},
156
{
157
.id = "MX98373",
158
.drv_name = "avs_max98373",
159
.mach_params = {
160
.i2s_link_mask = AVS_SSP(0),
161
},
162
.tplg_filename = "max98373-tplg.bin",
163
},
164
{
165
.id = "MX98357A",
166
.drv_name = "avs_max98357a",
167
.mach_params = {
168
.i2s_link_mask = AVS_SSP(0),
169
},
170
.tplg_filename = "max98357a-tplg.bin",
171
},
172
{
173
.id = "DLGS7219",
174
.drv_name = "avs_da7219",
175
.mach_params = {
176
.i2s_link_mask = AVS_SSP(1),
177
},
178
.tplg_filename = "da7219-tplg.bin",
179
},
180
{
181
.id = "ESSX8336",
182
.drv_name = "avs_es8336",
183
.mach_params = {
184
.i2s_link_mask = AVS_SSP(0),
185
},
186
.tplg_filename = "es8336-tplg.bin",
187
},
188
{},
189
};
190
191
static struct snd_soc_acpi_mach avs_apl_i2s_machines[] = {
192
{
193
.id = "INT343A",
194
.drv_name = "avs_rt298",
195
.mach_params = {
196
.i2s_link_mask = AVS_SSP(5),
197
},
198
.tplg_filename = "rt298-tplg.bin",
199
},
200
{
201
.id = "INT34C3",
202
.drv_name = "avs_tdf8532",
203
.mach_params = {
204
.i2s_link_mask = AVS_SSP_RANGE(0, 5),
205
},
206
.pdata = (struct avs_mach_pdata[]){ {
207
.tdms = (unsigned long[]){ 0x1, 0x1, 0x14, 0x1, 0x1, 0x1 }
208
} },
209
.tplg_filename = "tdf8532-tplg.bin",
210
},
211
{
212
.id = "MX98357A",
213
.drv_name = "avs_max98357a",
214
.mach_params = {
215
.i2s_link_mask = AVS_SSP(5),
216
},
217
.tplg_filename = "max98357a-tplg.bin",
218
},
219
{
220
.id = "DLGS7219",
221
.drv_name = "avs_da7219",
222
.mach_params = {
223
.i2s_link_mask = AVS_SSP(1),
224
},
225
.tplg_filename = "da7219-tplg.bin",
226
},
227
{},
228
};
229
230
static struct snd_soc_acpi_mach avs_gml_i2s_machines[] = {
231
{
232
.id = "INT343A",
233
.drv_name = "avs_rt298",
234
.mach_params = {
235
.i2s_link_mask = AVS_SSP(2),
236
},
237
.tplg_filename = "rt298-tplg.bin",
238
},
239
{},
240
};
241
242
static struct snd_soc_acpi_mach avs_cnl_i2s_machines[] = {
243
{
244
.id = "INT34C2",
245
.drv_name = "avs_rt274",
246
.mach_params = {
247
.i2s_link_mask = AVS_SSP(0),
248
},
249
.tplg_filename = "rt274-tplg.bin",
250
},
251
{
252
.id = "10EC5682",
253
.drv_name = "avs_rt5682",
254
.mach_params = {
255
.i2s_link_mask = AVS_SSP(1),
256
},
257
.tplg_filename = "rt5682-tplg.bin",
258
},
259
{},
260
};
261
262
static struct snd_soc_acpi_mach avs_icl_i2s_machines[] = {
263
{
264
.id = "INT343A",
265
.drv_name = "avs_rt298",
266
.mach_params = {
267
.i2s_link_mask = AVS_SSP(0),
268
},
269
.tplg_filename = "rt298-tplg.bin",
270
},
271
{
272
.id = "INT34C2",
273
.drv_name = "avs_rt274",
274
.mach_params = {
275
.i2s_link_mask = AVS_SSP(0),
276
},
277
.tplg_filename = "rt274-tplg.bin",
278
},
279
{},
280
};
281
282
static struct snd_soc_acpi_mach avs_tgl_i2s_machines[] = {
283
{
284
.id = "INT34C2",
285
.drv_name = "avs_rt274",
286
.mach_params = {
287
.i2s_link_mask = AVS_SSP(0),
288
},
289
.tplg_filename = "rt274-tplg.bin",
290
},
291
{
292
.id = "10EC0298",
293
.drv_name = "avs_rt298",
294
.mach_params = {
295
.i2s_link_mask = AVS_SSP(0),
296
},
297
.tplg_filename = "rt298-tplg.bin",
298
},
299
{
300
.id = "10EC1308",
301
.drv_name = "avs_rt1308",
302
.mach_params = {
303
.i2s_link_mask = AVS_SSP(1),
304
},
305
.tplg_filename = "rt1308-tplg.bin",
306
},
307
{
308
.id = "10EC5640",
309
.uid = "1",
310
.drv_name = "avs_rt5640",
311
.mach_params = {
312
.i2s_link_mask = AVS_SSP(0),
313
},
314
.tplg_filename = "rt5640-tplg.bin",
315
},
316
{
317
.id = "10EC5640",
318
.uid = "3",
319
.drv_name = "avs_rt5640",
320
.mach_params = {
321
.i2s_link_mask = AVS_SSP(1),
322
},
323
.tplg_filename = "rt5640-tplg.bin",
324
},
325
{
326
.id = "10EC5640",
327
.uid = "2",
328
.drv_name = "avs_rt5640",
329
.mach_params = {
330
.i2s_link_mask = AVS_SSP(2),
331
},
332
.tplg_filename = "rt5640-tplg.bin",
333
},
334
{
335
.id = "ESSX8336",
336
.drv_name = "avs_es8336",
337
.mach_params = {
338
.i2s_link_mask = AVS_SSP(0),
339
},
340
.tplg_filename = "es8336-tplg.bin",
341
},
342
{},
343
};
344
345
static struct snd_soc_acpi_mach avs_mbl_i2s_machines[] = {
346
{
347
.id = "PCM3168A",
348
.drv_name = "avs_pcm3168a",
349
.mach_params = {
350
.i2s_link_mask = AVS_SSP(0) | AVS_SSP(2),
351
},
352
.tplg_filename = "pcm3168a-tplg.bin",
353
},
354
{}
355
};
356
357
struct avs_acpi_boards {
358
int id;
359
struct snd_soc_acpi_mach *machs;
360
};
361
362
#define AVS_MACH_ENTRY(_id, _mach) \
363
{ .id = PCI_DEVICE_ID_INTEL_##_id, .machs = (_mach), }
364
365
/* supported I2S boards per platform */
366
static const struct avs_acpi_boards i2s_boards[] = {
367
AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines),
368
AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines),
369
AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines),
370
AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines),
371
AVS_MACH_ENTRY(HDA_CNL_LP, avs_cnl_i2s_machines),
372
AVS_MACH_ENTRY(HDA_CNL_H, avs_cnl_i2s_machines),
373
AVS_MACH_ENTRY(HDA_CML_LP, avs_cnl_i2s_machines),
374
AVS_MACH_ENTRY(HDA_ICL_LP, avs_icl_i2s_machines),
375
AVS_MACH_ENTRY(HDA_TGL_LP, avs_tgl_i2s_machines),
376
AVS_MACH_ENTRY(HDA_EHL_0, avs_tgl_i2s_machines),
377
AVS_MACH_ENTRY(HDA_ADL_N, avs_mbl_i2s_machines),
378
AVS_MACH_ENTRY(HDA_ADL_P, avs_tgl_i2s_machines),
379
AVS_MACH_ENTRY(HDA_RPL_P_0, avs_tgl_i2s_machines),
380
AVS_MACH_ENTRY(HDA_RPL_M, avs_mbl_i2s_machines),
381
AVS_MACH_ENTRY(HDA_FCL, avs_tgl_i2s_machines),
382
{ },
383
};
384
385
static struct snd_soc_acpi_mach *avs_get_i2s_machines(struct avs_dev *adev)
386
{
387
int id, i;
388
389
id = adev->base.pci->device;
390
for (i = 0; i < ARRAY_SIZE(i2s_boards); i++)
391
if (i2s_boards[i].id == id)
392
return i2s_boards[i].machs;
393
return NULL;
394
}
395
396
/* Platform devices spawned by AVS driver are removed with this hook. */
397
static void avs_unregister_board(void *pdev)
398
{
399
platform_device_unregister(pdev);
400
}
401
402
static struct platform_device *avs_register_board(struct avs_dev *adev, const char *name,
403
const void *data, size_t size)
404
{
405
struct platform_device *pdev;
406
int ret;
407
408
pdev = platform_device_register_data(NULL, name, PLATFORM_DEVID_AUTO, data, size);
409
if (IS_ERR(pdev))
410
return pdev;
411
412
ret = devm_add_action_or_reset(adev->dev, avs_unregister_board, pdev);
413
if (ret)
414
return ERR_PTR(ret);
415
416
return pdev;
417
}
418
419
static struct platform_device *avs_register_board_pdata(struct avs_dev *adev, const char *name,
420
struct snd_soc_acpi_mach *mach,
421
struct hda_codec *codec,
422
unsigned long *tdms, char *codec_name)
423
{
424
struct avs_mach_pdata *pdata;
425
426
pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL);
427
if (!pdata)
428
return ERR_PTR(-ENOMEM);
429
430
pdata->codec = codec;
431
pdata->tdms = tdms;
432
pdata->codec_name = codec_name;
433
pdata->obsolete_card_names = obsolete_card_names;
434
mach->pdata = pdata;
435
436
return avs_register_board(adev, name, mach, sizeof(*mach));
437
}
438
439
static int __maybe_unused avs_register_probe_board(struct avs_dev *adev)
440
{
441
struct platform_device *pdev;
442
443
pdev = avs_register_board(adev, "avs_probe_mb", NULL, 0);
444
if (IS_ERR(pdev))
445
return PTR_ERR(pdev);
446
447
return avs_register_probe_component(adev, dev_name(&pdev->dev));
448
}
449
450
static int avs_register_dmic_board(struct avs_dev *adev)
451
{
452
static struct snd_soc_acpi_mach mach = {
453
.tplg_filename = "dmic-tplg.bin",
454
};
455
struct platform_device *pdev;
456
char *codec_name;
457
458
if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) {
459
dev_dbg(adev->dev, "no DMIC endpoints present\n");
460
return 0;
461
}
462
463
/* DMIC present in Intel PCH is enumerated statically. */
464
pdev = avs_register_board(adev, "dmic-codec", NULL, 0);
465
if (IS_ERR(pdev))
466
return PTR_ERR(pdev);
467
468
codec_name = devm_kstrdup(adev->dev, dev_name(&pdev->dev), GFP_KERNEL);
469
if (!codec_name)
470
return -ENOMEM;
471
472
pdev = avs_register_board_pdata(adev, "avs_dmic", &mach, NULL, NULL, codec_name);
473
if (IS_ERR(pdev))
474
return PTR_ERR(pdev);
475
476
return avs_register_dmic_component(adev, dev_name(&pdev->dev));
477
}
478
479
static int avs_register_i2s_test_board(struct avs_dev *adev, int ssp_port, int tdm_slot)
480
{
481
struct snd_soc_acpi_mach mach = {{0}};
482
struct platform_device *pdev;
483
unsigned long *tdms;
484
485
tdms = devm_kcalloc(adev->dev, ssp_port + 1, sizeof(*tdms), GFP_KERNEL);
486
mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL,
487
AVS_STRING_FMT("i2s", "-test-tplg.bin",
488
ssp_port, tdm_slot));
489
if (!tdms || !mach.tplg_filename)
490
return -ENOMEM;
491
492
tdms[ssp_port] = BIT(tdm_slot);
493
mach.drv_name = "avs_i2s_test";
494
mach.mach_params.i2s_link_mask = AVS_SSP(ssp_port);
495
496
pdev = avs_register_board_pdata(adev, mach.drv_name, &mach, NULL, tdms, NULL);
497
if (IS_ERR(pdev))
498
return PTR_ERR(pdev);
499
500
return avs_register_i2s_component(adev, dev_name(&pdev->dev), AVS_SSP(ssp_port), tdms);
501
}
502
503
static int avs_register_i2s_test_boards(struct avs_dev *adev)
504
{
505
int max_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
506
int ssp_port, tdm_slot, ret;
507
unsigned long tdm_slots;
508
u32 *array, num_elems;
509
510
if (!i2s_test)
511
return 0;
512
513
ret = parse_int_array(i2s_test, strlen(i2s_test), (int **)&array);
514
if (ret) {
515
dev_err(adev->dev, "failed to parse i2s_test parameter\n");
516
return ret;
517
}
518
519
num_elems = *array;
520
if (num_elems > max_ssps) {
521
dev_err(adev->dev, "board supports only %d SSP, %d specified\n",
522
max_ssps, num_elems);
523
return -EINVAL;
524
}
525
526
for (ssp_port = 0; ssp_port < num_elems; ssp_port++) {
527
tdm_slots = array[1 + ssp_port];
528
for_each_set_bit(tdm_slot, &tdm_slots, 16) {
529
ret = avs_register_i2s_test_board(adev, ssp_port, tdm_slot);
530
if (ret)
531
return ret;
532
}
533
}
534
535
return 0;
536
}
537
538
static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
539
{
540
u32 i2s_mask = mach->mach_params.i2s_link_mask;
541
struct platform_device *pdev;
542
unsigned long *tdms = NULL;
543
544
if (mach->pdata)
545
tdms = ((struct avs_mach_pdata *)mach->pdata)->tdms;
546
547
pdev = avs_register_board_pdata(adev, mach->drv_name, mach, NULL, tdms, NULL);
548
if (IS_ERR(pdev))
549
return PTR_ERR(pdev);
550
551
return avs_register_i2s_component(adev, dev_name(&pdev->dev), i2s_mask, tdms);
552
}
553
554
static int avs_register_i2s_boards(struct avs_dev *adev)
555
{
556
int num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
557
struct snd_soc_acpi_mach *machs;
558
struct snd_soc_acpi_mach *mach;
559
int ret;
560
561
if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_SSP, -1, -1, -1)) {
562
dev_dbg(adev->dev, "no I2S endpoints present\n");
563
return 0;
564
}
565
566
machs = avs_get_i2s_machines(adev);
567
if (!machs) {
568
dev_dbg(adev->dev, "no I2S endpoints supported\n");
569
return 0;
570
}
571
572
for (mach = machs; mach->id[0]; mach++) {
573
if (!acpi_dev_present(mach->id, mach->uid, -1))
574
continue;
575
576
if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
577
dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
578
num_ssps, mach->drv_name,
579
(unsigned long)__fls(mach->mach_params.i2s_link_mask));
580
continue;
581
}
582
if (mach->machine_quirk)
583
if (!mach->machine_quirk(mach))
584
continue;
585
586
ret = avs_register_i2s_board(adev, mach);
587
if (ret < 0)
588
dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret);
589
}
590
591
return 0;
592
}
593
594
static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec)
595
{
596
struct hdac_device *hdev = &codec->core;
597
struct snd_soc_acpi_mach mach = {{0}};
598
struct platform_device *pdev;
599
600
mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin",
601
hdev->vendor_id);
602
if (!mach.tplg_filename)
603
return -ENOMEM;
604
605
pdev = avs_register_board_pdata(adev, "avs_hdaudio", &mach, codec, NULL, NULL);
606
if (IS_ERR(pdev))
607
return PTR_ERR(pdev);
608
609
return avs_register_hda_component(adev, dev_name(&pdev->dev));
610
}
611
612
static int avs_register_hda_boards(struct avs_dev *adev)
613
{
614
struct hdac_bus *bus = &adev->base.core;
615
struct hdac_device *hdev;
616
int ret;
617
618
if (!bus->num_codecs) {
619
dev_dbg(adev->dev, "no HDA endpoints present\n");
620
return 0;
621
}
622
623
list_for_each_entry(hdev, &bus->codec_list, list) {
624
struct hda_codec *codec;
625
626
codec = dev_to_hda_codec(&hdev->dev);
627
628
ret = avs_register_hda_board(adev, codec);
629
if (ret < 0)
630
dev_warn(adev->dev, "register hda-%08x failed: %d\n",
631
codec->core.vendor_id, ret);
632
}
633
634
return 0;
635
}
636
637
int avs_register_all_boards(struct avs_dev *adev)
638
{
639
int ret;
640
641
#ifdef CONFIG_DEBUG_FS
642
ret = avs_register_probe_board(adev);
643
if (ret < 0)
644
dev_warn(adev->dev, "enumerate PROBE endpoints failed: %d\n", ret);
645
#endif
646
647
ret = avs_register_dmic_board(adev);
648
if (ret < 0)
649
dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
650
ret);
651
652
ret = avs_register_i2s_test_boards(adev);
653
if (ret)
654
dev_dbg(adev->dev, "enumerate I2S TEST endpoints failed: %d\n", ret);
655
656
ret = avs_register_i2s_boards(adev);
657
if (ret < 0)
658
dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n",
659
ret);
660
661
ret = avs_register_hda_boards(adev);
662
if (ret < 0)
663
dev_warn(adev->dev, "enumerate HDA endpoints failed: %d\n",
664
ret);
665
666
return 0;
667
}
668
669
void avs_unregister_all_boards(struct avs_dev *adev)
670
{
671
snd_soc_unregister_component(adev->dev);
672
}
673
674