Browse Source

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

Mark Brown 8 năm trước cách đây
mục cha
commit
460f623a6e

+ 91 - 1
include/uapi/sound/snd_sst_tokens.h

@@ -163,8 +163,71 @@
  *
  *
  * %SKL_TKN_U32_DMA_BUF_SIZE:	DMA buffer size in millisec
  * %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
  * module_id and loadable flags dont have tokens as these values will be
  * read from the DSP FW manifest
  * 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 {
 enum SKL_TKNS {
 	SKL_TKN_UUID = 1,
 	SKL_TKN_UUID = 1,
@@ -218,7 +281,34 @@ enum SKL_TKNS {
 	SKL_TKL_U32_D0I3_CAPS, /* Typo added at v4.10 */
 	SKL_TKL_U32_D0I3_CAPS, /* Typo added at v4.10 */
 	SKL_TKN_U32_D0I3_CAPS = SKL_TKL_U32_D0I3_CAPS,
 	SKL_TKN_U32_D0I3_CAPS = SKL_TKL_U32_D0I3_CAPS,
 	SKL_TKN_U32_DMA_BUF_SIZE,
 	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
 #endif

+ 1 - 0
sound/soc/codecs/Makefile

@@ -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_MAX98090)	+= snd-soc-max98090.o
 obj-$(CONFIG_SND_SOC_MAX98095)	+= snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX98095)	+= snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX98357A)	+= snd-soc-max98357a.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_MAX9867)	+= snd-soc-max9867.o
 obj-$(CONFIG_SND_SOC_MAX98925)	+= snd-soc-max98925.o
 obj-$(CONFIG_SND_SOC_MAX98925)	+= snd-soc-max98925.o
 obj-$(CONFIG_SND_SOC_MAX98926)	+= snd-soc-max98926.o
 obj-$(CONFIG_SND_SOC_MAX98926)	+= snd-soc-max98926.o

+ 34 - 5
sound/soc/codecs/hdac_hdmi.c

@@ -121,6 +121,10 @@ struct hdac_hdmi_dai_port_map {
 	struct hdac_hdmi_cvt *cvt;
 	struct hdac_hdmi_cvt *cvt;
 };
 };
 
 
+struct hdac_hdmi_drv_data {
+	unsigned int vendor_nid;
+};
+
 struct hdac_hdmi_priv {
 struct hdac_hdmi_priv {
 	struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS];
 	struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS];
 	struct list_head pin_list;
 	struct list_head pin_list;
@@ -131,6 +135,7 @@ struct hdac_hdmi_priv {
 	int num_ports;
 	int num_ports;
 	struct mutex pin_mutex;
 	struct mutex pin_mutex;
 	struct hdac_chmap chmap;
 	struct hdac_chmap chmap;
+	struct hdac_hdmi_drv_data *drv_data;
 };
 };
 
 
 static struct hdac_hdmi_pcm *
 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_VENDOR_NID 0x08
+#define INTEL_GLK_VENDOR_NID 0x0b
 #define INTEL_GET_VENDOR_VERB 0xf81
 #define INTEL_GET_VENDOR_VERB 0xf81
 #define INTEL_SET_VENDOR_VERB 0x781
 #define INTEL_SET_VENDOR_VERB 0x781
 #define INTEL_EN_DP12			0x02 /* enable DP 1.2 features */
 #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)
 static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
 {
 {
 	unsigned int vendor_param;
 	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);
 				INTEL_GET_VENDOR_VERB, 0);
 	if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
 	if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
 		return;
 		return;
 
 
 	vendor_param |= INTEL_EN_ALL_PIN_CVTS;
 	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);
 				INTEL_SET_VENDOR_VERB, vendor_param);
 	if (vendor_param == -1)
 	if (vendor_param == -1)
 		return;
 		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)
 static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac)
 {
 {
 	unsigned int vendor_param;
 	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);
 				INTEL_GET_VENDOR_VERB, 0);
 	if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
 	if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
 		return;
 		return;
 
 
 	/* enable DP1.2 mode */
 	/* enable DP1.2 mode */
 	vendor_param |= INTEL_EN_DP12;
 	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);
 				INTEL_SET_VENDOR_VERB, vendor_param);
 	if (vendor_param == -1)
 	if (vendor_param == -1)
 		return;
 		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;
 	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)
 static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
 {
 {
 	struct hdac_device *codec = &edev->hdac;
 	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;
 	struct hdac_ext_link *hlink = NULL;
 	int num_dais = 0;
 	int num_dais = 0;
 	int ret = 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 */
 	/* hold the ref while we probe */
 	hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
 	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.is_pcm_attached = is_hdac_hdmi_pcm_attached;
 	hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
 	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);
 	dev_set_drvdata(&codec->dev, edev);
 
 
 	INIT_LIST_HEAD(&hdmi_priv->pin_list);
 	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(0x80862809, 0x100000, "Skylake HDMI", 0),
 	HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
 	HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
 	HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake 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),
 	{}
 	{}
 };
 };
 
 

+ 8 - 6
sound/soc/codecs/max98371.c

@@ -349,12 +349,14 @@ static struct snd_soc_dai_driver max98371_dai[] = {
 };
 };
 
 
 static const struct snd_soc_codec_driver max98371_codec = {
 static const struct snd_soc_codec_driver max98371_codec = {
-	.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),
+	.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 = {
 static const struct regmap_config max98371_regmap = {

+ 2 - 1
sound/soc/intel/Kconfig

@@ -255,11 +255,12 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
 
 
 config SND_SOC_INTEL_KBL_RT5663_RT5514_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"
         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_SST
         select SND_SOC_INTEL_SKYLAKE
         select SND_SOC_INTEL_SKYLAKE
         select SND_SOC_RT5663
         select SND_SOC_RT5663
         select SND_SOC_RT5514
         select SND_SOC_RT5514
+        select SND_SOC_RT5514_SPI
         select SND_SOC_MAX98927
         select SND_SOC_MAX98927
         select SND_SOC_HDAC_HDMI
         select SND_SOC_HDAC_HDMI
         help
         help

+ 5 - 5
sound/soc/intel/atom/sst-mfld-platform-pcm.c

@@ -76,7 +76,7 @@ int sst_unregister_dsp(struct sst_device *dev)
 }
 }
 EXPORT_SYMBOL_GPL(sst_unregister_dsp);
 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 |
 	.info =	(SNDRV_PCM_INFO_INTERLEAVED |
 			SNDRV_PCM_INFO_DOUBLE |
 			SNDRV_PCM_INFO_DOUBLE |
 			SNDRV_PCM_INFO_PAUSE |
 			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,
 	.startup = sst_media_open,
 	.shutdown = sst_media_close,
 	.shutdown = sst_media_close,
 	.prepare = sst_media_prepare,
 	.prepare = sst_media_prepare,
@@ -480,11 +480,11 @@ static struct snd_soc_dai_ops sst_media_dai_ops = {
 	.mute_stream = sst_media_digital_mute,
 	.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,
 	.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,
 	.startup = sst_enable_ssp,
 	.hw_params = sst_be_hw_params,
 	.hw_params = sst_be_hw_params,
 	.set_fmt = sst_set_format,
 	.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);
 	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,
 	.probe		= sst_soc_probe,
 	.ops		= &sst_platform_ops,
 	.ops		= &sst_platform_ops,
 	.compr_ops	= &sst_platform_compr_ops,
 	.compr_ops	= &sst_platform_compr_ops,

+ 2 - 2
sound/soc/intel/atom/sst/sst_drv_interface.c

@@ -407,7 +407,7 @@ static int sst_cdev_caps(struct snd_compr_caps *caps)
 	return 0;
 	return 0;
 }
 }
 
 
-static struct snd_compr_codec_caps caps_mp3 = {
+static const struct snd_compr_codec_caps caps_mp3 = {
 	.num_descriptors = 1,
 	.num_descriptors = 1,
 	.descriptor[0].max_ch = 2,
 	.descriptor[0].max_ch = 2,
 	.descriptor[0].sample_rates[0] = 48000,
 	.descriptor[0].sample_rates[0] = 48000,
@@ -424,7 +424,7 @@ static struct snd_compr_codec_caps caps_mp3 = {
 	.descriptor[0].formats = 0,
 	.descriptor[0].formats = 0,
 };
 };
 
 
-static struct snd_compr_codec_caps caps_aac = {
+static const struct snd_compr_codec_caps caps_aac = {
 	.num_descriptors = 2,
 	.num_descriptors = 2,
 	.descriptor[1].max_ch = 2,
 	.descriptor[1].max_ch = 2,
 	.descriptor[0].sample_rates[0] = 48000,
 	.descriptor[0].sample_rates[0] = 48000,

+ 1 - 1
sound/soc/intel/atom/sst/sst_pci.c

@@ -181,7 +181,7 @@ static void intel_sst_remove(struct pci_dev *pci)
 }
 }
 
 
 /* PCI Routines */
 /* 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},
 	{ PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
 	{ 0, }
 	{ 0, }
 };
 };

+ 2 - 2
sound/soc/intel/baytrail/sst-baytrail-pcm.c

@@ -309,7 +309,7 @@ static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
 	return snd_pcm_lib_default_mmap(substream, vma);
 	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,
 	.open		= sst_byt_pcm_open,
 	.close		= sst_byt_pcm_close,
 	.close		= sst_byt_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.ioctl		= snd_pcm_lib_ioctl,
@@ -395,7 +395,7 @@ static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
 	return 0;
 	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,
 	.probe		= sst_byt_pcm_probe,
 	.remove		= sst_byt_pcm_remove,
 	.remove		= sst_byt_pcm_remove,
 	.ops		= &sst_byt_pcm_ops,
 	.ops		= &sst_byt_pcm_ops,

+ 82 - 4
sound/soc/intel/boards/bxt_rt298.c

@@ -114,7 +114,44 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = {
 	{ "iDisp2 Tx", NULL, "iDisp2_out"},
 	{ "iDisp2 Tx", NULL, "iDisp2_out"},
 	{ "hifi1", NULL, "iDisp1 Tx"},
 	{ "hifi1", NULL, "iDisp1 Tx"},
 	{ "iDisp1 Tx", NULL, "iDisp1_out"},
 	{ "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)
 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 */
 /* broxton audio machine driver for SPT + RT298S */
 static struct snd_soc_card broxton_rt298 = {
 static struct snd_soc_card broxton_rt298 = {
 	.name = "broxton-rt298",
 	.name = "broxton-rt298",
-	.owner = THIS_MODULE,
 	.dai_link = broxton_rt298_dais,
 	.dai_link = broxton_rt298_dais,
 	.num_links = ARRAY_SIZE(broxton_rt298_dais),
 	.num_links = ARRAY_SIZE(broxton_rt298_dais),
 	.controls = broxton_controls,
 	.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)
 static int broxton_audio_probe(struct platform_device *pdev)
 {
 {
 	struct bxt_rt286_private *ctx;
 	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);
 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
 	if (!ctx)
 	if (!ctx)
@@ -516,18 +584,27 @@ static int broxton_audio_probe(struct platform_device *pdev)
 
 
 	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
 	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 = {
 static struct platform_driver broxton_audio = {
 	.probe = broxton_audio_probe,
 	.probe = broxton_audio_probe,
 	.driver = {
 	.driver = {
 		.name = "bxt_alc298s_i2s",
 		.name = "bxt_alc298s_i2s",
 		.pm = &snd_soc_pm_ops,
 		.pm = &snd_soc_pm_ops,
 	},
 	},
+	.id_table = bxt_board_ids,
 };
 };
 module_platform_driver(broxton_audio)
 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_DESCRIPTION("Intel SST Audio for Broxton");
 MODULE_LICENSE("GPL v2");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:bxt_alc298s_i2s");
 MODULE_ALIAS("platform:bxt_alc298s_i2s");
+MODULE_ALIAS("platform:glk_alc298s_i2s");

+ 258 - 52
sound/soc/intel/boards/kbl_rt5663_max98927.c

@@ -34,7 +34,7 @@
 #define MAXIM_DEV0_NAME "i2c-MX98927:00"
 #define MAXIM_DEV0_NAME "i2c-MX98927:00"
 #define MAXIM_DEV1_NAME "i2c-MX98927:01"
 #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 const struct snd_pcm_hw_constraint_list *dmic_constraints;
 static struct snd_soc_jack skylake_hdmi[3];
 static struct snd_soc_jack skylake_hdmi[3];
 
 
@@ -52,6 +52,8 @@ struct kbl_rt5663_private {
 enum {
 enum {
 	KBL_DPCM_AUDIO_PB = 0,
 	KBL_DPCM_AUDIO_PB = 0,
 	KBL_DPCM_AUDIO_CP,
 	KBL_DPCM_AUDIO_CP,
+	KBL_DPCM_AUDIO_HS_PB,
+	KBL_DPCM_AUDIO_ECHO_REF_CP,
 	KBL_DPCM_AUDIO_REF_CP,
 	KBL_DPCM_AUDIO_REF_CP,
 	KBL_DPCM_AUDIO_DMIC_CP,
 	KBL_DPCM_AUDIO_DMIC_CP,
 	KBL_DPCM_AUDIO_HDMI1_PB,
 	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("Left Spk", NULL),
 	SND_SOC_DAPM_SPK("Right Spk", NULL),
 	SND_SOC_DAPM_SPK("Right Spk", NULL),
 	SND_SOC_DAPM_MIC("SoC DMIC", 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" },
 	{ "IN1N", NULL, "Headset Mic" },
 	{ "DMic", NULL, "SoC DMIC" },
 	{ "DMic", NULL, "SoC DMIC" },
 
 
-	{ "HDMI", NULL, "hif5 Output" },
-	{ "DP", NULL, "hif6 Output" },
-
 	/* CODEC BE connections */
 	/* CODEC BE connections */
 	{ "Left HiFi Playback", NULL, "ssp0 Tx" },
 	{ "Left HiFi Playback", NULL, "ssp0 Tx" },
 	{ "Right 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" },
 	{ "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" },
 	{ "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 */
 	/* DMIC */
 	{ "dmic01_hifi", NULL, "DMIC01 Rx" },
 	{ "dmic01_hifi", NULL, "DMIC01 Rx" },
 	{ "DMIC01 Rx", NULL, "DMIC AIF" },
 	{ "DMIC01 Rx", NULL, "DMIC AIF" },
@@ -117,6 +122,49 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
 	{ "iDisp1 Tx", NULL, "iDisp1_out"},
 	{ "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[] = {
 static struct snd_soc_codec_conf max98927_codec_conf[] = {
 	{
 	{
 		.dev_name = MAXIM_DEV0_NAME,
 		.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.
 	 * Headset buttons map to the google Reference headset.
 	 * These can be configured by userspace.
 	 * 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_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
 			SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset,
 			SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset,
 			NULL, 0);
 			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);
 		dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
 		return ret;
 		return ret;
 	}
 	}
-
 	rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
 	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");
 	ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
 	if (ret) {
 	if (ret) {
 		dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", 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;
 	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 kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
 	struct snd_soc_dai *dai = rtd->codec_dai;
 	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)
 	if (!pcm)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	pcm->device = KBL_DPCM_AUDIO_HDMI1_PB;
+	pcm->device = device;
 	pcm->codec_dai = dai;
 	pcm->codec_dai = dai;
 
 
 	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
 	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;
 	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)
 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[] = {
 static unsigned int rates[] = {
 	48000,
 	48000,
 };
 };
 
 
-static struct snd_pcm_hw_constraint_list constraints_rates = {
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
 	.count = ARRAY_SIZE(rates),
 	.count = ARRAY_SIZE(rates),
 	.list  = rates,
 	.list  = rates,
 	.mask = 0,
 	.mask = 0,
@@ -252,7 +299,7 @@ static unsigned int channels[] = {
 	2,
 	2,
 };
 };
 
 
-static struct snd_pcm_hw_constraint_list constraints_channels = {
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
 	.count = ARRAY_SIZE(channels),
 	.count = ARRAY_SIZE(channels),
 	.list = channels,
 	.list = channels,
 	.mask = 0,
 	.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;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	int ret;
 	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 */
 	/* 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)
 	if (ret < 0)
 		dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
 		dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
 
 
@@ -381,7 +430,7 @@ static unsigned int rates_16000[] = {
 	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),
 	.count = ARRAY_SIZE(rates_16000),
 	.list  = rates_16000,
 	.list  = rates_16000,
 };
 };
@@ -443,6 +492,28 @@ static struct snd_soc_dai_link kabylake_dais[] = {
 		.dpcm_capture = 1,
 		.dpcm_capture = 1,
 		.ops = &kabylake_rt5663_fe_ops,
 		.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] = {
 	[KBL_DPCM_AUDIO_REF_CP] = {
 		.name = "Kbl Audio Reference cap",
 		.name = "Kbl Audio Reference cap",
 		.stream_name = "Wake on Voice",
 		.stream_name = "Wake on Voice",
@@ -538,7 +609,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
 		.no_pcm = 1,
 		.no_pcm = 1,
 		.codec_name = "i2c-10EC5663:00",
 		.codec_name = "i2c-10EC5663:00",
 		.codec_dai_name = KBL_REALTEK_CODEC_DAI,
 		.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 |
 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 			SND_SOC_DAIFMT_CBS_CFS,
 			SND_SOC_DAIFMT_CBS_CFS,
 		.ignore_pmdown_time = 1,
 		.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
 #define NAME_SIZE	32
 static int kabylake_card_late_probe(struct snd_soc_card *card)
 static int kabylake_card_late_probe(struct snd_soc_card *card)
 {
 {
 	struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card);
 	struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card);
 	struct kbl_hdmi_pcm *pcm;
 	struct kbl_hdmi_pcm *pcm;
+	struct snd_soc_codec *codec = NULL;
 	int err, i = 0;
 	int err, i = 0;
 	char jack_name[NAME_SIZE];
 	char jack_name[NAME_SIZE];
 
 
 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+		codec = pcm->codec_dai->codec;
 		snprintf(jack_name, sizeof(jack_name),
 		snprintf(jack_name, sizeof(jack_name),
 			"HDMI/DP, pcm=%d Jack", pcm->device);
 			"HDMI/DP, pcm=%d Jack", pcm->device);
 		err = snd_soc_card_jack_new(card, jack_name,
 		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++;
 		i++;
 	}
 	}
 
 
-	return 0;
+	if (!codec)
+		return -EINVAL;
+
+	return hdac_hdmi_jack_port_init(codec, &card->dapm);
 }
 }
 
 
 /* kabylake audio machine driver for SPT + RT5663 */
 /* 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",
 	.name = "kblrt5663max",
 	.owner = THIS_MODULE,
 	.owner = THIS_MODULE,
 	.dai_link = kabylake_dais,
 	.dai_link = kabylake_dais,
@@ -641,6 +819,22 @@ static struct snd_soc_card kabylake_audio_card = {
 	.late_probe = kabylake_card_late_probe,
 	.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)
 static int kabylake_audio_probe(struct platform_device *pdev)
 {
 {
 	struct kbl_rt5663_private *ctx;
 	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);
 	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);
 	pdata = dev_get_drvdata(&pdev->dev);
 	if (pdata)
 	if (pdata)
 		dmic_constraints = pdata->dmic_num == 2 ?
 		dmic_constraints = pdata->dmic_num == 2 ?
 			&constraints_dmic_2ch : &constraints_dmic_channels;
 			&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[] = {
 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("Naveen M <naveen.m@intel.com>");
 MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
 MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
 MODULE_LICENSE("GPL v2");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kbl_rt5663");
 MODULE_ALIAS("platform:kbl_rt5663_m98927");
 MODULE_ALIAS("platform:kbl_rt5663_m98927");

+ 68 - 13
sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c

@@ -18,6 +18,7 @@
  * GNU General Public License for more details.
  * GNU General Public License for more details.
  */
  */
 
 
+#include <linux/input.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <sound/core.h>
 #include <sound/core.h>
@@ -62,7 +63,10 @@ struct kbl_codec_private {
 enum {
 enum {
 	KBL_DPCM_AUDIO_PB = 0,
 	KBL_DPCM_AUDIO_PB = 0,
 	KBL_DPCM_AUDIO_CP,
 	KBL_DPCM_AUDIO_CP,
+	KBL_DPCM_AUDIO_HS_PB,
+	KBL_DPCM_AUDIO_ECHO_REF_CP,
 	KBL_DPCM_AUDIO_DMIC_CP,
 	KBL_DPCM_AUDIO_DMIC_CP,
+	KBL_DPCM_AUDIO_RT5514_DSP,
 	KBL_DPCM_AUDIO_HDMI1_PB,
 	KBL_DPCM_AUDIO_HDMI1_PB,
 	KBL_DPCM_AUDIO_HDMI2_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("Left Spk", NULL),
 	SND_SOC_DAPM_SPK("Right Spk", NULL),
 	SND_SOC_DAPM_SPK("Right Spk", NULL),
 	SND_SOC_DAPM_MIC("DMIC", 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" },
 	{ "IN1P", NULL, "Headset Mic" },
 	{ "IN1N", NULL, "Headset Mic" },
 	{ "IN1N", NULL, "Headset Mic" },
 
 
-	{ "HDMI", NULL, "hif5 Output" },
-	{ "DP", NULL, "hif6 Output" },
-
 	/* CODEC BE connections */
 	/* CODEC BE connections */
 	{ "Left HiFi Playback", NULL, "ssp0 Tx" },
 	{ "Left HiFi Playback", NULL, "ssp0 Tx" },
 	{ "Right 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" },
 	{ "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" },
 	{ "ssp1 Rx", NULL, "AIF Capture" },
 
 
 	{ "codec1_in", NULL, "ssp0 Rx" },
 	{ "codec1_in", NULL, "ssp0 Rx" },
 	{ "ssp0 Rx", NULL, "AIF1 Capture" },
 	{ "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 */
 	/* DMIC */
 	{ "DMIC1L", NULL, "DMIC" },
 	{ "DMIC1L", NULL, "DMIC" },
 	{ "DMIC1R", NULL, "DMIC" },
 	{ "DMIC1R", NULL, "DMIC" },
@@ -173,6 +179,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
 	int ret;
 	int ret;
 	struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
 	struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_jack *jack;
 
 
 	/*
 	/*
 	 * Headset buttons map to the google Reference headset.
 	 * 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;
 		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);
 	rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
 
 
 	ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC");
 	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;
 				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) {
 			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;
 				return ret;
 			}
 			}
 		}
 		}
@@ -442,6 +462,36 @@ static struct snd_soc_dai_link kabylake_dais[] = {
 		.dpcm_capture = 1,
 		.dpcm_capture = 1,
 		.ops = &kabylake_rt5663_fe_ops,
 		.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] = {
 	[KBL_DPCM_AUDIO_DMIC_CP] = {
 		.name = "Kbl Audio DMIC cap",
 		.name = "Kbl Audio DMIC cap",
 		.stream_name = "dmiccap",
 		.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_codec_private *ctx = snd_soc_card_get_drvdata(card);
 	struct kbl_hdmi_pcm *pcm;
 	struct kbl_hdmi_pcm *pcm;
+	struct snd_soc_codec *codec = NULL;
 	int err, i = 0;
 	int err, i = 0;
 	char jack_name[NAME_SIZE];
 	char jack_name[NAME_SIZE];
 
 
 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+		codec = pcm->codec_dai->codec;
 		err = snd_soc_card_jack_new(card, jack_name,
 		err = snd_soc_card_jack_new(card, jack_name,
 				SND_JACK_AVOUT, &ctx->kabylake_hdmi[i],
 				SND_JACK_AVOUT, &ctx->kabylake_hdmi[i],
 				NULL, 0);
 				NULL, 0);
@@ -565,7 +617,10 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
 		i++;
 		i++;
 	}
 	}
 
 
-	return 0;
+	if (!codec)
+		return -EINVAL;
+
+	return hdac_hdmi_jack_port_init(codec, &card->dapm);
 }
 }
 
 
 /*
 /*

+ 1 - 3
sound/soc/intel/boards/mfld_machine.c

@@ -376,10 +376,8 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
 	/* audio interrupt base of SRAM location where
 	/* audio interrupt base of SRAM location where
 	 * interrupts are stored by System FW */
 	 * interrupts are stored by System FW */
 	mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
 	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;
 		return -ENOMEM;
-	}
 
 
 	irq_mem = platform_get_resource_byname(
 	irq_mem = platform_get_resource_byname(
 				pdev, IORESOURCE_MEM, "IRQ_BASE");
 				pdev, IORESOURCE_MEM, "IRQ_BASE");

+ 1 - 1
sound/soc/intel/haswell/sst-haswell-pcm.c

@@ -1135,7 +1135,7 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)
 	return 0;
 	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,
 	.probe		= hsw_pcm_probe,
 	.remove		= hsw_pcm_remove,
 	.remove		= hsw_pcm_remove,
 	.ops		= &hsw_pcm_ops,
 	.ops		= &hsw_pcm_ops,

+ 3 - 2
sound/soc/intel/skylake/Makefile

@@ -8,7 +8,8 @@ endif
 obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
 obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
 
 
 # Skylake IPC Support
 # 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
 obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o

+ 7 - 7
sound/soc/intel/skylake/bxt-sst.c

@@ -530,7 +530,7 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
 	return 0;
 	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_D0 = bxt_set_dsp_D0,
 	.set_state_D3 = bxt_set_dsp_D3,
 	.set_state_D3 = bxt_set_dsp_D3,
 	.set_state_D0i3 = bxt_schedule_dsp_D0i3,
 	.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),
 	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);
 			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 */
 	/* set the D0i3 check */
 	skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0;
 	skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0;
 
 
-	skl->cores.count = 2;
 	skl->boot_complete = false;
 	skl->boot_complete = false;
 	init_waitqueue_head(&skl->boot_wait);
 	init_waitqueue_head(&skl->boot_wait);
 	INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
 	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);
 		release_firmware(ctx->dsp->fw);
 	skl_freeup_uuid_list(ctx);
 	skl_freeup_uuid_list(ctx);
 	skl_ipc_free(&ctx->ipc);
 	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);
 	ctx->dsp->ops->free(ctx->dsp);
 }
 }
 EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup);
 EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup);

+ 274 - 0
sound/soc/intel/skylake/cnl-sst-dsp.c

@@ -0,0 +1,274 @@
+/*
+ * 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);
+}

+ 112 - 0
sound/soc/intel/skylake/cnl-sst-dsp.h

@@ -0,0 +1,112 @@
+/*
+ * 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__*/

+ 497 - 0
sound/soc/intel/skylake/cnl-sst.c

@@ -0,0 +1,497 @@
+/*
+ * 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");

+ 135 - 28
sound/soc/intel/skylake/skl-messages.c

@@ -22,6 +22,7 @@
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
 #include "skl-sst-dsp.h"
 #include "skl-sst-dsp.h"
+#include "cnl-sst-dsp.h"
 #include "skl-sst-ipc.h"
 #include "skl-sst-ipc.h"
 #include "skl.h"
 #include "skl.h"
 #include "../common/sst-dsp.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[] = {
 static const struct skl_dsp_ops dsp_ops[] = {
 	{
 	{
 		.id = 0x9d70,
 		.id = 0x9d70,
+		.num_cores = 2,
 		.loader_ops = skl_get_loader_ops,
 		.loader_ops = skl_get_loader_ops,
 		.init = skl_sst_dsp_init,
 		.init = skl_sst_dsp_init,
 		.init_fw = skl_sst_init_fw,
 		.init_fw = skl_sst_init_fw,
@@ -208,6 +210,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
 	},
 	},
 	{
 	{
 		.id = 0x9d71,
 		.id = 0x9d71,
+		.num_cores = 2,
 		.loader_ops = skl_get_loader_ops,
 		.loader_ops = skl_get_loader_ops,
 		.init = kbl_sst_dsp_init,
 		.init = kbl_sst_dsp_init,
 		.init_fw = skl_sst_init_fw,
 		.init_fw = skl_sst_init_fw,
@@ -215,6 +218,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
 	},
 	},
 	{
 	{
 		.id = 0x5a98,
 		.id = 0x5a98,
+		.num_cores = 2,
 		.loader_ops = bxt_get_loader_ops,
 		.loader_ops = bxt_get_loader_ops,
 		.init = bxt_sst_dsp_init,
 		.init = bxt_sst_dsp_init,
 		.init_fw = bxt_sst_init_fw,
 		.init_fw = bxt_sst_init_fw,
@@ -222,11 +226,20 @@ static const struct skl_dsp_ops dsp_ops[] = {
 	},
 	},
 	{
 	{
 		.id = 0x3198,
 		.id = 0x3198,
+		.num_cores = 2,
 		.loader_ops = bxt_get_loader_ops,
 		.loader_ops = bxt_get_loader_ops,
 		.init = bxt_sst_dsp_init,
 		.init = bxt_sst_dsp_init,
 		.init_fw = bxt_sst_init_fw,
 		.init_fw = bxt_sst_init_fw,
 		.cleanup = bxt_sst_dsp_cleanup
 		.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)
 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;
 	struct skl_dsp_loader_ops loader_ops;
 	int irq = bus->irq;
 	int irq = bus->irq;
 	const struct skl_dsp_ops *ops;
 	const struct skl_dsp_ops *ops;
+	struct skl_dsp_cores *cores;
 	int ret;
 	int ret;
 
 
 	/* enable ppcap interrupt */
 	/* enable ppcap interrupt */
@@ -263,8 +277,10 @@ int skl_init_dsp(struct skl *skl)
 	}
 	}
 
 
 	ops = skl_get_dsp_ops(skl->pci->device);
 	ops = skl_get_dsp_ops(skl->pci->device);
-	if (!ops)
-		return -EIO;
+	if (!ops) {
+		ret = -EIO;
+		goto unmap_mmio;
+	}
 
 
 	loader_ops = ops->loader_ops();
 	loader_ops = ops->loader_ops();
 	ret = ops->init(bus->dev, mmio_base, irq,
 	ret = ops->init(bus->dev, mmio_base, irq,
@@ -272,11 +288,35 @@ int skl_init_dsp(struct skl *skl)
 				&skl->skl_sst);
 				&skl->skl_sst);
 
 
 	if (ret < 0)
 	if (ret < 0)
-		return ret;
+		goto unmap_mmio;
 
 
 	skl->skl_sst->dsp_ops = ops;
 	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);
 	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;
 	return ret;
 }
 }
 
 
@@ -291,6 +331,9 @@ int skl_free_dsp(struct skl *skl)
 
 
 	ctx->dsp_ops->cleanup(bus->dev, ctx);
 	ctx->dsp_ops->cleanup(bus->dev, ctx);
 
 
+	kfree(ctx->cores.state);
+	kfree(ctx->cores.usage_count);
+
 	if (ctx->dsp->addr.lpe)
 	if (ctx->dsp->addr.lpe)
 		iounmap(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_module_cfg *mconfig,
 			struct skl_base_cfg *base_cfg)
 			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.s_freq = format->s_freq;
 	base_cfg->audio_fmt.bit_depth = format->bit_depth;
 	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->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)
 			struct skl_cpr_cfg *cpr_mconfig)
 {
 {
 	u32 dma_io_buf;
 	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);
 	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;
 		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) {
 	switch (mconfig->hw_conn_type) {
 	case SKL_CONN_SOURCE:
 	case SKL_CONN_SOURCE:
 		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
 		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
-			dma_io_buf =  mconfig->ibs;
+			dma_io_buf =  res->ibs;
 		else
 		else
-			dma_io_buf =  mconfig->obs;
+			dma_io_buf =  res->obs;
 		break;
 		break;
 
 
 	case SKL_CONN_SINK:
 	case SKL_CONN_SINK:
 		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
 		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
-			dma_io_buf =  mconfig->obs;
+			dma_io_buf =  res->obs;
 		else
 		else
-			dma_io_buf =  mconfig->ibs;
+			dma_io_buf =  res->ibs;
 		break;
 		break;
 
 
 	default:
 	default:
@@ -543,11 +600,12 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
 	/* fallback to 2ms default value */
 	/* fallback to 2ms default value */
 	if (!cpr_mconfig->gtw_cfg.dma_buffer_size) {
 	if (!cpr_mconfig->gtw_cfg.dma_buffer_size) {
 		if (mconfig->hw_conn_type == SKL_CONN_SOURCE)
 		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
 		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->cpr_feature_mask = 0;
 	cpr_mconfig->gtw_cfg.config_length  = 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_module_cfg *mconfig,
 			struct skl_audio_data_format *out_fmt)
 			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->number_of_channels = (u8)format->channels;
 	out_fmt->s_freq = format->s_freq;
 	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_module_cfg *mconfig,
 			struct skl_src_module_cfg *src_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,
 	skl_set_base_module_format(ctx, mconfig,
 		(struct skl_base_cfg *)src_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_module_cfg *mconfig,
 			struct skl_up_down_mixer_cfg *mixer_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;
 	int i = 0;
 
 
 	skl_set_base_module_format(ctx,	mconfig,
 	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",
 	dev_dbg(ctx->dev, "%s: src module_id = %d  src_instance=%d\n",
 		__func__, src_module->id.module_id, src_module->id.pvt_id);
 		__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);
 		 dst_module->id.module_id, dst_module->id.pvt_id);
 
 
 	dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n",
 	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_ipc_bind_unbind_msg msg;
 	struct skl_module_inst_id src_id = src_mcfg->id;
 	struct skl_module_inst_id src_id = src_mcfg->id;
 	struct skl_module_inst_id dst_id = dst_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;
 	int src_index, dst_index, src_pin_state, dst_pin_state;
 
 
 	skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
 	skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
@@ -1019,6 +1083,21 @@ int skl_unbind_modules(struct skl_sst *ctx,
 	return ret;
 	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
  * 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
  * 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 *src_mcfg,
 			struct skl_module_cfg *dst_mcfg)
 			struct skl_module_cfg *dst_mcfg)
 {
 {
-	int ret;
+	int ret = 0;
 	struct skl_ipc_bind_unbind_msg msg;
 	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;
 	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);
 	skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
 
 
@@ -1053,6 +1136,29 @@ int skl_bind_modules(struct skl_sst *ctx,
 		return -EINVAL;
 		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;
 	msg.dst_queue = dst_index;
 
 
 	dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n",
 	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_state = SKL_MODULE_BIND_DONE;
 		src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_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;
 		dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE;
-	} else {
-		/* 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;
 	}
 	}
+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;
 	return ret;
 }
 }

+ 72 - 10
sound/soc/intel/skylake/skl-pcm.c

@@ -33,7 +33,7 @@
 #define HDA_STEREO 2
 #define HDA_STEREO 2
 #define HDA_QUAD 4
 #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 |
 	.info =			(SNDRV_PCM_INFO_MMAP |
 				 SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -628,7 +628,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
 	return 0;
 	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,
 	.startup = skl_pcm_open,
 	.shutdown = skl_pcm_close,
 	.shutdown = skl_pcm_close,
 	.prepare = skl_pcm_prepare,
 	.prepare = skl_pcm_prepare,
@@ -637,15 +637,15 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = {
 	.trigger = skl_pcm_trigger,
 	.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,
 	.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,
 	.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,
 	.prepare = skl_link_pcm_prepare,
 	.hw_params = skl_link_hw_params,
 	.hw_params = skl_link_hw_params,
 	.hw_free = skl_link_hw_free,
 	.hw_free = skl_link_hw_free,
@@ -674,6 +674,32 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
 		.sig_bits = 32,
 		.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",
 	.name = "Reference Pin",
 	.ops = &skl_pcm_dai_ops,
 	.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)
 static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig)
 {
 {
 	struct skl_sst *ctx = skl->skl_sst;
 	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;
 	struct uuid_module *module;
-	uuid_le *uuid_mod;
+	int i, ret = -EIO;
 
 
 	uuid_mod = (uuid_le *)mconfig->guid;
 	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) {
 	list_for_each_entry(module, &ctx->uuid_list, list) {
 		if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
 		if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
 			mconfig->id.module_id = module->id;
 			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;
+		}
+	}
+
+	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;
 
 
-	return -EIO;
+	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)
 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;
 	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,
 	.probe		= skl_platform_soc_probe,
 	.ops		= &skl_platform_ops,
 	.ops		= &skl_platform_ops,
 	.pcm_new	= skl_pcm_new,
 	.pcm_new	= skl_pcm_new,

+ 3 - 3
sound/soc/intel/skylake/skl-sst-dsp.c

@@ -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.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING;
 	skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1;
 	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.state[i] = SKL_DSP_RESET;
 		skl->cores.usage_count[i] = 0;
 		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;
 		return -EINVAL;
 	}
 	}
 
 
+	skl->cores.usage_count[core_id]++;
+
 	if (skl->cores.state[core_id] == SKL_DSP_RESET) {
 	if (skl->cores.state[core_id] == SKL_DSP_RESET) {
 		ret = ctx->fw_ops.set_state_D0(ctx, core_id);
 		ret = ctx->fw_ops.set_state_D0(ctx, core_id);
 		if (ret < 0) {
 		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:
 out:
 	dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
 	dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
 			core_id, skl->cores.state[core_id],
 			core_id, skl->cores.state[core_id],

+ 3 - 3
sound/soc/intel/skylake/skl-sst-ipc.c

@@ -283,7 +283,7 @@ enum skl_ipc_module_msg {
 	IPC_MOD_SET_D0IX = 8
 	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)
 		size_t tx_size)
 {
 {
 	if (tx_size)
 	if (tx_size)
@@ -347,7 +347,7 @@ out:
 
 
 }
 }
 
 
-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_ipc_header header)
 {
 {
 	struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc);
 	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 skl_ipc_header header)
 {
 {
 	struct ipc_message *msg;
 	struct ipc_message *msg;

+ 8 - 4
sound/soc/intel/skylake/skl-sst-ipc.h

@@ -44,12 +44,10 @@ struct skl_ipc_header {
 	u32 extension;
 	u32 extension;
 };
 };
 
 
-#define SKL_DSP_CORES_MAX  2
-
 struct skl_dsp_cores {
 struct skl_dsp_cores {
 	unsigned int count;
 	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);
 int skl_ipc_init(struct device *dev, struct skl_sst *skl);
 void skl_clear_module_cnt(struct sst_dsp *ctx);
 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 */
 #endif /* __SKL_IPC_H */

+ 1 - 5
sound/soc/intel/skylake/skl-sst-utils.c

@@ -368,7 +368,6 @@ int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
 {
 {
 	struct skl_sst *skl;
 	struct skl_sst *skl;
 	struct sst_dsp *sst;
 	struct sst_dsp *sst;
-	int ret;
 
 
 	skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
 	skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
 	if (skl == NULL)
 	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;
 	sst->dsp_ops = dsp_ops;
 	init_waitqueue_head(&skl->mod_load_wait);
 	init_waitqueue_head(&skl->mod_load_wait);
 	INIT_LIST_HEAD(&sst->module_list);
 	INIT_LIST_HEAD(&sst->module_list);
-	ret = skl_ipc_init(dev, skl);
-	if (ret)
-		return ret;
 
 
 	skl->is_first_boot = true;
 	skl->is_first_boot = true;
 	if (dsp)
 	if (dsp)
 		*dsp = skl;
 		*dsp = skl;
 
 
-	return ret;
+	return 0;
 }
 }
 
 
 int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo,
 int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo,

+ 8 - 4
sound/soc/intel/skylake/skl-sst.c

@@ -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_D0 = skl_set_dsp_D0,
 	.set_state_D3 = skl_set_dsp_D3,
 	.set_state_D3 = skl_set_dsp_D3,
 	.load_fw = skl_load_base_firmware,
 	.load_fw = skl_load_base_firmware,
@@ -512,7 +512,7 @@ static struct skl_dsp_fw_ops skl_fw_ops = {
 	.unload_mod = skl_unload_module,
 	.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_D0 = skl_set_dsp_D0,
 	.set_state_D3 = skl_set_dsp_D3,
 	.set_state_D3 = skl_set_dsp_D3,
 	.load_fw = skl_load_base_firmware,
 	.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),
 	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);
 			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;
 	return 0;
 }
 }

+ 633 - 108
sound/soc/intel/skylake/skl-topology.c

@@ -49,6 +49,9 @@ static const int mic_quatro_list[][SKL_CH_QUATRO] = {
 {0, 1, 2, 3},
 {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)
 void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps)
 {
 {
 	struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
 	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_module_cfg *mconfig)
 {
 {
 	struct skl_sst *ctx = skl->skl_sst;
 	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,
 		dev_err(ctx->dev,
 			"%s: module_id %d instance %d\n", __func__,
 			"%s: module_id %d instance %d\n", __func__,
 			mconfig->id.module_id, mconfig->id.instance_id);
 			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,
 static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
 				struct skl_module_cfg *mconfig)
 				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
 static void
 skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
 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,
 static void skl_dump_mconfig(struct skl_sst *ctx,
 					struct skl_module_cfg *mcfg)
 					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, "Dumping config\n");
 	dev_dbg(ctx->dev, "Input Format:\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, "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)
 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;
 	struct skl_module_fmt *in_fmt, *out_fmt;
 
 
 	/* Fixups will be applied to pin 0 only */
 	/* 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 (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		if (is_fe) {
 		if (is_fe) {
@@ -312,21 +328,23 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
 {
 {
 	int multiplier = 1;
 	int multiplier = 1;
 	struct skl_module_fmt *in_fmt, *out_fmt;
 	struct skl_module_fmt *in_fmt, *out_fmt;
+	struct skl_module_res *res;
 
 
 	/* Since fixups is applied to pin 0 only, ibs, obs needs
 	/* Since fixups is applied to pin 0 only, ibs, obs needs
 	 * change for pin 0 only
 	 * 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)
 	if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
 		multiplier = 5;
 		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) *
 			in_fmt->channels * (in_fmt->bit_depth >> 3) *
 			multiplier;
 			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) *
 			out_fmt->channels * (out_fmt->bit_depth >> 3) *
 			multiplier;
 			multiplier;
 }
 }
@@ -365,6 +383,8 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
 	struct nhlt_specific_cfg *cfg;
 	struct nhlt_specific_cfg *cfg;
 	struct skl *skl = get_skl_ctx(ctx->dev);
 	struct skl *skl = get_skl_ctx(ctx->dev);
 	u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
 	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 */
 	/* check if we already have blob */
 	if (m_cfg->formats_config.caps_size > 0)
 	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:
 	case SKL_DEVICE_DMIC:
 		link_type = NHLT_LINK_DMIC;
 		link_type = NHLT_LINK_DMIC;
 		dir = SNDRV_PCM_STREAM_CAPTURE;
 		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;
 		break;
 
 
 	case SKL_DEVICE_I2S:
 	case SKL_DEVICE_I2S:
 		link_type = NHLT_LINK_SSP;
 		link_type = NHLT_LINK_SSP;
 		if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
 		if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
 			dir = SNDRV_PCM_STREAM_PLAYBACK;
 			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 {
 		} else {
 			dir = SNDRV_PCM_STREAM_CAPTURE;
 			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;
 		break;
 
 
@@ -549,6 +569,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
 	struct snd_soc_dapm_widget *w;
 	struct snd_soc_dapm_widget *w;
 	struct skl_module_cfg *mconfig;
 	struct skl_module_cfg *mconfig;
 	struct skl_sst *ctx = skl->skl_sst;
 	struct skl_sst *ctx = skl->skl_sst;
+	u8 cfg_idx;
 	int ret = 0;
 	int ret = 0;
 
 
 	list_for_each_entry(w_module, &pipe->w_list, node) {
 	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;
 			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 */
 		/* check resource available */
 		if (!skl_is_pipe_mcps_avail(skl, mconfig))
 		if (!skl_is_pipe_mcps_avail(skl, mconfig))
 			return -ENOMEM;
 			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,
 			ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
 				mconfig->id.module_id, mconfig->guid);
 				mconfig->id.module_id, mconfig->guid);
 			if (ret < 0)
 			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)
 		if (mconfig->id.pvt_id < 0)
 			return ret;
 			return ret;
 		skl_tplg_set_module_init_data(w);
 		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);
 		ret = skl_init_module(ctx, mconfig);
 		if (ret < 0) {
 		if (ret < 0) {
 			skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
 			skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
-			return ret;
+			goto err;
 		}
 		}
 		skl_tplg_alloc_pipe_mcps(skl, mconfig);
 		skl_tplg_alloc_pipe_mcps(skl, mconfig);
 		ret = skl_tplg_set_module_params(w, ctx);
 		ret = skl_tplg_set_module_params(w, ctx);
 		if (ret < 0)
 		if (ret < 0)
-			return ret;
+			goto err;
 	}
 	}
 
 
 	return 0;
 	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,
 static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
 	 struct skl_pipe *pipe)
 	 struct skl_pipe *pipe)
 {
 {
-	int ret;
+	int ret = 0;
 	struct skl_pipe_module *w_module = NULL;
 	struct skl_pipe_module *w_module = NULL;
 	struct skl_module_cfg *mconfig = 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;
 		mconfig  = w_module->w->priv;
 		uuid_mod = (uuid_le *)mconfig->guid;
 		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) {
 			mconfig->m_state > SKL_MODULE_UNINIT) {
 			ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp,
 			ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp,
 						mconfig->id.module_id);
 						mconfig->id.module_id);
@@ -630,10 +666,76 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
 				return -EIO;
 				return -EIO;
 		}
 		}
 		skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
 		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 */
 	/* no modules to unload in this path, so return */
-	return 0;
+	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_sst *ctx = skl->skl_sst;
 	struct skl_module_deferred_bind *modules;
 	struct skl_module_deferred_bind *modules;
 
 
+	ret = skl_tplg_get_pipe_config(skl, mconfig);
+	if (ret < 0)
+		return ret;
+
 	/* check resource available */
 	/* check resource available */
 	if (!skl_is_pipe_mcps_avail(skl, mconfig))
 	if (!skl_is_pipe_mcps_avail(skl, mconfig))
 		return -EBUSY;
 		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.
 	 * check all out/in pins are in bind state.
 	 * if so set the module param
 	 * 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)
 		if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
 			return 0;
 			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)
 		if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
 			return 0;
 			return 0;
 	}
 	}
@@ -814,7 +920,7 @@ static int skl_tplg_module_add_deferred_bind(struct skl *skl,
 	int i;
 	int i;
 
 
 	/* only supported for module with static pin connection */
 	/* 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];
 		struct skl_module_pin *pin = &dst->m_in_pin[i];
 
 
 		if (pin->is_dynamic)
 		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 skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
 
 
 	return 0;
 	return 0;
@@ -1074,7 +1180,7 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
 	if (ret)
 	if (ret)
 		return 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) {
 		if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
 			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
 			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
 			if (!src_mconfig)
 			if (!src_mconfig)
@@ -1185,7 +1291,7 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
 	if (ret)
 	if (ret)
 		return 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) {
 		if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
 			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
 			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
 			if (!sink_mconfig)
 			if (!sink_mconfig)
@@ -1479,14 +1585,22 @@ int skl_tplg_update_pipe_params(struct device *dev,
 			struct skl_module_cfg *mconfig,
 			struct skl_module_cfg *mconfig,
 			struct skl_pipe_params *params)
 			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;
 	struct skl_module_fmt *format = NULL;
+	u8 cfg_idx = mconfig->pipe->cur_config_idx;
 
 
 	skl_tplg_fill_dma_id(mconfig, params);
 	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)
 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		format = &mconfig->in_fmt[0];
+		format = &mconfig->module->formats[0].inputs[0].fmt;
 	else
 	else
-		format = &mconfig->out_fmt[0];
+		format = &mconfig->module->formats[0].outputs[0].fmt;
 
 
 	/* set the hw_params */
 	/* set the hw_params */
 	format->s_freq = params->s_freq;
 	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) {
 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		mconfig->ibs = (format->s_freq / 1000) *
+		res->ibs = (format->s_freq / 1000) *
 				(format->channels) *
 				(format->channels) *
 				(format->bit_depth >> 3);
 				(format->bit_depth >> 3);
 	} else {
 	} else {
-		mconfig->obs = (format->s_freq / 1000) *
+		res->obs = (format->s_freq / 1000) *
 				(format->channels) *
 				(format->channels) *
 				(format->bit_depth >> 3);
 				(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,
 static int skl_tplg_fill_pipe_tkn(struct device *dev,
 			struct skl_pipe *pipe, u32 tkn,
 			struct skl_pipe *pipe, u32 tkn,
 			u32 tkn_val)
 			u32 tkn_val)
@@ -1814,6 +1976,14 @@ static int skl_tplg_fill_pipe_tkn(struct device *dev,
 		pipe->lp_mode = tkn_val;
 		pipe->lp_mode = tkn_val;
 		break;
 		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:
 	default:
 		dev_err(dev, "Token not handled %d\n", tkn);
 		dev_err(dev, "Token not handled %d\n", tkn);
 		return -EINVAL;
 		return -EINVAL;
@@ -1930,27 +2100,9 @@ static int skl_tplg_fill_pins_info(struct device *dev,
  * on the direction
  * on the direction
  */
  */
 static int skl_tplg_fill_fmt(struct device *dev,
 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) {
 	switch (tkn) {
 	case SKL_TKN_U32_FMT_CH:
 	case SKL_TKN_U32_FMT_CH:
 		dst_fmt->channels  = value;
 		dst_fmt->channels  = value;
@@ -1992,6 +2144,32 @@ static int skl_tplg_fill_fmt(struct device *dev,
 	return 0;
 	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,
 static int skl_tplg_get_uuid(struct device *dev, struct skl_module_cfg *mconfig,
 	      struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
 	      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;
 		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
  * 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 tkn_count = 0;
 	int ret;
 	int ret;
 	static int is_pipe_exists;
 	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)
 	if (tkn_elem->token > SKL_TKN_MAX)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	switch (tkn_elem->token) {
 	switch (tkn_elem->token) {
 	case SKL_TKN_U8_IN_QUEUE_COUNT:
 	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;
 		break;
 
 
 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
 	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;
 		break;
 
 
 	case SKL_TKN_U8_DYN_IN_PIN:
 	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)
 		if (!mconfig->m_in_pin)
 			return -ENOMEM;
 			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;
 		break;
 
 
 	case SKL_TKN_U8_DYN_OUT_PIN:
 	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)
 		if (!mconfig->m_out_pin)
 			return -ENOMEM;
 			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;
 		break;
 
 
 	case SKL_TKN_U8_TIME_SLOT:
 	case SKL_TKN_U8_TIME_SLOT:
@@ -2094,19 +2379,13 @@ static int skl_tplg_get_token(struct device *dev,
 		break;
 		break;
 
 
 	case SKL_TKN_U32_MEM_PAGES:
 	case SKL_TKN_U32_MEM_PAGES:
-		mconfig->mem_pages = tkn_elem->value;
-		break;
-
 	case SKL_TKN_U32_MAX_MCPS:
 	case SKL_TKN_U32_MAX_MCPS:
-		mconfig->mcps = tkn_elem->value;
-		break;
-
 	case SKL_TKN_U32_OBS:
 	case SKL_TKN_U32_OBS:
-		mconfig->obs = tkn_elem->value;
-		break;
-
 	case SKL_TKN_U32_IBS:
 	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;
 		break;
 
 
 	case SKL_TKN_U32_VBUS_ID:
 	case SKL_TKN_U32_VBUS_ID:
@@ -2139,10 +2418,16 @@ static int skl_tplg_get_token(struct device *dev,
 
 
 		break;
 		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_CONN_TYPE:
 	case SKL_TKN_U32_PIPE_PRIORITY:
 	case SKL_TKN_U32_PIPE_PRIORITY:
 	case SKL_TKN_U32_PIPE_MEM_PGS:
 	case SKL_TKN_U32_PIPE_MEM_PGS:
 	case SKL_TKN_U32_PMODE:
 	case SKL_TKN_U32_PMODE:
+	case SKL_TKN_U32_PIPE_DIRECTION:
+	case SKL_TKN_U32_NUM_CONFIGS:
 		if (is_pipe_exists) {
 		if (is_pipe_exists) {
 			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
 			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
 					tkn_elem->token, tkn_elem->value);
 					tkn_elem->token, tkn_elem->value);
@@ -2152,6 +2437,27 @@ static int skl_tplg_get_token(struct device *dev,
 
 
 		break;
 		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
 	 * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
 	 * direction and the pin count. The first four bits represent
 	 * 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_INTERLEAVE:
 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
 	case SKL_TKN_U32_FMT_CH_MAP:
 	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);
 				tkn_elem->value, dir, pin_index);
 
 
 		if (ret < 0)
 		if (ret < 0)
@@ -2397,11 +2703,11 @@ static void skl_clear_pin_config(struct snd_soc_platform *platform,
 					strlen(platform->component.name))) {
 					strlen(platform->component.name))) {
 		mconfig = w->priv;
 		mconfig = w->priv;
 		pipe = mconfig->pipe;
 		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].in_use = false;
 			mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
 			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].in_use = false;
 			mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
 			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)
 	if (!mconfig)
 		return -ENOMEM;
 		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;
 	w->priv = mconfig;
 
 
 	/*
 	/*
@@ -2602,13 +2915,13 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
 			str_elem->string,
 			str_elem->string,
 			ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name));
 			ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name));
 		ref_count++;
 		ref_count++;
-		tkn_count++;
 		break;
 		break;
 
 
 	default:
 	default:
 		dev_err(dev, "Not a string token %d\n", str_elem->token);
 		dev_err(dev, "Not a string token %d\n", str_elem->token);
 		break;
 		break;
 	}
 	}
+	tkn_count++;
 
 
 	return tkn_count;
 	return tkn_count;
 }
 }
@@ -2634,26 +2947,236 @@ static int skl_tplg_get_str_tkn(struct device *dev,
 	return tkn_count;
 	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,
 static int skl_tplg_get_int_tkn(struct device *dev,
 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
 		struct skl *skl)
 		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) {
 	switch (tkn_elem->token) {
 	case SKL_TKN_U32_LIB_COUNT:
 	case SKL_TKN_U32_LIB_COUNT:
 		skl->skl_sst->lib_count = tkn_elem->value;
 		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;
 		break;
 
 
 	default:
 	default:
 		dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
 		dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
+	tkn_count++;
 
 
 	return 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
  * Fill the manifest structure by parsing the tokens based on the
  * type.
  * type.
@@ -2686,7 +3209,11 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
 			continue;
 			continue;
 
 
 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
 		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;
 			continue;
 
 
 		default:
 		default:
@@ -2703,14 +3230,12 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
 
 
 			tkn_count = tkn_count + ret;
 			tkn_count = tkn_count + ret;
 			tkn_elem++;
 			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;
 		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;
 	num_blocks = ret;
 
 
 	off += array->size;
 	off += array->size;
-	array = (struct snd_soc_tplg_vendor_array *)
-			(manifest->priv.data + off);
-
 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
 	while (num_blocks > 0) {
 	while (num_blocks > 0) {
+		array = (struct snd_soc_tplg_vendor_array *)
+				(manifest->priv.data + off);
 		ret = skl_tplg_get_desc_blocks(dev, array);
 		ret = skl_tplg_get_desc_blocks(dev, array);
 
 
 		if (ret < 0)
 		if (ret < 0)
@@ -2771,6 +3295,7 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
 		} else {
 		} else {
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
+		off += ret;
 	}
 	}
 
 
 	return 0;
 	return 0;

+ 83 - 0
sound/soc/intel/skylake/skl-topology.h

@@ -44,6 +44,13 @@
 #define SKL_DEFAULT_MIC_SEL_GAIN	0x3FF
 #define SKL_DEFAULT_MIC_SEL_GAIN	0x3FF
 #define SKL_MIC_SEL_SWITCH	0x3
 #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 {
 enum skl_channel_index {
 	SKL_CHANNEL_LEFT = 0,
 	SKL_CHANNEL_LEFT = 0,
 	SKL_CHANNEL_RIGHT = 1,
 	SKL_CHANNEL_RIGHT = 1,
@@ -131,6 +138,11 @@ struct skl_cpr_cfg {
 	struct skl_cpr_gtw_cfg gtw_cfg;
 	struct skl_cpr_gtw_cfg gtw_cfg;
 } __packed;
 } __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_src_module_cfg {
 	struct skl_base_cfg base_cfg;
 	struct skl_base_cfg base_cfg;
@@ -214,6 +226,7 @@ struct skl_kpb_params {
 };
 };
 
 
 struct skl_module_inst_id {
 struct skl_module_inst_id {
+	uuid_le mod_uuid;
 	int module_id;
 	int module_id;
 	u32 instance_id;
 	u32 instance_id;
 	int pvt_id;
 	int pvt_id;
@@ -266,6 +279,23 @@ struct skl_pipe_params {
 	unsigned int link_bps;
 	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 {
 struct skl_pipe {
 	u8 ppl_id;
 	u8 ppl_id;
 	u8 pipe_priority;
 	u8 pipe_priority;
@@ -274,6 +304,10 @@ struct skl_pipe {
 	u8 lp_mode;
 	u8 lp_mode;
 	struct skl_pipe_params *p_params;
 	struct skl_pipe_params *p_params;
 	enum skl_pipe_state state;
 	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;
 	struct list_head w_list;
 	bool passthru;
 	bool passthru;
 };
 };
@@ -292,9 +326,57 @@ enum d0i3_capability {
 	SKL_D0I3_NON_STREAMING = 2,
 	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 {
 struct skl_module_cfg {
 	u8 guid[16];
 	u8 guid[16];
 	struct skl_module_inst_id id;
 	struct skl_module_inst_id id;
+	struct skl_module *module;
+	int res_idx;
+	int fmt_idx;
 	u8 domain;
 	u8 domain;
 	bool homogenous_inputs;
 	bool homogenous_inputs;
 	bool homogenous_outputs;
 	bool homogenous_outputs;
@@ -329,6 +411,7 @@ struct skl_module_cfg {
 	enum skl_module_state m_state;
 	enum skl_module_state m_state;
 	struct skl_pipe *pipe;
 	struct skl_pipe *pipe;
 	struct skl_specific_cfg formats_config;
 	struct skl_specific_cfg formats_config;
+	struct skl_pipe_mcfg mod_cfg[SKL_MAX_MODULES_IN_PIPE];
 };
 };
 
 
 struct skl_algo_data {
 struct skl_algo_data {

+ 21 - 7
sound/soc/intel/skylake/skl.c

@@ -415,7 +415,7 @@ static int skl_free(struct hdac_ext_bus *ebus)
 	snd_hdac_ext_stop_streams(ebus);
 	snd_hdac_ext_stop_streams(ebus);
 
 
 	if (bus->irq >= 0)
 	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_bus_free_stream_pages(bus);
 	snd_hdac_stream_free_all(ebus);
 	snd_hdac_stream_free_all(ebus);
 	snd_hdac_link_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 */
 /* 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);
 	struct hdac_bus *bus = ebus_to_hbus(ebus);
 	int c, max_slots;
 	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 = {
 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");
 		dev_info(bus->dev, "no hda codecs found!\n");
 
 
 	/* create codec instances */
 	/* 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)) {
 	if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
 		err = snd_hdac_display_power(bus, false);
 		err = snd_hdac_display_power(bus, false);
@@ -702,6 +698,8 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
 		return -ENXIO;
 		return -ENXIO;
 	}
 	}
 
 
+	skl_init_chip(bus, true);
+
 	snd_hdac_bus_parse_capabilities(bus);
 	snd_hdac_bus_parse_capabilities(bus);
 
 
 	if (skl_acquire_irq(ebus, 0) < 0)
 	if (skl_acquire_irq(ebus, 0) < 0)
@@ -982,6 +980,11 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
 		.quirk_data = &kbl_poppy_codecs,
 		.quirk_data = &kbl_poppy_codecs,
 		.pdata = &skl_dmic_data
 		.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 */
 /* PCI IDs */
 static const struct pci_device_id skl_ids[] = {
 static const struct pci_device_id skl_ids[] = {
 	/* Sunrise Point-LP */
 	/* Sunrise Point-LP */
@@ -1009,6 +1020,9 @@ static const struct pci_device_id skl_ids[] = {
 	/* GLK */
 	/* GLK */
 	{ PCI_DEVICE(0x8086, 0x3198),
 	{ PCI_DEVICE(0x8086, 0x3198),
 		.driver_data = (unsigned long)&sst_glk_devdata},
 		.driver_data = (unsigned long)&sst_glk_devdata},
+	/* CNL */
+	{ PCI_DEVICE(0x8086, 0x9dc8),
+		.driver_data = (unsigned long)&sst_cnl_devdata},
 	{ 0, }
 	{ 0, }
 };
 };
 MODULE_DEVICE_TABLE(pci, skl_ids);
 MODULE_DEVICE_TABLE(pci, skl_ids);

+ 3 - 0
sound/soc/intel/skylake/skl.h

@@ -71,6 +71,8 @@ struct skl {
 	struct work_struct probe_work;
 	struct work_struct probe_work;
 
 
 	struct skl_debug *debugfs;
 	struct skl_debug *debugfs;
+	u8 nr_modules;
+	struct skl_module **modules;
 };
 };
 
 
 #define skl_to_ebus(s)	(&(s)->ebus)
 #define skl_to_ebus(s)	(&(s)->ebus)
@@ -90,6 +92,7 @@ struct skl_machine_pdata {
 
 
 struct skl_dsp_ops {
 struct skl_dsp_ops {
 	int id;
 	int id;
+	unsigned int num_cores;
 	struct skl_dsp_loader_ops (*loader_ops)(void);
 	struct skl_dsp_loader_ops (*loader_ops)(void);
 	int (*init)(struct device *dev, void __iomem *mmio_base,
 	int (*init)(struct device *dev, void __iomem *mmio_base,
 			int irq, const char *fw_name,
 			int irq, const char *fw_name,