Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
authorMark Brown <broonie@kernel.org>
Fri, 1 Sep 2017 11:12:19 +0000 (12:12 +0100)
committerMark Brown <broonie@kernel.org>
Fri, 1 Sep 2017 11:12:19 +0000 (12:12 +0100)
30 files changed:
include/uapi/sound/snd_sst_tokens.h
sound/soc/codecs/Makefile
sound/soc/codecs/hdac_hdmi.c
sound/soc/codecs/max98371.c
sound/soc/intel/Kconfig
sound/soc/intel/atom/sst-mfld-platform-pcm.c
sound/soc/intel/atom/sst/sst_drv_interface.c
sound/soc/intel/atom/sst/sst_pci.c
sound/soc/intel/baytrail/sst-baytrail-pcm.c
sound/soc/intel/boards/bxt_rt298.c
sound/soc/intel/boards/kbl_rt5663_max98927.c
sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
sound/soc/intel/boards/mfld_machine.c
sound/soc/intel/haswell/sst-haswell-pcm.c
sound/soc/intel/skylake/Makefile
sound/soc/intel/skylake/bxt-sst.c
sound/soc/intel/skylake/cnl-sst-dsp.c [new file with mode: 0644]
sound/soc/intel/skylake/cnl-sst-dsp.h [new file with mode: 0644]
sound/soc/intel/skylake/cnl-sst.c [new file with mode: 0644]
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-sst-dsp.c
sound/soc/intel/skylake/skl-sst-ipc.c
sound/soc/intel/skylake/skl-sst-ipc.h
sound/soc/intel/skylake/skl-sst-utils.c
sound/soc/intel/skylake/skl-sst.c
sound/soc/intel/skylake/skl-topology.c
sound/soc/intel/skylake/skl-topology.h
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.h

index dedb205..f691e42 100644 (file)
  *
  * %SKL_TKN_U32_DMA_BUF_SIZE:  DMA buffer size in millisec
  *
+ * %SKL_TKN_U32_PIPE_DIR:       Specifies pipe direction. Can be
+ *                              playback/capture.
+ *
+ * %SKL_TKN_U32_NUM_CONFIGS:    Number of pipe configs
+ *
+ * %SKL_TKN_U32_PATH_MEM_PGS:   Size of memory (in pages) required for pipeline
+ *                              and its data
+ *
+ * %SKL_TKN_U32_PIPE_CONFIG_ID: Config id for the modules in the pipe
+ *                              and PCM params supported by that pipe
+ *                              config. This is used as index to fill
+ *                              up the pipe config and module config
+ *                              structure.
+ *
+ * %SKL_TKN_U32_CFG_FREQ:
+ * %SKL_TKN_U8_CFG_CHAN:
+ * %SKL_TKN_U8_CFG_BPS:         PCM params (freq, channels, bits per sample)
+ *                              supported for each of the pipe configs.
+ *
+ * %SKL_TKN_CFG_MOD_RES_ID:     Module's resource index for each of the
+ *                              pipe config
+ *
+ * %SKL_TKN_CFG_MOD_FMT_ID:     Module's interface index for each of the
+ *                              pipe config
+ *
+ * %SKL_TKN_U8_NUM_MOD:         Number of modules in the manifest
+ *
+ * %SKL_TKN_MM_U8_MOD_IDX:      Current index of the module in the manifest
+ *
+ * %SKL_TKN_MM_U8_NUM_RES:      Number of resources for the module
+ *
+ * %SKL_TKN_MM_U8_NUM_INTF:     Number of interfaces for the module
+ *
+ * %SKL_TKN_MM_U32_RES_ID:      Resource index for the resource info to
+ *                              be filled into.
+ *                              A module can support multiple resource
+ *                              configuration and is represnted as a
+ *                              resource table. This index is used to
+ *                              fill information into appropriate index.
+ *
+ * %SKL_TKN_MM_U32_CPS:         DSP cycles per second
+ *
+ * %SKL_TKN_MM_U32_DMA_SIZE:    Allocated buffer size for gateway DMA
+ *
+ * %SKL_TKN_MM_U32_CPC:         DSP cycles allocated per frame
+ *
+ * %SKL_TKN_MM_U32_RES_PIN_ID:  Resource pin index in the module
+ *
+ * %SKL_TKN_MM_U32_INTF_PIN_ID: Interface index in the module
+ *
+ * %SKL_TKN_MM_U32_PIN_BUF:     Buffer size of the module pin
+ *
+ * %SKL_TKN_MM_U32_FMT_ID:      Format index for each of the interface/
+ *                              format information to be filled into.
+ *
+ * %SKL_TKN_MM_U32_NUM_IN_FMT:  Number of input formats
+ * %SKL_TKN_MM_U32_NUM_OUT_FMT: Number of output formats
+ *
  * module_id and loadable flags dont have tokens as these values will be
  * read from the DSP FW manifest
+ *
+ * Tokens defined can be used either in the manifest or widget private data.
+ *
+ * SKL_TKN_MM is used as a suffix for all tokens that represent
+ * module data in the manifest.
  */
 enum SKL_TKNS {
        SKL_TKN_UUID = 1,
@@ -218,7 +281,34 @@ enum SKL_TKNS {
        SKL_TKL_U32_D0I3_CAPS, /* Typo added at v4.10 */
        SKL_TKN_U32_D0I3_CAPS = SKL_TKL_U32_D0I3_CAPS,
        SKL_TKN_U32_DMA_BUF_SIZE,
-       SKL_TKN_MAX = SKL_TKN_U32_DMA_BUF_SIZE,
+
+       SKL_TKN_U32_PIPE_DIRECTION,
+       SKL_TKN_U32_PIPE_CONFIG_ID,
+       SKL_TKN_U32_NUM_CONFIGS,
+       SKL_TKN_U32_PATH_MEM_PGS,
+
+       SKL_TKN_U32_CFG_FREQ,
+       SKL_TKN_U8_CFG_CHAN,
+       SKL_TKN_U8_CFG_BPS,
+       SKL_TKN_CFG_MOD_RES_ID,
+       SKL_TKN_CFG_MOD_FMT_ID,
+       SKL_TKN_U8_NUM_MOD,
+
+       SKL_TKN_MM_U8_MOD_IDX,
+       SKL_TKN_MM_U8_NUM_RES,
+       SKL_TKN_MM_U8_NUM_INTF,
+       SKL_TKN_MM_U32_RES_ID,
+       SKL_TKN_MM_U32_CPS,
+       SKL_TKN_MM_U32_DMA_SIZE,
+       SKL_TKN_MM_U32_CPC,
+       SKL_TKN_MM_U32_RES_PIN_ID,
+       SKL_TKN_MM_U32_INTF_PIN_ID,
+       SKL_TKN_MM_U32_PIN_BUF,
+       SKL_TKN_MM_U32_FMT_ID,
+       SKL_TKN_MM_U32_NUM_IN_FMT,
+       SKL_TKN_MM_U32_NUM_OUT_FMT,
+
+       SKL_TKN_MAX = SKL_TKN_MM_U32_NUM_OUT_FMT,
 };
 
 #endif
index a8a4b07..e22ec8f 100644 (file)
@@ -321,6 +321,7 @@ obj-$(CONFIG_SND_SOC_MAX98088)      += snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o
 obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX98357A)        += snd-soc-max98357a.o
+obj-$(CONFIG_SND_SOC_MAX98371) += snd-soc-max98371.o
 obj-$(CONFIG_SND_SOC_MAX9867)  += snd-soc-max9867.o
 obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o
 obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o
index e808f94..e824d47 100644 (file)
@@ -121,6 +121,10 @@ struct hdac_hdmi_dai_port_map {
        struct hdac_hdmi_cvt *cvt;
 };
 
+struct hdac_hdmi_drv_data {
+       unsigned int vendor_nid;
+};
+
 struct hdac_hdmi_priv {
        struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS];
        struct list_head pin_list;
@@ -131,6 +135,7 @@ struct hdac_hdmi_priv {
        int num_ports;
        struct mutex pin_mutex;
        struct hdac_chmap chmap;
+       struct hdac_hdmi_drv_data *drv_data;
 };
 
 static struct hdac_hdmi_pcm *
@@ -1321,6 +1326,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
 }
 
 #define INTEL_VENDOR_NID 0x08
+#define INTEL_GLK_VENDOR_NID 0x0b
 #define INTEL_GET_VENDOR_VERB 0xf81
 #define INTEL_SET_VENDOR_VERB 0x781
 #define INTEL_EN_DP12                  0x02 /* enable DP 1.2 features */
@@ -1329,14 +1335,17 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
 static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
 {
        unsigned int vendor_param;
+       struct hdac_ext_device *edev = to_ehdac_device(hdac);
+       struct hdac_hdmi_priv *hdmi = edev->private_data;
+       unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
 
-       vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+       vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
                                INTEL_GET_VENDOR_VERB, 0);
        if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
                return;
 
        vendor_param |= INTEL_EN_ALL_PIN_CVTS;
-       vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+       vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
                                INTEL_SET_VENDOR_VERB, vendor_param);
        if (vendor_param == -1)
                return;
@@ -1345,15 +1354,18 @@ static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
 static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac)
 {
        unsigned int vendor_param;
+       struct hdac_ext_device *edev = to_ehdac_device(hdac);
+       struct hdac_hdmi_priv *hdmi = edev->private_data;
+       unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
 
-       vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+       vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
                                INTEL_GET_VENDOR_VERB, 0);
        if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
                return;
 
        /* enable DP1.2 mode */
        vendor_param |= INTEL_EN_DP12;
-       vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+       vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
                                INTEL_SET_VENDOR_VERB, vendor_param);
        if (vendor_param == -1)
                return;
@@ -1927,6 +1939,14 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
        return port->eld.info.spk_alloc;
 }
 
+static struct hdac_hdmi_drv_data intel_glk_drv_data  = {
+       .vendor_nid = INTEL_GLK_VENDOR_NID,
+};
+
+static struct hdac_hdmi_drv_data intel_drv_data  = {
+       .vendor_nid = INTEL_VENDOR_NID,
+};
+
 static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
 {
        struct hdac_device *codec = &edev->hdac;
@@ -1935,6 +1955,8 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
        struct hdac_ext_link *hlink = NULL;
        int num_dais = 0;
        int ret = 0;
+       struct hdac_driver *hdrv = drv_to_hdac_driver(codec->dev.driver);
+       const struct hda_device_id *hdac_id = hdac_get_device_id(codec, hdrv);
 
        /* hold the ref while we probe */
        hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
@@ -1956,6 +1978,12 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
        hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached;
        hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
 
+       if (hdac_id->driver_data)
+               hdmi_priv->drv_data =
+                       (struct hdac_hdmi_drv_data *)hdac_id->driver_data;
+       else
+               hdmi_priv->drv_data = &intel_drv_data;
+
        dev_set_drvdata(&codec->dev, edev);
 
        INIT_LIST_HEAD(&hdmi_priv->pin_list);
@@ -2127,7 +2155,8 @@ static const struct hda_device_id hdmi_list[] = {
        HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
        HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
        HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0),
-       HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", 0),
+       HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI",
+                                                  &intel_glk_drv_data),
        {}
 };
 
index 781be9b..7bc2a17 100644 (file)
@@ -349,12 +349,14 @@ static struct snd_soc_dai_driver max98371_dai[] = {
 };
 
 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 = {
index b301bff..b3c7f55 100644 (file)
@@ -255,11 +255,12 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
 
 config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
         tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
-        depends on X86_INTEL_LPSS && I2C
+        depends on X86_INTEL_LPSS && I2C && SPI
         select SND_SOC_INTEL_SST
         select SND_SOC_INTEL_SKYLAKE
         select SND_SOC_RT5663
         select SND_SOC_RT5514
+        select SND_SOC_RT5514_SPI
         select SND_SOC_MAX98927
         select SND_SOC_HDAC_HDMI
         help
index b082b31..43e7fdd 100644 (file)
@@ -76,7 +76,7 @@ int sst_unregister_dsp(struct sst_device *dev)
 }
 EXPORT_SYMBOL_GPL(sst_unregister_dsp);
 
-static struct snd_pcm_hardware sst_platform_pcm_hw = {
+static const struct snd_pcm_hardware sst_platform_pcm_hw = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED |
                        SNDRV_PCM_INFO_DOUBLE |
                        SNDRV_PCM_INFO_PAUSE |
@@ -471,7 +471,7 @@ static void sst_disable_ssp(struct snd_pcm_substream *substream,
        }
 }
 
-static struct snd_soc_dai_ops sst_media_dai_ops = {
+static const struct snd_soc_dai_ops sst_media_dai_ops = {
        .startup = sst_media_open,
        .shutdown = sst_media_close,
        .prepare = sst_media_prepare,
@@ -480,11 +480,11 @@ static struct snd_soc_dai_ops sst_media_dai_ops = {
        .mute_stream = sst_media_digital_mute,
 };
 
-static struct snd_soc_dai_ops sst_compr_dai_ops = {
+static const struct snd_soc_dai_ops sst_compr_dai_ops = {
        .mute_stream = sst_media_digital_mute,
 };
 
-static struct snd_soc_dai_ops sst_be_dai_ops = {
+static const struct snd_soc_dai_ops sst_be_dai_ops = {
        .startup = sst_enable_ssp,
        .hw_params = sst_be_hw_params,
        .set_fmt = sst_set_format,
@@ -705,7 +705,7 @@ static int sst_soc_probe(struct snd_soc_platform *platform)
        return sst_dsp_init_v2_dpcm(platform);
 }
 
-static struct snd_soc_platform_driver sst_soc_platform_drv  = {
+static const struct snd_soc_platform_driver sst_soc_platform_drv  = {
        .probe          = sst_soc_probe,
        .ops            = &sst_platform_ops,
        .compr_ops      = &sst_platform_compr_ops,
index ce689c5..71af544 100644 (file)
@@ -407,7 +407,7 @@ static int sst_cdev_caps(struct snd_compr_caps *caps)
        return 0;
 }
 
-static struct snd_compr_codec_caps caps_mp3 = {
+static const struct snd_compr_codec_caps caps_mp3 = {
        .num_descriptors = 1,
        .descriptor[0].max_ch = 2,
        .descriptor[0].sample_rates[0] = 48000,
@@ -424,7 +424,7 @@ static struct snd_compr_codec_caps caps_mp3 = {
        .descriptor[0].formats = 0,
 };
 
-static struct snd_compr_codec_caps caps_aac = {
+static const struct snd_compr_codec_caps caps_aac = {
        .num_descriptors = 2,
        .descriptor[1].max_ch = 2,
        .descriptor[0].sample_rates[0] = 48000,
index 3a0b3bf..6906ee6 100644 (file)
@@ -181,7 +181,7 @@ static void intel_sst_remove(struct pci_dev *pci)
 }
 
 /* PCI Routines */
-static struct pci_device_id intel_sst_ids[] = {
+static const struct pci_device_id intel_sst_ids[] = {
        { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
        { 0, }
 };
index 4765ad4..c545293 100644 (file)
@@ -309,7 +309,7 @@ static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
        return snd_pcm_lib_default_mmap(substream, vma);
 }
 
-static struct snd_pcm_ops sst_byt_pcm_ops = {
+static const struct snd_pcm_ops sst_byt_pcm_ops = {
        .open           = sst_byt_pcm_open,
        .close          = sst_byt_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
@@ -395,7 +395,7 @@ static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
        return 0;
 }
 
-static struct snd_soc_platform_driver byt_soc_platform = {
+static const struct snd_soc_platform_driver byt_soc_platform = {
        .probe          = sst_byt_pcm_probe,
        .remove         = sst_byt_pcm_remove,
        .ops            = &sst_byt_pcm_ops,
index 0c3a3cb..7843104 100644 (file)
@@ -114,7 +114,44 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = {
        { "iDisp2 Tx", NULL, "iDisp2_out"},
        { "hifi1", NULL, "iDisp1 Tx"},
        { "iDisp1 Tx", NULL, "iDisp1_out"},
+};
+
+static const struct snd_soc_dapm_route geminilake_rt298_map[] = {
+       /* speaker */
+       {"Speaker", NULL, "SPOR"},
+       {"Speaker", NULL, "SPOL"},
+
+       /* HP jack connectors - unknown if we have jack detect */
+       {"Headphone Jack", NULL, "HPO Pin"},
+
+       /* other jacks */
+       {"MIC1", NULL, "Mic Jack"},
+
+       /* digital mics */
+       {"DMIC1 Pin", NULL, "DMIC2"},
+       {"DMic", NULL, "SoC DMIC"},
+
+       {"HDMI1", NULL, "hif5-0 Output"},
+       {"HDMI2", NULL, "hif6-0 Output"},
+       {"HDMI2", NULL, "hif7-0 Output"},
+
+       /* CODEC BE connections */
+       { "AIF1 Playback", NULL, "ssp2 Tx"},
+       { "ssp2 Tx", NULL, "codec0_out"},
+       { "ssp2 Tx", NULL, "codec1_out"},
+
+       { "codec0_in", NULL, "ssp2 Rx" },
+       { "ssp2 Rx", NULL, "AIF1 Capture" },
 
+       { "dmic01_hifi", NULL, "DMIC01 Rx" },
+       { "DMIC01 Rx", NULL, "Capture" },
+
+       { "hifi3", NULL, "iDisp3 Tx"},
+       { "iDisp3 Tx", NULL, "iDisp3_out"},
+       { "hifi2", NULL, "iDisp2 Tx"},
+       { "iDisp2 Tx", NULL, "iDisp2_out"},
+       { "hifi1", NULL, "iDisp1 Tx"},
+       { "iDisp1 Tx", NULL, "iDisp1_out"},
 };
 
 static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd)
@@ -492,7 +529,6 @@ static int bxt_card_late_probe(struct snd_soc_card *card)
 /* broxton audio machine driver for SPT + RT298S */
 static struct snd_soc_card broxton_rt298 = {
        .name = "broxton-rt298",
-       .owner = THIS_MODULE,
        .dai_link = broxton_rt298_dais,
        .num_links = ARRAY_SIZE(broxton_rt298_dais),
        .controls = broxton_controls,
@@ -506,9 +542,41 @@ static struct snd_soc_card broxton_rt298 = {
 
 };
 
+static struct snd_soc_card geminilake_rt298 = {
+       .name = "geminilake-rt298",
+       .dai_link = broxton_rt298_dais,
+       .num_links = ARRAY_SIZE(broxton_rt298_dais),
+       .controls = broxton_controls,
+       .num_controls = ARRAY_SIZE(broxton_controls),
+       .dapm_widgets = broxton_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
+       .dapm_routes = geminilake_rt298_map,
+       .num_dapm_routes = ARRAY_SIZE(geminilake_rt298_map),
+       .fully_routed = true,
+       .late_probe = bxt_card_late_probe,
+};
+
 static int broxton_audio_probe(struct platform_device *pdev)
 {
        struct bxt_rt286_private *ctx;
+       struct snd_soc_card *card =
+                       (struct snd_soc_card *)pdev->id_entry->driver_data;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) {
+               if (!strncmp(card->dai_link[i].codec_name, "i2c-INT343A:00",
+                                               I2C_NAME_SIZE)) {
+                       if (!strncmp(card->name, "broxton-rt298",
+                                               PLATFORM_NAME_SIZE)) {
+                               card->dai_link[i].name = "SSP5-Codec";
+                               card->dai_link[i].cpu_dai_name = "SSP5 Pin";
+                       } else if (!strncmp(card->name, "geminilake-rt298",
+                                               PLATFORM_NAME_SIZE)) {
+                               card->dai_link[i].name = "SSP2-Codec";
+                               card->dai_link[i].cpu_dai_name = "SSP2 Pin";
+                       }
+               }
+       }
 
        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
        if (!ctx)
@@ -516,18 +584,27 @@ static int broxton_audio_probe(struct platform_device *pdev)
 
        INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
 
-       broxton_rt298.dev = &pdev->dev;
-       snd_soc_card_set_drvdata(&broxton_rt298, ctx);
+       card->dev = &pdev->dev;
+       snd_soc_card_set_drvdata(card, ctx);
 
-       return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298);
+       return devm_snd_soc_register_card(&pdev->dev, card);
 }
 
+static const struct platform_device_id bxt_board_ids[] = {
+       { .name = "bxt_alc298s_i2s", .driver_data =
+                               (unsigned long)&broxton_rt298 },
+       { .name = "glk_alc298s_i2s", .driver_data =
+                               (unsigned long)&geminilake_rt298 },
+       {}
+};
+
 static struct platform_driver broxton_audio = {
        .probe = broxton_audio_probe,
        .driver = {
                .name = "bxt_alc298s_i2s",
                .pm = &snd_soc_pm_ops,
        },
+       .id_table = bxt_board_ids,
 };
 module_platform_driver(broxton_audio)
 
@@ -537,3 +614,4 @@ MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>");
 MODULE_DESCRIPTION("Intel SST Audio for Broxton");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:bxt_alc298s_i2s");
+MODULE_ALIAS("platform:glk_alc298s_i2s");
index f9ba977..7f76074 100644 (file)
@@ -34,7 +34,7 @@
 #define MAXIM_DEV0_NAME "i2c-MX98927:00"
 #define MAXIM_DEV1_NAME "i2c-MX98927:01"
 
-static struct snd_soc_card kabylake_audio_card;
+static struct snd_soc_card *kabylake_audio_card;
 static const struct snd_pcm_hw_constraint_list *dmic_constraints;
 static struct snd_soc_jack skylake_hdmi[3];
 
@@ -52,6 +52,8 @@ struct kbl_rt5663_private {
 enum {
        KBL_DPCM_AUDIO_PB = 0,
        KBL_DPCM_AUDIO_CP,
+       KBL_DPCM_AUDIO_HS_PB,
+       KBL_DPCM_AUDIO_ECHO_REF_CP,
        KBL_DPCM_AUDIO_REF_CP,
        KBL_DPCM_AUDIO_DMIC_CP,
        KBL_DPCM_AUDIO_HDMI1_PB,
@@ -72,8 +74,9 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
        SND_SOC_DAPM_SPK("Left Spk", NULL),
        SND_SOC_DAPM_SPK("Right Spk", NULL),
        SND_SOC_DAPM_MIC("SoC DMIC", NULL),
-       SND_SOC_DAPM_SPK("DP", NULL),
-       SND_SOC_DAPM_SPK("HDMI", NULL),
+       SND_SOC_DAPM_SPK("HDMI1", NULL),
+       SND_SOC_DAPM_SPK("HDMI2", NULL),
+       SND_SOC_DAPM_SPK("HDMI3", NULL),
 
 };
 
@@ -91,20 +94,22 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
        { "IN1N", NULL, "Headset Mic" },
        { "DMic", NULL, "SoC DMIC" },
 
-       { "HDMI", NULL, "hif5 Output" },
-       { "DP", NULL, "hif6 Output" },
-
        /* CODEC BE connections */
        { "Left HiFi Playback", NULL, "ssp0 Tx" },
        { "Right HiFi Playback", NULL, "ssp0 Tx" },
-       { "ssp0 Tx", NULL, "codec0_out" },
+       { "ssp0 Tx", NULL, "spk_out" },
 
        { "AIF Playback", NULL, "ssp1 Tx" },
-       { "ssp1 Tx", NULL, "codec1_out" },
+       { "ssp1 Tx", NULL, "hs_out" },
 
-       { "codec0_in", NULL, "ssp1 Rx" },
+       { "hs_in", NULL, "ssp1 Rx" },
        { "ssp1 Rx", NULL, "AIF Capture" },
 
+       /* IV feedback path */
+       { "codec0_fb_in", NULL, "ssp0 Rx"},
+       { "ssp0 Rx", NULL, "Left HiFi Capture" },
+       { "ssp0 Rx", NULL, "Right HiFi Capture" },
+
        /* DMIC */
        { "dmic01_hifi", NULL, "DMIC01 Rx" },
        { "DMIC01 Rx", NULL, "DMIC AIF" },
@@ -117,6 +122,49 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
        { "iDisp1 Tx", NULL, "iDisp1_out"},
 };
 
+enum {
+       KBL_DPCM_AUDIO_5663_PB = 0,
+       KBL_DPCM_AUDIO_5663_CP,
+       KBL_DPCM_AUDIO_5663_HDMI1_PB,
+       KBL_DPCM_AUDIO_5663_HDMI2_PB,
+};
+
+static const struct snd_kcontrol_new kabylake_5663_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_SPK("DP", NULL),
+       SND_SOC_DAPM_SPK("HDMI", NULL),
+};
+
+static const struct snd_soc_dapm_route kabylake_5663_map[] = {
+       { "Headphone Jack", NULL, "HPOL" },
+       { "Headphone Jack", NULL, "HPOR" },
+
+       /* other jacks */
+       { "IN1P", NULL, "Headset Mic" },
+       { "IN1N", NULL, "Headset Mic" },
+
+       { "HDMI", NULL, "hif5 Output" },
+       { "DP", NULL, "hif6 Output" },
+
+       /* CODEC BE connections */
+       { "AIF Playback", NULL, "ssp1 Tx" },
+       { "ssp1 Tx", NULL, "codec1_out" },
+
+       { "codec0_in", NULL, "ssp1 Rx" },
+       { "ssp1 Rx", NULL, "AIF Capture" },
+
+       { "hifi2", NULL, "iDisp2 Tx"},
+       { "iDisp2 Tx", NULL, "iDisp2_out"},
+       { "hifi1", NULL, "iDisp1 Tx"},
+       { "iDisp1 Tx", NULL, "iDisp1_out"},
+};
+
 static struct snd_soc_codec_conf max98927_codec_conf[] = {
        {
                .dev_name = MAXIM_DEV0_NAME,
@@ -165,7 +213,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack",
+       ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack",
                        SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
                        SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset,
                        NULL, 0);
@@ -173,8 +221,18 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
                dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
                return ret;
        }
-
        rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
+       return ret;
+}
+
+static int kabylake_rt5663_max98927_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+       int ret;
+
+       ret = kabylake_rt5663_codec_init(rtd);
+       if (ret)
+               return ret;
+
        ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
        if (ret) {
                dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", ret);
@@ -184,7 +242,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
        return ret;
 }
 
-static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
 {
        struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
        struct snd_soc_dai *dai = rtd->codec_dai;
@@ -194,7 +252,7 @@ static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
        if (!pcm)
                return -ENOMEM;
 
-       pcm->device = KBL_DPCM_AUDIO_HDMI1_PB;
+       pcm->device = device;
        pcm->codec_dai = dai;
 
        list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
@@ -202,47 +260,36 @@ static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
-static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
-       struct snd_soc_dai *dai = rtd->codec_dai;
-       struct kbl_hdmi_pcm *pcm;
-
-       pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
-       if (!pcm)
-               return -ENOMEM;
-
-       pcm->device = KBL_DPCM_AUDIO_HDMI2_PB;
-       pcm->codec_dai = dai;
-
-       list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+       return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
+}
 
-       return 0;
+static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+       return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
 }
 
 static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
-       struct snd_soc_dai *dai = rtd->codec_dai;
-       struct kbl_hdmi_pcm *pcm;
-
-       pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
-       if (!pcm)
-               return -ENOMEM;
-
-       pcm->device = KBL_DPCM_AUDIO_HDMI3_PB;
-       pcm->codec_dai = dai;
+       return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
+}
 
-       list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+static int kabylake_5663_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+{
+       return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI1_PB);
+}
 
-       return 0;
+static int kabylake_5663_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+       return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI2_PB);
 }
 
 static unsigned int rates[] = {
        48000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_rates = {
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
        .count = ARRAY_SIZE(rates),
        .list  = rates,
        .mask = 0,
@@ -252,7 +299,7 @@ static unsigned int channels[] = {
        2,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_channels = {
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
        .count = ARRAY_SIZE(channels),
        .list = channels,
        .mask = 0,
@@ -312,11 +359,13 @@ static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret;
 
-       ret = snd_soc_dai_set_sysclk(codec_dai,
-                       RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
        /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
-       rt5663_sel_asrc_clk_src(codec_dai->codec, RT5663_DA_STEREO_FILTER, 1);
+       rt5663_sel_asrc_clk_src(codec_dai->codec,
+                       RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
+                       RT5663_CLK_SEL_I2S1_ASRC);
 
+       ret = snd_soc_dai_set_sysclk(codec_dai,
+                       RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
        if (ret < 0)
                dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
 
@@ -381,7 +430,7 @@ static unsigned int rates_16000[] = {
        16000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_16000 = {
+static const struct snd_pcm_hw_constraint_list constraints_16000 = {
        .count = ARRAY_SIZE(rates_16000),
        .list  = rates_16000,
 };
@@ -443,6 +492,28 @@ static struct snd_soc_dai_link kabylake_dais[] = {
                .dpcm_capture = 1,
                .ops = &kabylake_rt5663_fe_ops,
        },
+       [KBL_DPCM_AUDIO_HS_PB] = {
+               .name = "Kbl Audio Headset Playback",
+               .stream_name = "Headset Audio",
+               .cpu_dai_name = "System Pin2",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+       [KBL_DPCM_AUDIO_ECHO_REF_CP] = {
+               .name = "Kbl Audio Echo Reference cap",
+               .stream_name = "Echoreference Capture",
+               .cpu_dai_name = "Echoref Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .init = NULL,
+               .capture_only = 1,
+               .nonatomic = 1,
+       },
        [KBL_DPCM_AUDIO_REF_CP] = {
                .name = "Kbl Audio Reference cap",
                .stream_name = "Wake on Voice",
@@ -538,7 +609,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
                .no_pcm = 1,
                .codec_name = "i2c-10EC5663:00",
                .codec_dai_name = KBL_REALTEK_CODEC_DAI,
-               .init = kabylake_rt5663_codec_init,
+               .init = kabylake_rt5663_max98927_codec_init,
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                        SND_SOC_DAIFMT_CBS_CFS,
                .ignore_pmdown_time = 1,
@@ -594,15 +665,119 @@ static struct snd_soc_dai_link kabylake_dais[] = {
        },
 };
 
+static struct snd_soc_dai_link kabylake_5663_dais[] = {
+       /* Front End DAI links */
+       [KBL_DPCM_AUDIO_5663_PB] = {
+               .name = "Kbl Audio Port",
+               .stream_name = "Audio",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .ops = &kabylake_rt5663_fe_ops,
+       },
+       [KBL_DPCM_AUDIO_5663_CP] = {
+               .name = "Kbl Audio Capture Port",
+               .stream_name = "Audio Record",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_capture = 1,
+               .ops = &kabylake_rt5663_fe_ops,
+       },
+       [KBL_DPCM_AUDIO_5663_HDMI1_PB] = {
+               .name = "Kbl HDMI Port1",
+               .stream_name = "Hdmi1",
+               .cpu_dai_name = "HDMI1 Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = NULL,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+       [KBL_DPCM_AUDIO_5663_HDMI2_PB] = {
+               .name = "Kbl HDMI Port2",
+               .stream_name = "Hdmi2",
+               .cpu_dai_name = "HDMI2 Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = NULL,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+
+       /* Back End DAI links */
+       {
+               /* SSP1 - Codec */
+               .name = "SSP1-Codec",
+               .id = 0,
+               .cpu_dai_name = "SSP1 Pin",
+               .platform_name = "0000:00:1f.3",
+               .no_pcm = 1,
+               .codec_name = "i2c-10EC5663:00",
+               .codec_dai_name = KBL_REALTEK_CODEC_DAI,
+               .init = kabylake_rt5663_codec_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = kabylake_ssp_fixup,
+               .ops = &kabylake_rt5663_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+       {
+               .name = "iDisp1",
+               .id = 1,
+               .cpu_dai_name = "iDisp1 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi1",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = kabylake_5663_hdmi1_init,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp2",
+               .id = 2,
+               .cpu_dai_name = "iDisp2 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi2",
+               .platform_name = "0000:00:1f.3",
+               .init = kabylake_5663_hdmi2_init,
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+};
+
 #define NAME_SIZE      32
 static int kabylake_card_late_probe(struct snd_soc_card *card)
 {
        struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card);
        struct kbl_hdmi_pcm *pcm;
+       struct snd_soc_codec *codec = NULL;
        int err, i = 0;
        char jack_name[NAME_SIZE];
 
        list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+               codec = pcm->codec_dai->codec;
                snprintf(jack_name, sizeof(jack_name),
                        "HDMI/DP, pcm=%d Jack", pcm->device);
                err = snd_soc_card_jack_new(card, jack_name,
@@ -620,11 +795,14 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
                i++;
        }
 
-       return 0;
+       if (!codec)
+               return -EINVAL;
+
+       return hdac_hdmi_jack_port_init(codec, &card->dapm);
 }
 
 /* kabylake audio machine driver for SPT + RT5663 */
-static struct snd_soc_card kabylake_audio_card = {
+static struct snd_soc_card kabylake_audio_card_rt5663_m98927 = {
        .name = "kblrt5663max",
        .owner = THIS_MODULE,
        .dai_link = kabylake_dais,
@@ -641,6 +819,22 @@ static struct snd_soc_card kabylake_audio_card = {
        .late_probe = kabylake_card_late_probe,
 };
 
+/* kabylake audio machine driver for RT5663 */
+static struct snd_soc_card kabylake_audio_card_rt5663 = {
+       .name = "kblrt5663",
+       .owner = THIS_MODULE,
+       .dai_link = kabylake_5663_dais,
+       .num_links = ARRAY_SIZE(kabylake_5663_dais),
+       .controls = kabylake_5663_controls,
+       .num_controls = ARRAY_SIZE(kabylake_5663_controls),
+       .dapm_widgets = kabylake_5663_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(kabylake_5663_widgets),
+       .dapm_routes = kabylake_5663_map,
+       .num_dapm_routes = ARRAY_SIZE(kabylake_5663_map),
+       .fully_routed = true,
+       .late_probe = kabylake_card_late_probe,
+};
+
 static int kabylake_audio_probe(struct platform_device *pdev)
 {
        struct kbl_rt5663_private *ctx;
@@ -652,19 +846,30 @@ static int kabylake_audio_probe(struct platform_device *pdev)
 
        INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
 
-       kabylake_audio_card.dev = &pdev->dev;
-       snd_soc_card_set_drvdata(&kabylake_audio_card, ctx);
+       kabylake_audio_card =
+               (struct snd_soc_card *)pdev->id_entry->driver_data;
+
+       kabylake_audio_card->dev = &pdev->dev;
+       snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
 
        pdata = dev_get_drvdata(&pdev->dev);
        if (pdata)
                dmic_constraints = pdata->dmic_num == 2 ?
                        &constraints_dmic_2ch : &constraints_dmic_channels;
 
-       return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card);
+       return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
 }
 
 static const struct platform_device_id kbl_board_ids[] = {
-       { .name = "kbl_rt5663_m98927" },
+       {
+               .name = "kbl_rt5663",
+               .driver_data = (kernel_ulong_t)&kabylake_audio_card_rt5663,
+       },
+       {
+               .name = "kbl_rt5663_m98927",
+               .driver_data =
+                       (kernel_ulong_t)&kabylake_audio_card_rt5663_m98927,
+       },
        { }
 };
 
@@ -684,4 +889,5 @@ MODULE_DESCRIPTION("Audio Machine driver-RT5663 & MAX98927 in I2S mode");
 MODULE_AUTHOR("Naveen M <naveen.m@intel.com>");
 MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kbl_rt5663");
 MODULE_ALIAS("platform:kbl_rt5663_m98927");
index cfd89ca..88ff542 100644 (file)
@@ -18,6 +18,7 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/input.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <sound/core.h>
@@ -62,7 +63,10 @@ struct kbl_codec_private {
 enum {
        KBL_DPCM_AUDIO_PB = 0,
        KBL_DPCM_AUDIO_CP,
+       KBL_DPCM_AUDIO_HS_PB,
+       KBL_DPCM_AUDIO_ECHO_REF_CP,
        KBL_DPCM_AUDIO_DMIC_CP,
+       KBL_DPCM_AUDIO_RT5514_DSP,
        KBL_DPCM_AUDIO_HDMI1_PB,
        KBL_DPCM_AUDIO_HDMI2_PB,
 };
@@ -81,8 +85,8 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
        SND_SOC_DAPM_SPK("Left Spk", NULL),
        SND_SOC_DAPM_SPK("Right Spk", NULL),
        SND_SOC_DAPM_MIC("DMIC", NULL),
-       SND_SOC_DAPM_SPK("DP", NULL),
-       SND_SOC_DAPM_SPK("HDMI", NULL),
+       SND_SOC_DAPM_SPK("HDMI1", NULL),
+       SND_SOC_DAPM_SPK("HDMI2", NULL),
 
 };
 
@@ -99,23 +103,25 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
        { "IN1P", NULL, "Headset Mic" },
        { "IN1N", NULL, "Headset Mic" },
 
-       { "HDMI", NULL, "hif5 Output" },
-       { "DP", NULL, "hif6 Output" },
-
        /* CODEC BE connections */
        { "Left HiFi Playback", NULL, "ssp0 Tx" },
        { "Right HiFi Playback", NULL, "ssp0 Tx" },
-       { "ssp0 Tx", NULL, "codec0_out" },
+       { "ssp0 Tx", NULL, "spk_out" },
 
        { "AIF Playback", NULL, "ssp1 Tx" },
-       { "ssp1 Tx", NULL, "codec1_out" },
+       { "ssp1 Tx", NULL, "hs_out" },
 
-       { "codec0_in", NULL, "ssp1 Rx" },
+       { "hs_in", NULL, "ssp1 Rx" },
        { "ssp1 Rx", NULL, "AIF Capture" },
 
        { "codec1_in", NULL, "ssp0 Rx" },
        { "ssp0 Rx", NULL, "AIF1 Capture" },
 
+       /* IV feedback path */
+       { "codec0_fb_in", NULL, "ssp0 Rx"},
+       { "ssp0 Rx", NULL, "Left HiFi Capture" },
+       { "ssp0 Rx", NULL, "Right HiFi Capture" },
+
        /* DMIC */
        { "DMIC1L", NULL, "DMIC" },
        { "DMIC1R", NULL, "DMIC" },
@@ -173,6 +179,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
        int ret;
        struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_jack *jack;
 
        /*
         * Headset buttons map to the google Reference headset.
@@ -187,6 +194,12 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
        }
 
+       jack = &ctx->kabylake_headset;
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
        rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
 
        ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC");
@@ -358,11 +371,18 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
                                return ret;
                        }
                }
-               if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME) ||
-                       !strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
-                       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF0, 3, 8, 16);
+               if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) {
+                       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
                        if (ret < 0) {
-                               dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
+                               dev_err(rtd->dev, "DEV0 TDM slot err:%d\n", ret);
+                               return ret;
+                       }
+               }
+
+               if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
+                       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
+                       if (ret < 0) {
+                               dev_err(rtd->dev, "DEV1 TDM slot err:%d\n", ret);
                                return ret;
                        }
                }
@@ -442,6 +462,36 @@ static struct snd_soc_dai_link kabylake_dais[] = {
                .dpcm_capture = 1,
                .ops = &kabylake_rt5663_fe_ops,
        },
+       [KBL_DPCM_AUDIO_HS_PB] = {
+               .name = "Kbl Audio Headset Playback",
+               .stream_name = "Headset Audio",
+               .cpu_dai_name = "System Pin2",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+       [KBL_DPCM_AUDIO_ECHO_REF_CP] = {
+               .name = "Kbl Audio Echo Reference cap",
+               .stream_name = "Echoreference Capture",
+               .cpu_dai_name = "Echoref Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .init = NULL,
+               .capture_only = 1,
+               .nonatomic = 1,
+       },
+       [KBL_DPCM_AUDIO_RT5514_DSP] = {
+               .name = "rt5514 dsp",
+               .stream_name = "Wake on Voice",
+               .cpu_dai_name = "spi-PRP0001:00",
+               .platform_name = "spi-PRP0001:00",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+       },
        [KBL_DPCM_AUDIO_DMIC_CP] = {
                .name = "Kbl Audio DMIC cap",
                .stream_name = "dmiccap",
@@ -548,10 +598,12 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
 {
        struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
        struct kbl_hdmi_pcm *pcm;
+       struct snd_soc_codec *codec = NULL;
        int err, i = 0;
        char jack_name[NAME_SIZE];
 
        list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+               codec = pcm->codec_dai->codec;
                err = snd_soc_card_jack_new(card, jack_name,
                                SND_JACK_AVOUT, &ctx->kabylake_hdmi[i],
                                NULL, 0);
@@ -565,7 +617,10 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
                i++;
        }
 
-       return 0;
+       if (!codec)
+               return -EINVAL;
+
+       return hdac_hdmi_jack_port_init(codec, &card->dapm);
 }
 
 /*
index 4e08885..6f44acf 100644 (file)
@@ -376,10 +376,8 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
        /* audio interrupt base of SRAM location where
         * interrupts are stored by System FW */
        mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
-       if (!mc_drv_ctx) {
-               pr_err("allocation failed\n");
+       if (!mc_drv_ctx)
                return -ENOMEM;
-       }
 
        irq_mem = platform_get_resource_byname(
                                pdev, IORESOURCE_MEM, "IRQ_BASE");
index 9e4094e..c044400 100644 (file)
@@ -1135,7 +1135,7 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)
        return 0;
 }
 
-static struct snd_soc_platform_driver hsw_soc_platform = {
+static const struct snd_soc_platform_driver hsw_soc_platform = {
        .probe          = hsw_pcm_probe,
        .remove         = hsw_pcm_remove,
        .ops            = &hsw_pcm_ops,
index e7d7772..3380deb 100644 (file)
@@ -8,7 +8,8 @@ endif
 obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
 
 # Skylake IPC Support
-snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \
-               skl-sst.o bxt-sst.o skl-sst-utils.o
+snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o \
+               skl-sst-cldma.o skl-sst.o bxt-sst.o cnl-sst.o \
+               skl-sst-utils.o
 
 obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o
index cf11b84..4524211 100644 (file)
@@ -530,7 +530,7 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
        return 0;
 }
 
-static struct skl_dsp_fw_ops bxt_fw_ops = {
+static const struct skl_dsp_fw_ops bxt_fw_ops = {
        .set_state_D0 = bxt_set_dsp_D0,
        .set_state_D3 = bxt_set_dsp_D3,
        .set_state_D0i3 = bxt_schedule_dsp_D0i3,
@@ -581,10 +581,15 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
        sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
                        SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
 
+       ret = skl_ipc_init(dev, skl);
+       if (ret) {
+               skl_dsp_free(sst);
+               return ret;
+       }
+
        /* set the D0i3 check */
        skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0;
 
-       skl->cores.count = 2;
        skl->boot_complete = false;
        init_waitqueue_head(&skl->boot_wait);
        INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
@@ -629,11 +634,6 @@ void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
                release_firmware(ctx->dsp->fw);
        skl_freeup_uuid_list(ctx);
        skl_ipc_free(&ctx->ipc);
-       ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
-
-       if (ctx->dsp->addr.lpe)
-               iounmap(ctx->dsp->addr.lpe);
-
        ctx->dsp->ops->free(ctx->dsp);
 }
 EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup);
diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.c b/sound/soc/intel/skylake/cnl-sst-dsp.c
new file mode 100644 (file)
index 0000000..2f83267
--- /dev/null
@@ -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);
+}
diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.h b/sound/soc/intel/skylake/cnl-sst-dsp.h
new file mode 100644 (file)
index 0000000..09bd218
--- /dev/null
@@ -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__*/
diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c
new file mode 100644 (file)
index 0000000..387de38
--- /dev/null
@@ -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");
index fb2f1f6..89f7013 100644 (file)
@@ -22,6 +22,7 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include "skl-sst-dsp.h"
+#include "cnl-sst-dsp.h"
 #include "skl-sst-ipc.h"
 #include "skl.h"
 #include "../common/sst-dsp.h"
@@ -201,6 +202,7 @@ static struct skl_dsp_loader_ops bxt_get_loader_ops(void)
 static const struct skl_dsp_ops dsp_ops[] = {
        {
                .id = 0x9d70,
+               .num_cores = 2,
                .loader_ops = skl_get_loader_ops,
                .init = skl_sst_dsp_init,
                .init_fw = skl_sst_init_fw,
@@ -208,6 +210,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
        },
        {
                .id = 0x9d71,
+               .num_cores = 2,
                .loader_ops = skl_get_loader_ops,
                .init = kbl_sst_dsp_init,
                .init_fw = skl_sst_init_fw,
@@ -215,6 +218,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
        },
        {
                .id = 0x5a98,
+               .num_cores = 2,
                .loader_ops = bxt_get_loader_ops,
                .init = bxt_sst_dsp_init,
                .init_fw = bxt_sst_init_fw,
@@ -222,11 +226,20 @@ static const struct skl_dsp_ops dsp_ops[] = {
        },
        {
                .id = 0x3198,
+               .num_cores = 2,
                .loader_ops = bxt_get_loader_ops,
                .init = bxt_sst_dsp_init,
                .init_fw = bxt_sst_init_fw,
                .cleanup = bxt_sst_dsp_cleanup
        },
+       {
+               .id = 0x9dc8,
+               .num_cores = 4,
+               .loader_ops = bxt_get_loader_ops,
+               .init = cnl_sst_dsp_init,
+               .init_fw = cnl_sst_init_fw,
+               .cleanup = cnl_sst_dsp_cleanup
+       },
 };
 
 const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
@@ -249,6 +262,7 @@ int skl_init_dsp(struct skl *skl)
        struct skl_dsp_loader_ops loader_ops;
        int irq = bus->irq;
        const struct skl_dsp_ops *ops;
+       struct skl_dsp_cores *cores;
        int ret;
 
        /* enable ppcap interrupt */
@@ -263,8 +277,10 @@ int skl_init_dsp(struct skl *skl)
        }
 
        ops = skl_get_dsp_ops(skl->pci->device);
-       if (!ops)
-               return -EIO;
+       if (!ops) {
+               ret = -EIO;
+               goto unmap_mmio;
+       }
 
        loader_ops = ops->loader_ops();
        ret = ops->init(bus->dev, mmio_base, irq,
@@ -272,11 +288,35 @@ int skl_init_dsp(struct skl *skl)
                                &skl->skl_sst);
 
        if (ret < 0)
-               return ret;
+               goto unmap_mmio;
 
        skl->skl_sst->dsp_ops = ops;
+       cores = &skl->skl_sst->cores;
+       cores->count = ops->num_cores;
+
+       cores->state = kcalloc(cores->count, sizeof(*cores->state), GFP_KERNEL);
+       if (!cores->state) {
+               ret = -ENOMEM;
+               goto unmap_mmio;
+       }
+
+       cores->usage_count = kcalloc(cores->count, sizeof(*cores->usage_count),
+                                    GFP_KERNEL);
+       if (!cores->usage_count) {
+               ret = -ENOMEM;
+               goto free_core_state;
+       }
+
        dev_dbg(bus->dev, "dsp registration status=%d\n", ret);
 
+       return 0;
+
+free_core_state:
+       kfree(cores->state);
+
+unmap_mmio:
+       iounmap(mmio_base);
+
        return ret;
 }
 
@@ -291,6 +331,9 @@ int skl_free_dsp(struct skl *skl)
 
        ctx->dsp_ops->cleanup(bus->dev, ctx);
 
+       kfree(ctx->cores.state);
+       kfree(ctx->cores.usage_count);
+
        if (ctx->dsp->addr.lpe)
                iounmap(ctx->dsp->addr.lpe);
 
@@ -400,9 +443,12 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
                        struct skl_module_cfg *mconfig,
                        struct skl_base_cfg *base_cfg)
 {
-       struct skl_module_fmt *format = &mconfig->in_fmt[0];
+       struct skl_module *module = mconfig->module;
+       struct skl_module_res *res = &module->resources[mconfig->res_idx];
+       struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx];
+       struct skl_module_fmt *format = &fmt->inputs[0].fmt;
 
-       base_cfg->audio_fmt.number_of_channels = (u8)format->channels;
+       base_cfg->audio_fmt.number_of_channels = format->channels;
 
        base_cfg->audio_fmt.s_freq = format->s_freq;
        base_cfg->audio_fmt.bit_depth = format->bit_depth;
@@ -417,10 +463,10 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
 
        base_cfg->audio_fmt.interleaving = format->interleaving_style;
 
-       base_cfg->cps = mconfig->mcps;
-       base_cfg->ibs = mconfig->ibs;
-       base_cfg->obs = mconfig->obs;
-       base_cfg->is_pages = mconfig->mem_pages;
+       base_cfg->cps = res->cps;
+       base_cfg->ibs = res->ibs;
+       base_cfg->obs = res->obs;
+       base_cfg->is_pages = res->is_pages;
 }
 
 /*
@@ -508,6 +554,9 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
                        struct skl_cpr_cfg *cpr_mconfig)
 {
        u32 dma_io_buf;
+       struct skl_module_res *res;
+       int res_idx = mconfig->res_idx;
+       struct skl *skl = get_skl_ctx(ctx->dev);
 
        cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig);
 
@@ -516,19 +565,27 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
                return;
        }
 
+       if (skl->nr_modules) {
+               res = &mconfig->module->resources[mconfig->res_idx];
+               cpr_mconfig->gtw_cfg.dma_buffer_size = res->dma_buffer_size;
+               goto skip_buf_size_calc;
+       } else {
+               res = &mconfig->module->resources[res_idx];
+       }
+
        switch (mconfig->hw_conn_type) {
        case SKL_CONN_SOURCE:
                if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
-                       dma_io_buf =  mconfig->ibs;
+                       dma_io_buf =  res->ibs;
                else
-                       dma_io_buf =  mconfig->obs;
+                       dma_io_buf =  res->obs;
                break;
 
        case SKL_CONN_SINK:
                if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
-                       dma_io_buf =  mconfig->obs;
+                       dma_io_buf =  res->obs;
                else
-                       dma_io_buf =  mconfig->ibs;
+                       dma_io_buf =  res->ibs;
                break;
 
        default:
@@ -543,11 +600,12 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
        /* fallback to 2ms default value */
        if (!cpr_mconfig->gtw_cfg.dma_buffer_size) {
                if (mconfig->hw_conn_type == SKL_CONN_SOURCE)
-                       cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs;
+                       cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->obs;
                else
-                       cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->ibs;
+                       cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->ibs;
        }
 
+skip_buf_size_calc:
        cpr_mconfig->cpr_feature_mask = 0;
        cpr_mconfig->gtw_cfg.config_length  = 0;
 
@@ -595,7 +653,9 @@ static void skl_setup_out_format(struct skl_sst *ctx,
                        struct skl_module_cfg *mconfig,
                        struct skl_audio_data_format *out_fmt)
 {
-       struct skl_module_fmt *format = &mconfig->out_fmt[0];
+       struct skl_module *module = mconfig->module;
+       struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx];
+       struct skl_module_fmt *format = &fmt->outputs[0].fmt;
 
        out_fmt->number_of_channels = (u8)format->channels;
        out_fmt->s_freq = format->s_freq;
@@ -620,7 +680,9 @@ static void skl_set_src_format(struct skl_sst *ctx,
                        struct skl_module_cfg *mconfig,
                        struct skl_src_module_cfg *src_mconfig)
 {
-       struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
+       struct skl_module *module = mconfig->module;
+       struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx];
+       struct skl_module_fmt *fmt = &iface->outputs[0].fmt;
 
        skl_set_base_module_format(ctx, mconfig,
                (struct skl_base_cfg *)src_mconfig);
@@ -637,7 +699,9 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx,
                        struct skl_module_cfg *mconfig,
                        struct skl_up_down_mixer_cfg *mixer_mconfig)
 {
-       struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
+       struct skl_module *module = mconfig->module;
+       struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx];
+       struct skl_module_fmt *fmt = &iface->outputs[0].fmt;
        int i = 0;
 
        skl_set_base_module_format(ctx, mconfig,
@@ -950,7 +1014,7 @@ static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg
 {
        dev_dbg(ctx->dev, "%s: src module_id = %d  src_instance=%d\n",
                __func__, src_module->id.module_id, src_module->id.pvt_id);
-       dev_dbg(ctx->dev, "%s: dst_module=%d dst_instacne=%d\n", __func__,
+       dev_dbg(ctx->dev, "%s: dst_module=%d dst_instance=%d\n", __func__,
                 dst_module->id.module_id, dst_module->id.pvt_id);
 
        dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n",
@@ -970,8 +1034,8 @@ int skl_unbind_modules(struct skl_sst *ctx,
        struct skl_ipc_bind_unbind_msg msg;
        struct skl_module_inst_id src_id = src_mcfg->id;
        struct skl_module_inst_id dst_id = dst_mcfg->id;
-       int in_max = dst_mcfg->max_in_queue;
-       int out_max = src_mcfg->max_out_queue;
+       int in_max = dst_mcfg->module->max_input_pins;
+       int out_max = src_mcfg->module->max_output_pins;
        int src_index, dst_index, src_pin_state, dst_pin_state;
 
        skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
@@ -1019,6 +1083,21 @@ int skl_unbind_modules(struct skl_sst *ctx,
        return ret;
 }
 
+static void fill_pin_params(struct skl_audio_data_format *pin_fmt,
+                               struct skl_module_fmt *format)
+{
+       pin_fmt->number_of_channels = format->channels;
+       pin_fmt->s_freq = format->s_freq;
+       pin_fmt->bit_depth = format->bit_depth;
+       pin_fmt->valid_bit_depth = format->valid_bit_depth;
+       pin_fmt->ch_cfg = format->ch_cfg;
+       pin_fmt->sample_type = format->sample_type;
+       pin_fmt->channel_map = format->ch_map;
+       pin_fmt->interleaving = format->interleaving_style;
+}
+
+#define CPR_SINK_FMT_PARAM_ID 2
+
 /*
  * Once a module is instantiated it need to be 'bind' with other modules in
  * the pipeline. For binding we need to find the module pins which are bind
@@ -1030,11 +1109,15 @@ int skl_bind_modules(struct skl_sst *ctx,
                        struct skl_module_cfg *src_mcfg,
                        struct skl_module_cfg *dst_mcfg)
 {
-       int ret;
+       int ret = 0;
        struct skl_ipc_bind_unbind_msg msg;
-       int in_max = dst_mcfg->max_in_queue;
-       int out_max = src_mcfg->max_out_queue;
+       int in_max = dst_mcfg->module->max_input_pins;
+       int out_max = src_mcfg->module->max_output_pins;
        int src_index, dst_index;
+       struct skl_module_fmt *format;
+       struct skl_cpr_pin_fmt pin_fmt;
+       struct skl_module *module;
+       struct skl_module_iface *fmt;
 
        skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
 
@@ -1053,6 +1136,29 @@ int skl_bind_modules(struct skl_sst *ctx,
                return -EINVAL;
        }
 
+       /*
+        * Copier module requires the separate large_config_set_ipc to
+        * configure the pins other than 0
+        */
+       if (src_mcfg->m_type == SKL_MODULE_TYPE_COPIER && src_index > 0) {
+               pin_fmt.sink_id = src_index;
+               module = src_mcfg->module;
+               fmt = &module->formats[src_mcfg->fmt_idx];
+
+               /* Input fmt is same as that of src module input cfg */
+               format = &fmt->inputs[0].fmt;
+               fill_pin_params(&(pin_fmt.src_fmt), format);
+
+               format = &fmt->outputs[src_index].fmt;
+               fill_pin_params(&(pin_fmt.dst_fmt), format);
+               ret = skl_set_module_params(ctx, (void *)&pin_fmt,
+                                       sizeof(struct skl_cpr_pin_fmt),
+                                       CPR_SINK_FMT_PARAM_ID, src_mcfg);
+
+               if (ret < 0)
+                       goto out;
+       }
+
        msg.dst_queue = dst_index;
 
        dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n",
@@ -1070,11 +1176,12 @@ int skl_bind_modules(struct skl_sst *ctx,
                src_mcfg->m_state = SKL_MODULE_BIND_DONE;
                src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE;
                dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE;
-       } else {
-               /* 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;
 }
index 0ebea34..2b1e513 100644 (file)
@@ -33,7 +33,7 @@
 #define HDA_STEREO 2
 #define HDA_QUAD 4
 
-static struct snd_pcm_hardware azx_pcm_hw = {
+static const struct snd_pcm_hardware azx_pcm_hw = {
        .info =                 (SNDRV_PCM_INFO_MMAP |
                                 SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -628,7 +628,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_dai_ops skl_pcm_dai_ops = {
+static const struct snd_soc_dai_ops skl_pcm_dai_ops = {
        .startup = skl_pcm_open,
        .shutdown = skl_pcm_close,
        .prepare = skl_pcm_prepare,
@@ -637,15 +637,15 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = {
        .trigger = skl_pcm_trigger,
 };
 
-static struct snd_soc_dai_ops skl_dmic_dai_ops = {
+static const struct snd_soc_dai_ops skl_dmic_dai_ops = {
        .hw_params = skl_be_hw_params,
 };
 
-static struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
+static const struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
        .hw_params = skl_be_hw_params,
 };
 
-static struct snd_soc_dai_ops skl_link_dai_ops = {
+static const struct snd_soc_dai_ops skl_link_dai_ops = {
        .prepare = skl_link_pcm_prepare,
        .hw_params = skl_link_hw_params,
        .hw_free = skl_link_hw_free,
@@ -674,6 +674,32 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
                .sig_bits = 32,
        },
 },
+{
+       .name = "System Pin2",
+       .ops = &skl_pcm_dai_ops,
+       .playback = {
+               .stream_name = "Headset Playback",
+               .channels_min = HDA_MONO,
+               .channels_max = HDA_STEREO,
+               .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
+                       SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+       },
+},
+{
+       .name = "Echoref Pin",
+       .ops = &skl_pcm_dai_ops,
+       .capture = {
+               .stream_name = "Echoreference Capture",
+               .channels_min = HDA_STEREO,
+               .channels_max = HDA_STEREO,
+               .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
+                       SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+       },
+},
 {
        .name = "Reference Pin",
        .ops = &skl_pcm_dai_ops,
@@ -1194,8 +1220,11 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
 static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig)
 {
        struct skl_sst *ctx = skl->skl_sst;
+       struct skl_module_inst_id *pin_id;
+       uuid_le *uuid_mod, *uuid_tplg;
+       struct skl_module *skl_module;
        struct uuid_module *module;
-       uuid_le *uuid_mod;
+       int i, ret = -EIO;
 
        uuid_mod = (uuid_le *)mconfig->guid;
 
@@ -1207,12 +1236,45 @@ static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig)
        list_for_each_entry(module, &ctx->uuid_list, list) {
                if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
                        mconfig->id.module_id = module->id;
-                       mconfig->is_loadable = module->is_loadable;
-                       return 0;
+                       if (mconfig->module)
+                               mconfig->module->loadable = module->is_loadable;
+                       ret = 0;
+                       break;
+               }
+       }
+
+       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)
@@ -1284,7 +1346,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
 
        return 0;
 }
-static struct snd_soc_platform_driver skl_platform_drv  = {
+static const struct snd_soc_platform_driver skl_platform_drv  = {
        .probe          = skl_platform_soc_probe,
        .ops            = &skl_platform_ops,
        .pcm_new        = skl_pcm_new,
index 0833272..19ee1d4 100644 (file)
@@ -47,7 +47,7 @@ void skl_dsp_init_core_state(struct sst_dsp *ctx)
        skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING;
        skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1;
 
-       for (i = SKL_DSP_CORE0_ID + 1; i < SKL_DSP_CORES_MAX; i++) {
+       for (i = SKL_DSP_CORE0_ID + 1; i < skl->cores.count; i++) {
                skl->cores.state[i] = SKL_DSP_RESET;
                skl->cores.usage_count[i] = 0;
        }
@@ -351,6 +351,8 @@ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
                return -EINVAL;
        }
 
+       skl->cores.usage_count[core_id]++;
+
        if (skl->cores.state[core_id] == SKL_DSP_RESET) {
                ret = ctx->fw_ops.set_state_D0(ctx, core_id);
                if (ret < 0) {
@@ -359,8 +361,6 @@ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
                }
        }
 
-       skl->cores.usage_count[core_id]++;
-
 out:
        dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
                        core_id, skl->cores.state[core_id],
index 498b153..5234faf 100644 (file)
@@ -283,7 +283,7 @@ enum skl_ipc_module_msg {
        IPC_MOD_SET_D0IX = 8
 };
 
-static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
+void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
                size_t tx_size)
 {
        if (tx_size)
@@ -347,7 +347,7 @@ 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_sst *skl = container_of(ipc, struct skl_sst, ipc);
@@ -406,7 +406,7 @@ static int skl_ipc_set_reply_error_code(u32 reply)
        }
 }
 
-static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
+void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
                struct skl_ipc_header header)
 {
        struct ipc_message *msg;
index e057da2..55f2d2c 100644 (file)
@@ -44,12 +44,10 @@ struct skl_ipc_header {
        u32 extension;
 };
 
-#define SKL_DSP_CORES_MAX  2
-
 struct skl_dsp_cores {
        unsigned int count;
-       enum skl_dsp_states state[SKL_DSP_CORES_MAX];
-       int usage_count[SKL_DSP_CORES_MAX];
+       enum skl_dsp_states *state;
+       int *usage_count;
 };
 
 /**
@@ -214,4 +212,10 @@ void skl_ipc_free(struct sst_generic_ipc *ipc);
 int skl_ipc_init(struct device *dev, struct skl_sst *skl);
 void skl_clear_module_cnt(struct sst_dsp *ctx);
 
+void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
+               struct skl_ipc_header header);
+int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
+               struct skl_ipc_header header);
+void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
+               size_t tx_size);
 #endif /* __SKL_IPC_H */
index 81ee251..369ef7c 100644 (file)
@@ -368,7 +368,6 @@ int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
 {
        struct skl_sst *skl;
        struct sst_dsp *sst;
-       int ret;
 
        skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
        if (skl == NULL)
@@ -388,15 +387,12 @@ int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
        sst->dsp_ops = dsp_ops;
        init_waitqueue_head(&skl->mod_load_wait);
        INIT_LIST_HEAD(&sst->module_list);
-       ret = skl_ipc_init(dev, skl);
-       if (ret)
-               return ret;
 
        skl->is_first_boot = true;
        if (dsp)
                *dsp = skl;
 
-       return ret;
+       return 0;
 }
 
 int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo,
index aba9ea1..a436abf 100644 (file)
@@ -503,7 +503,7 @@ static void skl_clear_module_table(struct sst_dsp *ctx)
        }
 }
 
-static struct skl_dsp_fw_ops skl_fw_ops = {
+static const struct skl_dsp_fw_ops skl_fw_ops = {
        .set_state_D0 = skl_set_dsp_D0,
        .set_state_D3 = skl_set_dsp_D3,
        .load_fw = skl_load_base_firmware,
@@ -512,7 +512,7 @@ static struct skl_dsp_fw_ops skl_fw_ops = {
        .unload_mod = skl_unload_module,
 };
 
-static struct skl_dsp_fw_ops kbl_fw_ops = {
+static const struct skl_dsp_fw_ops kbl_fw_ops = {
        .set_state_D0 = skl_set_dsp_D0,
        .set_state_D3 = skl_set_dsp_D3,
        .load_fw = skl_load_base_firmware,
@@ -561,9 +561,13 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
        sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
                        SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
 
-       sst->fw_ops = skl_fw_ops;
+       ret = skl_ipc_init(dev, skl);
+       if (ret) {
+               skl_dsp_free(sst);
+               return ret;
+       }
 
-       skl->cores.count = 2;
+       sst->fw_ops = skl_fw_ops;
 
        return 0;
 }
index 68c3f12..22f768c 100644 (file)
@@ -49,6 +49,9 @@ static const int mic_quatro_list[][SKL_CH_QUATRO] = {
 {0, 1, 2, 3},
 };
 
+#define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
+       ((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
+
 void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps)
 {
        struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
@@ -153,8 +156,10 @@ static bool skl_is_pipe_mcps_avail(struct skl *skl,
                                struct skl_module_cfg *mconfig)
 {
        struct skl_sst *ctx = skl->skl_sst;
+       u8 res_idx = mconfig->res_idx;
+       struct skl_module_res *res = &mconfig->module->resources[res_idx];
 
-       if (skl->resource.mcps + mconfig->mcps > skl->resource.max_mcps) {
+       if (skl->resource.mcps + res->cps > skl->resource.max_mcps) {
                dev_err(ctx->dev,
                        "%s: module_id %d instance %d\n", __func__,
                        mconfig->id.module_id, mconfig->id.instance_id);
@@ -170,7 +175,10 @@ static bool skl_is_pipe_mcps_avail(struct skl *skl,
 static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
                                struct skl_module_cfg *mconfig)
 {
-       skl->resource.mcps += mconfig->mcps;
+       u8 res_idx = mconfig->res_idx;
+       struct skl_module_res *res = &mconfig->module->resources[res_idx];
+
+       skl->resource.mcps += res->cps;
 }
 
 /*
@@ -179,7 +187,11 @@ static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
 static void
 skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
 {
-       skl->resource.mcps -= mconfig->mcps;
+       u8 res_idx = mconfig->res_idx;
+       struct skl_module_res *res = &mconfig->module->resources[res_idx];
+
+       res = &mconfig->module->resources[res_idx];
+       skl->resource.mcps -= res->cps;
 }
 
 /*
@@ -195,17 +207,21 @@ skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig)
 static void skl_dump_mconfig(struct skl_sst *ctx,
                                        struct skl_module_cfg *mcfg)
 {
+       struct skl_module_iface *iface = &mcfg->module->formats[0];
+
        dev_dbg(ctx->dev, "Dumping config\n");
        dev_dbg(ctx->dev, "Input Format:\n");
-       dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels);
-       dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq);
-       dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg);
-       dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth);
+       dev_dbg(ctx->dev, "channels = %d\n", iface->inputs[0].fmt.channels);
+       dev_dbg(ctx->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq);
+       dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg);
+       dev_dbg(ctx->dev, "valid bit depth = %d\n",
+                               iface->inputs[0].fmt.valid_bit_depth);
        dev_dbg(ctx->dev, "Output Format:\n");
-       dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels);
-       dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq);
-       dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth);
-       dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg);
+       dev_dbg(ctx->dev, "channels = %d\n", iface->outputs[0].fmt.channels);
+       dev_dbg(ctx->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq);
+       dev_dbg(ctx->dev, "valid bit depth = %d\n",
+                               iface->outputs[0].fmt.valid_bit_depth);
+       dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg);
 }
 
 static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
@@ -273,8 +289,8 @@ static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
        struct skl_module_fmt *in_fmt, *out_fmt;
 
        /* Fixups will be applied to pin 0 only */
-       in_fmt = &m_cfg->in_fmt[0];
-       out_fmt = &m_cfg->out_fmt[0];
+       in_fmt = &m_cfg->module->formats[0].inputs[0].fmt;
+       out_fmt = &m_cfg->module->formats[0].outputs[0].fmt;
 
        if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (is_fe) {
@@ -312,21 +328,23 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
 {
        int multiplier = 1;
        struct skl_module_fmt *in_fmt, *out_fmt;
+       struct skl_module_res *res;
 
        /* Since fixups is applied to pin 0 only, ibs, obs needs
         * change for pin 0 only
         */
-       in_fmt = &mcfg->in_fmt[0];
-       out_fmt = &mcfg->out_fmt[0];
+       res = &mcfg->module->resources[0];
+       in_fmt = &mcfg->module->formats[0].inputs[0].fmt;
+       out_fmt = &mcfg->module->formats[0].outputs[0].fmt;
 
        if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
                multiplier = 5;
 
-       mcfg->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
+       res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
                        in_fmt->channels * (in_fmt->bit_depth >> 3) *
                        multiplier;
 
-       mcfg->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
+       res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
                        out_fmt->channels * (out_fmt->bit_depth >> 3) *
                        multiplier;
 }
@@ -365,6 +383,8 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
        struct nhlt_specific_cfg *cfg;
        struct skl *skl = get_skl_ctx(ctx->dev);
        u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
+       int fmt_idx = m_cfg->fmt_idx;
+       struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx];
 
        /* check if we already have blob */
        if (m_cfg->formats_config.caps_size > 0)
@@ -375,23 +395,23 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
        case SKL_DEVICE_DMIC:
                link_type = NHLT_LINK_DMIC;
                dir = SNDRV_PCM_STREAM_CAPTURE;
-               s_freq = m_cfg->in_fmt[0].s_freq;
-               s_fmt = m_cfg->in_fmt[0].bit_depth;
-               ch = m_cfg->in_fmt[0].channels;
+               s_freq = m_iface->inputs[0].fmt.s_freq;
+               s_fmt = m_iface->inputs[0].fmt.bit_depth;
+               ch = m_iface->inputs[0].fmt.channels;
                break;
 
        case SKL_DEVICE_I2S:
                link_type = NHLT_LINK_SSP;
                if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
                        dir = SNDRV_PCM_STREAM_PLAYBACK;
-                       s_freq = m_cfg->out_fmt[0].s_freq;
-                       s_fmt = m_cfg->out_fmt[0].bit_depth;
-                       ch = m_cfg->out_fmt[0].channels;
+                       s_freq = m_iface->outputs[0].fmt.s_freq;
+                       s_fmt = m_iface->outputs[0].fmt.bit_depth;
+                       ch = m_iface->outputs[0].fmt.channels;
                } else {
                        dir = SNDRV_PCM_STREAM_CAPTURE;
-                       s_freq = m_cfg->in_fmt[0].s_freq;
-                       s_fmt = m_cfg->in_fmt[0].bit_depth;
-                       ch = m_cfg->in_fmt[0].channels;
+                       s_freq = m_iface->inputs[0].fmt.s_freq;
+                       s_fmt = m_iface->inputs[0].fmt.bit_depth;
+                       ch = m_iface->inputs[0].fmt.channels;
                }
                break;
 
@@ -549,6 +569,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
        struct snd_soc_dapm_widget *w;
        struct skl_module_cfg *mconfig;
        struct skl_sst *ctx = skl->skl_sst;
+       u8 cfg_idx;
        int ret = 0;
 
        list_for_each_entry(w_module, &pipe->w_list, node) {
@@ -564,11 +585,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
                        return -EIO;
                }
 
+               cfg_idx = mconfig->pipe->cur_config_idx;
+               mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
+               mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
+
                /* check resource available */
                if (!skl_is_pipe_mcps_avail(skl, mconfig))
                        return -ENOMEM;
 
-               if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
+               if (mconfig->module->loadable && ctx->dsp->fw_ops.load_mod) {
                        ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
                                mconfig->id.module_id, mconfig->guid);
                        if (ret < 0)
@@ -596,24 +621,35 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
                if (mconfig->id.pvt_id < 0)
                        return ret;
                skl_tplg_set_module_init_data(w);
+
+               ret = skl_dsp_get_core(ctx->dsp, mconfig->core_id);
+               if (ret < 0) {
+                       dev_err(ctx->dev, "Failed to wake up core %d ret=%d\n",
+                                               mconfig->core_id, ret);
+                       return ret;
+               }
+
                ret = skl_init_module(ctx, mconfig);
                if (ret < 0) {
                        skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
-                       return ret;
+                       goto err;
                }
                skl_tplg_alloc_pipe_mcps(skl, mconfig);
                ret = skl_tplg_set_module_params(w, ctx);
                if (ret < 0)
-                       return ret;
+                       goto err;
        }
 
        return 0;
+err:
+       skl_dsp_put_core(ctx->dsp, mconfig->core_id);
+       return ret;
 }
 
 static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
         struct skl_pipe *pipe)
 {
-       int ret;
+       int ret = 0;
        struct skl_pipe_module *w_module = NULL;
        struct skl_module_cfg *mconfig = NULL;
 
@@ -622,7 +658,7 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
                mconfig  = w_module->w->priv;
                uuid_mod = (uuid_le *)mconfig->guid;
 
-               if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod &&
+               if (mconfig->module->loadable && ctx->dsp->fw_ops.unload_mod &&
                        mconfig->m_state > SKL_MODULE_UNINIT) {
                        ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp,
                                                mconfig->id.module_id);
@@ -630,10 +666,76 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
                                return -EIO;
                }
                skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
+
+               ret = skl_dsp_put_core(ctx->dsp, mconfig->core_id);
+               if (ret < 0) {
+                       /* don't return; continue with other modules */
+                       dev_err(ctx->dev, "Failed to sleep core %d ret=%d\n",
+                               mconfig->core_id, ret);
+               }
        }
 
        /* no modules to unload in this path, so return */
-       return 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_module_deferred_bind *modules;
 
+       ret = skl_tplg_get_pipe_config(skl, mconfig);
+       if (ret < 0)
+               return ret;
+
        /* check resource available */
        if (!skl_is_pipe_mcps_avail(skl, mconfig))
                return -EBUSY;
@@ -758,12 +864,12 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
         * check all out/in pins are in bind state.
         * if so set the module param
         */
-       for (i = 0; i < mcfg->max_out_queue; i++) {
+       for (i = 0; i < mcfg->module->max_output_pins; i++) {
                if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
                        return 0;
        }
 
-       for (i = 0; i < mcfg->max_in_queue; i++) {
+       for (i = 0; i < mcfg->module->max_input_pins; i++) {
                if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
                        return 0;
        }
@@ -814,7 +920,7 @@ static int skl_tplg_module_add_deferred_bind(struct skl *skl,
        int i;
 
        /* only supported for module with static pin connection */
-       for (i = 0; i < dst->max_in_queue; i++) {
+       for (i = 0; i < dst->module->max_input_pins; i++) {
                struct skl_module_pin *pin = &dst->m_in_pin[i];
 
                if (pin->is_dynamic)
@@ -925,7 +1031,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
                }
        }
 
-       if (!sink)
+       if (!sink && next_sink)
                return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
 
        return 0;
@@ -1074,7 +1180,7 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
        if (ret)
                return ret;
 
-       for (i = 0; i < sink_mconfig->max_in_queue; i++) {
+       for (i = 0; i < sink_mconfig->module->max_input_pins; i++) {
                if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
                        src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
                        if (!src_mconfig)
@@ -1185,7 +1291,7 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
        if (ret)
                return ret;
 
-       for (i = 0; i < src_mconfig->max_out_queue; i++) {
+       for (i = 0; i < src_mconfig->module->max_output_pins; i++) {
                if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
                        sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
                        if (!sink_mconfig)
@@ -1479,14 +1585,22 @@ int skl_tplg_update_pipe_params(struct device *dev,
                        struct skl_module_cfg *mconfig,
                        struct skl_pipe_params *params)
 {
+       struct skl_module_res *res = &mconfig->module->resources[0];
+       struct skl *skl = get_skl_ctx(dev);
        struct skl_module_fmt *format = NULL;
+       u8 cfg_idx = mconfig->pipe->cur_config_idx;
 
        skl_tplg_fill_dma_id(mconfig, params);
+       mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
+       mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
+
+       if (skl->nr_modules)
+               return 0;
 
        if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               format = &mconfig->in_fmt[0];
+               format = &mconfig->module->formats[0].inputs[0].fmt;
        else
-               format = &mconfig->out_fmt[0];
+               format = &mconfig->module->formats[0].outputs[0].fmt;
 
        /* set the hw_params */
        format->s_freq = params->s_freq;
@@ -1514,11 +1628,11 @@ int skl_tplg_update_pipe_params(struct device *dev,
        }
 
        if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               mconfig->ibs = (format->s_freq / 1000) *
+               res->ibs = (format->s_freq / 1000) *
                                (format->channels) *
                                (format->bit_depth >> 3);
        } else {
-               mconfig->obs = (format->s_freq / 1000) *
+               res->obs = (format->s_freq / 1000) *
                                (format->channels) *
                                (format->bit_depth >> 3);
        }
@@ -1792,6 +1906,54 @@ static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
        },
 };
 
+static int skl_tplg_fill_pipe_cfg(struct device *dev,
+                       struct skl_pipe *pipe, u32 tkn,
+                       u32 tkn_val, int conf_idx, int dir)
+{
+       struct skl_pipe_fmt *fmt;
+       struct skl_path_config *config;
+
+       switch (dir) {
+       case SKL_DIR_IN:
+               fmt = &pipe->configs[conf_idx].in_fmt;
+               break;
+
+       case SKL_DIR_OUT:
+               fmt = &pipe->configs[conf_idx].out_fmt;
+               break;
+
+       default:
+               dev_err(dev, "Invalid direction: %d\n", dir);
+               return -EINVAL;
+       }
+
+       config = &pipe->configs[conf_idx];
+
+       switch (tkn) {
+       case SKL_TKN_U32_CFG_FREQ:
+               fmt->freq = tkn_val;
+               break;
+
+       case SKL_TKN_U8_CFG_CHAN:
+               fmt->channels = tkn_val;
+               break;
+
+       case SKL_TKN_U8_CFG_BPS:
+               fmt->bps = tkn_val;
+               break;
+
+       case SKL_TKN_U32_PATH_MEM_PGS:
+               config->mem_pages = tkn_val;
+               break;
+
+       default:
+               dev_err(dev, "Invalid token config: %d\n", tkn);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int skl_tplg_fill_pipe_tkn(struct device *dev,
                        struct skl_pipe *pipe, u32 tkn,
                        u32 tkn_val)
@@ -1814,6 +1976,14 @@ static int skl_tplg_fill_pipe_tkn(struct device *dev,
                pipe->lp_mode = tkn_val;
                break;
 
+       case SKL_TKN_U32_PIPE_DIRECTION:
+               pipe->direction = tkn_val;
+               break;
+
+       case SKL_TKN_U32_NUM_CONFIGS:
+               pipe->nr_cfgs = tkn_val;
+               break;
+
        default:
                dev_err(dev, "Token not handled %d\n", tkn);
                return -EINVAL;
@@ -1930,27 +2100,9 @@ static int skl_tplg_fill_pins_info(struct device *dev,
  * on the direction
  */
 static int skl_tplg_fill_fmt(struct device *dev,
-               struct skl_module_cfg *mconfig, u32 tkn,
-               u32 value, u32 dir, u32 pin_count)
+               struct skl_module_fmt *dst_fmt,
+               u32 tkn, u32 value)
 {
-       struct skl_module_fmt *dst_fmt;
-
-       switch (dir) {
-       case SKL_DIR_IN:
-               dst_fmt = mconfig->in_fmt;
-               dst_fmt += pin_count;
-               break;
-
-       case SKL_DIR_OUT:
-               dst_fmt = mconfig->out_fmt;
-               dst_fmt += pin_count;
-               break;
-
-       default:
-               dev_err(dev, "Invalid direction value\n");
-               return -EINVAL;
-       }
-
        switch (tkn) {
        case SKL_TKN_U32_FMT_CH:
                dst_fmt->channels  = value;
@@ -1992,6 +2144,32 @@ static int skl_tplg_fill_fmt(struct device *dev,
        return 0;
 }
 
+static int skl_tplg_widget_fill_fmt(struct device *dev,
+               struct skl_module_iface *fmt,
+               u32 tkn, u32 val, u32 dir, int fmt_idx)
+{
+       struct skl_module_fmt *dst_fmt;
+
+       if (!fmt)
+               return -EINVAL;
+
+       switch (dir) {
+       case SKL_DIR_IN:
+               dst_fmt = &fmt->inputs[fmt_idx].fmt;
+               break;
+
+       case SKL_DIR_OUT:
+               dst_fmt = &fmt->outputs[fmt_idx].fmt;
+               break;
+
+       default:
+               dev_err(dev, "Invalid direction: %d\n", dir);
+               return -EINVAL;
+       }
+
+       return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
+}
+
 static int skl_tplg_get_uuid(struct device *dev, struct skl_module_cfg *mconfig,
              struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
 {
@@ -2014,6 +2192,108 @@ static void skl_tplg_fill_pin_dynamic_val(
                mpin[i].is_dynamic = value;
 }
 
+/*
+ * Resource table in the manifest has pin specific resources
+ * like pin and pin buffer size
+ */
+static int skl_tplg_manifest_pin_res_tkn(struct device *dev,
+               struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+               struct skl_module_res *res, int pin_idx, int dir)
+{
+       struct skl_module_pin_resources *m_pin;
+
+       switch (dir) {
+       case SKL_DIR_IN:
+               m_pin = &res->input[pin_idx];
+               break;
+
+       case SKL_DIR_OUT:
+               m_pin = &res->output[pin_idx];
+               break;
+
+       default:
+               dev_err(dev, "Invalid pin direction: %d\n", dir);
+               return -EINVAL;
+       }
+
+       switch (tkn_elem->token) {
+       case SKL_TKN_MM_U32_RES_PIN_ID:
+               m_pin->pin_index = tkn_elem->value;
+               break;
+
+       case SKL_TKN_MM_U32_PIN_BUF:
+               m_pin->buf_size = tkn_elem->value;
+               break;
+
+       default:
+               dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Fill module specific resources from the manifest's resource
+ * table like CPS, DMA size, mem_pages.
+ */
+static int skl_tplg_fill_res_tkn(struct device *dev,
+               struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+               struct skl_module_res *res,
+               int pin_idx, int dir)
+{
+       int ret, tkn_count = 0;
+
+       if (!res)
+               return -EINVAL;
+
+       switch (tkn_elem->token) {
+       case SKL_TKN_MM_U32_CPS:
+               res->cps = tkn_elem->value;
+               break;
+
+       case SKL_TKN_MM_U32_DMA_SIZE:
+               res->dma_buffer_size = tkn_elem->value;
+               break;
+
+       case SKL_TKN_MM_U32_CPC:
+               res->cpc = tkn_elem->value;
+               break;
+
+       case SKL_TKN_U32_MEM_PAGES:
+               res->is_pages = tkn_elem->value;
+               break;
+
+       case SKL_TKN_U32_OBS:
+               res->obs = tkn_elem->value;
+               break;
+
+       case SKL_TKN_U32_IBS:
+               res->ibs = tkn_elem->value;
+               break;
+
+       case SKL_TKN_U32_MAX_MCPS:
+               res->cps = tkn_elem->value;
+               break;
+
+       case SKL_TKN_MM_U32_RES_PIN_ID:
+       case SKL_TKN_MM_U32_PIN_BUF:
+               ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
+                                                   pin_idx, dir);
+               if (ret < 0)
+                       return ret;
+               break;
+
+       default:
+               dev_err(dev, "Not a res type token: %d", tkn_elem->token);
+               return -EINVAL;
+
+       }
+       tkn_count++;
+
+       return tkn_count;
+}
+
 /*
  * Parse tokens to fill up the module private data
  */
@@ -2024,49 +2304,54 @@ static int skl_tplg_get_token(struct device *dev,
        int tkn_count = 0;
        int ret;
        static int is_pipe_exists;
-       static int pin_index, dir;
+       static int pin_index, dir, conf_idx;
+       struct skl_module_iface *iface = NULL;
+       struct skl_module_res *res = NULL;
+       int res_idx = mconfig->res_idx;
+       int fmt_idx = mconfig->fmt_idx;
+
+       /*
+        * If the manifest structure contains no modules, fill all
+        * the module data to 0th index.
+        * res_idx and fmt_idx are default set to 0.
+        */
+       if (skl->nr_modules == 0) {
+               res = &mconfig->module->resources[res_idx];
+               iface = &mconfig->module->formats[fmt_idx];
+       }
 
        if (tkn_elem->token > SKL_TKN_MAX)
                return -EINVAL;
 
        switch (tkn_elem->token) {
        case SKL_TKN_U8_IN_QUEUE_COUNT:
-               mconfig->max_in_queue = tkn_elem->value;
-               mconfig->m_in_pin = devm_kzalloc(dev, mconfig->max_in_queue *
-                                       sizeof(*mconfig->m_in_pin),
-                                       GFP_KERNEL);
-               if (!mconfig->m_in_pin)
-                       return -ENOMEM;
-
+               mconfig->module->max_input_pins = tkn_elem->value;
                break;
 
        case SKL_TKN_U8_OUT_QUEUE_COUNT:
-               mconfig->max_out_queue = tkn_elem->value;
-               mconfig->m_out_pin = devm_kzalloc(dev, mconfig->max_out_queue *
-                                       sizeof(*mconfig->m_out_pin),
-                                       GFP_KERNEL);
-
-               if (!mconfig->m_out_pin)
-                       return -ENOMEM;
-
+               mconfig->module->max_output_pins = tkn_elem->value;
                break;
 
        case SKL_TKN_U8_DYN_IN_PIN:
+               if (!mconfig->m_in_pin)
+                       mconfig->m_in_pin = devm_kzalloc(dev, MAX_IN_QUEUE *
+                                       sizeof(*mconfig->m_in_pin), GFP_KERNEL);
                if (!mconfig->m_in_pin)
                        return -ENOMEM;
 
-               skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin,
-                       mconfig->max_in_queue, tkn_elem->value);
-
+               skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE,
+                                             tkn_elem->value);
                break;
 
        case SKL_TKN_U8_DYN_OUT_PIN:
+               if (!mconfig->m_out_pin)
+                       mconfig->m_out_pin = devm_kzalloc(dev, MAX_IN_QUEUE *
+                                       sizeof(*mconfig->m_in_pin), GFP_KERNEL);
                if (!mconfig->m_out_pin)
                        return -ENOMEM;
 
-               skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin,
-                       mconfig->max_out_queue, tkn_elem->value);
-
+               skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE,
+                                             tkn_elem->value);
                break;
 
        case SKL_TKN_U8_TIME_SLOT:
@@ -2094,19 +2379,13 @@ static int skl_tplg_get_token(struct device *dev,
                break;
 
        case SKL_TKN_U32_MEM_PAGES:
-               mconfig->mem_pages = tkn_elem->value;
-               break;
-
        case SKL_TKN_U32_MAX_MCPS:
-               mconfig->mcps = tkn_elem->value;
-               break;
-
        case SKL_TKN_U32_OBS:
-               mconfig->obs = tkn_elem->value;
-               break;
-
        case SKL_TKN_U32_IBS:
-               mconfig->ibs = tkn_elem->value;
+               ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, dir, pin_index);
+               if (ret < 0)
+                       return ret;
+
                break;
 
        case SKL_TKN_U32_VBUS_ID:
@@ -2139,10 +2418,16 @@ static int skl_tplg_get_token(struct device *dev,
 
                break;
 
+       case SKL_TKN_U32_PIPE_CONFIG_ID:
+               conf_idx = tkn_elem->value;
+               break;
+
        case SKL_TKN_U32_PIPE_CONN_TYPE:
        case SKL_TKN_U32_PIPE_PRIORITY:
        case SKL_TKN_U32_PIPE_MEM_PGS:
        case SKL_TKN_U32_PMODE:
+       case SKL_TKN_U32_PIPE_DIRECTION:
+       case SKL_TKN_U32_NUM_CONFIGS:
                if (is_pipe_exists) {
                        ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
                                        tkn_elem->token, tkn_elem->value);
@@ -2152,6 +2437,27 @@ static int skl_tplg_get_token(struct device *dev,
 
                break;
 
+       case SKL_TKN_U32_PATH_MEM_PGS:
+       case SKL_TKN_U32_CFG_FREQ:
+       case SKL_TKN_U8_CFG_CHAN:
+       case SKL_TKN_U8_CFG_BPS:
+               if (mconfig->pipe->nr_cfgs) {
+                       ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe,
+                                       tkn_elem->token, tkn_elem->value,
+                                       conf_idx, dir);
+                       if (ret < 0)
+                               return ret;
+               }
+               break;
+
+       case SKL_TKN_CFG_MOD_RES_ID:
+               mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value;
+               break;
+
+       case SKL_TKN_CFG_MOD_FMT_ID:
+               mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value;
+               break;
+
        /*
         * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
         * direction and the pin count. The first four bits represent
@@ -2172,7 +2478,7 @@ static int skl_tplg_get_token(struct device *dev,
        case SKL_TKN_U32_FMT_INTERLEAVE:
        case SKL_TKN_U32_FMT_SAMPLE_TYPE:
        case SKL_TKN_U32_FMT_CH_MAP:
-               ret = skl_tplg_fill_fmt(dev, mconfig, tkn_elem->token,
+               ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token,
                                tkn_elem->value, dir, pin_index);
 
                if (ret < 0)
@@ -2397,11 +2703,11 @@ static void skl_clear_pin_config(struct snd_soc_platform *platform,
                                        strlen(platform->component.name))) {
                mconfig = w->priv;
                pipe = mconfig->pipe;
-               for (i = 0; i < mconfig->max_in_queue; i++) {
+               for (i = 0; i < mconfig->module->max_input_pins; i++) {
                        mconfig->m_in_pin[i].in_use = false;
                        mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
                }
-               for (i = 0; i < mconfig->max_out_queue; i++) {
+               for (i = 0; i < mconfig->module->max_output_pins; i++) {
                        mconfig->m_out_pin[i].in_use = false;
                        mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
                }
@@ -2460,6 +2766,13 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
        if (!mconfig)
                return -ENOMEM;
 
+       if (skl->nr_modules == 0) {
+               mconfig->module = devm_kzalloc(bus->dev,
+                               sizeof(*mconfig->module), GFP_KERNEL);
+               if (!mconfig->module)
+                       return -ENOMEM;
+       }
+
        w->priv = mconfig;
 
        /*
@@ -2602,13 +2915,13 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
                        str_elem->string,
                        ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name));
                ref_count++;
-               tkn_count++;
                break;
 
        default:
                dev_err(dev, "Not a string token %d\n", str_elem->token);
                break;
        }
+       tkn_count++;
 
        return tkn_count;
 }
@@ -2634,26 +2947,236 @@ static int skl_tplg_get_str_tkn(struct device *dev,
        return tkn_count;
 }
 
+static int skl_tplg_manifest_fill_fmt(struct device *dev,
+               struct skl_module_iface *fmt,
+               struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+               u32 dir, int fmt_idx)
+{
+       struct skl_module_pin_fmt *dst_fmt;
+       struct skl_module_fmt *mod_fmt;
+       int ret;
+
+       if (!fmt)
+               return -EINVAL;
+
+       switch (dir) {
+       case SKL_DIR_IN:
+               dst_fmt = &fmt->inputs[fmt_idx];
+               break;
+
+       case SKL_DIR_OUT:
+               dst_fmt = &fmt->outputs[fmt_idx];
+               break;
+
+       default:
+               dev_err(dev, "Invalid direction: %d\n", dir);
+               return -EINVAL;
+       }
+
+       mod_fmt = &dst_fmt->fmt;
+
+       switch (tkn_elem->token) {
+       case SKL_TKN_MM_U32_INTF_PIN_ID:
+               dst_fmt->id = tkn_elem->value;
+               break;
+
+       default:
+               ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
+                                       tkn_elem->value);
+               if (ret < 0)
+                       return ret;
+               break;
+       }
+
+       return 0;
+}
+
+static int skl_tplg_fill_mod_info(struct device *dev,
+               struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+               struct skl_module *mod)
+{
+
+       if (!mod)
+               return -EINVAL;
+
+       switch (tkn_elem->token) {
+       case SKL_TKN_U8_IN_PIN_TYPE:
+               mod->input_pin_type = tkn_elem->value;
+               break;
+
+       case SKL_TKN_U8_OUT_PIN_TYPE:
+               mod->output_pin_type = tkn_elem->value;
+               break;
+
+       case SKL_TKN_U8_IN_QUEUE_COUNT:
+               mod->max_input_pins = tkn_elem->value;
+               break;
+
+       case SKL_TKN_U8_OUT_QUEUE_COUNT:
+               mod->max_output_pins = tkn_elem->value;
+               break;
+
+       case SKL_TKN_MM_U8_NUM_RES:
+               mod->nr_resources = tkn_elem->value;
+               break;
+
+       case SKL_TKN_MM_U8_NUM_INTF:
+               mod->nr_interfaces = tkn_elem->value;
+               break;
+
+       default:
+               dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
 static int skl_tplg_get_int_tkn(struct device *dev,
                struct snd_soc_tplg_vendor_value_elem *tkn_elem,
                struct skl *skl)
 {
-       int tkn_count = 0;
+       int tkn_count = 0, ret;
+       static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
+       struct skl_module_res *res = NULL;
+       struct skl_module_iface *fmt = NULL;
+       struct skl_module *mod = NULL;
+       int i;
+
+       if (skl->modules) {
+               mod = skl->modules[mod_idx];
+               res = &mod->resources[res_val_idx];
+               fmt = &mod->formats[intf_val_idx];
+       }
 
        switch (tkn_elem->token) {
        case SKL_TKN_U32_LIB_COUNT:
                skl->skl_sst->lib_count = tkn_elem->value;
-               tkn_count++;
+               break;
+
+       case SKL_TKN_U8_NUM_MOD:
+               skl->nr_modules = tkn_elem->value;
+               skl->modules = devm_kcalloc(dev, skl->nr_modules,
+                               sizeof(*skl->modules), GFP_KERNEL);
+               if (!skl->modules)
+                       return -ENOMEM;
+
+               for (i = 0; i < skl->nr_modules; i++) {
+                       skl->modules[i] = devm_kzalloc(dev,
+                                       sizeof(struct skl_module), GFP_KERNEL);
+                       if (!skl->modules[i])
+                               return -ENOMEM;
+               }
+               break;
+
+       case SKL_TKN_MM_U8_MOD_IDX:
+               mod_idx = tkn_elem->value;
+               break;
+
+       case SKL_TKN_U8_IN_PIN_TYPE:
+       case SKL_TKN_U8_OUT_PIN_TYPE:
+       case SKL_TKN_U8_IN_QUEUE_COUNT:
+       case SKL_TKN_U8_OUT_QUEUE_COUNT:
+       case SKL_TKN_MM_U8_NUM_RES:
+       case SKL_TKN_MM_U8_NUM_INTF:
+               ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
+               if (ret < 0)
+                       return ret;
+               break;
+
+       case SKL_TKN_U32_DIR_PIN_COUNT:
+               dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
+               pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
+               break;
+
+       case SKL_TKN_MM_U32_RES_ID:
+               if (!res)
+                       return -EINVAL;
+
+               res->id = tkn_elem->value;
+               res_val_idx = tkn_elem->value;
+               break;
+
+       case SKL_TKN_MM_U32_FMT_ID:
+               if (!fmt)
+                       return -EINVAL;
+
+               fmt->fmt_idx = tkn_elem->value;
+               intf_val_idx = tkn_elem->value;
+               break;
+
+       case SKL_TKN_MM_U32_CPS:
+       case SKL_TKN_MM_U32_DMA_SIZE:
+       case SKL_TKN_MM_U32_CPC:
+       case SKL_TKN_U32_MEM_PAGES:
+       case SKL_TKN_U32_OBS:
+       case SKL_TKN_U32_IBS:
+       case SKL_TKN_MM_U32_RES_PIN_ID:
+       case SKL_TKN_MM_U32_PIN_BUF:
+               ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
+               if (ret < 0)
+                       return ret;
+
+               break;
+
+       case SKL_TKN_MM_U32_NUM_IN_FMT:
+               if (!fmt)
+                       return -EINVAL;
+
+               res->nr_input_pins = tkn_elem->value;
+               break;
+
+       case SKL_TKN_MM_U32_NUM_OUT_FMT:
+               if (!fmt)
+                       return -EINVAL;
+
+               res->nr_output_pins = tkn_elem->value;
+               break;
+
+       case SKL_TKN_U32_FMT_CH:
+       case SKL_TKN_U32_FMT_FREQ:
+       case SKL_TKN_U32_FMT_BIT_DEPTH:
+       case SKL_TKN_U32_FMT_SAMPLE_SIZE:
+       case SKL_TKN_U32_FMT_CH_CONFIG:
+       case SKL_TKN_U32_FMT_INTERLEAVE:
+       case SKL_TKN_U32_FMT_SAMPLE_TYPE:
+       case SKL_TKN_U32_FMT_CH_MAP:
+       case SKL_TKN_MM_U32_INTF_PIN_ID:
+               ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
+                                                dir, pin_idx);
+               if (ret < 0)
+                       return ret;
                break;
 
        default:
                dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
                return -EINVAL;
        }
+       tkn_count++;
 
        return tkn_count;
 }
 
+static int skl_tplg_get_manifest_uuid(struct device *dev,
+                               struct skl *skl,
+                               struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
+{
+       static int ref_count;
+       struct skl_module *mod;
+
+       if (uuid_tkn->token == SKL_TKN_UUID) {
+               mod = skl->modules[ref_count];
+               memcpy(&mod->uuid, &uuid_tkn->uuid, sizeof(uuid_tkn->uuid));
+               ref_count++;
+       } else {
+               dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /*
  * Fill the manifest structure by parsing the tokens based on the
  * type.
@@ -2686,7 +3209,11 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
                        continue;
 
                case SND_SOC_TPLG_TUPLE_TYPE_UUID:
-                       dev_warn(dev, "no uuid tokens for skl tplf manifest\n");
+                       ret = skl_tplg_get_manifest_uuid(dev, skl, array->uuid);
+                       if (ret < 0)
+                               return ret;
+
+                       tuple_size += sizeof(*array->uuid);
                        continue;
 
                default:
@@ -2703,14 +3230,12 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
 
                        tkn_count = tkn_count + ret;
                        tkn_elem++;
-                       tuple_size += tkn_count *
-                               sizeof(struct snd_soc_tplg_vendor_value_elem);
-                       break;
                }
+               tuple_size += (tkn_count * sizeof(*tkn_elem));
                tkn_count = 0;
        }
 
-       return 0;
+       return off;
 }
 
 /*
@@ -2733,11 +3258,10 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
        num_blocks = ret;
 
        off += array->size;
-       array = (struct snd_soc_tplg_vendor_array *)
-                       (manifest->priv.data + off);
-
        /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
        while (num_blocks > 0) {
+               array = (struct snd_soc_tplg_vendor_array *)
+                               (manifest->priv.data + off);
                ret = skl_tplg_get_desc_blocks(dev, array);
 
                if (ret < 0)
@@ -2771,6 +3295,7 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
                } else {
                        return -EINVAL;
                }
+               off += ret;
        }
 
        return 0;
index c25e886..2717db9 100644 (file)
 #define SKL_DEFAULT_MIC_SEL_GAIN       0x3FF
 #define SKL_MIC_SEL_SWITCH     0x3
 
+#define SKL_OUTPUT_PIN         0
+#define SKL_INPUT_PIN          1
+#define SKL_MAX_PATH_CONFIGS   8
+#define SKL_MAX_MODULES_IN_PIPE        8
+#define SKL_MAX_MODULE_FORMATS         32
+#define SKL_MAX_MODULE_RESOURCES       32
+
 enum skl_channel_index {
        SKL_CHANNEL_LEFT = 0,
        SKL_CHANNEL_RIGHT = 1,
@@ -131,6 +138,11 @@ struct skl_cpr_cfg {
        struct skl_cpr_gtw_cfg gtw_cfg;
 } __packed;
 
+struct skl_cpr_pin_fmt {
+       u32 sink_id;
+       struct skl_audio_data_format src_fmt;
+       struct skl_audio_data_format dst_fmt;
+} __packed;
 
 struct skl_src_module_cfg {
        struct skl_base_cfg base_cfg;
@@ -214,6 +226,7 @@ struct skl_kpb_params {
 };
 
 struct skl_module_inst_id {
+       uuid_le mod_uuid;
        int module_id;
        u32 instance_id;
        int pvt_id;
@@ -266,6 +279,23 @@ struct skl_pipe_params {
        unsigned int link_bps;
 };
 
+struct skl_pipe_fmt {
+       u32 freq;
+       u8 channels;
+       u8 bps;
+};
+
+struct skl_pipe_mcfg {
+       u8 res_idx;
+       u8 fmt_idx;
+};
+
+struct skl_path_config {
+       u8 mem_pages;
+       struct skl_pipe_fmt in_fmt;
+       struct skl_pipe_fmt out_fmt;
+};
+
 struct skl_pipe {
        u8 ppl_id;
        u8 pipe_priority;
@@ -274,6 +304,10 @@ struct skl_pipe {
        u8 lp_mode;
        struct skl_pipe_params *p_params;
        enum skl_pipe_state state;
+       u8 direction;
+       u8 cur_config_idx;
+       u8 nr_cfgs;
+       struct skl_path_config configs[SKL_MAX_PATH_CONFIGS];
        struct list_head w_list;
        bool passthru;
 };
@@ -292,9 +326,57 @@ enum d0i3_capability {
        SKL_D0I3_NON_STREAMING = 2,
 };
 
+struct skl_module_pin_fmt {
+       u8 id;
+       struct skl_module_fmt fmt;
+};
+
+struct skl_module_iface {
+       u8 fmt_idx;
+       u8 nr_in_fmt;
+       u8 nr_out_fmt;
+       struct skl_module_pin_fmt inputs[MAX_IN_QUEUE];
+       struct skl_module_pin_fmt outputs[MAX_OUT_QUEUE];
+};
+
+struct skl_module_pin_resources {
+       u8 pin_index;
+       u32 buf_size;
+};
+
+struct skl_module_res {
+       u8 id;
+       u32 is_pages;
+       u32 cps;
+       u32 ibs;
+       u32 obs;
+       u32 dma_buffer_size;
+       u32 cpc;
+       u8 nr_input_pins;
+       u8 nr_output_pins;
+       struct skl_module_pin_resources input[MAX_IN_QUEUE];
+       struct skl_module_pin_resources output[MAX_OUT_QUEUE];
+};
+
+struct skl_module {
+       uuid_le uuid;
+       u8 loadable;
+       u8 input_pin_type;
+       u8 output_pin_type;
+       u8 max_input_pins;
+       u8 max_output_pins;
+       u8 nr_resources;
+       u8 nr_interfaces;
+       struct skl_module_res resources[SKL_MAX_MODULE_RESOURCES];
+       struct skl_module_iface formats[SKL_MAX_MODULE_FORMATS];
+};
+
 struct skl_module_cfg {
        u8 guid[16];
        struct skl_module_inst_id id;
+       struct skl_module *module;
+       int res_idx;
+       int fmt_idx;
        u8 domain;
        bool homogenous_inputs;
        bool homogenous_outputs;
@@ -329,6 +411,7 @@ struct skl_module_cfg {
        enum skl_module_state m_state;
        struct skl_pipe *pipe;
        struct skl_specific_cfg formats_config;
+       struct skl_pipe_mcfg mod_cfg[SKL_MAX_MODULES_IN_PIPE];
 };
 
 struct skl_algo_data {
index 6b49feb..f94b484 100644 (file)
@@ -415,7 +415,7 @@ static int skl_free(struct hdac_ext_bus *ebus)
        snd_hdac_ext_stop_streams(ebus);
 
        if (bus->irq >= 0)
-               free_irq(bus->irq, (void *)bus);
+               free_irq(bus->irq, (void *)ebus);
        snd_hdac_bus_free_stream_pages(bus);
        snd_hdac_stream_free_all(ebus);
        snd_hdac_link_free_all(ebus);
@@ -528,7 +528,7 @@ static int probe_codec(struct hdac_ext_bus *ebus, int addr)
 }
 
 /* Codec initialization */
-static int skl_codec_create(struct hdac_ext_bus *ebus)
+static void skl_codec_create(struct hdac_ext_bus *ebus)
 {
        struct hdac_bus *bus = ebus_to_hbus(ebus);
        int c, max_slots;
@@ -559,8 +559,6 @@ static int skl_codec_create(struct hdac_ext_bus *ebus)
                        }
                }
        }
-
-       return 0;
 }
 
 static const struct hdac_bus_ops bus_core_ops = {
@@ -612,9 +610,7 @@ static void skl_probe_work(struct work_struct *work)
                dev_info(bus->dev, "no hda codecs found!\n");
 
        /* create codec instances */
-       err = skl_codec_create(ebus);
-       if (err < 0)
-               goto out_err;
+       skl_codec_create(ebus);
 
        if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
                err = snd_hdac_display_power(bus, false);
@@ -702,6 +698,8 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
                return -ENXIO;
        }
 
+       skl_init_chip(bus, true);
+
        snd_hdac_bus_parse_capabilities(bus);
 
        if (skl_acquire_irq(ebus, 0) < 0)
@@ -982,6 +980,11 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
                .quirk_data = &kbl_poppy_codecs,
                .pdata = &skl_dmic_data
        },
+       {
+               .id = "10EC5663",
+               .drv_name = "kbl_rt5663",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+       },
 
        {}
 };
@@ -995,6 +998,14 @@ static struct sst_acpi_mach sst_glk_devdata[] = {
        {}
 };
 
+static const struct sst_acpi_mach sst_cnl_devdata[] = {
+       {
+               .id = "INT34C2",
+               .drv_name = "cnl_rt274",
+               .fw_filename = "intel/dsp_fw_cnl.bin",
+       },
+};
+
 /* PCI IDs */
 static const struct pci_device_id skl_ids[] = {
        /* Sunrise Point-LP */
@@ -1009,6 +1020,9 @@ static const struct pci_device_id skl_ids[] = {
        /* GLK */
        { PCI_DEVICE(0x8086, 0x3198),
                .driver_data = (unsigned long)&sst_glk_devdata},
+       /* CNL */
+       { PCI_DEVICE(0x8086, 0x9dc8),
+               .driver_data = (unsigned long)&sst_cnl_devdata},
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, skl_ids);
index a6b134b..8d9d689 100644 (file)
@@ -71,6 +71,8 @@ struct skl {
        struct work_struct probe_work;
 
        struct skl_debug *debugfs;
+       u8 nr_modules;
+       struct skl_module **modules;
 };
 
 #define skl_to_ebus(s) (&(s)->ebus)
@@ -90,6 +92,7 @@ struct skl_machine_pdata {
 
 struct skl_dsp_ops {
        int id;
+       unsigned int num_cores;
        struct skl_dsp_loader_ops (*loader_ops)(void);
        int (*init)(struct device *dev, void __iomem *mmio_base,
                        int irq, const char *fw_name,