Commit 460f623a authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/intel' into asoc-next

parents 39e0a0ae 38a77085
......@@ -163,8 +163,71 @@
*
* %SKL_TKN_U32_DMA_BUF_SIZE: DMA buffer size in millisec
*
* %SKL_TKN_U32_PIPE_DIR: Specifies pipe direction. Can be
* playback/capture.
*
* %SKL_TKN_U32_NUM_CONFIGS: Number of pipe configs
*
* %SKL_TKN_U32_PATH_MEM_PGS: Size of memory (in pages) required for pipeline
* and its data
*
* %SKL_TKN_U32_PIPE_CONFIG_ID: Config id for the modules in the pipe
* and PCM params supported by that pipe
* config. This is used as index to fill
* up the pipe config and module config
* structure.
*
* %SKL_TKN_U32_CFG_FREQ:
* %SKL_TKN_U8_CFG_CHAN:
* %SKL_TKN_U8_CFG_BPS: PCM params (freq, channels, bits per sample)
* supported for each of the pipe configs.
*
* %SKL_TKN_CFG_MOD_RES_ID: Module's resource index for each of the
* pipe config
*
* %SKL_TKN_CFG_MOD_FMT_ID: Module's interface index for each of the
* pipe config
*
* %SKL_TKN_U8_NUM_MOD: Number of modules in the manifest
*
* %SKL_TKN_MM_U8_MOD_IDX: Current index of the module in the manifest
*
* %SKL_TKN_MM_U8_NUM_RES: Number of resources for the module
*
* %SKL_TKN_MM_U8_NUM_INTF: Number of interfaces for the module
*
* %SKL_TKN_MM_U32_RES_ID: Resource index for the resource info to
* be filled into.
* A module can support multiple resource
* configuration and is represnted as a
* resource table. This index is used to
* fill information into appropriate index.
*
* %SKL_TKN_MM_U32_CPS: DSP cycles per second
*
* %SKL_TKN_MM_U32_DMA_SIZE: Allocated buffer size for gateway DMA
*
* %SKL_TKN_MM_U32_CPC: DSP cycles allocated per frame
*
* %SKL_TKN_MM_U32_RES_PIN_ID: Resource pin index in the module
*
* %SKL_TKN_MM_U32_INTF_PIN_ID: Interface index in the module
*
* %SKL_TKN_MM_U32_PIN_BUF: Buffer size of the module pin
*
* %SKL_TKN_MM_U32_FMT_ID: Format index for each of the interface/
* format information to be filled into.
*
* %SKL_TKN_MM_U32_NUM_IN_FMT: Number of input formats
* %SKL_TKN_MM_U32_NUM_OUT_FMT: Number of output formats
*
* module_id and loadable flags dont have tokens as these values will be
* read from the DSP FW manifest
*
* Tokens defined can be used either in the manifest or widget private data.
*
* SKL_TKN_MM is used as a suffix for all tokens that represent
* module data in the manifest.
*/
enum SKL_TKNS {
SKL_TKN_UUID = 1,
......@@ -218,7 +281,34 @@ enum SKL_TKNS {
SKL_TKL_U32_D0I3_CAPS, /* Typo added at v4.10 */
SKL_TKN_U32_D0I3_CAPS = SKL_TKL_U32_D0I3_CAPS,
SKL_TKN_U32_DMA_BUF_SIZE,
SKL_TKN_MAX = SKL_TKN_U32_DMA_BUF_SIZE,
SKL_TKN_U32_PIPE_DIRECTION,
SKL_TKN_U32_PIPE_CONFIG_ID,
SKL_TKN_U32_NUM_CONFIGS,
SKL_TKN_U32_PATH_MEM_PGS,
SKL_TKN_U32_CFG_FREQ,
SKL_TKN_U8_CFG_CHAN,
SKL_TKN_U8_CFG_BPS,
SKL_TKN_CFG_MOD_RES_ID,
SKL_TKN_CFG_MOD_FMT_ID,
SKL_TKN_U8_NUM_MOD,
SKL_TKN_MM_U8_MOD_IDX,
SKL_TKN_MM_U8_NUM_RES,
SKL_TKN_MM_U8_NUM_INTF,
SKL_TKN_MM_U32_RES_ID,
SKL_TKN_MM_U32_CPS,
SKL_TKN_MM_U32_DMA_SIZE,
SKL_TKN_MM_U32_CPC,
SKL_TKN_MM_U32_RES_PIN_ID,
SKL_TKN_MM_U32_INTF_PIN_ID,
SKL_TKN_MM_U32_PIN_BUF,
SKL_TKN_MM_U32_FMT_ID,
SKL_TKN_MM_U32_NUM_IN_FMT,
SKL_TKN_MM_U32_NUM_OUT_FMT,
SKL_TKN_MAX = SKL_TKN_MM_U32_NUM_OUT_FMT,
};
#endif
......@@ -321,6 +321,7 @@ obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o
obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o
obj-$(CONFIG_SND_SOC_MAX98371) += snd-soc-max98371.o
obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o
obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o
obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o
......
......@@ -121,6 +121,10 @@ struct hdac_hdmi_dai_port_map {
struct hdac_hdmi_cvt *cvt;
};
struct hdac_hdmi_drv_data {
unsigned int vendor_nid;
};
struct hdac_hdmi_priv {
struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS];
struct list_head pin_list;
......@@ -131,6 +135,7 @@ struct hdac_hdmi_priv {
int num_ports;
struct mutex pin_mutex;
struct hdac_chmap chmap;
struct hdac_hdmi_drv_data *drv_data;
};
static struct hdac_hdmi_pcm *
......@@ -1321,6 +1326,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
}
#define INTEL_VENDOR_NID 0x08
#define INTEL_GLK_VENDOR_NID 0x0b
#define INTEL_GET_VENDOR_VERB 0xf81
#define INTEL_SET_VENDOR_VERB 0x781
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
......@@ -1329,14 +1335,17 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
{
unsigned int vendor_param;
struct hdac_ext_device *edev = to_ehdac_device(hdac);
struct hdac_hdmi_priv *hdmi = edev->private_data;
unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
return;
vendor_param |= INTEL_EN_ALL_PIN_CVTS;
vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
INTEL_SET_VENDOR_VERB, vendor_param);
if (vendor_param == -1)
return;
......@@ -1345,15 +1354,18 @@ static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac)
{
unsigned int vendor_param;
struct hdac_ext_device *edev = to_ehdac_device(hdac);
struct hdac_hdmi_priv *hdmi = edev->private_data;
unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
return;
/* enable DP1.2 mode */
vendor_param |= INTEL_EN_DP12;
vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
INTEL_SET_VENDOR_VERB, vendor_param);
if (vendor_param == -1)
return;
......@@ -1927,6 +1939,14 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
return port->eld.info.spk_alloc;
}
static struct hdac_hdmi_drv_data intel_glk_drv_data = {
.vendor_nid = INTEL_GLK_VENDOR_NID,
};
static struct hdac_hdmi_drv_data intel_drv_data = {
.vendor_nid = INTEL_VENDOR_NID,
};
static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
{
struct hdac_device *codec = &edev->hdac;
......@@ -1935,6 +1955,8 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
struct hdac_ext_link *hlink = NULL;
int num_dais = 0;
int ret = 0;
struct hdac_driver *hdrv = drv_to_hdac_driver(codec->dev.driver);
const struct hda_device_id *hdac_id = hdac_get_device_id(codec, hdrv);
/* hold the ref while we probe */
hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
......@@ -1956,6 +1978,12 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached;
hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
if (hdac_id->driver_data)
hdmi_priv->drv_data =
(struct hdac_hdmi_drv_data *)hdac_id->driver_data;
else
hdmi_priv->drv_data = &intel_drv_data;
dev_set_drvdata(&codec->dev, edev);
INIT_LIST_HEAD(&hdmi_priv->pin_list);
......@@ -2127,7 +2155,8 @@ static const struct hda_device_id hdmi_list[] = {
HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI",
&intel_glk_drv_data),
{}
};
......
......@@ -349,12 +349,14 @@ static struct snd_soc_dai_driver max98371_dai[] = {
};
static const struct snd_soc_codec_driver max98371_codec = {
.component_driver = {
.controls = max98371_snd_controls,
.num_controls = ARRAY_SIZE(max98371_snd_controls),
.dapm_routes = max98371_audio_map,
.num_dapm_routes = ARRAY_SIZE(max98371_audio_map),
.dapm_widgets = max98371_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets),
},
};
static const struct regmap_config max98371_regmap = {
......
......@@ -255,11 +255,12 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
depends on X86_INTEL_LPSS && I2C
depends on X86_INTEL_LPSS && I2C && SPI
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT5663
select SND_SOC_RT5514
select SND_SOC_RT5514_SPI
select SND_SOC_MAX98927
select SND_SOC_HDAC_HDMI
help
......
......@@ -76,7 +76,7 @@ int sst_unregister_dsp(struct sst_device *dev)
}
EXPORT_SYMBOL_GPL(sst_unregister_dsp);
static struct snd_pcm_hardware sst_platform_pcm_hw = {
static const struct snd_pcm_hardware sst_platform_pcm_hw = {
.info = (SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_DOUBLE |
SNDRV_PCM_INFO_PAUSE |
......@@ -471,7 +471,7 @@ static void sst_disable_ssp(struct snd_pcm_substream *substream,
}
}
static struct snd_soc_dai_ops sst_media_dai_ops = {
static const struct snd_soc_dai_ops sst_media_dai_ops = {
.startup = sst_media_open,
.shutdown = sst_media_close,
.prepare = sst_media_prepare,
......@@ -480,11 +480,11 @@ static struct snd_soc_dai_ops sst_media_dai_ops = {
.mute_stream = sst_media_digital_mute,
};
static struct snd_soc_dai_ops sst_compr_dai_ops = {
static const struct snd_soc_dai_ops sst_compr_dai_ops = {
.mute_stream = sst_media_digital_mute,
};
static struct snd_soc_dai_ops sst_be_dai_ops = {
static const struct snd_soc_dai_ops sst_be_dai_ops = {
.startup = sst_enable_ssp,
.hw_params = sst_be_hw_params,
.set_fmt = sst_set_format,
......@@ -705,7 +705,7 @@ static int sst_soc_probe(struct snd_soc_platform *platform)
return sst_dsp_init_v2_dpcm(platform);
}
static struct snd_soc_platform_driver sst_soc_platform_drv = {
static const struct snd_soc_platform_driver sst_soc_platform_drv = {
.probe = sst_soc_probe,
.ops = &sst_platform_ops,
.compr_ops = &sst_platform_compr_ops,
......
......@@ -407,7 +407,7 @@ static int sst_cdev_caps(struct snd_compr_caps *caps)
return 0;
}
static struct snd_compr_codec_caps caps_mp3 = {
static const struct snd_compr_codec_caps caps_mp3 = {
.num_descriptors = 1,
.descriptor[0].max_ch = 2,
.descriptor[0].sample_rates[0] = 48000,
......@@ -424,7 +424,7 @@ static struct snd_compr_codec_caps caps_mp3 = {
.descriptor[0].formats = 0,
};
static struct snd_compr_codec_caps caps_aac = {
static const struct snd_compr_codec_caps caps_aac = {
.num_descriptors = 2,
.descriptor[1].max_ch = 2,
.descriptor[0].sample_rates[0] = 48000,
......
......@@ -181,7 +181,7 @@ static void intel_sst_remove(struct pci_dev *pci)
}
/* PCI Routines */
static struct pci_device_id intel_sst_ids[] = {
static const struct pci_device_id intel_sst_ids[] = {
{ PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
{ 0, }
};
......
......@@ -309,7 +309,7 @@ static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
return snd_pcm_lib_default_mmap(substream, vma);
}
static struct snd_pcm_ops sst_byt_pcm_ops = {
static const struct snd_pcm_ops sst_byt_pcm_ops = {
.open = sst_byt_pcm_open,
.close = sst_byt_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
......@@ -395,7 +395,7 @@ static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
return 0;
}
static struct snd_soc_platform_driver byt_soc_platform = {
static const struct snd_soc_platform_driver byt_soc_platform = {
.probe = sst_byt_pcm_probe,
.remove = sst_byt_pcm_remove,
.ops = &sst_byt_pcm_ops,
......
......@@ -114,7 +114,44 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = {
{ "iDisp2 Tx", NULL, "iDisp2_out"},
{ "hifi1", NULL, "iDisp1 Tx"},
{ "iDisp1 Tx", NULL, "iDisp1_out"},
};
static const struct snd_soc_dapm_route geminilake_rt298_map[] = {
/* speaker */
{"Speaker", NULL, "SPOR"},
{"Speaker", NULL, "SPOL"},
/* HP jack connectors - unknown if we have jack detect */
{"Headphone Jack", NULL, "HPO Pin"},
/* other jacks */
{"MIC1", NULL, "Mic Jack"},
/* digital mics */
{"DMIC1 Pin", NULL, "DMIC2"},
{"DMic", NULL, "SoC DMIC"},
{"HDMI1", NULL, "hif5-0 Output"},
{"HDMI2", NULL, "hif6-0 Output"},
{"HDMI2", NULL, "hif7-0 Output"},
/* CODEC BE connections */
{ "AIF1 Playback", NULL, "ssp2 Tx"},
{ "ssp2 Tx", NULL, "codec0_out"},
{ "ssp2 Tx", NULL, "codec1_out"},
{ "codec0_in", NULL, "ssp2 Rx" },
{ "ssp2 Rx", NULL, "AIF1 Capture" },
{ "dmic01_hifi", NULL, "DMIC01 Rx" },
{ "DMIC01 Rx", NULL, "Capture" },
{ "hifi3", NULL, "iDisp3 Tx"},
{ "iDisp3 Tx", NULL, "iDisp3_out"},
{ "hifi2", NULL, "iDisp2 Tx"},
{ "iDisp2 Tx", NULL, "iDisp2_out"},
{ "hifi1", NULL, "iDisp1 Tx"},
{ "iDisp1 Tx", NULL, "iDisp1_out"},
};
static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd)
......@@ -492,7 +529,6 @@ static int bxt_card_late_probe(struct snd_soc_card *card)
/* broxton audio machine driver for SPT + RT298S */
static struct snd_soc_card broxton_rt298 = {
.name = "broxton-rt298",
.owner = THIS_MODULE,
.dai_link = broxton_rt298_dais,
.num_links = ARRAY_SIZE(broxton_rt298_dais),
.controls = broxton_controls,
......@@ -506,9 +542,41 @@ static struct snd_soc_card broxton_rt298 = {
};
static struct snd_soc_card geminilake_rt298 = {
.name = "geminilake-rt298",
.dai_link = broxton_rt298_dais,
.num_links = ARRAY_SIZE(broxton_rt298_dais),
.controls = broxton_controls,
.num_controls = ARRAY_SIZE(broxton_controls),
.dapm_widgets = broxton_widgets,
.num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
.dapm_routes = geminilake_rt298_map,
.num_dapm_routes = ARRAY_SIZE(geminilake_rt298_map),
.fully_routed = true,
.late_probe = bxt_card_late_probe,
};
static int broxton_audio_probe(struct platform_device *pdev)
{
struct bxt_rt286_private *ctx;
struct snd_soc_card *card =
(struct snd_soc_card *)pdev->id_entry->driver_data;
int i;
for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) {
if (!strncmp(card->dai_link[i].codec_name, "i2c-INT343A:00",
I2C_NAME_SIZE)) {
if (!strncmp(card->name, "broxton-rt298",
PLATFORM_NAME_SIZE)) {
card->dai_link[i].name = "SSP5-Codec";
card->dai_link[i].cpu_dai_name = "SSP5 Pin";
} else if (!strncmp(card->name, "geminilake-rt298",
PLATFORM_NAME_SIZE)) {
card->dai_link[i].name = "SSP2-Codec";
card->dai_link[i].cpu_dai_name = "SSP2 Pin";
}
}
}
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
if (!ctx)
......@@ -516,18 +584,27 @@ static int broxton_audio_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
broxton_rt298.dev = &pdev->dev;
snd_soc_card_set_drvdata(&broxton_rt298, ctx);
card->dev = &pdev->dev;
snd_soc_card_set_drvdata(card, ctx);
return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298);
return devm_snd_soc_register_card(&pdev->dev, card);
}
static const struct platform_device_id bxt_board_ids[] = {
{ .name = "bxt_alc298s_i2s", .driver_data =
(unsigned long)&broxton_rt298 },
{ .name = "glk_alc298s_i2s", .driver_data =
(unsigned long)&geminilake_rt298 },
{}
};
static struct platform_driver broxton_audio = {
.probe = broxton_audio_probe,
.driver = {
.name = "bxt_alc298s_i2s",
.pm = &snd_soc_pm_ops,
},
.id_table = bxt_board_ids,
};
module_platform_driver(broxton_audio)
......@@ -537,3 +614,4 @@ MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>");
MODULE_DESCRIPTION("Intel SST Audio for Broxton");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:bxt_alc298s_i2s");
MODULE_ALIAS("platform:glk_alc298s_i2s");
......@@ -34,7 +34,7 @@
#define MAXIM_DEV0_NAME "i2c-MX98927:00"
#define MAXIM_DEV1_NAME "i2c-MX98927:01"
static struct snd_soc_card kabylake_audio_card;
static struct snd_soc_card *kabylake_audio_card;
static const struct snd_pcm_hw_constraint_list *dmic_constraints;
static struct snd_soc_jack skylake_hdmi[3];
......@@ -52,6 +52,8 @@ struct kbl_rt5663_private {
enum {
KBL_DPCM_AUDIO_PB = 0,
KBL_DPCM_AUDIO_CP,
KBL_DPCM_AUDIO_HS_PB,
KBL_DPCM_AUDIO_ECHO_REF_CP,
KBL_DPCM_AUDIO_REF_CP,
KBL_DPCM_AUDIO_DMIC_CP,
KBL_DPCM_AUDIO_HDMI1_PB,
......@@ -72,8 +74,9 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
SND_SOC_DAPM_SPK("Left Spk", NULL),
SND_SOC_DAPM_SPK("Right Spk", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
SND_SOC_DAPM_SPK("DP", NULL),
SND_SOC_DAPM_SPK("HDMI", NULL),
SND_SOC_DAPM_SPK("HDMI1", NULL),
SND_SOC_DAPM_SPK("HDMI2", NULL),
SND_SOC_DAPM_SPK("HDMI3", NULL),
};
......@@ -91,20 +94,22 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
{ "IN1N", NULL, "Headset Mic" },
{ "DMic", NULL, "SoC DMIC" },
{ "HDMI", NULL, "hif5 Output" },
{ "DP", NULL, "hif6 Output" },
/* CODEC BE connections */
{ "Left HiFi Playback", NULL, "ssp0 Tx" },
{ "Right HiFi Playback", NULL, "ssp0 Tx" },
{ "ssp0 Tx", NULL, "codec0_out" },
{ "ssp0 Tx", NULL, "spk_out" },
{ "AIF Playback", NULL, "ssp1 Tx" },
{ "ssp1 Tx", NULL, "codec1_out" },
{ "ssp1 Tx", NULL, "hs_out" },
{ "codec0_in", NULL, "ssp1 Rx" },
{ "hs_in", NULL, "ssp1 Rx" },
{ "ssp1 Rx", NULL, "AIF Capture" },
/* IV feedback path */
{ "codec0_fb_in", NULL, "ssp0 Rx"},
{ "ssp0 Rx", NULL, "Left HiFi Capture" },
{ "ssp0 Rx", NULL, "Right HiFi Capture" },
/* DMIC */
{ "dmic01_hifi", NULL, "DMIC01 Rx" },
{ "DMIC01 Rx", NULL, "DMIC AIF" },
......@@ -117,6 +122,49 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
{ "iDisp1 Tx", NULL, "iDisp1_out"},
};
enum {
KBL_DPCM_AUDIO_5663_PB = 0,
KBL_DPCM_AUDIO_5663_CP,
KBL_DPCM_AUDIO_5663_HDMI1_PB,
KBL_DPCM_AUDIO_5663_HDMI2_PB,
};
static const struct snd_kcontrol_new kabylake_5663_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
};
static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SPK("DP", NULL),
SND_SOC_DAPM_SPK("HDMI", NULL),
};
static const struct snd_soc_dapm_route kabylake_5663_map[] = {
{ "Headphone Jack", NULL, "HPOL" },
{ "Headphone Jack", NULL, "HPOR" },
/* other jacks */
{ "IN1P", NULL, "Headset Mic" },
{ "IN1N", NULL, "Headset Mic" },
{ "HDMI", NULL, "hif5 Output" },
{ "DP", NULL, "hif6 Output" },
/* CODEC BE connections */
{ "AIF Playback", NULL, "ssp1 Tx" },
{ "ssp1 Tx", NULL, "codec1_out" },
{ "codec0_in", NULL, "ssp1 Rx" },
{ "ssp1 Rx", NULL, "AIF Capture" },
{ "hifi2", NULL, "iDisp2 Tx"},
{ "iDisp2 Tx", NULL, "iDisp2_out"},
{ "hifi1", NULL, "iDisp1 Tx"},
{ "iDisp1 Tx", NULL, "iDisp1_out"},
};
static struct snd_soc_codec_conf max98927_codec_conf[] = {
{
.dev_name = MAXIM_DEV0_NAME,
......@@ -165,7 +213,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack",
ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset,
NULL, 0);
......@@ -173,8 +221,18 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
return ret;
}
rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
return ret;
}
static int kabylake_rt5663_max98927_codec_init(struct snd_soc_pcm_runtime *rtd)
{
int ret;
ret = kabylake_rt5663_codec_init(rtd);
if (ret)
return ret;
ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
if (ret) {
dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", ret);
......@@ -184,7 +242,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
{
struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai = rtd->codec_dai;
......@@ -194,7 +252,7 @@ static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
if (!pcm)
return -ENOMEM;
pcm->device = KBL_DPCM_AUDIO_HDMI1_PB;
pcm->device = device;
pcm->codec_dai = dai;
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
......@@ -202,47 +260,36 @@ static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
{
struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai = rtd->codec_dai;
struct kbl_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
pcm->device = KBL_DPCM_AUDIO_HDMI2_PB;
pcm->codec_dai = dai;
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
}
return 0;
static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
{
return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
}
static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
{
struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai = rtd->codec_dai;
struct kbl_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
pcm->device = KBL_DPCM_AUDIO_HDMI3_PB;
pcm->codec_dai = dai;
return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
}
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
static int kabylake_5663_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
{
return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI1_PB);
}
return 0;
static int kabylake_5663_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
{
return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI2_PB);
}
static unsigned int rates[] = {
48000,
};
static struct snd_pcm_hw_constraint_list constraints_rates = {
static const struct snd_pcm_hw_constraint_list constraints_rates = {
.count = ARRAY_SIZE(rates),
.list = rates,
.mask = 0,
......@@ -252,7 +299,7 @@ static unsigned int channels[] = {
2,
};
static struct snd_pcm_hw_constraint_list constraints_channels = {
static const struct snd_pcm_hw_constraint_list constraints_channels = {
.count = ARRAY_SIZE(channels),
.list = channels,
.mask = 0,
......@@ -312,11 +359,13 @@ static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai,
RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
/* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
rt5663_sel_asrc_clk_src(codec_dai->codec, RT5663_DA_STEREO_FILTER, 1);
rt5663_sel_asrc_clk_src(codec_dai->codec,
RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
RT5663_CLK_SEL_I2S1_ASRC);
ret = snd_soc_dai_set_sysclk(codec_dai,
RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
if (ret < 0)
dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
......@@ -381,7 +430,7 @@ static unsigned int rates_16000[] = {
16000,
};
static struct snd_pcm_hw_constraint_list constraints_16000 = {
static const struct snd_pcm_hw_constraint_list constraints_16000 = {
.count = ARRAY_SIZE(rates_16000),
.list = rates_16000,
};
......@@ -443,6 +492,28 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dpcm_capture = 1,
.ops = &kabylake_rt5663_fe_ops,
},
[KBL_DPCM_AUDIO_HS_PB] = {
.name = "Kbl Audio Headset Playback",
.stream_name = "Headset Audio",
.cpu_dai_name = "System Pin2",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.nonatomic = 1,
.dynamic = 1,
},
[KBL_DPCM_AUDIO_ECHO_REF_CP] = {
.name = "Kbl Audio Echo Reference cap",
.stream_name = "Echoreference Capture",
.cpu_dai_name = "Echoref Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.init = NULL,
.capture_only = 1,
.nonatomic = 1,
},
[KBL_DPCM_AUDIO_REF_CP] = {
.name = "Kbl Audio Reference cap",
.stream_name = "Wake on Voice",
......@@ -538,7 +609,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.no_pcm = 1,
.codec_name = "i2c-10EC5663:00",
.codec_dai_name = KBL_REALTEK_CODEC_DAI,
.init = kabylake_rt5663_codec_init,
.init = kabylake_rt5663_max98927_codec_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ignore_pmdown_time = 1,
......@@ -594,15 +665,119 @@ static struct snd_soc_dai_link kabylake_dais[] = {
},
};
static struct snd_soc_dai_link kabylake_5663_dais[] = {
/* Front End DAI links */
[KBL_DPCM_AUDIO_5663_PB] = {
.name = "Kbl Audio Port",
.stream_name = "Audio",
.cpu_dai_name = "System Pin",
.platform_name = "0000:00:1f.3",
.dynamic = 1,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.nonatomic = 1,
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_playback = 1,
.ops = &kabylake_rt5663_fe_ops,
},
[KBL_DPCM_AUDIO_5663_CP] = {
.name = "Kbl Audio Capture Port",
.stream_name = "Audio Record",
.cpu_dai_name = "System Pin",
.platform_name = "0000:00:1f.3",
.dynamic = 1,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.nonatomic = 1,
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_capture = 1,
.ops = &kabylake_rt5663_fe_ops,
},
[KBL_DPCM_AUDIO_5663_HDMI1_PB] = {
.name = "Kbl HDMI Port1",
.stream_name = "Hdmi1",
.cpu_dai_name = "HDMI1 Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.init = NULL,
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.nonatomic = 1,
.dynamic = 1,
},
[KBL_DPCM_AUDIO_5663_HDMI2_PB] = {
.name = "Kbl HDMI Port2",
.stream_name = "Hdmi2",
.cpu_dai_name = "HDMI2 Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.init = NULL,
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.nonatomic = 1,
.dynamic = 1,
},
/* Back End DAI links */
{
/* SSP1 - Codec */
.name = "SSP1-Codec",
.id = 0,
.cpu_dai_name = "SSP1 Pin",
.platform_name = "0000:00:1f.3",
.no_pcm = 1,
.codec_name = "i2c-10EC5663:00",
.codec_dai_name = KBL_REALTEK_CODEC_DAI,
.init = kabylake_rt5663_codec_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ignore_pmdown_time = 1,
.be_hw_params_fixup = kabylake_ssp_fixup,
.ops = &kabylake_rt5663_ops,
.dpcm_playback = 1,
.dpcm_capture = 1,
},
{
.name = "iDisp1",
.id = 1,
.cpu_dai_name = "iDisp1 Pin",
.codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi1",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.init = kabylake_5663_hdmi1_init,
.no_pcm = 1,
},
{
.name = "iDisp2",
.id = 2,
.cpu_dai_name = "iDisp2 Pin",
.codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi2",
.platform_name = "0000:00:1f.3",
.init = kabylake_5663_hdmi2_init,
.dpcm_playback = 1,
.no_pcm = 1,
},
};
#define NAME_SIZE 32
static int kabylake_card_late_probe(struct snd_soc_card *card)
{
struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card);
struct kbl_hdmi_pcm *pcm;
struct snd_soc_codec *codec = NULL;
int err, i = 0;
char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
codec = pcm->codec_dai->codec;
snprintf(jack_name, sizeof(jack_name),
"HDMI/DP, pcm=%d Jack", pcm->device);
err = snd_soc_card_jack_new(card, jack_name,
......@@ -620,11 +795,14 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
i++;
}
return 0;
if (!codec)
return -EINVAL;
return hdac_hdmi_jack_port_init(codec, &card->dapm);
}
/* kabylake audio machine driver for SPT + RT5663 */
static struct snd_soc_card kabylake_audio_card = {
static struct snd_soc_card kabylake_audio_card_rt5663_m98927 = {
.name = "kblrt5663max",
.owner = THIS_MODULE,
.dai_link = kabylake_dais,
......@@ -641,6 +819,22 @@ static struct snd_soc_card kabylake_audio_card = {
.late_probe = kabylake_card_late_probe,
};
/* kabylake audio machine driver for RT5663 */
static struct snd_soc_card kabylake_audio_card_rt5663 = {
.name = "kblrt5663",
.owner = THIS_MODULE,
.dai_link = kabylake_5663_dais,
.num_links = ARRAY_SIZE(kabylake_5663_dais),
.controls = kabylake_5663_controls,
.num_controls = ARRAY_SIZE(kabylake_5663_controls),
.dapm_widgets = kabylake_5663_widgets,
.num_dapm_widgets = ARRAY_SIZE(kabylake_5663_widgets),
.dapm_routes = kabylake_5663_map,
.num_dapm_routes = ARRAY_SIZE(kabylake_5663_map),
.fully_routed = true,
.late_probe = kabylake_card_late_probe,
};
static int kabylake_audio_probe(struct platform_device *pdev)
{
struct kbl_rt5663_private *ctx;
......@@ -652,19 +846,30 @@ static int kabylake_audio_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
kabylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&kabylake_audio_card, ctx);
kabylake_audio_card =
(struct snd_soc_card *)pdev->id_entry->driver_data;
kabylake_audio_card->dev = &pdev->dev;
snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
pdata = dev_get_drvdata(&pdev->dev);
if (pdata)
dmic_constraints = pdata->dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card);
return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
}
static const struct platform_device_id kbl_board_ids[] = {
{ .name = "kbl_rt5663_m98927" },
{
.name = "kbl_rt5663",
.driver_data = (kernel_ulong_t)&kabylake_audio_card_rt5663,
},
{
.name = "kbl_rt5663_m98927",
.driver_data =
(kernel_ulong_t)&kabylake_audio_card_rt5663_m98927,
},
{ }
};
......@@ -684,4 +889,5 @@ MODULE_DESCRIPTION("Audio Machine driver-RT5663 & MAX98927 in I2S mode");
MODULE_AUTHOR("Naveen M <naveen.m@intel.com>");
MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:kbl_rt5663");
MODULE_ALIAS("platform:kbl_rt5663_m98927");
......@@ -18,6 +18,7 @@
* GNU General Public License for more details.
*/
#include <linux/input.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/core.h>
......@@ -62,7 +63,10 @@ struct kbl_codec_private {
enum {
KBL_DPCM_AUDIO_PB = 0,
KBL_DPCM_AUDIO_CP,
KBL_DPCM_AUDIO_HS_PB,
KBL_DPCM_AUDIO_ECHO_REF_CP,
KBL_DPCM_AUDIO_DMIC_CP,
KBL_DPCM_AUDIO_RT5514_DSP,
KBL_DPCM_AUDIO_HDMI1_PB,
KBL_DPCM_AUDIO_HDMI2_PB,
};
......@@ -81,8 +85,8 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
SND_SOC_DAPM_SPK("Left Spk", NULL),
SND_SOC_DAPM_SPK("Right Spk", NULL),
SND_SOC_DAPM_MIC("DMIC", NULL),
SND_SOC_DAPM_SPK("DP", NULL),
SND_SOC_DAPM_SPK("HDMI", NULL),
SND_SOC_DAPM_SPK("HDMI1", NULL),
SND_SOC_DAPM_SPK("HDMI2", NULL),
};
......@@ -99,23 +103,25 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
{ "IN1P", NULL, "Headset Mic" },
{ "IN1N", NULL, "Headset Mic" },
{ "HDMI", NULL, "hif5 Output" },
{ "DP", NULL, "hif6 Output" },
/* CODEC BE connections */
{ "Left HiFi Playback", NULL, "ssp0 Tx" },
{ "Right HiFi Playback", NULL, "ssp0 Tx" },
{ "ssp0 Tx", NULL, "codec0_out" },
{ "ssp0 Tx", NULL, "spk_out" },
{ "AIF Playback", NULL, "ssp1 Tx" },
{ "ssp1 Tx", NULL, "codec1_out" },
{ "ssp1 Tx", NULL, "hs_out" },
{ "codec0_in", NULL, "ssp1 Rx" },
{ "hs_in", NULL, "ssp1 Rx" },
{ "ssp1 Rx", NULL, "AIF Capture" },
{ "codec1_in", NULL, "ssp0 Rx" },
{ "ssp0 Rx", NULL, "AIF1 Capture" },
/* IV feedback path */
{ "codec0_fb_in", NULL, "ssp0 Rx"},
{ "ssp0 Rx", NULL, "Left HiFi Capture" },
{ "ssp0 Rx", NULL, "Right HiFi Capture" },
/* DMIC */
{ "DMIC1L", NULL, "DMIC" },
{ "DMIC1R", NULL, "DMIC" },
......@@ -173,6 +179,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
int ret;
struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_jack *jack;
/*
* Headset buttons map to the google Reference headset.
......@@ -187,6 +194,12 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
jack = &ctx->kabylake_headset;
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC");
......@@ -358,11 +371,18 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
return ret;
}
}
if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME) ||
!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF0, 3, 8, 16);
if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) {
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
if (ret < 0) {
dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
dev_err(rtd->dev, "DEV0 TDM slot err:%d\n", ret);
return ret;
}
}
if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
if (ret < 0) {
dev_err(rtd->dev, "DEV1 TDM slot err:%d\n", ret);
return ret;
}
}
......@@ -442,6 +462,36 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dpcm_capture = 1,
.ops = &kabylake_rt5663_fe_ops,
},
[KBL_DPCM_AUDIO_HS_PB] = {
.name = "Kbl Audio Headset Playback",
.stream_name = "Headset Audio",
.cpu_dai_name = "System Pin2",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.nonatomic = 1,
.dynamic = 1,
},
[KBL_DPCM_AUDIO_ECHO_REF_CP] = {
.name = "Kbl Audio Echo Reference cap",
.stream_name = "Echoreference Capture",
.cpu_dai_name = "Echoref Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.init = NULL,
.capture_only = 1,
.nonatomic = 1,
},
[KBL_DPCM_AUDIO_RT5514_DSP] = {
.name = "rt5514 dsp",
.stream_name = "Wake on Voice",
.cpu_dai_name = "spi-PRP0001:00",
.platform_name = "spi-PRP0001:00",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
},
[KBL_DPCM_AUDIO_DMIC_CP] = {
.name = "Kbl Audio DMIC cap",
.stream_name = "dmiccap",
......@@ -548,10 +598,12 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
{
struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
struct kbl_hdmi_pcm *pcm;
struct snd_soc_codec *codec = NULL;
int err, i = 0;
char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
codec = pcm->codec_dai->codec;
err = snd_soc_card_jack_new(card, jack_name,
SND_JACK_AVOUT, &ctx->kabylake_hdmi[i],
NULL, 0);
......@@ -565,7 +617,10 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
i++;
}
return 0;
if (!codec)
return -EINVAL;
return hdac_hdmi_jack_port_init(codec, &card->dapm);
}
/*
......
......@@ -376,10 +376,8 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
/* audio interrupt base of SRAM location where
* interrupts are stored by System FW */
mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
if (!mc_drv_ctx) {
pr_err("allocation failed\n");
if (!mc_drv_ctx)
return -ENOMEM;
}
irq_mem = platform_get_resource_byname(
pdev, IORESOURCE_MEM, "IRQ_BASE");
......
......@@ -1135,7 +1135,7 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)
return 0;
}
static struct snd_soc_platform_driver hsw_soc_platform = {
static const struct snd_soc_platform_driver hsw_soc_platform = {
.probe = hsw_pcm_probe,
.remove = hsw_pcm_remove,
.ops = &hsw_pcm_ops,
......
......@@ -8,7 +8,8 @@ endif
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
# Skylake IPC Support
snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \
skl-sst.o bxt-sst.o skl-sst-utils.o
snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o \
skl-sst-cldma.o skl-sst.o bxt-sst.o cnl-sst.o \
skl-sst-utils.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o
......@@ -530,7 +530,7 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
return 0;
}
static struct skl_dsp_fw_ops bxt_fw_ops = {
static const struct skl_dsp_fw_ops bxt_fw_ops = {
.set_state_D0 = bxt_set_dsp_D0,
.set_state_D3 = bxt_set_dsp_D3,
.set_state_D0i3 = bxt_schedule_dsp_D0i3,
......@@ -581,10 +581,15 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
ret = skl_ipc_init(dev, skl);
if (ret) {
skl_dsp_free(sst);
return ret;
}
/* set the D0i3 check */
skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0;
skl->cores.count = 2;
skl->boot_complete = false;
init_waitqueue_head(&skl->boot_wait);
INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
......@@ -629,11 +634,6 @@ void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
release_firmware(ctx->dsp->fw);
skl_freeup_uuid_list(ctx);
skl_ipc_free(&ctx->ipc);
ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
if (ctx->dsp->addr.lpe)
iounmap(ctx->dsp->addr.lpe);
ctx->dsp->ops->free(ctx->dsp);
}
EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup);
......
/*
* cnl-sst-dsp.c - CNL SST library generic function
*
* Copyright (C) 2016-17, Intel Corporation.
* Author: Guneshwor Singh <guneshwor.o.singh@intel.com>
*
* Modified from:
* SKL SST library generic function
* Copyright (C) 2014-15, Intel Corporation.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/device.h>
#include "../common/sst-dsp.h"
#include "../common/sst-ipc.h"
#include "../common/sst-dsp-priv.h"
#include "cnl-sst-dsp.h"
/* various timeout values */
#define CNL_DSP_PU_TO 50
#define CNL_DSP_PD_TO 50
#define CNL_DSP_RESET_TO 50
static int
cnl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
{
/* update bits */
sst_dsp_shim_update_bits_unlocked(ctx,
CNL_ADSP_REG_ADSPCS, CNL_ADSPCS_CRST(core_mask),
CNL_ADSPCS_CRST(core_mask));
/* poll with timeout to check if operation successful */
return sst_dsp_register_poll(ctx,
CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CRST(core_mask),
CNL_ADSPCS_CRST(core_mask),
CNL_DSP_RESET_TO,
"Set reset");
}
static int
cnl_dsp_core_unset_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
{
/* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CRST(core_mask), 0);
/* poll with timeout to check if operation successful */
return sst_dsp_register_poll(ctx,
CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CRST(core_mask),
0,
CNL_DSP_RESET_TO,
"Unset reset");
}
static bool is_cnl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask)
{
int val;
bool is_enable;
val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPCS);
is_enable = (val & CNL_ADSPCS_CPA(core_mask)) &&
(val & CNL_ADSPCS_SPA(core_mask)) &&
!(val & CNL_ADSPCS_CRST(core_mask)) &&
!(val & CNL_ADSPCS_CSTALL(core_mask));
dev_dbg(ctx->dev, "DSP core(s) enabled? %d: core_mask %#x\n",
is_enable, core_mask);
return is_enable;
}
static int cnl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask)
{
/* stall core */
sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CSTALL(core_mask),
CNL_ADSPCS_CSTALL(core_mask));
/* set reset state */
return cnl_dsp_core_set_reset_state(ctx, core_mask);
}
static int cnl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask)
{
int ret;
/* unset reset state */
ret = cnl_dsp_core_unset_reset_state(ctx, core_mask);
if (ret < 0)
return ret;
/* run core */
sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CSTALL(core_mask), 0);
if (!is_cnl_dsp_core_enable(ctx, core_mask)) {
cnl_dsp_reset_core(ctx, core_mask);
dev_err(ctx->dev, "DSP core mask %#x enable failed\n",
core_mask);
ret = -EIO;
}
return ret;
}
static int cnl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask)
{
/* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_SPA(core_mask),
CNL_ADSPCS_SPA(core_mask));
/* poll with timeout to check if operation successful */
return sst_dsp_register_poll(ctx, CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CPA(core_mask),
CNL_ADSPCS_CPA(core_mask),
CNL_DSP_PU_TO,
"Power up");
}
static int cnl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask)
{
/* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_SPA(core_mask), 0);
/* poll with timeout to check if operation successful */
return sst_dsp_register_poll(ctx,
CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CPA(core_mask),
0,
CNL_DSP_PD_TO,
"Power down");
}
int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask)
{
int ret;
/* power up */
ret = cnl_dsp_core_power_up(ctx, core_mask);
if (ret < 0) {
dev_dbg(ctx->dev, "DSP core mask %#x power up failed",
core_mask);
return ret;
}
return cnl_dsp_start_core(ctx, core_mask);
}
int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask)
{
int ret;
ret = cnl_dsp_reset_core(ctx, core_mask);
if (ret < 0) {
dev_err(ctx->dev, "DSP core mask %#x reset failed\n",
core_mask);
return ret;
}
/* power down core*/
ret = cnl_dsp_core_power_down(ctx, core_mask);
if (ret < 0) {
dev_err(ctx->dev, "DSP core mask %#x power down failed\n",
core_mask);
return ret;
}
if (is_cnl_dsp_core_enable(ctx, core_mask)) {
dev_err(ctx->dev, "DSP core mask %#x disable failed\n",
core_mask);
ret = -EIO;
}
return ret;
}
irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id)
{
struct sst_dsp *ctx = dev_id;
u32 val;
irqreturn_t ret = IRQ_NONE;
spin_lock(&ctx->spinlock);
val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS);
ctx->intr_status = val;
if (val == 0xffffffff) {
spin_unlock(&ctx->spinlock);
return IRQ_NONE;
}
if (val & CNL_ADSPIS_IPC) {
cnl_ipc_int_disable(ctx);
ret = IRQ_WAKE_THREAD;
}
spin_unlock(&ctx->spinlock);
return ret;
}
void cnl_dsp_free(struct sst_dsp *dsp)
{
cnl_ipc_int_disable(dsp);
free_irq(dsp->irq, dsp);
cnl_ipc_op_int_disable(dsp);
cnl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK);
}
EXPORT_SYMBOL_GPL(cnl_dsp_free);
void cnl_ipc_int_enable(struct sst_dsp *ctx)
{
sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_ADSPIC,
CNL_ADSPIC_IPC, CNL_ADSPIC_IPC);
}
void cnl_ipc_int_disable(struct sst_dsp *ctx)
{
sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPIC,
CNL_ADSPIC_IPC, 0);
}
void cnl_ipc_op_int_enable(struct sst_dsp *ctx)
{
/* enable IPC DONE interrupt */
sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
CNL_ADSP_REG_HIPCCTL_DONE,
CNL_ADSP_REG_HIPCCTL_DONE);
/* enable IPC BUSY interrupt */
sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
CNL_ADSP_REG_HIPCCTL_BUSY,
CNL_ADSP_REG_HIPCCTL_BUSY);
}
void cnl_ipc_op_int_disable(struct sst_dsp *ctx)
{
/* disable IPC DONE interrupt */
sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
CNL_ADSP_REG_HIPCCTL_DONE, 0);
/* disable IPC BUSY interrupt */
sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
CNL_ADSP_REG_HIPCCTL_BUSY, 0);
}
bool cnl_ipc_int_status(struct sst_dsp *ctx)
{
return sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS) &
CNL_ADSPIS_IPC;
}
void cnl_ipc_free(struct sst_generic_ipc *ipc)
{
cnl_ipc_op_int_disable(ipc->dsp);
sst_ipc_fini(ipc);
}
/*
* Cannonlake SST DSP Support
*
* Copyright (C) 2016-17, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef __CNL_SST_DSP_H__
#define __CNL_SST_DSP_H__
struct sst_dsp;
struct skl_sst;
struct sst_dsp_device;
struct sst_generic_ipc;
/* Intel HD Audio General DSP Registers */
#define CNL_ADSP_GEN_BASE 0x0
#define CNL_ADSP_REG_ADSPCS (CNL_ADSP_GEN_BASE + 0x04)
#define CNL_ADSP_REG_ADSPIC (CNL_ADSP_GEN_BASE + 0x08)
#define CNL_ADSP_REG_ADSPIS (CNL_ADSP_GEN_BASE + 0x0c)
/* Intel HD Audio Inter-Processor Communication Registers */
#define CNL_ADSP_IPC_BASE 0xc0
#define CNL_ADSP_REG_HIPCTDR (CNL_ADSP_IPC_BASE + 0x00)
#define CNL_ADSP_REG_HIPCTDA (CNL_ADSP_IPC_BASE + 0x04)
#define CNL_ADSP_REG_HIPCTDD (CNL_ADSP_IPC_BASE + 0x08)
#define CNL_ADSP_REG_HIPCIDR (CNL_ADSP_IPC_BASE + 0x10)
#define CNL_ADSP_REG_HIPCIDA (CNL_ADSP_IPC_BASE + 0x14)
#define CNL_ADSP_REG_HIPCIDD (CNL_ADSP_IPC_BASE + 0x18)
#define CNL_ADSP_REG_HIPCCTL (CNL_ADSP_IPC_BASE + 0x28)
/* HIPCTDR */
#define CNL_ADSP_REG_HIPCTDR_BUSY BIT(31)
/* HIPCTDA */
#define CNL_ADSP_REG_HIPCTDA_DONE BIT(31)
/* HIPCIDR */
#define CNL_ADSP_REG_HIPCIDR_BUSY BIT(31)
/* HIPCIDA */
#define CNL_ADSP_REG_HIPCIDA_DONE BIT(31)
/* CNL HIPCCTL */
#define CNL_ADSP_REG_HIPCCTL_DONE BIT(1)
#define CNL_ADSP_REG_HIPCCTL_BUSY BIT(0)
/* CNL HIPCT */
#define CNL_ADSP_REG_HIPCT_BUSY BIT(31)
/* Intel HD Audio SRAM Window 1 */
#define CNL_ADSP_SRAM1_BASE 0xa0000
#define CNL_ADSP_MMIO_LEN 0x10000
#define CNL_ADSP_W0_STAT_SZ 0x1000
#define CNL_ADSP_W0_UP_SZ 0x1000
#define CNL_ADSP_W1_SZ 0x1000
#define CNL_FW_STS_MASK 0xf
#define CNL_ADSPIC_IPC 0x1
#define CNL_ADSPIS_IPC 0x1
#define CNL_DSP_CORES 4
#define CNL_DSP_CORES_MASK ((1 << CNL_DSP_CORES) - 1)
/* core reset - asserted high */
#define CNL_ADSPCS_CRST_SHIFT 0
#define CNL_ADSPCS_CRST(x) (x << CNL_ADSPCS_CRST_SHIFT)
/* core run/stall - when set to 1 core is stalled */
#define CNL_ADSPCS_CSTALL_SHIFT 8
#define CNL_ADSPCS_CSTALL(x) (x << CNL_ADSPCS_CSTALL_SHIFT)
/* set power active - when set to 1 turn core on */
#define CNL_ADSPCS_SPA_SHIFT 16
#define CNL_ADSPCS_SPA(x) (x << CNL_ADSPCS_SPA_SHIFT)
/* current power active - power status of cores, set by hardware */
#define CNL_ADSPCS_CPA_SHIFT 24
#define CNL_ADSPCS_CPA(x) (x << CNL_ADSPCS_CPA_SHIFT)
int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core);
int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core);
irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id);
void cnl_dsp_free(struct sst_dsp *dsp);
void cnl_ipc_int_enable(struct sst_dsp *ctx);
void cnl_ipc_int_disable(struct sst_dsp *ctx);
void cnl_ipc_op_int_enable(struct sst_dsp *ctx);
void cnl_ipc_op_int_disable(struct sst_dsp *ctx);
bool cnl_ipc_int_status(struct sst_dsp *ctx);
void cnl_ipc_free(struct sst_generic_ipc *ipc);
int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
struct skl_sst **dsp);
int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx);
void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
#endif /*__CNL_SST_DSP_H__*/
/*
* cnl-sst.c - DSP library functions for CNL platform
*
* Copyright (C) 2016-17, Intel Corporation.
*
* Author: Guneshwor Singh <guneshwor.o.singh@intel.com>
*
* Modified from:
* HDA DSP library functions for SKL platform
* Copyright (C) 2014-15, Intel Corporation.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/device.h>
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
#include "../common/sst-ipc.h"
#include "cnl-sst-dsp.h"
#include "skl-sst-dsp.h"
#include "skl-sst-ipc.h"
#define CNL_FW_ROM_INIT 0x1
#define CNL_FW_INIT 0x5
#define CNL_IPC_PURGE 0x01004000
#define CNL_INIT_TIMEOUT 300
#define CNL_BASEFW_TIMEOUT 3000
#define CNL_ADSP_SRAM0_BASE 0x80000
/* Firmware status window */
#define CNL_ADSP_FW_STATUS CNL_ADSP_SRAM0_BASE
#define CNL_ADSP_ERROR_CODE (CNL_ADSP_FW_STATUS + 0x4)
#define CNL_INSTANCE_ID 0
#define CNL_BASE_FW_MODULE_ID 0
#define CNL_ADSP_FW_HDR_OFFSET 0x2000
#define CNL_ROM_CTRL_DMA_ID 0x9
static int cnl_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize)
{
int ret, stream_tag;
stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab);
if (stream_tag <= 0) {
dev_err(ctx->dev, "dma prepare failed: 0%#x\n", stream_tag);
return stream_tag;
}
ctx->dsp_ops.stream_tag = stream_tag;
memcpy(ctx->dmab.area, fwdata, fwsize);
/* purge FW request */
sst_dsp_shim_write(ctx, CNL_ADSP_REG_HIPCIDR,
CNL_ADSP_REG_HIPCIDR_BUSY | (CNL_IPC_PURGE |
((stream_tag - 1) << CNL_ROM_CTRL_DMA_ID)));
ret = cnl_dsp_enable_core(ctx, SKL_DSP_CORE0_MASK);
if (ret < 0) {
dev_err(ctx->dev, "dsp boot core failed ret: %d\n", ret);
ret = -EIO;
goto base_fw_load_failed;
}
/* enable interrupt */
cnl_ipc_int_enable(ctx);
cnl_ipc_op_int_enable(ctx);
ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK,
CNL_FW_ROM_INIT, CNL_INIT_TIMEOUT,
"rom load");
if (ret < 0) {
dev_err(ctx->dev, "rom init timeout, ret: %d\n", ret);
goto base_fw_load_failed;
}
return 0;
base_fw_load_failed:
ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag);
cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
return ret;
}
static int sst_transfer_fw_host_dma(struct sst_dsp *ctx)
{
int ret;
ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag);
ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK,
CNL_FW_INIT, CNL_BASEFW_TIMEOUT,
"firmware boot");
ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag);
ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag);
return ret;
}
static int cnl_load_base_firmware(struct sst_dsp *ctx)
{
struct firmware stripped_fw;
struct skl_sst *cnl = ctx->thread_context;
int ret;
if (!ctx->fw) {
ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
if (ret < 0) {
dev_err(ctx->dev, "request firmware failed: %d\n", ret);
goto cnl_load_base_firmware_failed;
}
}
/* parse uuids if first boot */
if (cnl->is_first_boot) {
ret = snd_skl_parse_uuids(ctx, ctx->fw,
CNL_ADSP_FW_HDR_OFFSET, 0);
if (ret < 0)
goto cnl_load_base_firmware_failed;
}
stripped_fw.data = ctx->fw->data;
stripped_fw.size = ctx->fw->size;
skl_dsp_strip_extended_manifest(&stripped_fw);
ret = cnl_prepare_fw(ctx, stripped_fw.data, stripped_fw.size);
if (ret < 0) {
dev_err(ctx->dev, "prepare firmware failed: %d\n", ret);
goto cnl_load_base_firmware_failed;
}
ret = sst_transfer_fw_host_dma(ctx);
if (ret < 0) {
dev_err(ctx->dev, "transfer firmware failed: %d\n", ret);
cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
goto cnl_load_base_firmware_failed;
}
ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete,
msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
if (ret == 0) {
dev_err(ctx->dev, "FW ready timed-out\n");
cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
ret = -EIO;
goto cnl_load_base_firmware_failed;
}
cnl->fw_loaded = true;
return 0;
cnl_load_base_firmware_failed:
release_firmware(ctx->fw);
ctx->fw = NULL;
return ret;
}
static int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
{
struct skl_sst *cnl = ctx->thread_context;
unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
struct skl_ipc_dxstate_info dx;
int ret;
if (!cnl->fw_loaded) {
cnl->boot_complete = false;
ret = cnl_load_base_firmware(ctx);
if (ret < 0) {
dev_err(ctx->dev, "fw reload failed: %d\n", ret);
return ret;
}
cnl->cores.state[core_id] = SKL_DSP_RUNNING;
return ret;
}
ret = cnl_dsp_enable_core(ctx, core_mask);
if (ret < 0) {
dev_err(ctx->dev, "enable dsp core %d failed: %d\n",
core_id, ret);
goto err;
}
if (core_id == SKL_DSP_CORE0_ID) {
/* enable interrupt */
cnl_ipc_int_enable(ctx);
cnl_ipc_op_int_enable(ctx);
cnl->boot_complete = false;
ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete,
msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
if (ret == 0) {
dev_err(ctx->dev,
"dsp boot timeout, status=%#x error=%#x\n",
sst_dsp_shim_read(ctx, CNL_ADSP_FW_STATUS),
sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE));
goto err;
}
} else {
dx.core_mask = core_mask;
dx.dx_mask = core_mask;
ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID,
CNL_BASE_FW_MODULE_ID, &dx);
if (ret < 0) {
dev_err(ctx->dev, "set_dx failed, core: %d ret: %d\n",
core_id, ret);
goto err;
}
}
cnl->cores.state[core_id] = SKL_DSP_RUNNING;
return 0;
err:
cnl_dsp_disable_core(ctx, core_mask);
return ret;
}
static int cnl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
{
struct skl_sst *cnl = ctx->thread_context;
unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
struct skl_ipc_dxstate_info dx;
int ret;
dx.core_mask = core_mask;
dx.dx_mask = SKL_IPC_D3_MASK;
ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID,
CNL_BASE_FW_MODULE_ID, &dx);
if (ret < 0) {
dev_err(ctx->dev,
"dsp core %d to d3 failed; continue reset\n",
core_id);
cnl->fw_loaded = false;
}
/* disable interrupts if core 0 */
if (core_id == SKL_DSP_CORE0_ID) {
skl_ipc_op_int_disable(ctx);
skl_ipc_int_disable(ctx);
}
ret = cnl_dsp_disable_core(ctx, core_mask);
if (ret < 0) {
dev_err(ctx->dev, "disable dsp core %d failed: %d\n",
core_id, ret);
return ret;
}
cnl->cores.state[core_id] = SKL_DSP_RESET;
return ret;
}
static unsigned int cnl_get_errno(struct sst_dsp *ctx)
{
return sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE);
}
static const struct skl_dsp_fw_ops cnl_fw_ops = {
.set_state_D0 = cnl_set_dsp_D0,
.set_state_D3 = cnl_set_dsp_D3,
.load_fw = cnl_load_base_firmware,
.get_fw_errcode = cnl_get_errno,
};
static struct sst_ops cnl_ops = {
.irq_handler = cnl_dsp_sst_interrupt,
.write = sst_shim32_write,
.read = sst_shim32_read,
.ram_read = sst_memcpy_fromio_32,
.ram_write = sst_memcpy_toio_32,
.free = cnl_dsp_free,
};
#define CNL_IPC_GLB_NOTIFY_RSP_SHIFT 29
#define CNL_IPC_GLB_NOTIFY_RSP_MASK 0x1
#define CNL_IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> CNL_IPC_GLB_NOTIFY_RSP_SHIFT) \
& CNL_IPC_GLB_NOTIFY_RSP_MASK)
static irqreturn_t cnl_dsp_irq_thread_handler(int irq, void *context)
{
struct sst_dsp *dsp = context;
struct skl_sst *cnl = sst_dsp_get_thread_context(dsp);
struct sst_generic_ipc *ipc = &cnl->ipc;
struct skl_ipc_header header = {0};
u32 hipcida, hipctdr, hipctdd;
int ipc_irq = 0;
/* here we handle ipc interrupts only */
if (!(dsp->intr_status & CNL_ADSPIS_IPC))
return IRQ_NONE;
hipcida = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDA);
hipctdr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDR);
/* reply message from dsp */
if (hipcida & CNL_ADSP_REG_HIPCIDA_DONE) {
sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL,
CNL_ADSP_REG_HIPCCTL_DONE, 0);
/* clear done bit - tell dsp operation is complete */
sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCIDA,
CNL_ADSP_REG_HIPCIDA_DONE, CNL_ADSP_REG_HIPCIDA_DONE);
ipc_irq = 1;
/* unmask done interrupt */
sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL,
CNL_ADSP_REG_HIPCCTL_DONE, CNL_ADSP_REG_HIPCCTL_DONE);
}
/* new message from dsp */
if (hipctdr & CNL_ADSP_REG_HIPCTDR_BUSY) {
hipctdd = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDD);
header.primary = hipctdr;
header.extension = hipctdd;
dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x",
header.primary);
dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x",
header.extension);
if (CNL_IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) {
/* Handle Immediate reply from DSP Core */
skl_ipc_process_reply(ipc, header);
} else {
dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n");
skl_ipc_process_notification(ipc, header);
}
/* clear busy interrupt */
sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDR,
CNL_ADSP_REG_HIPCTDR_BUSY, CNL_ADSP_REG_HIPCTDR_BUSY);
/* set done bit to ack dsp */
sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDA,
CNL_ADSP_REG_HIPCTDA_DONE, CNL_ADSP_REG_HIPCTDA_DONE);
ipc_irq = 1;
}
if (ipc_irq == 0)
return IRQ_NONE;
cnl_ipc_int_enable(dsp);
/* continue to send any remaining messages */
schedule_work(&ipc->kwork);
return IRQ_HANDLED;
}
static struct sst_dsp_device cnl_dev = {
.thread = cnl_dsp_irq_thread_handler,
.ops = &cnl_ops,
};
static void cnl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
{
struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header);
if (msg->tx_size)
sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size);
sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDD,
header->extension);
sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDR,
header->primary | CNL_ADSP_REG_HIPCIDR_BUSY);
}
static bool cnl_ipc_is_dsp_busy(struct sst_dsp *dsp)
{
u32 hipcidr;
hipcidr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDR);
return (hipcidr & CNL_ADSP_REG_HIPCIDR_BUSY);
}
static int cnl_ipc_init(struct device *dev, struct skl_sst *cnl)
{
struct sst_generic_ipc *ipc;
int err;
ipc = &cnl->ipc;
ipc->dsp = cnl->dsp;
ipc->dev = dev;
ipc->tx_data_max_size = CNL_ADSP_W1_SZ;
ipc->rx_data_max_size = CNL_ADSP_W0_UP_SZ;
err = sst_ipc_init(ipc);
if (err)
return err;
/*
* overriding tx_msg and is_dsp_busy since
* ipc registers are different for cnl
*/
ipc->ops.tx_msg = cnl_ipc_tx_msg;
ipc->ops.tx_data_copy = skl_ipc_tx_data_copy;
ipc->ops.is_dsp_busy = cnl_ipc_is_dsp_busy;
return 0;
}
int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
struct skl_sst **dsp)
{
struct skl_sst *cnl;
struct sst_dsp *sst;
int ret;
ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &cnl_dev);
if (ret < 0) {
dev_err(dev, "%s: no device\n", __func__);
return ret;
}
cnl = *dsp;
sst = cnl->dsp;
sst->fw_ops = cnl_fw_ops;
sst->addr.lpe = mmio_base;
sst->addr.shim = mmio_base;
sst->addr.sram0_base = CNL_ADSP_SRAM0_BASE;
sst->addr.sram1_base = CNL_ADSP_SRAM1_BASE;
sst->addr.w0_stat_sz = CNL_ADSP_W0_STAT_SZ;
sst->addr.w0_up_sz = CNL_ADSP_W0_UP_SZ;
sst_dsp_mailbox_init(sst, (CNL_ADSP_SRAM0_BASE + CNL_ADSP_W0_STAT_SZ),
CNL_ADSP_W0_UP_SZ, CNL_ADSP_SRAM1_BASE,
CNL_ADSP_W1_SZ);
ret = cnl_ipc_init(dev, cnl);
if (ret) {
skl_dsp_free(sst);
return ret;
}
cnl->boot_complete = false;
init_waitqueue_head(&cnl->boot_wait);
return 0;
}
EXPORT_SYMBOL_GPL(cnl_sst_dsp_init);
int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx)
{
int ret;
struct sst_dsp *sst = ctx->dsp;
ret = ctx->dsp->fw_ops.load_fw(sst);
if (ret < 0) {
dev_err(dev, "load base fw failed: %d", ret);
return ret;
}
skl_dsp_init_core_state(sst);
ctx->is_first_boot = false;
return 0;
}
EXPORT_SYMBOL_GPL(cnl_sst_init_fw);
void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
{
if (ctx->dsp->fw)
release_firmware(ctx->dsp->fw);
skl_freeup_uuid_list(ctx);
cnl_ipc_free(&ctx->ipc);
ctx->dsp->ops->free(ctx->dsp);
}
EXPORT_SYMBOL_GPL(cnl_sst_dsp_cleanup);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Intel Cannonlake IPC driver");
......@@ -22,6 +22,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include "skl-sst-dsp.h"
#include "cnl-sst-dsp.h"
#include "skl-sst-ipc.h"
#include "skl.h"
#include "../common/sst-dsp.h"
......@@ -201,6 +202,7 @@ static struct skl_dsp_loader_ops bxt_get_loader_ops(void)
static const struct skl_dsp_ops dsp_ops[] = {
{
.id = 0x9d70,
.num_cores = 2,
.loader_ops = skl_get_loader_ops,
.init = skl_sst_dsp_init,
.init_fw = skl_sst_init_fw,
......@@ -208,6 +210,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
},
{
.id = 0x9d71,
.num_cores = 2,
.loader_ops = skl_get_loader_ops,
.init = kbl_sst_dsp_init,
.init_fw = skl_sst_init_fw,
......@@ -215,6 +218,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
},
{
.id = 0x5a98,
.num_cores = 2,
.loader_ops = bxt_get_loader_ops,
.init = bxt_sst_dsp_init,
.init_fw = bxt_sst_init_fw,
......@@ -222,11 +226,20 @@ static const struct skl_dsp_ops dsp_ops[] = {
},
{
.id = 0x3198,
.num_cores = 2,
.loader_ops = bxt_get_loader_ops,
.init = bxt_sst_dsp_init,
.init_fw = bxt_sst_init_fw,
.cleanup = bxt_sst_dsp_cleanup
},
{
.id = 0x9dc8,
.num_cores = 4,
.loader_ops = bxt_get_loader_ops,
.init = cnl_sst_dsp_init,
.init_fw = cnl_sst_init_fw,
.cleanup = cnl_sst_dsp_cleanup
},
};
const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
......@@ -249,6 +262,7 @@ int skl_init_dsp(struct skl *skl)
struct skl_dsp_loader_ops loader_ops;
int irq = bus->irq;
const struct skl_dsp_ops *ops;
struct skl_dsp_cores *cores;
int ret;
/* enable ppcap interrupt */
......@@ -263,8 +277,10 @@ int skl_init_dsp(struct skl *skl)
}
ops = skl_get_dsp_ops(skl->pci->device);
if (!ops)
return -EIO;
if (!ops) {
ret = -EIO;
goto unmap_mmio;
}
loader_ops = ops->loader_ops();
ret = ops->init(bus->dev, mmio_base, irq,
......@@ -272,11 +288,35 @@ int skl_init_dsp(struct skl *skl)
&skl->skl_sst);
if (ret < 0)
return ret;
goto unmap_mmio;
skl->skl_sst->dsp_ops = ops;
cores = &skl->skl_sst->cores;
cores->count = ops->num_cores;
cores->state = kcalloc(cores->count, sizeof(*cores->state), GFP_KERNEL);
if (!cores->state) {
ret = -ENOMEM;
goto unmap_mmio;
}
cores->usage_count = kcalloc(cores->count, sizeof(*cores->usage_count),
GFP_KERNEL);
if (!cores->usage_count) {
ret = -ENOMEM;
goto free_core_state;
}
dev_dbg(bus->dev, "dsp registration status=%d\n", ret);
return 0;
free_core_state:
kfree(cores->state);
unmap_mmio:
iounmap(mmio_base);
return ret;
}
......@@ -291,6 +331,9 @@ int skl_free_dsp(struct skl *skl)
ctx->dsp_ops->cleanup(bus->dev, ctx);
kfree(ctx->cores.state);
kfree(ctx->cores.usage_count);
if (ctx->dsp->addr.lpe)
iounmap(ctx->dsp->addr.lpe);
......@@ -400,9 +443,12 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_base_cfg *base_cfg)
{
struct skl_module_fmt *format = &mconfig->in_fmt[0];
struct skl_module *module = mconfig->module;
struct skl_module_res *res = &module->resources[mconfig->res_idx];
struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx];
struct skl_module_fmt *format = &fmt->inputs[0].fmt;
base_cfg->audio_fmt.number_of_channels = (u8)format->channels;
base_cfg->audio_fmt.number_of_channels = format->channels;
base_cfg->audio_fmt.s_freq = format->s_freq;
base_cfg->audio_fmt.bit_depth = format->bit_depth;
......@@ -417,10 +463,10 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
base_cfg->audio_fmt.interleaving = format->interleaving_style;
base_cfg->cps = mconfig->mcps;
base_cfg->ibs = mconfig->ibs;
base_cfg->obs = mconfig->obs;
base_cfg->is_pages = mconfig->mem_pages;
base_cfg->cps = res->cps;
base_cfg->ibs = res->ibs;
base_cfg->obs = res->obs;
base_cfg->is_pages = res->is_pages;
}
/*
......@@ -508,6 +554,9 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
struct skl_cpr_cfg *cpr_mconfig)
{
u32 dma_io_buf;
struct skl_module_res *res;
int res_idx = mconfig->res_idx;
struct skl *skl = get_skl_ctx(ctx->dev);
cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig);
......@@ -516,19 +565,27 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
return;
}
if (skl->nr_modules) {
res = &mconfig->module->resources[mconfig->res_idx];
cpr_mconfig->gtw_cfg.dma_buffer_size = res->dma_buffer_size;
goto skip_buf_size_calc;
} else {
res = &mconfig->module->resources[res_idx];
}
switch (mconfig->hw_conn_type) {
case SKL_CONN_SOURCE:
if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
dma_io_buf = mconfig->ibs;
dma_io_buf = res->ibs;
else
dma_io_buf = mconfig->obs;
dma_io_buf = res->obs;
break;
case SKL_CONN_SINK:
if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
dma_io_buf = mconfig->obs;
dma_io_buf = res->obs;
else
dma_io_buf = mconfig->ibs;
dma_io_buf = res->ibs;
break;
default:
......@@ -543,11 +600,12 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
/* fallback to 2ms default value */
if (!cpr_mconfig->gtw_cfg.dma_buffer_size) {
if (mconfig->hw_conn_type == SKL_CONN_SOURCE)
cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs;
cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->obs;
else
cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->ibs;
cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->ibs;
}
skip_buf_size_calc:
cpr_mconfig->cpr_feature_mask = 0;
cpr_mconfig->gtw_cfg.config_length = 0;
......@@ -595,7 +653,9 @@ static void skl_setup_out_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_audio_data_format *out_fmt)
{
struct skl_module_fmt *format = &mconfig->out_fmt[0];
struct skl_module *module = mconfig->module;
struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx];
struct skl_module_fmt *format = &fmt->outputs[0].fmt;
out_fmt->number_of_channels = (u8)format->channels;
out_fmt->s_freq = format->s_freq;
......@@ -620,7 +680,9 @@ static void skl_set_src_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_src_module_cfg *src_mconfig)
{
struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
struct skl_module *module = mconfig->module;
struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx];
struct skl_module_fmt *fmt = &iface->outputs[0].fmt;
skl_set_base_module_format(ctx, mconfig,
(struct skl_base_cfg *)src_mconfig);
......@@ -637,7 +699,9 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_up_down_mixer_cfg *mixer_mconfig)
{
struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
struct skl_module *module = mconfig->module;
struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx];
struct skl_module_fmt *fmt = &iface->outputs[0].fmt;
int i = 0;
skl_set_base_module_format(ctx, mconfig,
......@@ -950,7 +1014,7 @@ static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg
{
dev_dbg(ctx->dev, "%s: src module_id = %d src_instance=%d\n",
__func__, src_module->id.module_id, src_module->id.pvt_id);
dev_dbg(ctx->dev, "%s: dst_module=%d dst_instacne=%d\n", __func__,
dev_dbg(ctx->dev, "%s: dst_module=%d dst_instance=%d\n", __func__,
dst_module->id.module_id, dst_module->id.pvt_id);
dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n",
......@@ -970,8 +1034,8 @@ int skl_unbind_modules(struct skl_sst *ctx,
struct skl_ipc_bind_unbind_msg msg;
struct skl_module_inst_id src_id = src_mcfg->id;
struct skl_module_inst_id dst_id = dst_mcfg->id;
int in_max = dst_mcfg->max_in_queue;
int out_max = src_mcfg->max_out_queue;
int in_max = dst_mcfg->module->max_input_pins;
int out_max = src_mcfg->module->max_output_pins;
int src_index, dst_index, src_pin_state, dst_pin_state;
skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
......@@ -1019,6 +1083,21 @@ int skl_unbind_modules(struct skl_sst *ctx,
return ret;
}
static void fill_pin_params(struct skl_audio_data_format *pin_fmt,
struct skl_module_fmt *format)
{
pin_fmt->number_of_channels = format->channels;
pin_fmt->s_freq = format->s_freq;
pin_fmt->bit_depth = format->bit_depth;
pin_fmt->valid_bit_depth = format->valid_bit_depth;
pin_fmt->ch_cfg = format->ch_cfg;
pin_fmt->sample_type = format->sample_type;
pin_fmt->channel_map = format->ch_map;
pin_fmt->interleaving = format->interleaving_style;
}
#define CPR_SINK_FMT_PARAM_ID 2
/*
* Once a module is instantiated it need to be 'bind' with other modules in
* the pipeline. For binding we need to find the module pins which are bind
......@@ -1030,11 +1109,15 @@ int skl_bind_modules(struct skl_sst *ctx,
struct skl_module_cfg *src_mcfg,
struct skl_module_cfg *dst_mcfg)
{
int ret;
int ret = 0;
struct skl_ipc_bind_unbind_msg msg;
int in_max = dst_mcfg->max_in_queue;
int out_max = src_mcfg->max_out_queue;
int in_max = dst_mcfg->module->max_input_pins;
int out_max = src_mcfg->module->max_output_pins;
int src_index, dst_index;
struct skl_module_fmt *format;
struct skl_cpr_pin_fmt pin_fmt;
struct skl_module *module;
struct skl_module_iface *fmt;
skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
......@@ -1053,6 +1136,29 @@ int skl_bind_modules(struct skl_sst *ctx,
return -EINVAL;
}
/*
* Copier module requires the separate large_config_set_ipc to
* configure the pins other than 0
*/
if (src_mcfg->m_type == SKL_MODULE_TYPE_COPIER && src_index > 0) {
pin_fmt.sink_id = src_index;
module = src_mcfg->module;
fmt = &module->formats[src_mcfg->fmt_idx];
/* Input fmt is same as that of src module input cfg */
format = &fmt->inputs[0].fmt;
fill_pin_params(&(pin_fmt.src_fmt), format);
format = &fmt->outputs[src_index].fmt;
fill_pin_params(&(pin_fmt.dst_fmt), format);
ret = skl_set_module_params(ctx, (void *)&pin_fmt,
sizeof(struct skl_cpr_pin_fmt),
CPR_SINK_FMT_PARAM_ID, src_mcfg);
if (ret < 0)
goto out;
}
msg.dst_queue = dst_index;
dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n",
......@@ -1070,11 +1176,12 @@ int skl_bind_modules(struct skl_sst *ctx,
src_mcfg->m_state = SKL_MODULE_BIND_DONE;
src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE;
dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE;
} else {
return ret;
}
out:
/* error case , if IPC fails, clear the queue index */
skl_free_queue(src_mcfg->m_out_pin, src_index);
skl_free_queue(dst_mcfg->m_in_pin, dst_index);
}
return ret;
}
......
......@@ -33,7 +33,7 @@
#define HDA_STEREO 2
#define HDA_QUAD 4
static struct snd_pcm_hardware azx_pcm_hw = {
static const struct snd_pcm_hardware azx_pcm_hw = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
......@@ -628,7 +628,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
return 0;
}
static struct snd_soc_dai_ops skl_pcm_dai_ops = {
static const struct snd_soc_dai_ops skl_pcm_dai_ops = {
.startup = skl_pcm_open,
.shutdown = skl_pcm_close,
.prepare = skl_pcm_prepare,
......@@ -637,15 +637,15 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = {
.trigger = skl_pcm_trigger,
};
static struct snd_soc_dai_ops skl_dmic_dai_ops = {
static const struct snd_soc_dai_ops skl_dmic_dai_ops = {
.hw_params = skl_be_hw_params,
};
static struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
static const struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
.hw_params = skl_be_hw_params,
};
static struct snd_soc_dai_ops skl_link_dai_ops = {
static const struct snd_soc_dai_ops skl_link_dai_ops = {
.prepare = skl_link_pcm_prepare,
.hw_params = skl_link_hw_params,
.hw_free = skl_link_hw_free,
......@@ -674,6 +674,32 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.sig_bits = 32,
},
},
{
.name = "System Pin2",
.ops = &skl_pcm_dai_ops,
.playback = {
.stream_name = "Headset Playback",
.channels_min = HDA_MONO,
.channels_max = HDA_STEREO,
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
},
},
{
.name = "Echoref Pin",
.ops = &skl_pcm_dai_ops,
.capture = {
.stream_name = "Echoreference Capture",
.channels_min = HDA_STEREO,
.channels_max = HDA_STEREO,
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
},
},
{
.name = "Reference Pin",
.ops = &skl_pcm_dai_ops,
......@@ -1194,8 +1220,11 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig)
{
struct skl_sst *ctx = skl->skl_sst;
struct skl_module_inst_id *pin_id;
uuid_le *uuid_mod, *uuid_tplg;
struct skl_module *skl_module;
struct uuid_module *module;
uuid_le *uuid_mod;
int i, ret = -EIO;
uuid_mod = (uuid_le *)mconfig->guid;
......@@ -1207,12 +1236,45 @@ static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig)
list_for_each_entry(module, &ctx->uuid_list, list) {
if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
mconfig->id.module_id = module->id;
mconfig->is_loadable = module->is_loadable;
return 0;
if (mconfig->module)
mconfig->module->loadable = module->is_loadable;
ret = 0;
break;
}
}
return -EIO;
if (ret)
return ret;
uuid_mod = &module->uuid;
ret = -EIO;
for (i = 0; i < skl->nr_modules; i++) {
skl_module = skl->modules[i];
uuid_tplg = &skl_module->uuid;
if (!uuid_le_cmp(*uuid_mod, *uuid_tplg)) {
mconfig->module = skl_module;
ret = 0;
break;
}
}
if (skl->nr_modules && ret)
return ret;
list_for_each_entry(module, &ctx->uuid_list, list) {
for (i = 0; i < MAX_IN_QUEUE; i++) {
pin_id = &mconfig->m_in_pin[i].id;
if (!uuid_le_cmp(pin_id->mod_uuid, module->uuid))
pin_id->module_id = module->id;
}
for (i = 0; i < MAX_OUT_QUEUE; i++) {
pin_id = &mconfig->m_out_pin[i].id;
if (!uuid_le_cmp(pin_id->mod_uuid, module->uuid))
pin_id->module_id = module->id;
}
}
return 0;
}
static int skl_populate_modules(struct skl *skl)
......@@ -1284,7 +1346,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
return 0;
}
static struct snd_soc_platform_driver skl_platform_drv = {
static const struct snd_soc_platform_driver skl_platform_drv = {
.probe = skl_platform_soc_probe,
.ops = &skl_platform_ops,
.pcm_new = skl_pcm_new,
......
......@@ -47,7 +47,7 @@ void skl_dsp_init_core_state(struct sst_dsp *ctx)
skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING;
skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1;
for (i = SKL_DSP_CORE0_ID + 1; i < SKL_DSP_CORES_MAX; i++) {
for (i = SKL_DSP_CORE0_ID + 1; i < skl->cores.count; i++) {
skl->cores.state[i] = SKL_DSP_RESET;
skl->cores.usage_count[i] = 0;
}
......@@ -351,6 +351,8 @@ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
return -EINVAL;
}
skl->cores.usage_count[core_id]++;
if (skl->cores.state[core_id] == SKL_DSP_RESET) {
ret = ctx->fw_ops.set_state_D0(ctx, core_id);
if (ret < 0) {
......@@ -359,8 +361,6 @@ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
}
}
skl->cores.usage_count[core_id]++;
out:
dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
core_id, skl->cores.state[core_id],
......
......@@ -283,7 +283,7 @@ enum skl_ipc_module_msg {
IPC_MOD_SET_D0IX = 8
};
static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
size_t tx_size)
{
if (tx_size)
......@@ -347,7 +347,7 @@ static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc,
}
static int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
struct skl_ipc_header header)
{
struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc);
......@@ -406,7 +406,7 @@ static int skl_ipc_set_reply_error_code(u32 reply)
}
}
static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
struct skl_ipc_header header)
{
struct ipc_message *msg;
......
......@@ -44,12 +44,10 @@ struct skl_ipc_header {
u32 extension;
};
#define SKL_DSP_CORES_MAX 2
struct skl_dsp_cores {
unsigned int count;
enum skl_dsp_states state[SKL_DSP_CORES_MAX];
int usage_count[SKL_DSP_CORES_MAX];
enum skl_dsp_states *state;
int *usage_count;
};
/**
......@@ -214,4 +212,10 @@ void skl_ipc_free(struct sst_generic_ipc *ipc);
int skl_ipc_init(struct device *dev, struct skl_sst *skl);
void skl_clear_module_cnt(struct sst_dsp *ctx);
void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
struct skl_ipc_header header);
int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
struct skl_ipc_header header);
void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
size_t tx_size);
#endif /* __SKL_IPC_H */
......@@ -368,7 +368,6 @@ int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
{
struct skl_sst *skl;
struct sst_dsp *sst;
int ret;
skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
if (skl == NULL)
......@@ -388,15 +387,12 @@ int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
sst->dsp_ops = dsp_ops;
init_waitqueue_head(&skl->mod_load_wait);
INIT_LIST_HEAD(&sst->module_list);
ret = skl_ipc_init(dev, skl);
if (ret)
return ret;
skl->is_first_boot = true;
if (dsp)
*dsp = skl;
return ret;
return 0;
}
int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo,
......
......@@ -503,7 +503,7 @@ static void skl_clear_module_table(struct sst_dsp *ctx)
}
}
static struct skl_dsp_fw_ops skl_fw_ops = {
static const struct skl_dsp_fw_ops skl_fw_ops = {
.set_state_D0 = skl_set_dsp_D0,
.set_state_D3 = skl_set_dsp_D3,
.load_fw = skl_load_base_firmware,
......@@ -512,7 +512,7 @@ static struct skl_dsp_fw_ops skl_fw_ops = {
.unload_mod = skl_unload_module,
};
static struct skl_dsp_fw_ops kbl_fw_ops = {
static const struct skl_dsp_fw_ops kbl_fw_ops = {
.set_state_D0 = skl_set_dsp_D0,
.set_state_D3 = skl_set_dsp_D3,
.load_fw = skl_load_base_firmware,
......@@ -561,9 +561,13 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
sst->fw_ops = skl_fw_ops;
ret = skl_ipc_init(dev, skl);
if (ret) {
skl_dsp_free(sst);
return ret;
}
skl->cores.count = 2;
sst->fw_ops = skl_fw_ops;
return 0;
}
......
......@@ -49,6 +49,9 @@ static const int mic_quatro_list[][SKL_CH_QUATRO] = {
{0, 1, 2, 3},
};
#define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps)
{
struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3;
......@@ -153,8 +156,10 @@ static bool skl_is_pipe_mcps_avail(struct skl *skl,
struct skl_module_cfg *mconfig)
{
struct skl_sst *ctx = skl->skl_sst;
u8 res_idx = mconfig->res_idx;
struct skl_module_res *res = &mconfig->module->resources[res_idx];
if (skl->resource.mcps + mconfig->mcps > skl->resource.max_mcps) {
if (skl->resource.mcps + res->cps > skl->resource.max_mcps) {
dev_err(ctx->dev,
"%s: module_id %d instance %d\n", __func__,
mconfig->id.module_id, mconfig->id.instance_id);
......@@ -170,7 +175,10 @@ static bool skl_is_pipe_mcps_avail(struct skl *skl,
static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
struct skl_module_cfg *mconfig)
{
skl->resource.mcps += mconfig->mcps;
u8 res_idx = mconfig->res_idx;
struct skl_module_res *res = &mconfig->module->resources[res_idx];
skl->resource.mcps += res->cps;
}
/*
......@@ -179,7 +187,11 @@ static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
static void
skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
{
skl->resource.mcps -= mconfig->mcps;
u8 res_idx = mconfig->res_idx;
struct skl_module_res *res = &mconfig->module->resources[res_idx];
res = &mconfig->module->resources[res_idx];
skl->resource.mcps -= res->cps;
}
/*
......@@ -195,17 +207,21 @@ skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig)
static void skl_dump_mconfig(struct skl_sst *ctx,
struct skl_module_cfg *mcfg)
{
struct skl_module_iface *iface = &mcfg->module->formats[0];
dev_dbg(ctx->dev, "Dumping config\n");
dev_dbg(ctx->dev, "Input Format:\n");
dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels);
dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq);
dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg);
dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth);
dev_dbg(ctx->dev, "channels = %d\n", iface->inputs[0].fmt.channels);
dev_dbg(ctx->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq);
dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg);
dev_dbg(ctx->dev, "valid bit depth = %d\n",
iface->inputs[0].fmt.valid_bit_depth);
dev_dbg(ctx->dev, "Output Format:\n");
dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels);
dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq);
dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth);
dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg);
dev_dbg(ctx->dev, "channels = %d\n", iface->outputs[0].fmt.channels);
dev_dbg(ctx->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq);
dev_dbg(ctx->dev, "valid bit depth = %d\n",
iface->outputs[0].fmt.valid_bit_depth);
dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg);
}
static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
......@@ -273,8 +289,8 @@ static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
struct skl_module_fmt *in_fmt, *out_fmt;
/* Fixups will be applied to pin 0 only */
in_fmt = &m_cfg->in_fmt[0];
out_fmt = &m_cfg->out_fmt[0];
in_fmt = &m_cfg->module->formats[0].inputs[0].fmt;
out_fmt = &m_cfg->module->formats[0].outputs[0].fmt;
if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (is_fe) {
......@@ -312,21 +328,23 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
{
int multiplier = 1;
struct skl_module_fmt *in_fmt, *out_fmt;
struct skl_module_res *res;
/* Since fixups is applied to pin 0 only, ibs, obs needs
* change for pin 0 only
*/
in_fmt = &mcfg->in_fmt[0];
out_fmt = &mcfg->out_fmt[0];
res = &mcfg->module->resources[0];
in_fmt = &mcfg->module->formats[0].inputs[0].fmt;
out_fmt = &mcfg->module->formats[0].outputs[0].fmt;
if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
multiplier = 5;
mcfg->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
in_fmt->channels * (in_fmt->bit_depth >> 3) *
multiplier;
mcfg->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
out_fmt->channels * (out_fmt->bit_depth >> 3) *
multiplier;
}
......@@ -365,6 +383,8 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
struct nhlt_specific_cfg *cfg;
struct skl *skl = get_skl_ctx(ctx->dev);
u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
int fmt_idx = m_cfg->fmt_idx;
struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx];
/* check if we already have blob */
if (m_cfg->formats_config.caps_size > 0)
......@@ -375,23 +395,23 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
case SKL_DEVICE_DMIC:
link_type = NHLT_LINK_DMIC;
dir = SNDRV_PCM_STREAM_CAPTURE;
s_freq = m_cfg->in_fmt[0].s_freq;
s_fmt = m_cfg->in_fmt[0].bit_depth;
ch = m_cfg->in_fmt[0].channels;
s_freq = m_iface->inputs[0].fmt.s_freq;
s_fmt = m_iface->inputs[0].fmt.bit_depth;
ch = m_iface->inputs[0].fmt.channels;
break;
case SKL_DEVICE_I2S:
link_type = NHLT_LINK_SSP;
if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
dir = SNDRV_PCM_STREAM_PLAYBACK;
s_freq = m_cfg->out_fmt[0].s_freq;
s_fmt = m_cfg->out_fmt[0].bit_depth;
ch = m_cfg->out_fmt[0].channels;
s_freq = m_iface->outputs[0].fmt.s_freq;
s_fmt = m_iface->outputs[0].fmt.bit_depth;
ch = m_iface->outputs[0].fmt.channels;
} else {
dir = SNDRV_PCM_STREAM_CAPTURE;
s_freq = m_cfg->in_fmt[0].s_freq;
s_fmt = m_cfg->in_fmt[0].bit_depth;
ch = m_cfg->in_fmt[0].channels;
s_freq = m_iface->inputs[0].fmt.s_freq;
s_fmt = m_iface->inputs[0].fmt.bit_depth;
ch = m_iface->inputs[0].fmt.channels;
}
break;
......@@ -549,6 +569,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
struct snd_soc_dapm_widget *w;
struct skl_module_cfg *mconfig;
struct skl_sst *ctx = skl->skl_sst;
u8 cfg_idx;
int ret = 0;
list_for_each_entry(w_module, &pipe->w_list, node) {
......@@ -564,11 +585,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
return -EIO;
}
cfg_idx = mconfig->pipe->cur_config_idx;
mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
/* check resource available */
if (!skl_is_pipe_mcps_avail(skl, mconfig))
return -ENOMEM;
if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
if (mconfig->module->loadable && ctx->dsp->fw_ops.load_mod) {
ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
mconfig->id.module_id, mconfig->guid);
if (ret < 0)
......@@ -596,24 +621,35 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
if (mconfig->id.pvt_id < 0)
return ret;
skl_tplg_set_module_init_data(w);
ret = skl_dsp_get_core(ctx->dsp, mconfig->core_id);
if (ret < 0) {
dev_err(ctx->dev, "Failed to wake up core %d ret=%d\n",
mconfig->core_id, ret);
return ret;
}
ret = skl_init_module(ctx, mconfig);
if (ret < 0) {
skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
return ret;
goto err;
}
skl_tplg_alloc_pipe_mcps(skl, mconfig);
ret = skl_tplg_set_module_params(w, ctx);
if (ret < 0)
return ret;
goto err;
}
return 0;
err:
skl_dsp_put_core(ctx->dsp, mconfig->core_id);
return ret;
}
static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
struct skl_pipe *pipe)
{
int ret;
int ret = 0;
struct skl_pipe_module *w_module = NULL;
struct skl_module_cfg *mconfig = NULL;
......@@ -622,7 +658,7 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
mconfig = w_module->w->priv;
uuid_mod = (uuid_le *)mconfig->guid;
if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod &&
if (mconfig->module->loadable && ctx->dsp->fw_ops.unload_mod &&
mconfig->m_state > SKL_MODULE_UNINIT) {
ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp,
mconfig->id.module_id);
......@@ -630,10 +666,76 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
return -EIO;
}
skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
ret = skl_dsp_put_core(ctx->dsp, mconfig->core_id);
if (ret < 0) {
/* don't return; continue with other modules */
dev_err(ctx->dev, "Failed to sleep core %d ret=%d\n",
mconfig->core_id, ret);
}
}
/* no modules to unload in this path, so return */
return ret;
}
/*
* Here, we select pipe format based on the pipe type and pipe
* direction to determine the current config index for the pipeline.
* The config index is then used to select proper module resources.
* Intermediate pipes currently have a fixed format hence we select the
* 0th configuratation by default for such pipes.
*/
static int
skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig)
{
struct skl_sst *ctx = skl->skl_sst;
struct skl_pipe *pipe = mconfig->pipe;
struct skl_pipe_params *params = pipe->p_params;
struct skl_path_config *pconfig = &pipe->configs[0];
struct skl_pipe_fmt *fmt = NULL;
bool in_fmt = false;
int i;
if (pipe->nr_cfgs == 0) {
pipe->cur_config_idx = 0;
return 0;
}
if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) {
dev_dbg(ctx->dev, "No conn_type detected, take 0th config\n");
pipe->cur_config_idx = 0;
pipe->memory_pages = pconfig->mem_pages;
return 0;
}
if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE &&
pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
(pipe->conn_type == SKL_PIPE_CONN_TYPE_BE &&
pipe->direction == SNDRV_PCM_STREAM_CAPTURE))
in_fmt = true;
for (i = 0; i < pipe->nr_cfgs; i++) {
pconfig = &pipe->configs[i];
if (in_fmt)
fmt = &pconfig->in_fmt;
else
fmt = &pconfig->out_fmt;
if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
fmt->channels, fmt->freq, fmt->bps)) {
pipe->cur_config_idx = i;
pipe->memory_pages = pconfig->mem_pages;
dev_dbg(ctx->dev, "Using pipe config: %d\n", i);
return 0;
}
}
dev_err(ctx->dev, "Invalid pipe config: %d %d %d for pipe: %d\n",
params->ch, params->s_freq, params->s_fmt, pipe->ppl_id);
return -EINVAL;
}
/*
......@@ -655,6 +757,10 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
struct skl_sst *ctx = skl->skl_sst;
struct skl_module_deferred_bind *modules;
ret = skl_tplg_get_pipe_config(skl, mconfig);
if (ret < 0)
return ret;
/* check resource available */
if (!skl_is_pipe_mcps_avail(skl, mconfig))
return -EBUSY;
......@@ -758,12 +864,12 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
* check all out/in pins are in bind state.
* if so set the module param
*/
for (i = 0; i < mcfg->max_out_queue; i++) {
for (i = 0; i < mcfg->module->max_output_pins; i++) {
if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
return 0;
}
for (i = 0; i < mcfg->max_in_queue; i++) {
for (i = 0; i < mcfg->module->max_input_pins; i++) {
if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
return 0;
}
......@@ -814,7 +920,7 @@ static int skl_tplg_module_add_deferred_bind(struct skl *skl,
int i;
/* only supported for module with static pin connection */
for (i = 0; i < dst->max_in_queue; i++) {
for (i = 0; i < dst->module->max_input_pins; i++) {
struct skl_module_pin *pin = &dst->m_in_pin[i];
if (pin->is_dynamic)
......@@ -925,7 +1031,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
}
}
if (!sink)
if (!sink && next_sink)
return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
return 0;
......@@ -1074,7 +1180,7 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
if (ret)
return ret;
for (i = 0; i < sink_mconfig->max_in_queue; i++) {
for (i = 0; i < sink_mconfig->module->max_input_pins; i++) {
if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
if (!src_mconfig)
......@@ -1185,7 +1291,7 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
if (ret)
return ret;
for (i = 0; i < src_mconfig->max_out_queue; i++) {
for (i = 0; i < src_mconfig->module->max_output_pins; i++) {
if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
if (!sink_mconfig)
......@@ -1479,14 +1585,22 @@ int skl_tplg_update_pipe_params(struct device *dev,
struct skl_module_cfg *mconfig,
struct skl_pipe_params *params)
{
struct skl_module_res *res = &mconfig->module->resources[0];
struct skl *skl = get_skl_ctx(dev);
struct skl_module_fmt *format = NULL;
u8 cfg_idx = mconfig->pipe->cur_config_idx;
skl_tplg_fill_dma_id(mconfig, params);
mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
if (skl->nr_modules)
return 0;
if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
format = &mconfig->in_fmt[0];
format = &mconfig->module->formats[0].inputs[0].fmt;
else
format = &mconfig->out_fmt[0];
format = &mconfig->module->formats[0].outputs[0].fmt;
/* set the hw_params */
format->s_freq = params->s_freq;
......@@ -1514,11 +1628,11 @@ int skl_tplg_update_pipe_params(struct device *dev,
}
if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
mconfig->ibs = (format->s_freq / 1000) *
res->ibs = (format->s_freq / 1000) *
(format->channels) *
(format->bit_depth >> 3);
} else {
mconfig->obs = (format->s_freq / 1000) *
res->obs = (format->s_freq / 1000) *
(format->channels) *
(format->bit_depth >> 3);
}
......@@ -1792,6 +1906,54 @@ static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
},
};
static int skl_tplg_fill_pipe_cfg(struct device *dev,
struct skl_pipe *pipe, u32 tkn,
u32 tkn_val, int conf_idx, int dir)
{
struct skl_pipe_fmt *fmt;
struct skl_path_config *config;
switch (dir) {
case SKL_DIR_IN:
fmt = &pipe->configs[conf_idx].in_fmt;
break;
case SKL_DIR_OUT:
fmt = &pipe->configs[conf_idx].out_fmt;
break;
default:
dev_err(dev, "Invalid direction: %d\n", dir);
return -EINVAL;
}
config = &pipe->configs[conf_idx];
switch (tkn) {
case SKL_TKN_U32_CFG_FREQ:
fmt->freq = tkn_val;
break;
case SKL_TKN_U8_CFG_CHAN:
fmt->channels = tkn_val;
break;
case SKL_TKN_U8_CFG_BPS:
fmt->bps = tkn_val;
break;
case SKL_TKN_U32_PATH_MEM_PGS:
config->mem_pages = tkn_val;
break;
default:
dev_err(dev, "Invalid token config: %d\n", tkn);
return -EINVAL;
}
return 0;
}
static int skl_tplg_fill_pipe_tkn(struct device *dev,
struct skl_pipe *pipe, u32 tkn,
u32 tkn_val)
......@@ -1814,6 +1976,14 @@ static int skl_tplg_fill_pipe_tkn(struct device *dev,
pipe->lp_mode = tkn_val;
break;
case SKL_TKN_U32_PIPE_DIRECTION:
pipe->direction = tkn_val;
break;
case SKL_TKN_U32_NUM_CONFIGS:
pipe->nr_cfgs = tkn_val;
break;
default:
dev_err(dev, "Token not handled %d\n", tkn);
return -EINVAL;
......@@ -1930,27 +2100,9 @@ static int skl_tplg_fill_pins_info(struct device *dev,
* on the direction
*/
static int skl_tplg_fill_fmt(struct device *dev,
struct skl_module_cfg *mconfig, u32 tkn,
u32 value, u32 dir, u32 pin_count)
struct skl_module_fmt *dst_fmt,
u32 tkn, u32 value)
{
struct skl_module_fmt *dst_fmt;
switch (dir) {
case SKL_DIR_IN:
dst_fmt = mconfig->in_fmt;
dst_fmt += pin_count;
break;
case SKL_DIR_OUT:
dst_fmt = mconfig->out_fmt;
dst_fmt += pin_count;
break;
default:
dev_err(dev, "Invalid direction value\n");
return -EINVAL;
}
switch (tkn) {
case SKL_TKN_U32_FMT_CH:
dst_fmt->channels = value;
......@@ -1992,6 +2144,32 @@ static int skl_tplg_fill_fmt(struct device *dev,
return 0;
}
static int skl_tplg_widget_fill_fmt(struct device *dev,
struct skl_module_iface *fmt,
u32 tkn, u32 val, u32 dir, int fmt_idx)
{
struct skl_module_fmt *dst_fmt;
if (!fmt)
return -EINVAL;
switch (dir) {
case SKL_DIR_IN:
dst_fmt = &fmt->inputs[fmt_idx].fmt;
break;
case SKL_DIR_OUT:
dst_fmt = &fmt->outputs[fmt_idx].fmt;
break;
default:
dev_err(dev, "Invalid direction: %d\n", dir);
return -EINVAL;
}
return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
}
static int skl_tplg_get_uuid(struct device *dev, struct skl_module_cfg *mconfig,
struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
{
......@@ -2014,6 +2192,108 @@ static void skl_tplg_fill_pin_dynamic_val(
mpin[i].is_dynamic = value;
}
/*
* Resource table in the manifest has pin specific resources
* like pin and pin buffer size
*/
static int skl_tplg_manifest_pin_res_tkn(struct device *dev,
struct snd_soc_tplg_vendor_value_elem *tkn_elem,
struct skl_module_res *res, int pin_idx, int dir)
{
struct skl_module_pin_resources *m_pin;
switch (dir) {
case SKL_DIR_IN:
m_pin = &res->input[pin_idx];
break;
case SKL_DIR_OUT:
m_pin = &res->output[pin_idx];
break;
default:
dev_err(dev, "Invalid pin direction: %d\n", dir);
return -EINVAL;
}
switch (tkn_elem->token) {
case SKL_TKN_MM_U32_RES_PIN_ID:
m_pin->pin_index = tkn_elem->value;
break;
case SKL_TKN_MM_U32_PIN_BUF:
m_pin->buf_size = tkn_elem->value;
break;
default:
dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
return -EINVAL;
}
return 0;
}
/*
* Fill module specific resources from the manifest's resource
* table like CPS, DMA size, mem_pages.
*/
static int skl_tplg_fill_res_tkn(struct device *dev,
struct snd_soc_tplg_vendor_value_elem *tkn_elem,
struct skl_module_res *res,
int pin_idx, int dir)
{
int ret, tkn_count = 0;
if (!res)
return -EINVAL;
switch (tkn_elem->token) {
case SKL_TKN_MM_U32_CPS:
res->cps = tkn_elem->value;
break;
case SKL_TKN_MM_U32_DMA_SIZE:
res->dma_buffer_size = tkn_elem->value;
break;
case SKL_TKN_MM_U32_CPC:
res->cpc = tkn_elem->value;
break;
case SKL_TKN_U32_MEM_PAGES:
res->is_pages = tkn_elem->value;
break;
case SKL_TKN_U32_OBS:
res->obs = tkn_elem->value;
break;
case SKL_TKN_U32_IBS:
res->ibs = tkn_elem->value;
break;
case SKL_TKN_U32_MAX_MCPS:
res->cps = tkn_elem->value;
break;
case SKL_TKN_MM_U32_RES_PIN_ID:
case SKL_TKN_MM_U32_PIN_BUF:
ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
pin_idx, dir);
if (ret < 0)
return ret;
break;
default:
dev_err(dev, "Not a res type token: %d", tkn_elem->token);
return -EINVAL;
}
tkn_count++;
return tkn_count;
}
/*
* Parse tokens to fill up the module private data
*/
......@@ -2024,49 +2304,54 @@ static int skl_tplg_get_token(struct device *dev,
int tkn_count = 0;
int ret;
static int is_pipe_exists;
static int pin_index, dir;
static int pin_index, dir, conf_idx;
struct skl_module_iface *iface = NULL;
struct skl_module_res *res = NULL;
int res_idx = mconfig->res_idx;
int fmt_idx = mconfig->fmt_idx;
/*
* If the manifest structure contains no modules, fill all
* the module data to 0th index.
* res_idx and fmt_idx are default set to 0.
*/
if (skl->nr_modules == 0) {
res = &mconfig->module->resources[res_idx];
iface = &mconfig->module->formats[fmt_idx];
}
if (tkn_elem->token > SKL_TKN_MAX)
return -EINVAL;
switch (tkn_elem->token) {
case SKL_TKN_U8_IN_QUEUE_COUNT:
mconfig->max_in_queue = tkn_elem->value;
mconfig->m_in_pin = devm_kzalloc(dev, mconfig->max_in_queue *
sizeof(*mconfig->m_in_pin),
GFP_KERNEL);
if (!mconfig->m_in_pin)
return -ENOMEM;
mconfig->module->max_input_pins = tkn_elem->value;
break;
case SKL_TKN_U8_OUT_QUEUE_COUNT:
mconfig->max_out_queue = tkn_elem->value;
mconfig->m_out_pin = devm_kzalloc(dev, mconfig->max_out_queue *
sizeof(*mconfig->m_out_pin),
GFP_KERNEL);
if (!mconfig->m_out_pin)
return -ENOMEM;
mconfig->module->max_output_pins = tkn_elem->value;
break;
case SKL_TKN_U8_DYN_IN_PIN:
if (!mconfig->m_in_pin)
mconfig->m_in_pin = devm_kzalloc(dev, MAX_IN_QUEUE *
sizeof(*mconfig->m_in_pin), GFP_KERNEL);
if (!mconfig->m_in_pin)
return -ENOMEM;
skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin,
mconfig->max_in_queue, tkn_elem->value);
skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE,
tkn_elem->value);
break;
case SKL_TKN_U8_DYN_OUT_PIN:
if (!mconfig->m_out_pin)
mconfig->m_out_pin = devm_kzalloc(dev, MAX_IN_QUEUE *
sizeof(*mconfig->m_in_pin), GFP_KERNEL);
if (!mconfig->m_out_pin)
return -ENOMEM;
skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin,
mconfig->max_out_queue, tkn_elem->value);
skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE,
tkn_elem->value);
break;
case SKL_TKN_U8_TIME_SLOT:
......@@ -2094,19 +2379,13 @@ static int skl_tplg_get_token(struct device *dev,
break;
case SKL_TKN_U32_MEM_PAGES:
mconfig->mem_pages = tkn_elem->value;
break;
case SKL_TKN_U32_MAX_MCPS:
mconfig->mcps = tkn_elem->value;
break;
case SKL_TKN_U32_OBS:
mconfig->obs = tkn_elem->value;
break;
case SKL_TKN_U32_IBS:
mconfig->ibs = tkn_elem->value;
ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, dir, pin_index);
if (ret < 0)
return ret;
break;
case SKL_TKN_U32_VBUS_ID:
......@@ -2139,10 +2418,16 @@ static int skl_tplg_get_token(struct device *dev,
break;
case SKL_TKN_U32_PIPE_CONFIG_ID:
conf_idx = tkn_elem->value;
break;
case SKL_TKN_U32_PIPE_CONN_TYPE:
case SKL_TKN_U32_PIPE_PRIORITY:
case SKL_TKN_U32_PIPE_MEM_PGS:
case SKL_TKN_U32_PMODE:
case SKL_TKN_U32_PIPE_DIRECTION:
case SKL_TKN_U32_NUM_CONFIGS:
if (is_pipe_exists) {
ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
tkn_elem->token, tkn_elem->value);
......@@ -2152,6 +2437,27 @@ static int skl_tplg_get_token(struct device *dev,
break;
case SKL_TKN_U32_PATH_MEM_PGS:
case SKL_TKN_U32_CFG_FREQ:
case SKL_TKN_U8_CFG_CHAN:
case SKL_TKN_U8_CFG_BPS:
if (mconfig->pipe->nr_cfgs) {
ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe,
tkn_elem->token, tkn_elem->value,
conf_idx, dir);
if (ret < 0)
return ret;
}
break;
case SKL_TKN_CFG_MOD_RES_ID:
mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value;
break;
case SKL_TKN_CFG_MOD_FMT_ID:
mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value;
break;
/*
* SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
* direction and the pin count. The first four bits represent
......@@ -2172,7 +2478,7 @@ static int skl_tplg_get_token(struct device *dev,
case SKL_TKN_U32_FMT_INTERLEAVE:
case SKL_TKN_U32_FMT_SAMPLE_TYPE:
case SKL_TKN_U32_FMT_CH_MAP:
ret = skl_tplg_fill_fmt(dev, mconfig, tkn_elem->token,
ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token,
tkn_elem->value, dir, pin_index);
if (ret < 0)
......@@ -2397,11 +2703,11 @@ static void skl_clear_pin_config(struct snd_soc_platform *platform,
strlen(platform->component.name))) {
mconfig = w->priv;
pipe = mconfig->pipe;
for (i = 0; i < mconfig->max_in_queue; i++) {
for (i = 0; i < mconfig->module->max_input_pins; i++) {
mconfig->m_in_pin[i].in_use = false;
mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
}
for (i = 0; i < mconfig->max_out_queue; i++) {
for (i = 0; i < mconfig->module->max_output_pins; i++) {
mconfig->m_out_pin[i].in_use = false;
mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
}
......@@ -2460,6 +2766,13 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
if (!mconfig)
return -ENOMEM;
if (skl->nr_modules == 0) {
mconfig->module = devm_kzalloc(bus->dev,
sizeof(*mconfig->module), GFP_KERNEL);
if (!mconfig->module)
return -ENOMEM;
}
w->priv = mconfig;
/*
......@@ -2602,13 +2915,13 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
str_elem->string,
ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name));
ref_count++;
tkn_count++;
break;
default:
dev_err(dev, "Not a string token %d\n", str_elem->token);
break;
}
tkn_count++;
return tkn_count;
}
......@@ -2634,26 +2947,236 @@ static int skl_tplg_get_str_tkn(struct device *dev,
return tkn_count;
}
static int skl_tplg_manifest_fill_fmt(struct device *dev,
struct skl_module_iface *fmt,
struct snd_soc_tplg_vendor_value_elem *tkn_elem,
u32 dir, int fmt_idx)
{
struct skl_module_pin_fmt *dst_fmt;
struct skl_module_fmt *mod_fmt;
int ret;
if (!fmt)
return -EINVAL;
switch (dir) {
case SKL_DIR_IN:
dst_fmt = &fmt->inputs[fmt_idx];
break;
case SKL_DIR_OUT:
dst_fmt = &fmt->outputs[fmt_idx];
break;
default:
dev_err(dev, "Invalid direction: %d\n", dir);
return -EINVAL;
}
mod_fmt = &dst_fmt->fmt;
switch (tkn_elem->token) {
case SKL_TKN_MM_U32_INTF_PIN_ID:
dst_fmt->id = tkn_elem->value;
break;
default:
ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
tkn_elem->value);
if (ret < 0)
return ret;
break;
}
return 0;
}
static int skl_tplg_fill_mod_info(struct device *dev,
struct snd_soc_tplg_vendor_value_elem *tkn_elem,
struct skl_module *mod)
{
if (!mod)
return -EINVAL;
switch (tkn_elem->token) {
case SKL_TKN_U8_IN_PIN_TYPE:
mod->input_pin_type = tkn_elem->value;
break;
case SKL_TKN_U8_OUT_PIN_TYPE:
mod->output_pin_type = tkn_elem->value;
break;
case SKL_TKN_U8_IN_QUEUE_COUNT:
mod->max_input_pins = tkn_elem->value;
break;
case SKL_TKN_U8_OUT_QUEUE_COUNT:
mod->max_output_pins = tkn_elem->value;
break;
case SKL_TKN_MM_U8_NUM_RES:
mod->nr_resources = tkn_elem->value;
break;
case SKL_TKN_MM_U8_NUM_INTF:
mod->nr_interfaces = tkn_elem->value;
break;
default:
dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
return -EINVAL;
}
return 0;
}
static int skl_tplg_get_int_tkn(struct device *dev,
struct snd_soc_tplg_vendor_value_elem *tkn_elem,
struct skl *skl)
{
int tkn_count = 0;
int tkn_count = 0, ret;
static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
struct skl_module_res *res = NULL;
struct skl_module_iface *fmt = NULL;
struct skl_module *mod = NULL;
int i;
if (skl->modules) {
mod = skl->modules[mod_idx];
res = &mod->resources[res_val_idx];
fmt = &mod->formats[intf_val_idx];
}
switch (tkn_elem->token) {
case SKL_TKN_U32_LIB_COUNT:
skl->skl_sst->lib_count = tkn_elem->value;
tkn_count++;
break;
case SKL_TKN_U8_NUM_MOD:
skl->nr_modules = tkn_elem->value;
skl->modules = devm_kcalloc(dev, skl->nr_modules,
sizeof(*skl->modules), GFP_KERNEL);
if (!skl->modules)
return -ENOMEM;
for (i = 0; i < skl->nr_modules; i++) {
skl->modules[i] = devm_kzalloc(dev,
sizeof(struct skl_module), GFP_KERNEL);
if (!skl->modules[i])
return -ENOMEM;
}
break;
case SKL_TKN_MM_U8_MOD_IDX:
mod_idx = tkn_elem->value;
break;
case SKL_TKN_U8_IN_PIN_TYPE:
case SKL_TKN_U8_OUT_PIN_TYPE:
case SKL_TKN_U8_IN_QUEUE_COUNT:
case SKL_TKN_U8_OUT_QUEUE_COUNT:
case SKL_TKN_MM_U8_NUM_RES:
case SKL_TKN_MM_U8_NUM_INTF:
ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
if (ret < 0)
return ret;
break;
case SKL_TKN_U32_DIR_PIN_COUNT:
dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
break;
case SKL_TKN_MM_U32_RES_ID:
if (!res)
return -EINVAL;
res->id = tkn_elem->value;
res_val_idx = tkn_elem->value;
break;
case SKL_TKN_MM_U32_FMT_ID:
if (!fmt)
return -EINVAL;
fmt->fmt_idx = tkn_elem->value;
intf_val_idx = tkn_elem->value;
break;
case SKL_TKN_MM_U32_CPS:
case SKL_TKN_MM_U32_DMA_SIZE:
case SKL_TKN_MM_U32_CPC:
case SKL_TKN_U32_MEM_PAGES:
case SKL_TKN_U32_OBS:
case SKL_TKN_U32_IBS:
case SKL_TKN_MM_U32_RES_PIN_ID:
case SKL_TKN_MM_U32_PIN_BUF:
ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
if (ret < 0)
return ret;
break;
case SKL_TKN_MM_U32_NUM_IN_FMT:
if (!fmt)
return -EINVAL;
res->nr_input_pins = tkn_elem->value;
break;
case SKL_TKN_MM_U32_NUM_OUT_FMT:
if (!fmt)
return -EINVAL;
res->nr_output_pins = tkn_elem->value;
break;
case SKL_TKN_U32_FMT_CH:
case SKL_TKN_U32_FMT_FREQ:
case SKL_TKN_U32_FMT_BIT_DEPTH:
case SKL_TKN_U32_FMT_SAMPLE_SIZE:
case SKL_TKN_U32_FMT_CH_CONFIG:
case SKL_TKN_U32_FMT_INTERLEAVE:
case SKL_TKN_U32_FMT_SAMPLE_TYPE:
case SKL_TKN_U32_FMT_CH_MAP:
case SKL_TKN_MM_U32_INTF_PIN_ID:
ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
dir, pin_idx);
if (ret < 0)
return ret;
break;
default:
dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
return -EINVAL;
}
tkn_count++;
return tkn_count;
}
static int skl_tplg_get_manifest_uuid(struct device *dev,
struct skl *skl,
struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
{
static int ref_count;
struct skl_module *mod;
if (uuid_tkn->token == SKL_TKN_UUID) {
mod = skl->modules[ref_count];
memcpy(&mod->uuid, &uuid_tkn->uuid, sizeof(uuid_tkn->uuid));
ref_count++;
} else {
dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token);
return -EINVAL;
}
return 0;
}
/*
* Fill the manifest structure by parsing the tokens based on the
* type.
......@@ -2686,7 +3209,11 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
continue;
case SND_SOC_TPLG_TUPLE_TYPE_UUID:
dev_warn(dev, "no uuid tokens for skl tplf manifest\n");
ret = skl_tplg_get_manifest_uuid(dev, skl, array->uuid);
if (ret < 0)
return ret;
tuple_size += sizeof(*array->uuid);
continue;
default:
......@@ -2703,14 +3230,12 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
tkn_count = tkn_count + ret;
tkn_elem++;
tuple_size += tkn_count *
sizeof(struct snd_soc_tplg_vendor_value_elem);
break;
}
tuple_size += (tkn_count * sizeof(*tkn_elem));
tkn_count = 0;
}
return 0;
return off;
}
/*
......@@ -2733,11 +3258,10 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
num_blocks = ret;
off += array->size;
array = (struct snd_soc_tplg_vendor_array *)
(manifest->priv.data + off);
/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
while (num_blocks > 0) {
array = (struct snd_soc_tplg_vendor_array *)
(manifest->priv.data + off);
ret = skl_tplg_get_desc_blocks(dev, array);
if (ret < 0)
......@@ -2771,6 +3295,7 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
} else {
return -EINVAL;
}
off += ret;
}
return 0;
......
......@@ -44,6 +44,13 @@
#define SKL_DEFAULT_MIC_SEL_GAIN 0x3FF
#define SKL_MIC_SEL_SWITCH 0x3
#define SKL_OUTPUT_PIN 0
#define SKL_INPUT_PIN 1
#define SKL_MAX_PATH_CONFIGS 8
#define SKL_MAX_MODULES_IN_PIPE 8
#define SKL_MAX_MODULE_FORMATS 32
#define SKL_MAX_MODULE_RESOURCES 32
enum skl_channel_index {
SKL_CHANNEL_LEFT = 0,
SKL_CHANNEL_RIGHT = 1,
......@@ -131,6 +138,11 @@ struct skl_cpr_cfg {
struct skl_cpr_gtw_cfg gtw_cfg;
} __packed;
struct skl_cpr_pin_fmt {
u32 sink_id;
struct skl_audio_data_format src_fmt;
struct skl_audio_data_format dst_fmt;
} __packed;
struct skl_src_module_cfg {
struct skl_base_cfg base_cfg;
......@@ -214,6 +226,7 @@ struct skl_kpb_params {
};
struct skl_module_inst_id {
uuid_le mod_uuid;
int module_id;
u32 instance_id;
int pvt_id;
......@@ -266,6 +279,23 @@ struct skl_pipe_params {
unsigned int link_bps;
};
struct skl_pipe_fmt {
u32 freq;
u8 channels;
u8 bps;
};
struct skl_pipe_mcfg {
u8 res_idx;
u8 fmt_idx;
};
struct skl_path_config {
u8 mem_pages;
struct skl_pipe_fmt in_fmt;
struct skl_pipe_fmt out_fmt;
};
struct skl_pipe {
u8 ppl_id;
u8 pipe_priority;
......@@ -274,6 +304,10 @@ struct skl_pipe {
u8 lp_mode;
struct skl_pipe_params *p_params;
enum skl_pipe_state state;
u8 direction;
u8 cur_config_idx;
u8 nr_cfgs;
struct skl_path_config configs[SKL_MAX_PATH_CONFIGS];
struct list_head w_list;
bool passthru;
};
......@@ -292,9 +326,57 @@ enum d0i3_capability {
SKL_D0I3_NON_STREAMING = 2,
};
struct skl_module_pin_fmt {
u8 id;
struct skl_module_fmt fmt;
};
struct skl_module_iface {
u8 fmt_idx;
u8 nr_in_fmt;
u8 nr_out_fmt;
struct skl_module_pin_fmt inputs[MAX_IN_QUEUE];
struct skl_module_pin_fmt outputs[MAX_OUT_QUEUE];
};
struct skl_module_pin_resources {
u8 pin_index;
u32 buf_size;
};
struct skl_module_res {
u8 id;
u32 is_pages;
u32 cps;
u32 ibs;
u32 obs;
u32 dma_buffer_size;
u32 cpc;
u8 nr_input_pins;
u8 nr_output_pins;
struct skl_module_pin_resources input[MAX_IN_QUEUE];
struct skl_module_pin_resources output[MAX_OUT_QUEUE];
};
struct skl_module {
uuid_le uuid;
u8 loadable;
u8 input_pin_type;
u8 output_pin_type;
u8 max_input_pins;
u8 max_output_pins;
u8 nr_resources;
u8 nr_interfaces;
struct skl_module_res resources[SKL_MAX_MODULE_RESOURCES];
struct skl_module_iface formats[SKL_MAX_MODULE_FORMATS];
};
struct skl_module_cfg {
u8 guid[16];
struct skl_module_inst_id id;
struct skl_module *module;
int res_idx;
int fmt_idx;
u8 domain;
bool homogenous_inputs;
bool homogenous_outputs;
......@@ -329,6 +411,7 @@ struct skl_module_cfg {
enum skl_module_state m_state;
struct skl_pipe *pipe;
struct skl_specific_cfg formats_config;
struct skl_pipe_mcfg mod_cfg[SKL_MAX_MODULES_IN_PIPE];
};
struct skl_algo_data {
......
......@@ -415,7 +415,7 @@ static int skl_free(struct hdac_ext_bus *ebus)
snd_hdac_ext_stop_streams(ebus);
if (bus->irq >= 0)
free_irq(bus->irq, (void *)bus);
free_irq(bus->irq, (void *)ebus);
snd_hdac_bus_free_stream_pages(bus);
snd_hdac_stream_free_all(ebus);
snd_hdac_link_free_all(ebus);
......@@ -528,7 +528,7 @@ static int probe_codec(struct hdac_ext_bus *ebus, int addr)
}
/* Codec initialization */
static int skl_codec_create(struct hdac_ext_bus *ebus)
static void skl_codec_create(struct hdac_ext_bus *ebus)
{
struct hdac_bus *bus = ebus_to_hbus(ebus);
int c, max_slots;
......@@ -559,8 +559,6 @@ static int skl_codec_create(struct hdac_ext_bus *ebus)
}
}
}
return 0;
}
static const struct hdac_bus_ops bus_core_ops = {
......@@ -612,9 +610,7 @@ static void skl_probe_work(struct work_struct *work)
dev_info(bus->dev, "no hda codecs found!\n");
/* create codec instances */
err = skl_codec_create(ebus);
if (err < 0)
goto out_err;
skl_codec_create(ebus);
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
err = snd_hdac_display_power(bus, false);
......@@ -702,6 +698,8 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
return -ENXIO;
}
skl_init_chip(bus, true);
snd_hdac_bus_parse_capabilities(bus);
if (skl_acquire_irq(ebus, 0) < 0)
......@@ -982,6 +980,11 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
.quirk_data = &kbl_poppy_codecs,
.pdata = &skl_dmic_data
},
{
.id = "10EC5663",
.drv_name = "kbl_rt5663",
.fw_filename = "intel/dsp_fw_kbl.bin",
},
{}
};
......@@ -995,6 +998,14 @@ static struct sst_acpi_mach sst_glk_devdata[] = {
{}
};
static const struct sst_acpi_mach sst_cnl_devdata[] = {
{
.id = "INT34C2",
.drv_name = "cnl_rt274",
.fw_filename = "intel/dsp_fw_cnl.bin",
},
};
/* PCI IDs */
static const struct pci_device_id skl_ids[] = {
/* Sunrise Point-LP */
......@@ -1009,6 +1020,9 @@ static const struct pci_device_id skl_ids[] = {
/* GLK */
{ PCI_DEVICE(0x8086, 0x3198),
.driver_data = (unsigned long)&sst_glk_devdata},
/* CNL */
{ PCI_DEVICE(0x8086, 0x9dc8),
.driver_data = (unsigned long)&sst_cnl_devdata},
{ 0, }
};
MODULE_DEVICE_TABLE(pci, skl_ids);
......
......@@ -71,6 +71,8 @@ struct skl {
struct work_struct probe_work;
struct skl_debug *debugfs;
u8 nr_modules;
struct skl_module **modules;
};
#define skl_to_ebus(s) (&(s)->ebus)
......@@ -90,6 +92,7 @@ struct skl_machine_pdata {
struct skl_dsp_ops {
int id;
unsigned int num_cores;
struct skl_dsp_loader_ops (*loader_ops)(void);
int (*init)(struct device *dev, void __iomem *mmio_base,
int irq, const char *fw_name,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment