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"
@@ -2286,7 +2287,7 @@ static const struct snd_soc_tplg_bytes_ext_ops sof_bytes_ext_ops[] = {
22862287 {SOF_TPLG_KCTL_BYTES_VOLATILE_RO , snd_sof_bytes_ext_volatile_get },
22872288};
22882289
2289- static const struct snd_soc_tplg_ops sof_tplg_ops = {
2290+ static struct snd_soc_tplg_ops sof_tplg_ops = {
22902291 /* external kcontrol init - used for any driver specific init */
22912292 .control_load = sof_control_load ,
22922293 .control_unload = sof_control_unload ,
@@ -2309,7 +2310,7 @@ static const struct snd_soc_tplg_ops sof_tplg_ops = {
23092310 .link_unload = sof_link_unload ,
23102311
23112312 /* completion - called at completion of firmware loading */
2312- . complete = sof_complete ,
2313+ /* complete will be added in the last tplg ops */
23132314
23142315 /* manifest - optional to inform component of manifest */
23152316 .manifest = sof_manifest ,
@@ -2462,15 +2463,161 @@ static const struct snd_soc_tplg_ops sof_dspless_tplg_ops = {
24622463 .bytes_ext_ops_count = ARRAY_SIZE (sof_dspless_bytes_ext_ops ),
24632464};
24642465
2466+ #define MAX_TPLG_NUM 5
2467+
2468+ enum tplg_device_id {
2469+ TPLG_DEVICE_SDW_JACK ,
2470+ TPLG_DEVICE_SDW_AMP ,
2471+ TPLG_DEVICE_SDW_MIC ,
2472+ TPLG_DEVICE_HOST_DMIC ,
2473+ TPLG_DEVICE_HDMI ,
2474+ };
2475+
2476+ struct topology_file {
2477+ char * device ;
2478+ char * file ;
2479+ int be_id ;
2480+ };
2481+
2482+ static bool is_platform_support_separated_tplg (const char * platform )
2483+ {
2484+
2485+ if (!strcmp (platform , "hda" ) || !strcmp (platform , "mtl" ) ||
2486+ !strcmp (platform , "lnl" ) || !strcmp (platform , "ptl" ))
2487+ return true;
2488+
2489+ return false;
2490+ }
2491+
2492+ /* The code is from https://stackoverflow.com/questions/47116974/remove-a-substring-from-a-string-in-c */
2493+ static char * strremove (char * str , const char * sub ) {
2494+ size_t len = strlen (sub );
2495+ if (len > 0 ) {
2496+ char * p = str ;
2497+ size_t size = 0 ;
2498+ while ((p = strstr (p , sub )) != NULL ) {
2499+ size = (size == 0 ) ? (p - str ) + strlen (p + len ) + 1 : size - len ;
2500+ memmove (p , p + len , size - (p - str ));
2501+ }
2502+ }
2503+ return str ;
2504+ }
2505+
24652506int snd_sof_load_topology (struct snd_soc_component * scomp , const char * file )
24662507{
24672508 struct snd_sof_dev * sdev = snd_soc_component_get_drvdata (scomp );
2509+ struct snd_sof_pdata * sof_pdata = sdev -> pdata ;
2510+ struct topology_file tplg_files [MAX_TPLG_NUM ];
2511+ struct snd_soc_dai_link * dai_link ;
24682512 const struct firmware * fw ;
2513+ bool load_default_tplg = false;
2514+ unsigned long tplg_mask = 0 ;
2515+ char platform [4 ];
2516+ char * tplg_name ;
2517+ int tplg_num = 0 ;
2518+ int tplg_dev ;
24692519 int ret ;
2520+ int i ;
24702521
24712522 dev_dbg (scomp -> dev , "loading topology:%s\n" , file );
24722523
2473- ret = request_firmware (& fw , file , scomp -> dev );
2524+ tplg_name = (char * )file ;
2525+ if (sdev -> pdata -> ipc_type == SOF_IPC_TYPE_3 )
2526+ goto legacy_tplg ;
2527+
2528+ sscanf (sof_pdata -> tplg_filename , "sof-%3s-*.tplg" , platform );
2529+ if (!is_platform_support_separated_tplg (platform ))
2530+ goto legacy_tplg ;
2531+
2532+ for_each_card_prelinks (scomp -> card , i , dai_link ) {
2533+ char * tplg_device ;
2534+
2535+ dev_dbg (scomp -> dev , "dai_link %s id %d\n" , dai_link -> name , dai_link -> id );
2536+ if (strstr (dai_link -> name , "SimpleJack" )) {
2537+ tplg_dev = TPLG_DEVICE_SDW_JACK ;
2538+ tplg_device = "sdca-jack" ;
2539+ } else if (strstr (dai_link -> name , "SmartAmp" )) {
2540+ tplg_dev = TPLG_DEVICE_SDW_AMP ;
2541+ tplg_device = devm_kasprintf (sdev -> dev , GFP_KERNEL ,
2542+ "sdca-%damp" , dai_link -> num_cpus );
2543+ } else if (strstr (dai_link -> name , "SmartMic" )) {
2544+ tplg_dev = TPLG_DEVICE_SDW_MIC ;
2545+ tplg_device = "sdca-mic" ;
2546+ } else if (strstr (dai_link -> name , "dmic" )) {
2547+ if (strstr (file , "-2ch" )) {
2548+ tplg_device = "dmic-2ch" ;
2549+ tplg_name = strremove (tplg_name , "-2ch" );
2550+ } else if (strstr (file , "-4ch" )) {
2551+ tplg_device = "dmic-4ch" ;
2552+ tplg_name = strremove (tplg_name , "-4ch" );
2553+ } else {
2554+ dev_warn (scomp -> dev ,
2555+ "only -2ch and -4ch are supported for dmic\n" );
2556+ continue ;
2557+ }
2558+ tplg_dev = TPLG_DEVICE_HOST_DMIC ;
2559+ } else if (strstr (dai_link -> name , "iDisp" )) {
2560+ tplg_dev = TPLG_DEVICE_HDMI ;
2561+ if (strstr (file , "hda-generic" )) {
2562+ tplg_device = "idisp" ;
2563+ } else {
2564+ tplg_device = "sdca-hdmi" ;
2565+ }
2566+ } else {
2567+ /* The dai link is not supported by sperated tplg yet */
2568+ load_default_tplg = true;
2569+ continue ;
2570+ }
2571+ if (tplg_mask & BIT (tplg_dev ))
2572+ continue ;
2573+ tplg_mask |= BIT (tplg_dev );
2574+ tplg_files [tplg_num ].be_id = dai_link -> id ;
2575+ tplg_files [tplg_num ].device = tplg_device ;
2576+ tplg_num ++ ;
2577+ }
2578+ dev_dbg (scomp -> dev , "tplg_mask %#lx tplg_num %d\n" , tplg_mask , tplg_num );
2579+
2580+ for (i = 0 ; i < tplg_num ; i ++ ) {
2581+ tplg_files [i ].file = devm_kasprintf (sdev -> dev , GFP_KERNEL ,
2582+ "%s/sof-%s-%s-id%d.tplg" ,
2583+ sof_pdata -> tplg_filename_prefix , platform ,
2584+ tplg_files [i ].device ,
2585+ tplg_files [i ].be_id );
2586+ dev_dbg (scomp -> dev , "Requesting %d %s\n" , i , tplg_files [i ].file );
2587+ ret = request_firmware (& fw , tplg_files [i ].file , scomp -> dev );
2588+ if (ret < 0 ) {
2589+ if (i == 0 ) {
2590+ dev_dbg (scomp -> dev ,"Fail back to %s\n" , tplg_name );
2591+ goto legacy_tplg ;
2592+ }
2593+
2594+ dev_err (scomp -> dev , "error: tplg request firmware %s failed err: %d\n" ,
2595+ tplg_files [i ].file , ret );
2596+ goto out ;
2597+ }
2598+ /* set complete = sof_complete if it is the last topology */
2599+ if (!load_default_tplg && i == tplg_num - 1 )
2600+ sof_tplg_ops .complete = sof_complete ;
2601+ if (sdev -> dspless_mode_selected )
2602+ ret = snd_soc_tplg_component_load (scomp , & sof_dspless_tplg_ops , fw );
2603+ else
2604+ ret = snd_soc_tplg_component_load (scomp , & sof_tplg_ops , fw );
2605+
2606+ if (ret < 0 ) {
2607+ dev_err (scomp -> dev , "error: tplg component load failed %d\n" ,
2608+ ret );
2609+ release_firmware (fw );
2610+ return - EINVAL ;
2611+ }
2612+
2613+ release_firmware (fw );
2614+ }
2615+ /* Load topology successfully, goto out */
2616+ if (!load_default_tplg )
2617+ goto out ;
2618+
2619+ legacy_tplg :
2620+ ret = request_firmware (& fw , tplg_name , scomp -> dev );
24742621 if (ret < 0 ) {
24752622 dev_err (scomp -> dev , "error: tplg request firmware %s failed err: %d\n" ,
24762623 file , ret );
@@ -2479,6 +2626,7 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
24792626 return ret ;
24802627 }
24812628
2629+ sof_tplg_ops .complete = sof_complete ;
24822630 if (sdev -> dspless_mode_selected )
24832631 ret = snd_soc_tplg_component_load (scomp , & sof_dspless_tplg_ops , fw );
24842632 else
@@ -2492,6 +2640,7 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
24922640
24932641 release_firmware (fw );
24942642
2643+ out :
24952644 if (ret >= 0 && sdev -> led_present )
24962645 ret = snd_ctl_led_request ();
24972646
0 commit comments