Path: blob/master/sound/soc/intel/boards/sof_board_helpers.c
26493 views
// SPDX-License-Identifier: GPL-2.0-only1//2// Copyright(c) 2023 Intel Corporation34#include <sound/soc.h>5#include "../common/soc-intel-quirks.h"6#include "hda_dsp_common.h"7#include "sof_board_helpers.h"89/*10* Intel HDMI DAI Link11*/12static int hdmi_init(struct snd_soc_pcm_runtime *rtd)13{14struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);15struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0);1617ctx->hdmi.hdmi_comp = dai->component;1819return 0;20}2122int sof_intel_board_card_late_probe(struct snd_soc_card *card)23{24struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);2526if (!ctx->hdmi_num)27return 0;2829if (!ctx->hdmi.idisp_codec)30return 0;3132if (!ctx->hdmi.hdmi_comp)33return -EINVAL;3435return hda_dsp_hdmi_build_controls(card, ctx->hdmi.hdmi_comp);36}37EXPORT_SYMBOL_NS(sof_intel_board_card_late_probe, "SND_SOC_INTEL_SOF_BOARD_HELPERS");3839/*40* DMIC DAI Link41*/42static const struct snd_soc_dapm_widget dmic_widgets[] = {43SND_SOC_DAPM_MIC("SoC DMIC", NULL),44};4546static const struct snd_soc_dapm_route dmic_routes[] = {47{"DMic", NULL, "SoC DMIC"},48};4950static int dmic_init(struct snd_soc_pcm_runtime *rtd)51{52struct snd_soc_card *card = rtd->card;53int ret;5455ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,56ARRAY_SIZE(dmic_widgets));57if (ret) {58dev_err(rtd->dev, "fail to add dmic widgets, ret %d\n", ret);59return ret;60}6162ret = snd_soc_dapm_add_routes(&card->dapm, dmic_routes,63ARRAY_SIZE(dmic_routes));64if (ret) {65dev_err(rtd->dev, "fail to add dmic routes, ret %d\n", ret);66return ret;67}6869return 0;70}7172/*73* HDA External Codec DAI Link74*/75static const struct snd_soc_dapm_widget hda_widgets[] = {76SND_SOC_DAPM_MIC("Analog In", NULL),77SND_SOC_DAPM_MIC("Digital In", NULL),78SND_SOC_DAPM_MIC("Alt Analog In", NULL),7980SND_SOC_DAPM_HP("Analog Out", NULL),81SND_SOC_DAPM_SPK("Digital Out", NULL),82SND_SOC_DAPM_HP("Alt Analog Out", NULL),83};8485static const struct snd_soc_dapm_route hda_routes[] = {86{ "Codec Input Pin1", NULL, "Analog In" },87{ "Codec Input Pin2", NULL, "Digital In" },88{ "Codec Input Pin3", NULL, "Alt Analog In" },8990{ "Analog Out", NULL, "Codec Output Pin1" },91{ "Digital Out", NULL, "Codec Output Pin2" },92{ "Alt Analog Out", NULL, "Codec Output Pin3" },9394/* CODEC BE connections */95{ "codec0_in", NULL, "Analog CPU Capture" },96{ "Analog CPU Capture", NULL, "Analog Codec Capture" },97{ "codec1_in", NULL, "Digital CPU Capture" },98{ "Digital CPU Capture", NULL, "Digital Codec Capture" },99{ "codec2_in", NULL, "Alt Analog CPU Capture" },100{ "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" },101102{ "Analog Codec Playback", NULL, "Analog CPU Playback" },103{ "Analog CPU Playback", NULL, "codec0_out" },104{ "Digital Codec Playback", NULL, "Digital CPU Playback" },105{ "Digital CPU Playback", NULL, "codec1_out" },106{ "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" },107{ "Alt Analog CPU Playback", NULL, "codec2_out" },108};109110static int hda_init(struct snd_soc_pcm_runtime *rtd)111{112struct snd_soc_card *card = rtd->card;113int ret;114115ret = snd_soc_dapm_new_controls(&card->dapm, hda_widgets,116ARRAY_SIZE(hda_widgets));117if (ret) {118dev_err(rtd->dev, "fail to add hda widgets, ret %d\n", ret);119return ret;120}121122ret = snd_soc_dapm_add_routes(&card->dapm, hda_routes,123ARRAY_SIZE(hda_routes));124if (ret)125dev_err(rtd->dev, "fail to add hda routes, ret %d\n", ret);126127return ret;128}129130/*131* DAI Link Helpers132*/133134enum sof_dmic_be_type {135SOF_DMIC_01,136SOF_DMIC_16K,137};138139enum sof_hda_be_type {140SOF_HDA_ANALOG,141SOF_HDA_DIGITAL,142};143144/* DEFAULT_LINK_ORDER: the order used in sof_rt5682 */145#define DEFAULT_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_CODEC, \146SOF_LINK_DMIC01, \147SOF_LINK_DMIC16K, \148SOF_LINK_IDISP_HDMI, \149SOF_LINK_AMP, \150SOF_LINK_BT_OFFLOAD, \151SOF_LINK_HDMI_IN)152153static struct snd_soc_dai_link_component dmic_component[] = {154{155.name = "dmic-codec",156.dai_name = "dmic-hifi",157}158};159160SND_SOC_DAILINK_DEF(hda_analog_cpus,161DAILINK_COMP_ARRAY(COMP_CPU("Analog CPU DAI")));162SND_SOC_DAILINK_DEF(hda_analog_codecs,163DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Analog Codec DAI")));164165SND_SOC_DAILINK_DEF(hda_digital_cpus,166DAILINK_COMP_ARRAY(COMP_CPU("Digital CPU DAI")));167SND_SOC_DAILINK_DEF(hda_digital_codecs,168DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Digital Codec DAI")));169170static struct snd_soc_dai_link_component platform_component[] = {171{172/* name might be overridden during probe */173.name = "0000:00:1f.3"174}175};176177static int set_ssp_codec_link(struct device *dev, struct snd_soc_dai_link *link,178int be_id, enum snd_soc_acpi_intel_codec codec_type,179int ssp_codec)180{181struct snd_soc_dai_link_component *cpus;182183dev_dbg(dev, "link %d: ssp codec %s, ssp %d\n", be_id,184snd_soc_acpi_intel_get_codec_name(codec_type), ssp_codec);185186/* link name */187link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec);188if (!link->name)189return -ENOMEM;190191/* cpus */192cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),193GFP_KERNEL);194if (!cpus)195return -ENOMEM;196197if (soc_intel_is_byt() || soc_intel_is_cht()) {198/* backward-compatibility for BYT/CHT boards */199cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssp%d-port",200ssp_codec);201} else {202cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin",203ssp_codec);204}205if (!cpus->dai_name)206return -ENOMEM;207208link->cpus = cpus;209link->num_cpus = 1;210211/* codecs - caller to handle */212213/* platforms */214link->platforms = platform_component;215link->num_platforms = ARRAY_SIZE(platform_component);216217link->id = be_id;218link->no_pcm = 1;219220return 0;221}222223static int set_dmic_link(struct device *dev, struct snd_soc_dai_link *link,224int be_id, enum sof_dmic_be_type be_type)225{226struct snd_soc_dai_link_component *cpus;227228/* cpus */229cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),230GFP_KERNEL);231if (!cpus)232return -ENOMEM;233234switch (be_type) {235case SOF_DMIC_01:236dev_dbg(dev, "link %d: dmic01\n", be_id);237238link->name = "dmic01";239cpus->dai_name = "DMIC01 Pin";240break;241case SOF_DMIC_16K:242dev_dbg(dev, "link %d: dmic16k\n", be_id);243244link->name = "dmic16k";245cpus->dai_name = "DMIC16k Pin";246break;247default:248dev_err(dev, "invalid be type %d\n", be_type);249return -EINVAL;250}251252link->cpus = cpus;253link->num_cpus = 1;254255/* codecs */256link->codecs = dmic_component;257link->num_codecs = ARRAY_SIZE(dmic_component);258259/* platforms */260link->platforms = platform_component;261link->num_platforms = ARRAY_SIZE(platform_component);262263link->id = be_id;264if (be_type == SOF_DMIC_01)265link->init = dmic_init;266link->ignore_suspend = 1;267link->no_pcm = 1;268link->capture_only = 1;269270return 0;271}272273static int set_idisp_hdmi_link(struct device *dev, struct snd_soc_dai_link *link,274int be_id, int hdmi_id, bool idisp_codec)275{276struct snd_soc_dai_link_component *cpus, *codecs;277278dev_dbg(dev, "link %d: idisp hdmi %d, idisp codec %d\n", be_id, hdmi_id,279idisp_codec);280281/* link name */282link->name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", hdmi_id);283if (!link->name)284return -ENOMEM;285286/* cpus */287cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),288GFP_KERNEL);289if (!cpus)290return -ENOMEM;291292cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", hdmi_id);293if (!cpus->dai_name)294return -ENOMEM;295296link->cpus = cpus;297link->num_cpus = 1;298299/* codecs */300if (idisp_codec) {301codecs = devm_kzalloc(dev,302sizeof(struct snd_soc_dai_link_component),303GFP_KERNEL);304if (!codecs)305return -ENOMEM;306307codecs->name = "ehdaudio0D2";308codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL,309"intel-hdmi-hifi%d", hdmi_id);310if (!codecs->dai_name)311return -ENOMEM;312313link->codecs = codecs;314} else {315link->codecs = &snd_soc_dummy_dlc;316}317link->num_codecs = 1;318319/* platforms */320link->platforms = platform_component;321link->num_platforms = ARRAY_SIZE(platform_component);322323link->id = be_id;324link->init = (hdmi_id == 1) ? hdmi_init : NULL;325link->no_pcm = 1;326link->playback_only = 1;327328return 0;329}330331static int set_ssp_amp_link(struct device *dev, struct snd_soc_dai_link *link,332int be_id, enum snd_soc_acpi_intel_codec amp_type,333int ssp_amp)334{335struct snd_soc_dai_link_component *cpus;336337dev_dbg(dev, "link %d: ssp amp %s, ssp %d\n", be_id,338snd_soc_acpi_intel_get_codec_name(amp_type), ssp_amp);339340/* link name */341link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_amp);342if (!link->name)343return -ENOMEM;344345/* cpus */346cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),347GFP_KERNEL);348if (!cpus)349return -ENOMEM;350351cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_amp);352if (!cpus->dai_name)353return -ENOMEM;354355link->cpus = cpus;356link->num_cpus = 1;357358/* codecs - caller to handle */359360/* platforms */361/* feedback stream or firmware-generated echo reference */362link->platforms = platform_component;363link->num_platforms = ARRAY_SIZE(platform_component);364365link->id = be_id;366link->no_pcm = 1;367368return 0;369}370371static int set_bt_offload_link(struct device *dev, struct snd_soc_dai_link *link,372int be_id, int ssp_bt)373{374struct snd_soc_dai_link_component *cpus;375376dev_dbg(dev, "link %d: bt offload, ssp %d\n", be_id, ssp_bt);377378/* link name */379link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", ssp_bt);380if (!link->name)381return -ENOMEM;382383/* cpus */384cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),385GFP_KERNEL);386if (!cpus)387return -ENOMEM;388389cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_bt);390if (!cpus->dai_name)391return -ENOMEM;392393link->cpus = cpus;394link->num_cpus = 1;395396/* codecs */397link->codecs = &snd_soc_dummy_dlc;398link->num_codecs = 1;399400/* platforms */401link->platforms = platform_component;402link->num_platforms = ARRAY_SIZE(platform_component);403404link->id = be_id;405link->no_pcm = 1;406407return 0;408}409410static int set_hdmi_in_link(struct device *dev, struct snd_soc_dai_link *link,411int be_id, int ssp_hdmi)412{413struct snd_soc_dai_link_component *cpus;414415dev_dbg(dev, "link %d: hdmi-in, ssp %d\n", be_id, ssp_hdmi);416417/* link name */418link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", ssp_hdmi);419if (!link->name)420return -ENOMEM;421422/* cpus */423cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),424GFP_KERNEL);425if (!cpus)426return -ENOMEM;427428cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_hdmi);429if (!cpus->dai_name)430return -ENOMEM;431432link->cpus = cpus;433link->num_cpus = 1;434435/* codecs */436link->codecs = &snd_soc_dummy_dlc;437link->num_codecs = 1;438439/* platforms */440link->platforms = platform_component;441link->num_platforms = ARRAY_SIZE(platform_component);442443link->id = be_id;444link->no_pcm = 1;445link->capture_only = 1;446447return 0;448}449450static int set_hda_codec_link(struct device *dev, struct snd_soc_dai_link *link,451int be_id, enum sof_hda_be_type be_type)452{453switch (be_type) {454case SOF_HDA_ANALOG:455dev_dbg(dev, "link %d: hda analog\n", be_id);456457link->name = "Analog Playback and Capture";458459/* cpus */460link->cpus = hda_analog_cpus;461link->num_cpus = ARRAY_SIZE(hda_analog_cpus);462463/* codecs */464link->codecs = hda_analog_codecs;465link->num_codecs = ARRAY_SIZE(hda_analog_codecs);466break;467case SOF_HDA_DIGITAL:468dev_dbg(dev, "link %d: hda digital\n", be_id);469470link->name = "Digital Playback and Capture";471472/* cpus */473link->cpus = hda_digital_cpus;474link->num_cpus = ARRAY_SIZE(hda_digital_cpus);475476/* codecs */477link->codecs = hda_digital_codecs;478link->num_codecs = ARRAY_SIZE(hda_digital_codecs);479break;480default:481dev_err(dev, "invalid be type %d\n", be_type);482return -EINVAL;483}484485/* platforms */486link->platforms = platform_component;487link->num_platforms = ARRAY_SIZE(platform_component);488489link->id = be_id;490if (be_type == SOF_HDA_ANALOG)491link->init = hda_init;492link->no_pcm = 1;493494return 0;495}496497static int calculate_num_links(struct sof_card_private *ctx)498{499int num_links = 0;500501/* headphone codec */502if (ctx->codec_type != CODEC_NONE)503num_links++;504505/* dmic01 and dmic16k */506if (ctx->dmic_be_num > 0)507num_links++;508509if (ctx->dmic_be_num > 1)510num_links++;511512/* idisp HDMI */513num_links += ctx->hdmi_num;514515/* speaker amp */516if (ctx->amp_type != CODEC_NONE)517num_links++;518519/* BT audio offload */520if (ctx->bt_offload_present)521num_links++;522523/* HDMI-In */524num_links += hweight32(ctx->ssp_mask_hdmi_in);525526/* HDA external codec */527if (ctx->hda_codec_present)528num_links += 2;529530return num_links;531}532533int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,534struct sof_card_private *ctx)535{536struct snd_soc_dai_link *links;537int num_links;538int i;539int idx = 0;540int ret;541int ssp_hdmi_in = 0;542unsigned long link_order, link;543unsigned long link_ids, be_id;544545num_links = calculate_num_links(ctx);546547links = devm_kcalloc(dev, num_links, sizeof(struct snd_soc_dai_link),548GFP_KERNEL);549if (!links)550return -ENOMEM;551552if (ctx->link_order_overwrite)553link_order = ctx->link_order_overwrite;554else555link_order = DEFAULT_LINK_ORDER;556557if (ctx->link_id_overwrite)558link_ids = ctx->link_id_overwrite;559else560link_ids = 0;561562dev_dbg(dev, "create dai links, link_order 0x%lx, id_overwrite 0x%lx\n",563link_order, link_ids);564565while (link_order) {566link = link_order & SOF_LINK_ORDER_MASK;567link_order >>= SOF_LINK_ORDER_SHIFT;568569if (ctx->link_id_overwrite) {570be_id = link_ids & SOF_LINK_IDS_MASK;571link_ids >>= SOF_LINK_IDS_SHIFT;572} else {573/* use array index as link id */574be_id = idx;575}576577switch (link) {578case SOF_LINK_CODEC:579/* headphone codec */580if (ctx->codec_type == CODEC_NONE)581continue;582583ret = set_ssp_codec_link(dev, &links[idx], be_id,584ctx->codec_type, ctx->ssp_codec);585if (ret) {586dev_err(dev, "fail to set codec link, ret %d\n",587ret);588return ret;589}590591ctx->codec_link = &links[idx];592idx++;593break;594case SOF_LINK_DMIC01:595/* dmic01 */596if (ctx->dmic_be_num == 0)597continue;598599/* at least we have dmic01 */600ret = set_dmic_link(dev, &links[idx], be_id, SOF_DMIC_01);601if (ret) {602dev_err(dev, "fail to set dmic01 link, ret %d\n",603ret);604return ret;605}606607idx++;608break;609case SOF_LINK_DMIC16K:610/* dmic16k */611if (ctx->dmic_be_num <= 1)612continue;613614/* set up 2 BE links at most */615ret = set_dmic_link(dev, &links[idx], be_id,616SOF_DMIC_16K);617if (ret) {618dev_err(dev, "fail to set dmic16k link, ret %d\n",619ret);620return ret;621}622623idx++;624break;625case SOF_LINK_IDISP_HDMI:626/* idisp HDMI */627for (i = 1; i <= ctx->hdmi_num; i++) {628ret = set_idisp_hdmi_link(dev, &links[idx],629be_id, i,630ctx->hdmi.idisp_codec);631if (ret) {632dev_err(dev, "fail to set hdmi link, ret %d\n",633ret);634return ret;635}636637idx++;638be_id++;639}640break;641case SOF_LINK_AMP:642/* speaker amp */643if (ctx->amp_type == CODEC_NONE)644continue;645646ret = set_ssp_amp_link(dev, &links[idx], be_id,647ctx->amp_type, ctx->ssp_amp);648if (ret) {649dev_err(dev, "fail to set amp link, ret %d\n",650ret);651return ret;652}653654ctx->amp_link = &links[idx];655idx++;656break;657case SOF_LINK_BT_OFFLOAD:658/* BT audio offload */659if (!ctx->bt_offload_present)660continue;661662ret = set_bt_offload_link(dev, &links[idx], be_id,663ctx->ssp_bt);664if (ret) {665dev_err(dev, "fail to set bt link, ret %d\n",666ret);667return ret;668}669670idx++;671break;672case SOF_LINK_HDMI_IN:673/* HDMI-In */674for_each_set_bit(ssp_hdmi_in, &ctx->ssp_mask_hdmi_in, 32) {675ret = set_hdmi_in_link(dev, &links[idx], be_id,676ssp_hdmi_in);677if (ret) {678dev_err(dev, "fail to set hdmi-in link, ret %d\n",679ret);680return ret;681}682683idx++;684be_id++;685}686break;687case SOF_LINK_HDA:688/* HDA external codec */689if (!ctx->hda_codec_present)690continue;691692ret = set_hda_codec_link(dev, &links[idx], be_id,693SOF_HDA_ANALOG);694if (ret) {695dev_err(dev, "fail to set hda analog link, ret %d\n",696ret);697return ret;698}699700idx++;701be_id++;702703ret = set_hda_codec_link(dev, &links[idx], be_id,704SOF_HDA_DIGITAL);705if (ret) {706dev_err(dev, "fail to set hda digital link, ret %d\n",707ret);708return ret;709}710711idx++;712break;713case SOF_LINK_NONE:714/* caught here if it's not used as terminator in macro */715fallthrough;716default:717dev_err(dev, "invalid link type %ld\n", link);718return -EINVAL;719}720}721722if (idx != num_links) {723dev_err(dev, "link number mismatch, idx %d, num_links %d\n", idx,724num_links);725return -EINVAL;726}727728card->dai_link = links;729card->num_links = num_links;730731return 0;732}733EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, "SND_SOC_INTEL_SOF_BOARD_HELPERS");734735struct sof_card_private *736sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk)737{738struct sof_card_private *ctx;739740dev_dbg(dev, "create ctx, board_quirk 0x%lx\n", board_quirk);741742ctx = devm_kzalloc(dev, sizeof(struct sof_card_private), GFP_KERNEL);743if (!ctx)744return NULL;745746ctx->codec_type = snd_soc_acpi_intel_detect_codec_type(dev);747ctx->amp_type = snd_soc_acpi_intel_detect_amp_type(dev);748749ctx->dmic_be_num = 2;750ctx->hdmi_num = (board_quirk & SOF_NUM_IDISP_HDMI_MASK) >>751SOF_NUM_IDISP_HDMI_SHIFT;752/* default number of HDMI DAI's */753if (!ctx->hdmi_num)754ctx->hdmi_num = 3;755756/* port number/mask of peripherals attached to ssp interface */757if (ctx->codec_type != CODEC_NONE)758ctx->ssp_codec = (board_quirk & SOF_SSP_PORT_CODEC_MASK) >>759SOF_SSP_PORT_CODEC_SHIFT;760761if (ctx->amp_type != CODEC_NONE)762ctx->ssp_amp = (board_quirk & SOF_SSP_PORT_AMP_MASK) >>763SOF_SSP_PORT_AMP_SHIFT;764765if (board_quirk & SOF_BT_OFFLOAD_PRESENT) {766ctx->bt_offload_present = true;767ctx->ssp_bt = (board_quirk & SOF_SSP_PORT_BT_OFFLOAD_MASK) >>768SOF_SSP_PORT_BT_OFFLOAD_SHIFT;769}770771ctx->ssp_mask_hdmi_in = (board_quirk & SOF_SSP_MASK_HDMI_CAPTURE_MASK) >>772SOF_SSP_MASK_HDMI_CAPTURE_SHIFT;773774return ctx;775}776EXPORT_SYMBOL_NS(sof_intel_board_get_ctx, "SND_SOC_INTEL_SOF_BOARD_HELPERS");777778MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers");779MODULE_AUTHOR("Brent Lu <[email protected]>");780MODULE_LICENSE("GPL");781MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON");782MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_MATCH");783784785