Skip to content

Commit ee0ee64

Browse files
committed
ASoC: SOF: topology: load multiple topologies
Get device information from dai links and load topology for each device. This allow user create a topology for single device. The driver will select the needed topologies and we don't need to create topologies for each product. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
1 parent 8547018 commit ee0ee64

File tree

1 file changed

+182
-3
lines changed

1 file changed

+182
-3
lines changed

sound/soc/sof/topology.c

Lines changed: 182 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/errno.h>
1414
#include <linux/firmware.h>
1515
#include <linux/workqueue.h>
16+
#include <sound/soc_sdw_utils.h>
1617
#include <sound/tlv.h>
1718
#include <uapi/sound/sof/tokens.h>
1819
#include "sof-priv.h"
@@ -2288,7 +2289,7 @@ static const struct snd_soc_tplg_bytes_ext_ops sof_bytes_ext_ops[] = {
22882289
{SOF_TPLG_KCTL_BYTES_VOLATILE_RO, snd_sof_bytes_ext_volatile_get},
22892290
};
22902291

2291-
static const struct snd_soc_tplg_ops sof_tplg_ops = {
2292+
static struct snd_soc_tplg_ops sof_tplg_ops = {
22922293
/* external kcontrol init - used for any driver specific init */
22932294
.control_load = sof_control_load,
22942295
.control_unload = sof_control_unload,
@@ -2311,7 +2312,7 @@ static const struct snd_soc_tplg_ops sof_tplg_ops = {
23112312
.link_unload = sof_link_unload,
23122313

23132314
/* completion - called at completion of firmware loading */
2314-
.complete = sof_complete,
2315+
/* complete will be added in the last tplg ops */
23152316

23162317
/* manifest - optional to inform component of manifest */
23172318
.manifest = sof_manifest,
@@ -2464,15 +2465,191 @@ static const struct snd_soc_tplg_ops sof_dspless_tplg_ops = {
24642465
.bytes_ext_ops_count = ARRAY_SIZE(sof_dspless_bytes_ext_ops),
24652466
};
24662467

2468+
enum tplg_device_id {
2469+
TPLG_DEVICE_SDW_JACK,
2470+
TPLG_DEVICE_SDW_AMP,
2471+
TPLG_DEVICE_SDW_MIC,
2472+
TPLG_DEVICE_PCH_DMIC,
2473+
TPLG_DEVICE_HDMI,
2474+
TPLG_DEVICE_MAX
2475+
};
2476+
2477+
#define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDW_JACK) | BIT(TPLG_DEVICE_SDW_AMP) | \
2478+
BIT(TPLG_DEVICE_SDW_MIC))
2479+
2480+
struct topology_file {
2481+
char *device;
2482+
char *file;
2483+
int be_id;
2484+
int dev;
2485+
};
2486+
2487+
/* The code is from https://stackoverflow.com/questions/47116974/remove-a-substring-from-a-string-in-c */
2488+
static char *strremove(char *str, const char *sub)
2489+
{
2490+
size_t len = strlen(sub);
2491+
2492+
if (len > 0) {
2493+
char *p = str;
2494+
size_t size = 0;
2495+
2496+
while ((p = strstr(p, sub)) != NULL) {
2497+
size = (size == 0) ? (p - str) + strlen(p + len) + 1 : size - len;
2498+
memmove(p, p + len, size - (p - str));
2499+
}
2500+
}
2501+
return str;
2502+
}
2503+
24672504
int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
24682505
{
24692506
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2507+
struct topology_file tplg_files[TPLG_DEVICE_MAX];
2508+
struct snd_sof_pdata *sof_pdata = sdev->pdata;
2509+
struct snd_soc_dai_link *dai_link;
24702510
const struct firmware *fw;
2511+
bool load_default_tplg = false;
2512+
unsigned long tplg_mask = 0;
2513+
char platform[4];
2514+
int tplg_num = 0;
2515+
char *tplg_name;
2516+
int tplg_dev;
24712517
int ret;
2518+
int i;
24722519

24732520
dev_dbg(scomp->dev, "loading topology:%s\n", file);
24742521

2475-
ret = request_firmware(&fw, file, scomp->dev);
2522+
tplg_name = devm_kasprintf(sdev->dev, GFP_KERNEL, "%s", file);
2523+
if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3)
2524+
goto legacy_tplg;
2525+
2526+
ret = sscanf(sof_pdata->tplg_filename, "sof-%3s-*.tplg", platform);
2527+
if (ret != 1)
2528+
goto legacy_tplg;
2529+
2530+
for_each_card_prelinks(scomp->card, i, dai_link) {
2531+
char *tplg_device;
2532+
2533+
if (tplg_num >= TPLG_DEVICE_MAX) {
2534+
dev_err(scomp->dev,
2535+
"Invalid tplg_num %d, check what happened\n", tplg_num);
2536+
return -EINVAL;
2537+
}
2538+
2539+
dev_dbg(scomp->dev, "dai_link %s id %d\n", dai_link->name, dai_link->id);
2540+
if (strstr(dai_link->name, "SimpleJack")) {
2541+
tplg_dev = TPLG_DEVICE_SDW_JACK;
2542+
tplg_device = "sdca-jack";
2543+
} else if (strstr(dai_link->name, "SmartAmp")) {
2544+
tplg_dev = TPLG_DEVICE_SDW_AMP;
2545+
tplg_device = devm_kasprintf(sdev->dev, GFP_KERNEL,
2546+
"sdca-%damp", dai_link->num_cpus);
2547+
if (!tplg_device)
2548+
return -ENOMEM;
2549+
} else if (strstr(dai_link->name, "SmartMic")) {
2550+
tplg_dev = TPLG_DEVICE_SDW_MIC;
2551+
tplg_device = "sdca-mic";
2552+
} else if (strstr(dai_link->name, "dmic")) {
2553+
if (strstr(file, "-2ch")) {
2554+
tplg_device = "dmic-2ch";
2555+
tplg_name = strremove(tplg_name, "-2ch");
2556+
} else if (strstr(file, "-4ch")) {
2557+
tplg_device = "dmic-4ch";
2558+
tplg_name = strremove(tplg_name, "-4ch");
2559+
} else {
2560+
dev_warn(scomp->dev,
2561+
"only -2ch and -4ch are supported for dmic\n");
2562+
continue;
2563+
}
2564+
tplg_dev = TPLG_DEVICE_PCH_DMIC;
2565+
} else if (strstr(dai_link->name, "iDisp")) {
2566+
tplg_dev = TPLG_DEVICE_HDMI;
2567+
tplg_device = "sdca-hdmi";
2568+
2569+
} else {
2570+
/* The dai link is not supported by sperated tplg yet */
2571+
load_default_tplg = true;
2572+
continue;
2573+
}
2574+
if (tplg_mask & BIT(tplg_dev))
2575+
continue;
2576+
2577+
tplg_mask |= BIT(tplg_dev);
2578+
tplg_files[tplg_num].be_id = dai_link->id;
2579+
tplg_files[tplg_num].device = tplg_device;
2580+
tplg_files[tplg_num].dev = tplg_dev;
2581+
tplg_num++;
2582+
}
2583+
dev_dbg(scomp->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num);
2584+
2585+
/* Currently, only SDCA topology supported */
2586+
if (!(tplg_mask & SDCA_DEVICE_MASK)) {
2587+
/* Restore the default firmware name */
2588+
tplg_name = (char *)file;
2589+
goto legacy_tplg;
2590+
}
2591+
2592+
for (i = 0; i < tplg_num; i++) {
2593+
switch (tplg_files[i].dev) {
2594+
case TPLG_DEVICE_SDW_JACK:
2595+
case TPLG_DEVICE_SDW_AMP:
2596+
case TPLG_DEVICE_SDW_MIC:
2597+
case TPLG_DEVICE_HDMI:
2598+
tplg_files[i].file = devm_kasprintf(sdev->dev, GFP_KERNEL,
2599+
"%s/sof-%s-id%d.tplg",
2600+
sof_pdata->tplg_filename_prefix,
2601+
tplg_files[i].device,
2602+
tplg_files[i].be_id);
2603+
break;
2604+
default:
2605+
tplg_files[i].file = devm_kasprintf(sdev->dev, GFP_KERNEL,
2606+
"%s/sof-%s-%s-id%d.tplg",
2607+
sof_pdata->tplg_filename_prefix,
2608+
platform,
2609+
tplg_files[i].device,
2610+
tplg_files[i].be_id);
2611+
break;
2612+
}
2613+
if (!tplg_files[i].file)
2614+
return -ENOMEM;
2615+
2616+
dev_dbg(scomp->dev, "Requesting %d %s\n", i, tplg_files[i].file);
2617+
ret = firmware_request_nowarn(&fw, tplg_files[i].file, scomp->dev);
2618+
if (ret < 0) {
2619+
if (i == 0) {
2620+
/* Restore the default firmware name */
2621+
tplg_name = (char *)file;
2622+
dev_dbg(scomp->dev, "Fail back to %s\n", tplg_name);
2623+
goto legacy_tplg;
2624+
}
2625+
2626+
dev_err(scomp->dev, "tplg request firmware %s failed err: %d\n",
2627+
tplg_files[i].file, ret);
2628+
goto out;
2629+
}
2630+
/* set complete = sof_complete if it is the last topology */
2631+
if (!load_default_tplg && i == tplg_num - 1)
2632+
sof_tplg_ops.complete = sof_complete;
2633+
2634+
if (sdev->dspless_mode_selected)
2635+
ret = snd_soc_tplg_component_load(scomp, &sof_dspless_tplg_ops, fw);
2636+
else
2637+
ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw);
2638+
2639+
release_firmware(fw);
2640+
2641+
if (ret < 0) {
2642+
dev_err(scomp->dev, "tplg component load failed %d\n",
2643+
ret);
2644+
return ret;
2645+
}
2646+
}
2647+
/* Load topology successfully, goto out */
2648+
if (!load_default_tplg)
2649+
goto out;
2650+
2651+
legacy_tplg:
2652+
ret = request_firmware(&fw, tplg_name, scomp->dev);
24762653
if (ret < 0) {
24772654
dev_err(scomp->dev, "error: tplg request firmware %s failed err: %d\n",
24782655
file, ret);
@@ -2481,6 +2658,7 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
24812658
return ret;
24822659
}
24832660

2661+
sof_tplg_ops.complete = sof_complete;
24842662
if (sdev->dspless_mode_selected)
24852663
ret = snd_soc_tplg_component_load(scomp, &sof_dspless_tplg_ops, fw);
24862664
else
@@ -2492,6 +2670,7 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
24922670

24932671
release_firmware(fw);
24942672

2673+
out:
24952674
if (ret >= 0 && sdev->led_present)
24962675
ret = snd_ctl_led_request();
24972676

0 commit comments

Comments
 (0)