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 
dmi_match_quirk(void * arg)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 
avs_get_i2s_boards(struct avs_dev * adev)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 */
board_pdev_unregister(void * data)267 static void board_pdev_unregister(void *data)
268 {
269 	platform_device_unregister(data);
270 }
271 
avs_register_dmic_board(struct avs_dev * adev)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 
avs_register_i2s_board(struct avs_dev * adev,struct snd_soc_acpi_mach * mach)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,
330 			(unsigned long)__fls(mach->mach_params.i2s_link_mask));
331 		return -ENODEV;
332 	}
333 
334 	name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name,
335 			      mach->mach_params.i2s_link_mask);
336 	if (!name)
337 		return -ENOMEM;
338 
339 	ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, mach->pdata);
340 	if (ret < 0)
341 		return ret;
342 
343 	mach->mach_params.platform = name;
344 
345 	board = platform_device_register_data(NULL, mach->drv_name, mach->mach_params.i2s_link_mask,
346 					      (const void *)mach, sizeof(*mach));
347 	if (IS_ERR(board)) {
348 		dev_err(adev->dev, "ssp board register failed\n");
349 		return PTR_ERR(board);
350 	}
351 
352 	ret = devm_add_action(adev->dev, board_pdev_unregister, board);
353 	if (ret < 0) {
354 		platform_device_unregister(board);
355 		return ret;
356 	}
357 
358 	return 0;
359 }
360 
avs_register_i2s_boards(struct avs_dev * adev)361 static int avs_register_i2s_boards(struct avs_dev *adev)
362 {
363 	const struct avs_acpi_boards *boards;
364 	struct snd_soc_acpi_mach *mach;
365 	int ret;
366 
367 	if (!adev->nhlt || !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_SSP)) {
368 		dev_dbg(adev->dev, "no I2S endpoints present\n");
369 		return 0;
370 	}
371 
372 	if (i2s_test) {
373 		int i, num_ssps;
374 
375 		num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
376 		/* constrain just in case FW says there can be more SSPs than possible */
377 		num_ssps = min_t(int, ARRAY_SIZE(avs_test_i2s_machines), num_ssps);
378 
379 		mach = avs_test_i2s_machines;
380 
381 		for (i = 0; i < num_ssps; i++) {
382 			ret = avs_register_i2s_board(adev, &mach[i]);
383 			if (ret < 0)
384 				dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name,
385 					 ret);
386 		}
387 		return 0;
388 	}
389 
390 	boards = avs_get_i2s_boards(adev);
391 	if (!boards) {
392 		dev_dbg(adev->dev, "no I2S endpoints supported\n");
393 		return 0;
394 	}
395 
396 	for (mach = boards->machs; mach->id[0]; mach++) {
397 		if (!acpi_dev_present(mach->id, NULL, -1))
398 			continue;
399 
400 		if (mach->machine_quirk)
401 			if (!mach->machine_quirk(mach))
402 				continue;
403 
404 		ret = avs_register_i2s_board(adev, mach);
405 		if (ret < 0)
406 			dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret);
407 	}
408 
409 	return 0;
410 }
411 
avs_register_hda_board(struct avs_dev * adev,struct hda_codec * codec)412 static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec)
413 {
414 	struct snd_soc_acpi_mach mach = {{0}};
415 	struct platform_device *board;
416 	struct hdac_device *hdev = &codec->core;
417 	char *pname;
418 	int ret, id;
419 
420 	pname = devm_kasprintf(adev->dev, GFP_KERNEL, "%s-platform", dev_name(&hdev->dev));
421 	if (!pname)
422 		return -ENOMEM;
423 
424 	ret = avs_hda_platform_register(adev, pname);
425 	if (ret < 0)
426 		return ret;
427 
428 	mach.pdata = codec;
429 	mach.mach_params.platform = pname;
430 	mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin",
431 					    hdev->vendor_id);
432 	if (!mach.tplg_filename)
433 		return -ENOMEM;
434 
435 	id = adev->base.core.idx * HDA_MAX_CODECS + hdev->addr;
436 	board = platform_device_register_data(NULL, "avs_hdaudio", id, (const void *)&mach,
437 					      sizeof(mach));
438 	if (IS_ERR(board)) {
439 		dev_err(adev->dev, "hda board register failed\n");
440 		return PTR_ERR(board);
441 	}
442 
443 	ret = devm_add_action(adev->dev, board_pdev_unregister, board);
444 	if (ret < 0) {
445 		platform_device_unregister(board);
446 		return ret;
447 	}
448 
449 	return 0;
450 }
451 
avs_register_hda_boards(struct avs_dev * adev)452 static int avs_register_hda_boards(struct avs_dev *adev)
453 {
454 	struct hdac_bus *bus = &adev->base.core;
455 	struct hdac_device *hdev;
456 	int ret;
457 
458 	if (!bus->num_codecs) {
459 		dev_dbg(adev->dev, "no HDA endpoints present\n");
460 		return 0;
461 	}
462 
463 	list_for_each_entry(hdev, &bus->codec_list, list) {
464 		struct hda_codec *codec;
465 
466 		codec = dev_to_hda_codec(&hdev->dev);
467 
468 		ret = avs_register_hda_board(adev, codec);
469 		if (ret < 0)
470 			dev_warn(adev->dev, "register hda-%08x failed: %d\n",
471 				 codec->core.vendor_id, ret);
472 	}
473 
474 	return 0;
475 }
476 
avs_register_all_boards(struct avs_dev * adev)477 int avs_register_all_boards(struct avs_dev *adev)
478 {
479 	int ret;
480 
481 	ret = avs_register_dmic_board(adev);
482 	if (ret < 0)
483 		dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
484 			 ret);
485 
486 	ret = avs_register_i2s_boards(adev);
487 	if (ret < 0)
488 		dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n",
489 			 ret);
490 
491 	ret = avs_register_hda_boards(adev);
492 	if (ret < 0)
493 		dev_warn(adev->dev, "enumerate HDA endpoints failed: %d\n",
494 			 ret);
495 
496 	return 0;
497 }
498 
avs_unregister_all_boards(struct avs_dev * adev)499 void avs_unregister_all_boards(struct avs_dev *adev)
500 {
501 	snd_soc_unregister_component(adev->dev);
502 }
503