|
26 | 26 | #include <sound/intel-dsp-config.h> |
27 | 27 | #include <sound/intel-nhlt.h> |
28 | 28 | #include <sound/soc-acpi-intel-ssp-common.h> |
| 29 | +#include <sound/soc_sdw_utils.h> |
29 | 30 | #include <sound/sof.h> |
30 | 31 | #include <sound/sof/xtensa.h> |
31 | 32 | #include <sound/hda-mlink.h> |
32 | 33 | #include "../sof-audio.h" |
33 | 34 | #include "../sof-pci-dev.h" |
34 | 35 | #include "../ops.h" |
35 | 36 | #include "../ipc4-topology.h" |
| 37 | +#include "../../intel/common/sof-function-topology-lib.h" |
36 | 38 | #include "hda.h" |
37 | 39 |
|
38 | 40 | #include <trace/events/sof_intel.h> |
@@ -1117,13 +1119,137 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, |
1117 | 1119 |
|
1118 | 1120 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) |
1119 | 1121 |
|
| 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 | + adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s", |
| 1166 | + codec_info_list[i].name_prefix); |
| 1167 | + for (j = 0; j < codec_info_list[i].dai_num; j++) { |
| 1168 | + if (!is_endpoint_present(sdw_device, &codec_info_list[i], |
| 1169 | + codec_info_list[i].dais[j].dai_type)) |
| 1170 | + continue; |
| 1171 | + adr_dev[index].endpoints[ep_index].num = ep_index; |
| 1172 | + /* Assume all amp are aggregated */ |
| 1173 | + if (codec_info_list[i].dais[j].dai_type == SOC_SDW_DAI_TYPE_AMP) { |
| 1174 | + adr_dev[index].endpoints[ep_index].aggregated = 1; |
| 1175 | + adr_dev[index].endpoints[ep_index].group_id = amp_group_id; |
| 1176 | + amp_group_id++; |
| 1177 | + } else { |
| 1178 | + adr_dev[index].endpoints[ep_index].aggregated = 0; |
| 1179 | + adr_dev[index].endpoints[ep_index].group_id = 0; |
| 1180 | + } |
| 1181 | + adr_dev[index].endpoints[ep_index].group_position = 0; |
| 1182 | + ep_index++; |
| 1183 | + } |
| 1184 | + adr_dev[index].num_endpoints = ep_index; |
| 1185 | + break; |
| 1186 | + } |
| 1187 | + |
| 1188 | + if (i == asoc_sdw_get_codec_info_list_count()) { |
| 1189 | + dev_err(dev, "part id %#x is not supported\n", sdw_device->id.part_id); |
| 1190 | + return NULL; |
| 1191 | + } |
| 1192 | + |
| 1193 | + adr_dev[index].adr = ((u64)sdw_device->id.class_id & 0xFF) | |
| 1194 | + ((u64)sdw_device->id.part_id & 0xFFFF) << 8 | |
| 1195 | + ((u64)sdw_device->id.mfg_id & 0xFFFF) << 24 | |
| 1196 | + ((u64)(sdw_device->id.unique_id & 0xF) << 40) | |
| 1197 | + ((u64)(sdw_device->id.sdw_version & 0xF) << 44) | |
| 1198 | + ((u64)(sdw_device->bus->link_id & 0xF) << 48); |
| 1199 | + |
| 1200 | + /* |
| 1201 | + * The name_prefix comes from codec_info_list which has a name_prefix per codec. |
| 1202 | + * And we need to give a unique name_prefix for each amp and should be backwards |
| 1203 | + * compatible to the existing acpi match tables to not break existing UCMs. |
| 1204 | + * For the "AMP" name_prefix, we append the amp index to it. However, for the |
| 1205 | + * "Left" name_prefix, we convert the second amp name_prefix to "Right" and |
| 1206 | + * for the third and further amps, we set the name_prefix to "AMP<amp_index>". |
| 1207 | + */ |
| 1208 | + if (!strcmp(adr_dev[index].name_prefix, "AMP")) { |
| 1209 | + adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s%d", |
| 1210 | + adr_dev[index].name_prefix, |
| 1211 | + *amp_index); |
| 1212 | + if (!adr_dev[index].name_prefix) |
| 1213 | + return NULL; |
| 1214 | + (*amp_index)++; |
| 1215 | + } |
| 1216 | + |
| 1217 | + if (!strcmp(adr_dev[index].name_prefix, "Left")) { |
| 1218 | + /* Convert the second amp name_prefix to Right */ |
| 1219 | + if ((*amp_index) == 2) { |
| 1220 | + adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, |
| 1221 | + "%s", "Right"); |
| 1222 | + if (!adr_dev[index].name_prefix) |
| 1223 | + return NULL; |
| 1224 | + } |
| 1225 | + /* Set the name_fix to AMP<amp_index> if there are more than 2 amps */ |
| 1226 | + if (*amp_index > 2) { |
| 1227 | + adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s%d", |
| 1228 | + "AMP", *amp_index); |
| 1229 | + if (!adr_dev[index].name_prefix) |
| 1230 | + return NULL; |
| 1231 | + } |
| 1232 | + (*amp_index)++; |
| 1233 | + } |
| 1234 | + |
| 1235 | + dev_dbg(dev, "adr[%d] 0x%llx link id %d name_prefix \"%s\" is found\n", |
| 1236 | + index, adr_dev[index].adr, sdw_device->bus->link_id, adr_dev[index].name_prefix); |
| 1237 | + |
| 1238 | + link->num_adr++; |
| 1239 | + |
| 1240 | + return adr_dev; |
| 1241 | +} |
| 1242 | + |
1120 | 1243 | static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev) |
1121 | 1244 | { |
1122 | 1245 | struct snd_sof_pdata *pdata = sdev->pdata; |
1123 | 1246 | struct snd_soc_acpi_link_adr *link; |
| 1247 | + struct snd_soc_acpi_link_adr *links; |
1124 | 1248 | struct sdw_peripherals *peripherals; |
1125 | 1249 | struct snd_soc_acpi_mach *mach; |
1126 | 1250 | struct sof_intel_hda_dev *hdev; |
| 1251 | + int amp_index = 1; |
| 1252 | + int link_index; |
1127 | 1253 | u32 link_mask; |
1128 | 1254 | int i; |
1129 | 1255 |
|
@@ -1201,7 +1327,44 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev |
1201 | 1327 | peripherals->array[i]->id.part_id, |
1202 | 1328 | peripherals->array[i]->id.sdw_version); |
1203 | 1329 |
|
1204 | | - return NULL; |
| 1330 | + if (!peripherals->num_peripherals) |
| 1331 | + return NULL; |
| 1332 | + |
| 1333 | + /* Create default SDW mach */ |
| 1334 | + mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL); |
| 1335 | + if (!mach) |
| 1336 | + return NULL; |
| 1337 | + |
| 1338 | + links = devm_kcalloc(sdev->dev, peripherals->num_peripherals, sizeof(*links), GFP_KERNEL); |
| 1339 | + if (!links) |
| 1340 | + return NULL; |
| 1341 | + |
| 1342 | + link_mask = 0; |
| 1343 | + link_index = 0; |
| 1344 | + /* Generate snd_soc_acpi_link_adr struct for each peripheral reported by the ACPI table */ |
| 1345 | + for (i = 0; i < peripherals->num_peripherals; i++) { |
| 1346 | + links[link_index].adr_d = find_acpi_adr_device(sdev->dev, peripherals->array[i], |
| 1347 | + &links[link_index], &_index); |
| 1348 | + link_mask |= links[link_index].mask; |
| 1349 | + |
| 1350 | + /* |
| 1351 | + * Only increase the link_index when the next periperal is on a different link. |
| 1352 | + * Assume that peripherals are grouped by link_id in the ACPI table. |
| 1353 | + */ |
| 1354 | + if (i < peripherals->num_peripherals - 1 && |
| 1355 | + peripherals->array[i + 1]->bus->link_id != peripherals->array[i]->bus->link_id) |
| 1356 | + link_index++; |
| 1357 | + } |
| 1358 | + |
| 1359 | + mach->drv_name = "sof_sdw"; |
| 1360 | + mach->sof_tplg_filename = "sof-sdw-generic.tplg"; |
| 1361 | + mach->mach_params.links = links; |
| 1362 | + mach->mach_params.link_mask = link_mask; |
| 1363 | + mach->mach_params.platform = dev_name(sdev->dev); |
| 1364 | + mach->get_function_tplg_files = sof_sdw_get_tplg_files; |
| 1365 | + dev_info(sdev->dev, "Use default SDW machine driver %s topology: %s\n", |
| 1366 | + mach->drv_name, mach->sof_tplg_filename); |
| 1367 | + return mach; |
1205 | 1368 | } |
1206 | 1369 | #else |
1207 | 1370 | static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev) |
@@ -1529,6 +1692,7 @@ MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); |
1529 | 1692 | MODULE_IMPORT_NS("SND_INTEL_SOUNDWIRE_ACPI"); |
1530 | 1693 | MODULE_IMPORT_NS("SOUNDWIRE_INTEL_INIT"); |
1531 | 1694 | MODULE_IMPORT_NS("SOUNDWIRE_INTEL"); |
| 1695 | +MODULE_IMPORT_NS("SND_SOC_SDW_UTILS"); |
1532 | 1696 | MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK"); |
1533 | 1697 | MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON"); |
1534 | 1698 | MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_MATCH"); |
0 commit comments