|
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> |
@@ -1131,14 +1133,159 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, |
1131 | 1133 |
|
1132 | 1134 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) |
1133 | 1135 |
|
| 1136 | +static bool is_endpoint_present(struct sdw_slave *sdw_device, |
| 1137 | + struct asoc_sdw_codec_info *dai_info, int dai_type) |
| 1138 | +{ |
| 1139 | + int i; |
| 1140 | + |
| 1141 | + for (i = 0; i < sdw_device->sdca_data.num_functions; i++) { |
| 1142 | + if (dai_type == dai_info->dais[i].dai_type) |
| 1143 | + return true; |
| 1144 | + } |
| 1145 | + dev_dbg(&sdw_device->dev, "Endpoint DAI type %d not found\n", dai_type); |
| 1146 | + return false; |
| 1147 | +} |
| 1148 | + |
| 1149 | +static struct snd_soc_acpi_adr_device *find_acpi_adr_device(struct device *dev, |
| 1150 | + struct sdw_slave *sdw_device, |
| 1151 | + struct snd_soc_acpi_link_adr *link, |
| 1152 | + int *amp_index) |
| 1153 | +{ |
| 1154 | + struct snd_soc_acpi_adr_device *adr_dev; |
| 1155 | + const char *name_prefix = ""; |
| 1156 | + int index = link->num_adr; |
| 1157 | + bool is_amp = true; /* Set it to false if the codec wiah any NON-AMP DAI type */ |
| 1158 | + int ep_index = 0; |
| 1159 | + int i, j; |
| 1160 | + |
| 1161 | + link->mask = BIT(sdw_device->bus->link_id); |
| 1162 | + /* index is 0 based, we need allocate index + 1 for the array size */ |
| 1163 | + if (!index) |
| 1164 | + adr_dev = devm_kzalloc(dev, sizeof(*adr_dev), GFP_KERNEL); |
| 1165 | + else |
| 1166 | + adr_dev = devm_krealloc(dev, (struct snd_soc_acpi_adr_device *)link->adr_d, |
| 1167 | + (index + 1) * sizeof(*adr_dev), GFP_KERNEL); |
| 1168 | + |
| 1169 | + if (!adr_dev) |
| 1170 | + return NULL; |
| 1171 | + |
| 1172 | + for (i = 0; i < asoc_sdw_get_codec_info_list_count(); i++) { |
| 1173 | + struct snd_soc_acpi_endpoint *endpoints; |
| 1174 | + int amp_group_id = 1; |
| 1175 | + |
| 1176 | + if (sdw_device->id.part_id != codec_info_list[i].part_id) |
| 1177 | + continue; |
| 1178 | + |
| 1179 | + endpoints = devm_kcalloc(dev, codec_info_list[i].dai_num, |
| 1180 | + sizeof(struct snd_soc_acpi_endpoint), GFP_KERNEL); |
| 1181 | + if (!endpoints) { |
| 1182 | + dev_err(dev, "failed to allocate memory for endpoints\n"); |
| 1183 | + return NULL; |
| 1184 | + } |
| 1185 | + |
| 1186 | + name_prefix = codec_info_list[i].name_prefix; |
| 1187 | + for (j = 0; j < codec_info_list[i].dai_num; j++) { |
| 1188 | + /* Check if the endpoint is present by the SDCA DisCo table */ |
| 1189 | + if (!is_endpoint_present(sdw_device, &codec_info_list[i], |
| 1190 | + codec_info_list[i].dais[j].dai_type)) |
| 1191 | + continue; |
| 1192 | + |
| 1193 | + endpoints[ep_index].num = ep_index; |
| 1194 | + if (codec_info_list[i].dais[j].dai_type == SOC_SDW_DAI_TYPE_AMP) { |
| 1195 | + /* Assume all amp are aggregated */ |
| 1196 | + endpoints[ep_index].aggregated = 1; |
| 1197 | + endpoints[ep_index].group_id = amp_group_id; |
| 1198 | + endpoints[ep_index].group_position = *amp_index; |
| 1199 | + /* Set group id = 2 for feedback capture endpoint */ |
| 1200 | + amp_group_id++; |
| 1201 | + } else { |
| 1202 | + endpoints[ep_index].aggregated = 0; |
| 1203 | + endpoints[ep_index].group_id = 0; |
| 1204 | + endpoints[ep_index].group_position = 0; |
| 1205 | + is_amp = false; |
| 1206 | + } |
| 1207 | + ep_index++; |
| 1208 | + } |
| 1209 | + adr_dev[index].endpoints = endpoints; |
| 1210 | + adr_dev[index].num_endpoints = ep_index; |
| 1211 | + break; |
| 1212 | + } |
| 1213 | + |
| 1214 | + if (i == asoc_sdw_get_codec_info_list_count()) { |
| 1215 | + dev_err(dev, "part id %#x is not supported\n", sdw_device->id.part_id); |
| 1216 | + return NULL; |
| 1217 | + } |
| 1218 | + |
| 1219 | + adr_dev[index].adr = ((u64)sdw_device->id.class_id & 0xFF) | |
| 1220 | + ((u64)sdw_device->id.part_id & 0xFFFF) << 8 | |
| 1221 | + ((u64)sdw_device->id.mfg_id & 0xFFFF) << 24 | |
| 1222 | + ((u64)(sdw_device->id.unique_id & 0xF) << 40) | |
| 1223 | + ((u64)(sdw_device->id.sdw_version & 0xF) << 44) | |
| 1224 | + ((u64)(sdw_device->bus->link_id & 0xF) << 48); |
| 1225 | + |
| 1226 | + if (!is_amp) { |
| 1227 | + /* For non-amp codecs, get name_prefix from codec_info_list[] */ |
| 1228 | + adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s", name_prefix); |
| 1229 | + goto done_name_prefix; |
| 1230 | + } |
| 1231 | + |
| 1232 | + /* |
| 1233 | + * The name_prefix comes from codec_info_list which has a name_prefix per codec. |
| 1234 | + * And we need to give a unique name_prefix for each amp and should be backwards |
| 1235 | + * compatible to the existing acpi match tables to not break existing UCMs. |
| 1236 | + * For the common name_prefix, we append the amp index to it. However, for the |
| 1237 | + * "Left" name_prefix, we convert the second amp name_prefix to "Right" and |
| 1238 | + * for the third and further amps, we set the name_prefix to "AMP<amp_index>". |
| 1239 | + */ |
| 1240 | + if (!strcmp(name_prefix, "Left")) { |
| 1241 | + switch (*amp_index) { |
| 1242 | + case 1: |
| 1243 | + adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, |
| 1244 | + "%s", "Left"); |
| 1245 | + break; |
| 1246 | + case 2: |
| 1247 | + adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, |
| 1248 | + "%s", "Right"); |
| 1249 | + break; |
| 1250 | + default: |
| 1251 | + /* Set the name_fix to AMP<amp_index> if there are more than 2 amps */ |
| 1252 | + adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s%d", |
| 1253 | + "AMP", *amp_index); |
| 1254 | + break; |
| 1255 | + } |
| 1256 | + } else { |
| 1257 | + adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s%d", |
| 1258 | + name_prefix, |
| 1259 | + *amp_index); |
| 1260 | + } |
| 1261 | + (*amp_index)++; |
| 1262 | + |
| 1263 | +done_name_prefix: |
| 1264 | + if (!adr_dev[index].name_prefix) { |
| 1265 | + dev_err(dev, "failed to allocate memory for name_prefix\n"); |
| 1266 | + return NULL; |
| 1267 | + } |
| 1268 | + |
| 1269 | + dev_dbg(dev, "adr[%d] 0x%llx link id %d name_prefix \"%s\" is found\n", |
| 1270 | + index, adr_dev[index].adr, sdw_device->bus->link_id, adr_dev[index].name_prefix); |
| 1271 | + |
| 1272 | + link->num_adr++; |
| 1273 | + |
| 1274 | + return adr_dev; |
| 1275 | +} |
| 1276 | + |
1134 | 1277 | static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev) |
1135 | 1278 | { |
1136 | 1279 | struct snd_sof_pdata *pdata = sdev->pdata; |
1137 | 1280 | const struct snd_soc_acpi_link_adr *link; |
| 1281 | + const struct sof_intel_dsp_desc *chip; |
| 1282 | + struct snd_soc_acpi_link_adr *links; |
1138 | 1283 | struct sdw_peripherals *peripherals; |
1139 | 1284 | struct snd_soc_acpi_mach *mach; |
1140 | 1285 | struct sof_intel_hda_dev *hdev; |
1141 | | - u32 link_mask; |
| 1286 | + int link_index, link_num; |
| 1287 | + int amp_index = 1; |
| 1288 | + u32 link_mask = 0; |
1142 | 1289 | int i; |
1143 | 1290 |
|
1144 | 1291 | hdev = pdata->hw_pdata; |
@@ -1215,7 +1362,50 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev |
1215 | 1362 | peripherals->array[i]->id.part_id, |
1216 | 1363 | peripherals->array[i]->id.sdw_version); |
1217 | 1364 |
|
1218 | | - return NULL; |
| 1365 | + chip = get_chip_info(sdev->pdata); |
| 1366 | + |
| 1367 | + /* SDCA was not well supported in the BIOS before ACE2.0 */ |
| 1368 | + if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) |
| 1369 | + return NULL; |
| 1370 | + |
| 1371 | + if (!peripherals->num_peripherals) |
| 1372 | + return NULL; |
| 1373 | + |
| 1374 | + /* Create default SDW mach */ |
| 1375 | + mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL); |
| 1376 | + if (!mach) |
| 1377 | + return NULL; |
| 1378 | + |
| 1379 | + /* Get link mask and link number */ |
| 1380 | + for (i = 0; i < peripherals->num_peripherals; i++) |
| 1381 | + link_mask |= BIT(peripherals->array[i]->bus->link_id); |
| 1382 | + |
| 1383 | + link_num = hweight32(link_mask); |
| 1384 | + links = devm_kcalloc(sdev->dev, link_num, sizeof(*links), GFP_KERNEL); |
| 1385 | + if (!links) |
| 1386 | + return NULL; |
| 1387 | + |
| 1388 | + /* Generate snd_soc_acpi_link_adr struct for each peripheral reported by the ACPI table */ |
| 1389 | + for (i = 0; i < peripherals->num_peripherals; i++) { |
| 1390 | + /* link_index = the number of used links below the current link */ |
| 1391 | + link_index = hweight32(link_mask & (BIT(peripherals->array[i]->bus->link_id) - 1)); |
| 1392 | + links[link_index].adr_d = find_acpi_adr_device(sdev->dev, peripherals->array[i], |
| 1393 | + &links[link_index], &_index); |
| 1394 | + } |
| 1395 | + |
| 1396 | + mach->drv_name = "sof_sdw"; |
| 1397 | + mach->mach_params.links = links; |
| 1398 | + mach->mach_params.link_mask = link_mask; |
| 1399 | + mach->mach_params.platform = dev_name(sdev->dev); |
| 1400 | + mach->get_function_tplg_files = sof_sdw_get_tplg_files; |
| 1401 | + /* |
| 1402 | + * Set mach->sof_tplg_filename as a dummy topology to avoid tplg file checking |
| 1403 | + * and being used. |
| 1404 | + */ |
| 1405 | + mach->sof_tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, "sof-%s-dummy.tplg", chip->platform); |
| 1406 | + |
| 1407 | + dev_info(sdev->dev, "Use SoundWire default machine driver with function topologies\n"); |
| 1408 | + return mach; |
1219 | 1409 | } |
1220 | 1410 | #else |
1221 | 1411 | static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev) |
@@ -1555,6 +1745,7 @@ MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); |
1555 | 1745 | MODULE_IMPORT_NS("SND_INTEL_SOUNDWIRE_ACPI"); |
1556 | 1746 | MODULE_IMPORT_NS("SOUNDWIRE_INTEL_INIT"); |
1557 | 1747 | MODULE_IMPORT_NS("SOUNDWIRE_INTEL"); |
| 1748 | +MODULE_IMPORT_NS("SND_SOC_SDW_UTILS"); |
1558 | 1749 | MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK"); |
1559 | 1750 | MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON"); |
1560 | 1751 | MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_MATCH"); |
0 commit comments