-
Notifications
You must be signed in to change notification settings - Fork 133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Detect SSP port number from NHLT table #4492
Changes from all commits
e74385f
fcecb95
32f5e1f
3a9fd36
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,6 +68,7 @@ | |
#define SOF_SSP_HDMI_CAPTURE_PRESENT_MASK (GENMASK(30, 27)) | ||
#define SOF_HDMI_CAPTURE_SSP_MASK(quirk) \ | ||
(((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) | ||
#define SOF_TPLG_NHLT_SSP_DETECT BIT(31) | ||
|
||
/* Default: MCLK on, MCLK 19.2M, SSP0 */ | ||
static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | | ||
|
@@ -560,6 +561,22 @@ static int sof_card_late_probe(struct snd_soc_card *card) | |
return hdac_hdmi_jack_port_init(component, &card->dapm); | ||
} | ||
|
||
static int soc_card_add_dai_link(struct snd_soc_card *card, | ||
struct snd_soc_dai_link *dai_link) | ||
{ | ||
if (!strcmp(dai_link->name, "NHLT-RENDER-CAPTURE") || | ||
!strcmp(dai_link->name, "NHLT-RENDER-ONLY") || | ||
!strcmp(dai_link->name, "NHLT-CAPTURE-ONLY") || | ||
!strcmp(dai_link->name, "NHLT-BT")) { | ||
/* fixup and register this dai link later when we receive NHLT | ||
* table from IPC4 topology | ||
*/ | ||
dai_link->ignore = true; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static const struct snd_kcontrol_new sof_controls[] = { | ||
SOC_DAPM_PIN_SWITCH("Headphone Jack"), | ||
SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
|
@@ -703,8 +720,12 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, | |
goto devm_err; | ||
|
||
/* codec SSP */ | ||
links[id].name = devm_kasprintf(dev, GFP_KERNEL, | ||
"SSP%d-Codec", ssp_codec); | ||
if (sof_rt5682_quirk & SOF_TPLG_NHLT_SSP_DETECT) | ||
links[id].name = devm_kasprintf(dev, GFP_KERNEL, | ||
"NHLT-RENDER-CAPTURE"); | ||
else | ||
links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. won't this break IPC3? |
||
ssp_codec); | ||
if (!links[id].name) | ||
goto devm_err; | ||
|
||
|
@@ -830,8 +851,12 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, | |
|
||
/* speaker amp */ | ||
if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) { | ||
links[id].name = devm_kasprintf(dev, GFP_KERNEL, | ||
"SSP%d-Codec", ssp_amp); | ||
if (sof_rt5682_quirk & SOF_TPLG_NHLT_SSP_DETECT) | ||
links[id].name = devm_kasprintf(dev, GFP_KERNEL, | ||
"NHLT-RENDER-ONLY"); | ||
else | ||
links[id].name = devm_kasprintf(dev, GFP_KERNEL, | ||
"SSP%d-Codec", ssp_amp); | ||
if (!links[id].name) | ||
goto devm_err; | ||
|
||
|
@@ -906,23 +931,29 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, | |
int port = (sof_rt5682_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> | ||
SOF_BT_OFFLOAD_SSP_SHIFT; | ||
|
||
if (sof_rt5682_quirk & SOF_TPLG_NHLT_SSP_DETECT) | ||
links[id].name = devm_kasprintf(dev, GFP_KERNEL, | ||
"NHLT-BT"); | ||
else | ||
links[id].name = devm_kasprintf(dev, GFP_KERNEL, | ||
"SSP%d-BT", port); | ||
if (!links[id].name) | ||
goto devm_err; | ||
|
||
links[id].id = id; | ||
links[id].cpus = &cpus[id]; | ||
links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, | ||
"SSP%d Pin", port); | ||
if (!links[id].cpus->dai_name) | ||
goto devm_err; | ||
links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); | ||
if (!links[id].name) | ||
goto devm_err; | ||
links[id].num_cpus = 1; | ||
links[id].codecs = &asoc_dummy_dlc; | ||
links[id].num_codecs = 1; | ||
links[id].platforms = platform_component; | ||
links[id].num_platforms = ARRAY_SIZE(platform_component); | ||
links[id].dpcm_playback = 1; | ||
links[id].dpcm_capture = 1; | ||
links[id].no_pcm = 1; | ||
links[id].num_cpus = 1; | ||
} | ||
|
||
/* HDMI-In SSP */ | ||
|
@@ -1079,6 +1110,9 @@ static int sof_audio_probe(struct platform_device *pdev) | |
if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_PRESENT) | ||
sof_rt1015_codec_conf(&sof_audio_card_rt5682); | ||
|
||
if (sof_rt5682_quirk & SOF_TPLG_NHLT_SSP_DETECT) | ||
sof_audio_card_rt5682.add_dai_link = soc_card_add_dai_link; | ||
|
||
INIT_LIST_HEAD(&ctx->hdmi_pcm_list); | ||
|
||
sof_audio_card_rt5682.dev = &pdev->dev; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1297,8 +1297,9 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s | |
struct sof_ipc4_fw_data *ipc4_data = sdev->private; | ||
struct nhlt_specific_cfg *cfg; | ||
int sample_rate, channel_count; | ||
int bit_depth, ret; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. commit message s/direcion/direction There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
int bit_depth, ret, i; | ||
u32 nhlt_type; | ||
static const u8 nhlt_devices[] = {NHLT_DEVICE_I2S, NHLT_DEVICE_BT}; | ||
|
||
/* convert to NHLT type */ | ||
switch (linktype) { | ||
|
@@ -1323,9 +1324,15 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s | |
dai_index, nhlt_type, dir); | ||
|
||
/* find NHLT blob with matching params */ | ||
cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type, | ||
bit_depth, bit_depth, channel_count, sample_rate, | ||
dir, 0); | ||
for (i = 0; i < ARRAY_SIZE(nhlt_devices); i++) { | ||
cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, | ||
dai_index, nhlt_type, bit_depth, | ||
bit_depth, channel_count, sample_rate, | ||
dir, nhlt_devices[i]); | ||
if (cfg || (linktype == SOF_DAI_INTEL_DMIC)) | ||
goto cfg_found; | ||
} | ||
cfg_found: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the main issue I have is that this is not backwards compatible. You need a new topology to get this to work. Is this not too late already? @ranj063 please chime in here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's backward compatible. Because current implementation set the device type of all endpoints to 0 (BT), and use Render(0) and Capture(1) in direction field. So current topologies could work with the code. |
||
|
||
if (!cfg) { | ||
dev_err(sdev->dev, | ||
|
@@ -2725,6 +2732,78 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * | |
return 0; | ||
} | ||
|
||
static int sof_ipc4_nhlt_register_dai_links(struct snd_soc_component *scomp) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. adding dai links in the SOF ipc4 code is a major layering violation. This belongs in machine drivers IMHO. The SOF driver should only add CPU dais, not muck with dai links. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem is topology is loaded after machine driver registers soundcard. If we want to extract ssp numbers from NHLT, then we have to register the dai links in sof-topology layer... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's a bit too much for me... I am not hot on hard-coding such names in a generic layer. need to think a bit more on all this. |
||
{ | ||
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); | ||
struct sof_ipc4_fw_data *ipc4_data = sdev->private; | ||
struct snd_soc_card *card = scomp->card; | ||
struct snd_soc_dai_link *dai_link = card->dai_link; | ||
int capture_mask, render_mask; | ||
int ssp_mask, ssp_num; | ||
int i, is_bt, ret; | ||
|
||
capture_mask = intel_nhlt_ssp_dir_mask(scomp->dev, ipc4_data->nhlt, NHLT_DIRECTION_CAPTURE); | ||
render_mask = intel_nhlt_ssp_dir_mask(scomp->dev, ipc4_data->nhlt, NHLT_DIRECTION_RENDER); | ||
|
||
for (i = 0; i < card->num_links; i++, dai_link++) { | ||
if (!strcmp(dai_link->name, "NHLT-RENDER-CAPTURE")) { | ||
/* headset codec */ | ||
ssp_mask = render_mask & capture_mask; | ||
is_bt = 0; | ||
} else if (!strcmp(dai_link->name, "NHLT-RENDER-ONLY")) { | ||
/* speaker amplifier */ | ||
ssp_mask = render_mask & ~capture_mask; | ||
is_bt = 0; | ||
} else if (!strcmp(dai_link->name, "NHLT-CAPTURE-ONLY")) { | ||
/* HDMI in */ | ||
ssp_mask = ~render_mask & capture_mask; | ||
is_bt = 0; | ||
} else if (!strcmp(dai_link->name, "NHLT-BT")) { | ||
/* bluetooth sideband */ | ||
ssp_mask = intel_nhlt_ssp_endpoint_mask(ipc4_data->nhlt, | ||
NHLT_DEVICE_BT); | ||
is_bt = 1; | ||
} else | ||
continue; | ||
|
||
if (hweight32(ssp_mask) != 1) { | ||
dev_warn(scomp->dev, "Invalid mask 0x%x for dai link %s\n", | ||
ssp_mask, dai_link->name); | ||
continue; | ||
} | ||
|
||
ssp_num = ffs(ssp_mask) - 1; /* ffs returns 1-based result */ | ||
|
||
if (is_bt) | ||
dai_link->name = devm_kasprintf(card->dev, GFP_KERNEL, | ||
"SSP%d-BT", ssp_num); | ||
else | ||
dai_link->name = devm_kasprintf(card->dev, GFP_KERNEL, | ||
"SSP%d-Codec", ssp_num); | ||
if (!dai_link->name) | ||
return -ENOMEM; | ||
|
||
/* stream_name is initialized in soc_check_tplg_fes() function | ||
* with dai link name */ | ||
dai_link->stream_name = devm_kstrdup(card->dev, dai_link->name, | ||
GFP_KERNEL); | ||
if (!dai_link->stream_name) | ||
return -ENOMEM; | ||
|
||
dai_link->cpus->dai_name = devm_kasprintf(card->dev, GFP_KERNEL, | ||
"SSP%d Pin", ssp_num); | ||
if (!dai_link->cpus->dai_name) | ||
return -ENOMEM; | ||
|
||
dai_link->ignore = false; | ||
ret = snd_soc_add_pcm_runtimes(card, dai_link, 1); | ||
if (ret < 0) | ||
return ret; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index, | ||
struct snd_soc_tplg_manifest *man) | ||
{ | ||
|
@@ -2735,7 +2814,7 @@ static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index, | |
u32 size = le32_to_cpu(man->priv.size); | ||
u8 *man_ptr = man->priv.data; | ||
u32 len_check; | ||
int i; | ||
int i, ret; | ||
|
||
if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) { | ||
dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n", | ||
|
@@ -2773,6 +2852,13 @@ static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index, | |
le32_to_cpu(manifest_tlv->size), GFP_KERNEL); | ||
if (!ipc4_data->nhlt) | ||
return -ENOMEM; | ||
|
||
/* register 'ignored' dai links which link name and | ||
* codec dai name need fixup with info from NHLT table | ||
*/ | ||
ret = sof_ipc4_nhlt_register_dai_links(scomp); | ||
if (ret) | ||
return ret; | ||
break; | ||
default: | ||
dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know what this 'ignore' means but it certainly does not immediately translate as 'fixup and register later'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
soc-core(soc_check_tplg_fes() function) uses this flag to skip FE dai links in machine driver. Here we use this flag to make snd_soc_add_pcm_runtime() function skipping this dai link.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"borrow this flag" really means overloading a concept used for FE and extend it for BEs. That's not so good, this will add confusions left and right. We should be really careful with such moves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked the soc.h and the flag means "do not create pcm". Maybe the reason to use this flag could be different? soc-core uses this flag to skip FE links and we use it to skip links which link/stream names need to be resolved later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's best to avoid using the same flag for two completely different purposes, which means adding a new one with a clearly defined behavior.
I am still in the dark on what the problem statement is and why the SOF driver is involved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree we cannot repurpose an existing flag for a compltely different purpose