Skip to content

Commit 133b10f

Browse files
committed
ASoC: SOF: Intel: use sof_sdw as default SDW machine driver
If there is no SoundWire machine matches the existing acpi match table, get the required machine date from the acpi table and construct the link adrs and endpoints. Pass the data to the default Intel SoundWire machine driver. And we don't need to add new item to the acpi match table in common cases. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
1 parent 3ea7ccc commit 133b10f

1 file changed

Lines changed: 182 additions & 2 deletions

File tree

sound/soc/sof/intel/hda.c

Lines changed: 182 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@
2626
#include <sound/intel-dsp-config.h>
2727
#include <sound/intel-nhlt.h>
2828
#include <sound/soc-acpi-intel-ssp-common.h>
29+
#include <sound/soc_sdw_utils.h>
2930
#include <sound/sof.h>
3031
#include <sound/sof/xtensa.h>
3132
#include <sound/hda-mlink.h>
3233
#include "../sof-audio.h"
3334
#include "../sof-pci-dev.h"
3435
#include "../ops.h"
3536
#include "../ipc4-topology.h"
37+
#include "../../intel/common/sof-function-topology-lib.h"
3638
#include "hda.h"
3739

3840
#include <trace/events/sof_intel.h>
@@ -1117,14 +1119,144 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
11171119

11181120
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
11191121

1122+
static bool is_endpoint_present(struct sdw_slave *sdw_device,
1123+
struct asoc_sdw_codec_info *dai_info, int dai_type)
1124+
{
1125+
int i;
1126+
1127+
for (i = 0; i < sdw_device->sdca_data.num_functions; i++) {
1128+
if (dai_type == dai_info->dais[i].dai_type)
1129+
return true;
1130+
}
1131+
dev_dbg(&sdw_device->dev, "Endpoint DAI type %d not found\n", dai_type);
1132+
return false;
1133+
}
1134+
1135+
static struct snd_soc_acpi_adr_device *find_acpi_adr_device(struct device *dev,
1136+
struct sdw_slave *sdw_device,
1137+
struct snd_soc_acpi_link_adr *link,
1138+
int *amp_index)
1139+
{
1140+
struct snd_soc_acpi_adr_device *adr_dev;
1141+
int index = link->num_adr;
1142+
int ep_index = 0;
1143+
int i, j;
1144+
1145+
link->mask = BIT(sdw_device->bus->link_id);
1146+
/* index is 0 based, we need allocate index + 1 for the array size */
1147+
if (!index)
1148+
adr_dev = devm_kzalloc(dev, sizeof(*adr_dev), GFP_KERNEL);
1149+
else
1150+
adr_dev = devm_krealloc(dev, (struct snd_soc_acpi_adr_device *)link->adr_d,
1151+
(index + 1) * sizeof(*adr_dev), GFP_KERNEL);
1152+
1153+
if (!adr_dev)
1154+
return NULL;
1155+
1156+
for (i = 0; i < asoc_sdw_get_codec_info_list_count(); i++) {
1157+
if (sdw_device->id.part_id != codec_info_list[i].part_id)
1158+
continue;
1159+
1160+
int amp_group_id = 1;
1161+
1162+
adr_dev[index].endpoints =
1163+
devm_kzalloc(dev, codec_info_list[i].dai_num *
1164+
sizeof(struct snd_soc_acpi_endpoint), GFP_KERNEL);
1165+
1166+
/* Get name_prefix from codec_info_list[] */
1167+
adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s",
1168+
codec_info_list[i].name_prefix);
1169+
for (j = 0; j < codec_info_list[i].dai_num; j++) {
1170+
/* Check if the endpoint is present by the SDCA DisCo table */
1171+
if (!is_endpoint_present(sdw_device, &codec_info_list[i],
1172+
codec_info_list[i].dais[j].dai_type))
1173+
continue;
1174+
1175+
adr_dev[index].endpoints[ep_index].num = ep_index;
1176+
if (codec_info_list[i].dais[j].dai_type == SOC_SDW_DAI_TYPE_AMP) {
1177+
/* Assume all amp are aggregated */
1178+
adr_dev[index].endpoints[ep_index].aggregated = 1;
1179+
adr_dev[index].endpoints[ep_index].group_id = amp_group_id;
1180+
adr_dev[index].endpoints[ep_index].group_position = *amp_index;
1181+
/* Set group id = 2 for feedback capture endpoint */
1182+
amp_group_id++;
1183+
} else {
1184+
adr_dev[index].endpoints[ep_index].aggregated = 0;
1185+
adr_dev[index].endpoints[ep_index].group_id = 0;
1186+
adr_dev[index].endpoints[ep_index].group_position = 0;
1187+
}
1188+
ep_index++;
1189+
}
1190+
adr_dev[index].num_endpoints = ep_index;
1191+
break;
1192+
}
1193+
1194+
if (i == asoc_sdw_get_codec_info_list_count()) {
1195+
dev_err(dev, "part id %#x is not supported\n", sdw_device->id.part_id);
1196+
return NULL;
1197+
}
1198+
1199+
adr_dev[index].adr = ((u64)sdw_device->id.class_id & 0xFF) |
1200+
((u64)sdw_device->id.part_id & 0xFFFF) << 8 |
1201+
((u64)sdw_device->id.mfg_id & 0xFFFF) << 24 |
1202+
((u64)(sdw_device->id.unique_id & 0xF) << 40) |
1203+
((u64)(sdw_device->id.sdw_version & 0xF) << 44) |
1204+
((u64)(sdw_device->bus->link_id & 0xF) << 48);
1205+
1206+
/*
1207+
* The name_prefix comes from codec_info_list which has a name_prefix per codec.
1208+
* And we need to give a unique name_prefix for each amp and should be backwards
1209+
* compatible to the existing acpi match tables to not break existing UCMs.
1210+
* For the "AMP" name_prefix, we append the amp index to it. However, for the
1211+
* "Left" name_prefix, we convert the second amp name_prefix to "Right" and
1212+
* for the third and further amps, we set the name_prefix to "AMP<amp_index>".
1213+
*/
1214+
if (!strcmp(adr_dev[index].name_prefix, "AMP")) {
1215+
adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
1216+
adr_dev[index].name_prefix,
1217+
*amp_index);
1218+
if (!adr_dev[index].name_prefix)
1219+
return NULL;
1220+
(*amp_index)++;
1221+
}
1222+
1223+
if (!strcmp(adr_dev[index].name_prefix, "Left")) {
1224+
/* Convert the second amp name_prefix to Right */
1225+
if ((*amp_index) == 2) {
1226+
adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL,
1227+
"%s", "Right");
1228+
if (!adr_dev[index].name_prefix)
1229+
return NULL;
1230+
}
1231+
/* Set the name_fix to AMP<amp_index> if there are more than 2 amps */
1232+
if (*amp_index > 2) {
1233+
adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
1234+
"AMP", *amp_index);
1235+
if (!adr_dev[index].name_prefix)
1236+
return NULL;
1237+
}
1238+
(*amp_index)++;
1239+
}
1240+
1241+
dev_dbg(dev, "adr[%d] 0x%llx link id %d name_prefix \"%s\" is found\n",
1242+
index, adr_dev[index].adr, sdw_device->bus->link_id, adr_dev[index].name_prefix);
1243+
1244+
link->num_adr++;
1245+
1246+
return adr_dev;
1247+
}
1248+
11201249
static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev)
11211250
{
11221251
struct snd_sof_pdata *pdata = sdev->pdata;
11231252
struct snd_soc_acpi_link_adr *link;
1253+
struct snd_soc_acpi_link_adr *links;
11241254
struct sdw_peripherals *peripherals;
11251255
struct snd_soc_acpi_mach *mach;
11261256
struct sof_intel_hda_dev *hdev;
1127-
u32 link_mask;
1257+
int link_index, link_num;
1258+
int amp_index = 1;
1259+
u32 link_mask = 0;
11281260
int i;
11291261

11301262
hdev = pdata->hw_pdata;
@@ -1201,7 +1333,54 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
12011333
peripherals->array[i]->id.part_id,
12021334
peripherals->array[i]->id.sdw_version);
12031335

1204-
return NULL;
1336+
if (!peripherals->num_peripherals)
1337+
return NULL;
1338+
1339+
/* Create default SDW mach */
1340+
mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
1341+
if (!mach)
1342+
return NULL;
1343+
1344+
/* Get link mask and link number */
1345+
for (i = 0; i < peripherals->num_peripherals; i++)
1346+
link_mask |= BIT(peripherals->array[i]->bus->link_id);
1347+
1348+
link_num = hweight32(link_mask);
1349+
links = devm_kcalloc(sdev->dev, link_num, sizeof(*links), GFP_KERNEL);
1350+
if (!links)
1351+
return NULL;
1352+
1353+
link_index = 0;
1354+
/* Generate snd_soc_acpi_link_adr struct for each peripheral reported by the ACPI table */
1355+
for (i = 0; i < peripherals->num_peripherals; i++) {
1356+
links[link_index].adr_d = find_acpi_adr_device(sdev->dev, peripherals->array[i],
1357+
&links[link_index], &amp_index);
1358+
1359+
/*
1360+
* Only increase the link_index when the next periperal is on a different link.
1361+
* Assume that peripherals are grouped by link_id in the ACPI table.
1362+
*/
1363+
if (i < peripherals->num_peripherals - 1 &&
1364+
peripherals->array[i + 1]->bus->link_id != peripherals->array[i]->bus->link_id)
1365+
link_index++;
1366+
1367+
if (link_index > link_num) {
1368+
dev_err(sdev->dev,
1369+
"link_index %d exceeds the link number %d link_mask #%x\n",
1370+
link_index, link_num, link_mask);
1371+
return NULL;
1372+
}
1373+
}
1374+
1375+
mach->drv_name = "sof_sdw";
1376+
mach->sof_tplg_filename = "sof-sdw-generic.tplg";
1377+
mach->mach_params.links = links;
1378+
mach->mach_params.link_mask = link_mask;
1379+
mach->mach_params.platform = dev_name(sdev->dev);
1380+
mach->get_function_tplg_files = sof_sdw_get_tplg_files;
1381+
dev_info(sdev->dev, "Use default SDW machine driver %s topology: %s\n",
1382+
mach->drv_name, mach->sof_tplg_filename);
1383+
return mach;
12051384
}
12061385
#else
12071386
static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev)
@@ -1529,6 +1708,7 @@ MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
15291708
MODULE_IMPORT_NS("SND_INTEL_SOUNDWIRE_ACPI");
15301709
MODULE_IMPORT_NS("SOUNDWIRE_INTEL_INIT");
15311710
MODULE_IMPORT_NS("SOUNDWIRE_INTEL");
1711+
MODULE_IMPORT_NS("SND_SOC_SDW_UTILS");
15321712
MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
15331713
MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
15341714
MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_MATCH");

0 commit comments

Comments
 (0)