Merge branch 'fix/intel' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorMark Brown <broonie@kernel.org>
Mon, 8 Jan 2018 15:54:50 +0000 (15:54 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 8 Jan 2018 15:54:50 +0000 (15:54 +0000)
22 files changed:
include/uapi/sound/snd_sst_tokens.h
sound/soc/intel/atom/sst/sst_acpi.c
sound/soc/intel/boards/bytcr_rt5651.c
sound/soc/intel/boards/haswell.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/common/sst-dsp.c
sound/soc/intel/skylake/bxt-sst.c
sound/soc/intel/skylake/cnl-sst.c
sound/soc/intel/skylake/skl-i2s.h [new file with mode: 0644]
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-nhlt.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-ssp-clk.h [new file with mode: 0644]
sound/soc/intel/skylake/skl-sst-dsp.c
sound/soc/intel/skylake/skl-sst-dsp.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.c
sound/soc/intel/skylake/skl.h

index 326054a72bc7e9ca240a39128be9585531c025cc..8ba0112e533688a26cb3012be334fbc35c9c4e67 100644 (file)
  * %SKL_TKN_MM_U32_NUM_IN_FMT:  Number of input formats
  * %SKL_TKN_MM_U32_NUM_OUT_FMT: Number of output formats
  *
+ * %SKL_TKN_U32_ASTATE_IDX:     Table Index for the A-State entry to be filled
+ *                              with kcps and clock source
+ *
+ * %SKL_TKN_U32_ASTATE_COUNT:   Number of valid entries in A-State table
+ *
+ * %SKL_TKN_U32_ASTATE_KCPS:    Specifies the core load threshold (in kilo
+ *                              cycles per second) below which DSP is clocked
+ *                              from source specified by clock source.
+ *
+ * %SKL_TKN_U32_ASTATE_CLK_SRC: Clock source for A-State entry
+ *
  * module_id and loadable flags dont have tokens as these values will be
  * read from the DSP FW manifest
  *
@@ -309,7 +320,11 @@ enum SKL_TKNS {
        SKL_TKN_MM_U32_NUM_IN_FMT,
        SKL_TKN_MM_U32_NUM_OUT_FMT,
 
-       SKL_TKN_MAX = SKL_TKN_MM_U32_NUM_OUT_FMT,
+       SKL_TKN_U32_ASTATE_IDX,
+       SKL_TKN_U32_ASTATE_COUNT,
+       SKL_TKN_U32_ASTATE_KCPS,
+       SKL_TKN_U32_ASTATE_CLK_SRC,
+       SKL_TKN_MAX = SKL_TKN_U32_ASTATE_CLK_SRC,
 };
 
 #endif
index 32d6e02e21049719feb32691ee0ded359b5a4572..6cd481bec27524c6e8bd395071ba066fd97871e2 100644 (file)
@@ -236,6 +236,9 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
        /* Find the IRQ */
        ctx->irq_num = platform_get_irq(pdev,
                                ctx->pdata->res_info->acpi_ipc_irq_index);
+       if (ctx->irq_num <= 0)
+               return ctx->irq_num < 0 ? ctx->irq_num : -EIO;
+
        return 0;
 }
 
index d955836c6870a8ad7d6cbe4939fbc3c457738c77..488ec48f296a9c9cdd99771274d0714112f1a720 100644 (file)
@@ -38,6 +38,7 @@ enum {
        BYT_RT5651_DMIC_MAP,
        BYT_RT5651_IN1_MAP,
        BYT_RT5651_IN2_MAP,
+       BYT_RT5651_IN1_IN2_MAP,
 };
 
 #define BYT_RT5651_MAP(quirk)  ((quirk) & GENMASK(7, 0))
@@ -171,6 +172,13 @@ static const struct snd_soc_dapm_route byt_rt5651_intmic_in2_map[] = {
        {"IN2P", NULL, "Internal Mic"},
 };
 
+static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_in2_map[] = {
+       {"Internal Mic", NULL, "micbias1"},
+       {"IN1P", NULL, "Internal Mic"},
+       {"IN2P", NULL, "Internal Mic"},
+       {"IN3P", NULL, "Headset Mic"},
+};
+
 static const struct snd_kcontrol_new byt_rt5651_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphone"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -256,7 +264,7 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "KIANO"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "KIANO SlimNote 14.2"),
                },
-               .driver_data = (void *)(BYT_RT5651_IN2_MAP),
+               .driver_data = (void *)(BYT_RT5651_IN1_IN2_MAP),
        },
        {}
 };
@@ -281,6 +289,10 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
                custom_map = byt_rt5651_intmic_in2_map;
                num_routes = ARRAY_SIZE(byt_rt5651_intmic_in2_map);
                break;
+       case BYT_RT5651_IN1_IN2_MAP:
+               custom_map = byt_rt5651_intmic_in1_in2_map;
+               num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_in2_map);
+               break;
        default:
                custom_map = byt_rt5651_intmic_dmic_map;
                num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map);
index 5e1ea0371c9097bf1c79737bc1892d7667479480..3c51607792044fe5200842a6a23be2d4f175fe3c 100644 (file)
@@ -76,7 +76,7 @@ static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* set correct codec filter for DAI format and clock config */
-       snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000);
+       snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000);
 
        return ret;
 }
index 6f9a8bcf20f3ebb4407a2452eed8870a11b40c02..94a34db4f8c05a32409142b6477c3af287a304d3 100644 (file)
@@ -225,7 +225,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
        }
 
        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_0, KEY_PLAYPAUSE);
        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);
index 6072164f2d43db7c7f8f50000892f6e61e80d79c..5ae0459d59c2bacb5fae0953f621930ceafbccaf 100644 (file)
@@ -195,7 +195,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
        }
 
        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_0, KEY_PLAYPAUSE);
        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);
index 6f44acfb4aae7337aa1f4009e0a6c0b71efad2c3..7cb44fdde1ee80a78e78f25b9c0de09b18748f86 100644 (file)
@@ -372,6 +372,8 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
 
        /* retrive the irq number */
        irq = platform_get_irq(pdev, 0);
+       if (irq <= 0)
+               return irq < 0 ? irq : -ENODEV;
 
        /* audio interrupt base of SRAM location where
         * interrupts are stored by System FW */
index 11c0805393ff96c50b03b2b29fb70a32b53fa3dc..fd82f4b1d4a07bc2b289a27b9edf4a4610606587 100644 (file)
@@ -269,7 +269,7 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
         */
 
        timeout = jiffies + msecs_to_jiffies(time);
-       while (((sst_dsp_shim_read_unlocked(ctx, offset) & mask) != target)
+       while ((((reg = sst_dsp_shim_read_unlocked(ctx, offset)) & mask) != target)
                && time_before(jiffies, timeout)) {
                k++;
                if (k > 10)
@@ -278,8 +278,6 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
                usleep_range(s, 2*s);
        }
 
-       reg = sst_dsp_shim_read_unlocked(ctx, offset);
-
        if ((reg & mask) == target) {
                dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n",
                                        reg, operation);
index 4524211960e4a4a5941f08a8a2066096e471cf6f..440bca7afbf142874bf150a580eea27b91ae016b 100644 (file)
@@ -595,7 +595,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
        INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
        skl->d0i3.state = SKL_DSP_D0I3_NONE;
 
-       return 0;
+       return skl_dsp_acquire_irq(sst);
 }
 EXPORT_SYMBOL_GPL(bxt_sst_dsp_init);
 
index 387de388ce29405be5ad10875cb66a17adf39f55..245df1067ba8902e2151cc999fd5172220f2968c 100644 (file)
@@ -458,7 +458,7 @@ int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
        cnl->boot_complete = false;
        init_waitqueue_head(&cnl->boot_wait);
 
-       return 0;
+       return skl_dsp_acquire_irq(sst);
 }
 EXPORT_SYMBOL_GPL(cnl_sst_dsp_init);
 
diff --git a/sound/soc/intel/skylake/skl-i2s.h b/sound/soc/intel/skylake/skl-i2s.h
new file mode 100644 (file)
index 0000000..dcf819b
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  skl-i2s.h - i2s blob mapping
+ *
+ *  Copyright (C) 2017 Intel Corp
+ *  Author: Subhransu S. Prusty < subhransu.s.prusty@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  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 __SOUND_SOC_SKL_I2S_H
+#define __SOUND_SOC_SKL_I2S_H
+
+#define SKL_I2S_MAX_TIME_SLOTS         8
+#define SKL_MCLK_DIV_CLK_SRC_MASK      GENMASK(17, 16)
+
+#define SKL_MNDSS_DIV_CLK_SRC_MASK     GENMASK(21, 20)
+#define SKL_SHIFT(x)                   (ffs(x) - 1)
+#define SKL_MCLK_DIV_RATIO_MASK                GENMASK(11, 0)
+
+struct skl_i2s_config {
+       u32 ssc0;
+       u32 ssc1;
+       u32 sscto;
+       u32 sspsp;
+       u32 sstsa;
+       u32 ssrsa;
+       u32 ssc2;
+       u32 sspsp2;
+       u32 ssc3;
+       u32 ssioc;
+} __packed;
+
+struct skl_i2s_config_mclk {
+       u32 mdivctrl;
+       u32 mdivr;
+};
+
+/**
+ * struct skl_i2s_config_blob_legacy - Structure defines I2S Gateway
+ * configuration legacy blob
+ *
+ * @gtw_attr:          Gateway attribute for the I2S Gateway
+ * @tdm_ts_group:      TDM slot mapping against channels in the Gateway.
+ * @i2s_cfg:           I2S HW registers
+ * @mclk:              MCLK clock source and divider values
+ */
+struct skl_i2s_config_blob_legacy {
+       u32 gtw_attr;
+       u32 tdm_ts_group[SKL_I2S_MAX_TIME_SLOTS];
+       struct skl_i2s_config i2s_cfg;
+       struct skl_i2s_config_mclk mclk;
+};
+
+#endif /* __SOUND_SOC_SKL_I2S_H */
index 61b5bfa79d1325b5a42e69119ccb1e39c20c0b6c..8cbf080c38b3ef1acfcecb8f869bfbcee59eb732 100644 (file)
@@ -55,6 +55,19 @@ static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab)
        return 0;
 }
 
+#define SKL_ASTATE_PARAM_ID    4
+
+void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data)
+{
+       struct skl_ipc_large_config_msg msg = {0};
+
+       msg.large_param_id = SKL_ASTATE_PARAM_ID;
+       msg.param_data_size = (cnt * sizeof(struct skl_astate_param) +
+                               sizeof(cnt));
+
+       skl_ipc_set_large_config(&ctx->ipc, &msg, data);
+}
+
 #define NOTIFICATION_PARAM_ID 3
 #define NOTIFICATION_MASK 0xf
 
@@ -404,11 +417,20 @@ int skl_resume_dsp(struct skl *skl)
        if (skl->skl_sst->is_first_boot == true)
                return 0;
 
+       /* disable dynamic clock gating during fw and lib download */
+       ctx->enable_miscbdcge(ctx->dev, false);
+
        ret = skl_dsp_wake(ctx->dsp);
+       ctx->enable_miscbdcge(ctx->dev, true);
        if (ret < 0)
                return ret;
 
        skl_dsp_enable_notification(skl->skl_sst, false);
+
+       if (skl->cfg.astate_cfg != NULL) {
+               skl_dsp_set_astate_cfg(skl->skl_sst, skl->cfg.astate_cfg->count,
+                                       skl->cfg.astate_cfg);
+       }
        return ret;
 }
 
index 1ce414d86d8a422969719aa755692a8c20ca11b4..d9b3dc89a1dc49cefbe7d5d89907b72c261a9ba9 100644 (file)
@@ -19,6 +19,7 @@
  */
 #include <linux/pci.h>
 #include "skl.h"
+#include "skl-i2s.h"
 
 #define NHLT_ACPI_HEADER_SIG   "NHLT"
 
@@ -272,3 +273,157 @@ void skl_nhlt_remove_sysfs(struct skl *skl)
 
        sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr);
 }
+
+/*
+ * Queries NHLT for all the fmt configuration for a particular endpoint and
+ * stores all possible rates supported in a rate table for the corresponding
+ * sclk/sclkfs.
+ */
+static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks,
+                               struct nhlt_fmt *fmt, u8 id)
+{
+       struct skl_i2s_config_blob_legacy *i2s_config;
+       struct skl_clk_parent_src *parent;
+       struct skl_ssp_clk *sclk, *sclkfs;
+       struct nhlt_fmt_cfg *fmt_cfg;
+       struct wav_fmt_ext *wav_fmt;
+       unsigned long rate = 0;
+       bool present = false;
+       int rate_index = 0;
+       u16 channels, bps;
+       u8 clk_src;
+       int i, j;
+       u32 fs;
+
+       sclk = &ssp_clks[SKL_SCLK_OFS];
+       sclkfs = &ssp_clks[SKL_SCLKFS_OFS];
+
+       if (fmt->fmt_count == 0)
+               return;
+
+       for (i = 0; i < fmt->fmt_count; i++) {
+               fmt_cfg = &fmt->fmt_config[i];
+               wav_fmt = &fmt_cfg->fmt_ext;
+
+               channels = wav_fmt->fmt.channels;
+               bps = wav_fmt->fmt.bits_per_sample;
+               fs = wav_fmt->fmt.samples_per_sec;
+
+               /*
+                * In case of TDM configuration on a ssp, there can
+                * be more than one blob in which channel masks are
+                * different for each usecase for a specific rate and bps.
+                * But the sclk rate will be generated for the total
+                * number of channels used for that endpoint.
+                *
+                * So for the given fs and bps, choose blob which has
+                * the superset of all channels for that endpoint and
+                * derive the rate.
+                */
+               for (j = i; j < fmt->fmt_count; j++) {
+                       fmt_cfg = &fmt->fmt_config[j];
+                       wav_fmt = &fmt_cfg->fmt_ext;
+                       if ((fs == wav_fmt->fmt.samples_per_sec) &&
+                          (bps == wav_fmt->fmt.bits_per_sample))
+                               channels = max_t(u16, channels,
+                                               wav_fmt->fmt.channels);
+               }
+
+               rate = channels * bps * fs;
+
+               /* check if the rate is added already to the given SSP's sclk */
+               for (j = 0; (j < SKL_MAX_CLK_RATES) &&
+                           (sclk[id].rate_cfg[j].rate != 0); j++) {
+                       if (sclk[id].rate_cfg[j].rate == rate) {
+                               present = true;
+                               break;
+                       }
+               }
+
+               /* Fill rate and parent for sclk/sclkfs */
+               if (!present) {
+                       /* MCLK Divider Source Select */
+                       i2s_config = (struct skl_i2s_config_blob_legacy *)
+                                               fmt->fmt_config[0].config.caps;
+                       clk_src = ((i2s_config->mclk.mdivctrl)
+                                       & SKL_MNDSS_DIV_CLK_SRC_MASK) >>
+                                       SKL_SHIFT(SKL_MNDSS_DIV_CLK_SRC_MASK);
+
+                       parent = skl_get_parent_clk(clk_src);
+
+                       /*
+                        * Do not copy the config data if there is no parent
+                        * clock available for this clock source select
+                        */
+                       if (!parent)
+                               continue;
+
+                       sclk[id].rate_cfg[rate_index].rate = rate;
+                       sclk[id].rate_cfg[rate_index].config = fmt_cfg;
+                       sclkfs[id].rate_cfg[rate_index].rate = rate;
+                       sclkfs[id].rate_cfg[rate_index].config = fmt_cfg;
+                       sclk[id].parent_name = parent->name;
+                       sclkfs[id].parent_name = parent->name;
+
+                       rate_index++;
+               }
+       }
+}
+
+static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk,
+                               struct nhlt_fmt *fmt, u8 id)
+{
+       struct skl_i2s_config_blob_legacy *i2s_config;
+       struct nhlt_specific_cfg *fmt_cfg;
+       struct skl_clk_parent_src *parent;
+       u32 clkdiv, div_ratio;
+       u8 clk_src;
+
+       fmt_cfg = &fmt->fmt_config[0].config;
+       i2s_config = (struct skl_i2s_config_blob_legacy *)fmt_cfg->caps;
+
+       /* MCLK Divider Source Select */
+       clk_src = ((i2s_config->mclk.mdivctrl) & SKL_MCLK_DIV_CLK_SRC_MASK) >>
+                                       SKL_SHIFT(SKL_MCLK_DIV_CLK_SRC_MASK);
+
+       clkdiv = i2s_config->mclk.mdivr & SKL_MCLK_DIV_RATIO_MASK;
+
+       /* bypass divider */
+       div_ratio = 1;
+
+       if (clkdiv != SKL_MCLK_DIV_RATIO_MASK)
+               /* Divider is 2 + clkdiv */
+               div_ratio = clkdiv + 2;
+
+       /* Calculate MCLK rate from source using div value */
+       parent = skl_get_parent_clk(clk_src);
+       if (!parent)
+               return;
+
+       mclk[id].rate_cfg[0].rate = parent->rate/div_ratio;
+       mclk[id].rate_cfg[0].config = &fmt->fmt_config[0];
+       mclk[id].parent_name = parent->name;
+}
+
+void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks)
+{
+       struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
+       struct nhlt_endpoint *epnt;
+       struct nhlt_fmt *fmt;
+       int i;
+       u8 id;
+
+       epnt = (struct nhlt_endpoint *)nhlt->desc;
+       for (i = 0; i < nhlt->endpoint_count; i++) {
+               if (epnt->linktype == NHLT_LINK_SSP) {
+                       id = epnt->virtual_bus_id;
+
+                       fmt = (struct nhlt_fmt *)(epnt->config.caps
+                                       + epnt->config.size);
+
+                       skl_get_ssp_clks(skl, ssp_clks, fmt, id);
+                       skl_get_mclk(skl, ssp_clks, fmt, id);
+               }
+               epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
+       }
+}
index 1dd97479e0c014bf1f814f16dd419268529454e0..e4682853382614d83d73bf27a8e5a7ee3810bbca 100644 (file)
@@ -537,7 +537,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
 
        snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
 
-       link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
+       link = snd_hdac_ext_bus_get_link(ebus, codec_dai->component->name);
        if (!link)
                return -EINVAL;
 
@@ -620,7 +620,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
 
        link_dev->link_prepared = 0;
 
-       link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
+       link = snd_hdac_ext_bus_get_link(ebus, rtd->codec_dai->component->name);
        if (!link)
                return -EINVAL;
 
@@ -1343,7 +1343,11 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
                        return -EIO;
                }
 
+               /* disable dynamic clock gating during fw and lib download */
+               skl->skl_sst->enable_miscbdcge(platform->dev, false);
+
                ret = ops->init_fw(platform->dev, skl->skl_sst);
+               skl->skl_sst->enable_miscbdcge(platform->dev, true);
                if (ret < 0) {
                        dev_err(platform->dev, "Failed to boot first fw: %d\n", ret);
                        return ret;
@@ -1351,6 +1355,12 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
                skl_populate_modules(skl);
                skl->skl_sst->update_d0i3c = skl_update_d0i3c;
                skl_dsp_enable_notification(skl->skl_sst, false);
+
+               if (skl->cfg.astate_cfg != NULL) {
+                       skl_dsp_set_astate_cfg(skl->skl_sst,
+                                       skl->cfg.astate_cfg->count,
+                                       skl->cfg.astate_cfg);
+               }
        }
        pm_runtime_mark_last_busy(platform->dev);
        pm_runtime_put_autosuspend(platform->dev);
diff --git a/sound/soc/intel/skylake/skl-ssp-clk.h b/sound/soc/intel/skylake/skl-ssp-clk.h
new file mode 100644 (file)
index 0000000..c9ea840
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  skl-ssp-clk.h - Skylake ssp clock information and ipc structure
+ *
+ *  Copyright (C) 2017 Intel Corp
+ *  Author: Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>
+ *  Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  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 SOUND_SOC_SKL_SSP_CLK_H
+#define SOUND_SOC_SKL_SSP_CLK_H
+
+#define SKL_MAX_SSP            6
+/* xtal/cardinal/pll, parent of ssp clocks and mclk */
+#define SKL_MAX_CLK_SRC                3
+#define SKL_MAX_SSP_CLK_TYPES  3 /* mclk, sclk, sclkfs */
+
+#define SKL_MAX_CLK_CNT                (SKL_MAX_SSP * SKL_MAX_SSP_CLK_TYPES)
+
+/* Max number of configurations supported for each clock */
+#define SKL_MAX_CLK_RATES      10
+
+#define SKL_SCLK_OFS           SKL_MAX_SSP
+#define SKL_SCLKFS_OFS         (SKL_SCLK_OFS + SKL_MAX_SSP)
+
+enum skl_clk_type {
+       SKL_MCLK,
+       SKL_SCLK,
+       SKL_SCLK_FS,
+};
+
+enum skl_clk_src_type {
+       SKL_XTAL,
+       SKL_CARDINAL,
+       SKL_PLL,
+};
+
+struct skl_clk_parent_src {
+       u8 clk_id;
+       const char *name;
+       unsigned long rate;
+       const char *parent_name;
+};
+
+struct skl_clk_rate_cfg_table {
+       unsigned long rate;
+       void *config;
+};
+
+/*
+ * rate for mclk will be in rates[0]. For sclk and sclkfs, rates[] store
+ * all possible clocks ssp can generate for that platform.
+ */
+struct skl_ssp_clk {
+       const char *name;
+       const char *parent_name;
+       struct skl_clk_rate_cfg_table rate_cfg[SKL_MAX_CLK_RATES];
+};
+
+struct skl_clk_pdata {
+       struct skl_clk_parent_src *parent_clks;
+       int num_clks;
+       struct skl_ssp_clk *ssp_clks;
+       void *pvt_data;
+};
+
+#endif /* SOUND_SOC_SKL_SSP_CLK_H */
index 19ee1d4f3bdff5b2ff5973d702c9ddf714de38ea..71e31ad0bb3fb0a11b0d906bfef6a7b3922ddae4 100644 (file)
@@ -435,16 +435,22 @@ struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
                        return NULL;
        }
 
+       return sst;
+}
+
+int skl_dsp_acquire_irq(struct sst_dsp *sst)
+{
+       struct sst_dsp_device *sst_dev = sst->sst_dev;
+       int ret;
+
        /* Register the ISR */
        ret = request_threaded_irq(sst->irq, sst->ops->irq_handler,
                sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
-       if (ret) {
+       if (ret)
                dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n",
                               sst->irq);
-               return NULL;
-       }
 
-       return sst;
+       return ret;
 }
 
 void skl_dsp_free(struct sst_dsp *dsp)
index eba20d37ba8c077d483fce9b673831f3ff832f30..12fc9a73dc8a6d782725ea4ed16be359aa9a95c1 100644 (file)
@@ -206,6 +206,7 @@ int skl_cldma_wait_interruptible(struct sst_dsp *ctx);
 void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state);
 struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
                struct sst_dsp_device *sst_dev, int irq);
+int skl_dsp_acquire_irq(struct sst_dsp *sst);
 bool is_skl_dsp_running(struct sst_dsp *ctx);
 
 unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx);
@@ -251,6 +252,9 @@ void skl_freeup_uuid_list(struct skl_sst *ctx);
 
 int skl_dsp_strip_extended_manifest(struct firmware *fw);
 void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable);
+
+void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data);
+
 int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
                struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp,
                struct sst_dsp_device *skl_dev);
index 8ff89280d9fd44f11e34121f1dddd7647004c688..2ae405617876281749525db63dad5fffd0e8305d 100644 (file)
@@ -178,7 +178,8 @@ static inline int skl_pvtid_128(struct uuid_module *module)
  * skl_get_pvt_id: generate a private id for use as module id
  *
  * @ctx: driver context
- * @mconfig: module configuration data
+ * @uuid_mod: module's uuid
+ * @instance_id: module's instance id
  *
  * This generates a 128 bit private unique id for a module TYPE so that
  * module instance is unique
@@ -208,7 +209,8 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id);
  * skl_put_pvt_id: free up the private id allocated
  *
  * @ctx: driver context
- * @mconfig: module configuration data
+ * @uuid_mod: module's uuid
+ * @pvt_id: module pvt id
  *
  * This frees a 128 bit private unique id previously generated
  */
index a436abf2fe3f38b65e93f9637de0f804b859a2aa..5a7e41b65ef3d8aa3302d6c2a449ef58f26edc72 100644 (file)
@@ -569,7 +569,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
 
        sst->fw_ops = skl_fw_ops;
 
-       return 0;
+       return skl_dsp_acquire_irq(sst);
 }
 EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
 
index a072bcf209d2aa4c9c72503466e027e6867cd9bb..6a5f8462c3804070f19ece3bf7e5e66e7602df38 100644 (file)
@@ -3056,11 +3056,13 @@ 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, ret;
+       int tkn_count = 0, ret, size;
        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;
+       static struct skl_astate_param *astate_table;
+       static int astate_cfg_idx, count;
        int i;
 
        if (skl->modules) {
@@ -3093,6 +3095,46 @@ static int skl_tplg_get_int_tkn(struct device *dev,
                mod_idx = tkn_elem->value;
                break;
 
+       case SKL_TKN_U32_ASTATE_COUNT:
+               if (astate_table != NULL) {
+                       dev_err(dev, "More than one entry for A-State count");
+                       return -EINVAL;
+               }
+
+               if (tkn_elem->value > SKL_MAX_ASTATE_CFG) {
+                       dev_err(dev, "Invalid A-State count %d\n",
+                               tkn_elem->value);
+                       return -EINVAL;
+               }
+
+               size = tkn_elem->value * sizeof(struct skl_astate_param) +
+                               sizeof(count);
+               skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
+               if (!skl->cfg.astate_cfg)
+                       return -ENOMEM;
+
+               astate_table = skl->cfg.astate_cfg->astate_table;
+               count = skl->cfg.astate_cfg->count = tkn_elem->value;
+               break;
+
+       case SKL_TKN_U32_ASTATE_IDX:
+               if (tkn_elem->value >= count) {
+                       dev_err(dev, "Invalid A-State index %d\n",
+                               tkn_elem->value);
+                       return -EINVAL;
+               }
+
+               astate_cfg_idx = tkn_elem->value;
+               break;
+
+       case SKL_TKN_U32_ASTATE_KCPS:
+               astate_table[astate_cfg_idx].kcps = tkn_elem->value;
+               break;
+
+       case SKL_TKN_U32_ASTATE_CLK_SRC:
+               astate_table[astate_cfg_idx].clk_src = 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:
index 31d8634e8aa1c4f71e7f089bd1da0545e1345ab0..32ce64c6b2dced88c562bea3aef2dfdb9d1fa687 100644 (file)
@@ -355,6 +355,7 @@ static int skl_resume(struct device *dev)
 
                if (ebus->cmd_dma_state)
                        snd_hdac_bus_init_cmd_io(&ebus->bus);
+               ret = 0;
        } else {
                ret = _skl_resume(ebus);
 
@@ -435,19 +436,51 @@ static int skl_free(struct hdac_ext_bus *ebus)
        return 0;
 }
 
-static int skl_machine_device_register(struct skl *skl, void *driver_data)
+/*
+ * For each ssp there are 3 clocks (mclk/sclk/sclkfs).
+ * e.g. for ssp0, clocks will be named as
+ *      "ssp0_mclk", "ssp0_sclk", "ssp0_sclkfs"
+ * So for skl+, there are 6 ssps, so 18 clocks will be created.
+ */
+static struct skl_ssp_clk skl_ssp_clks[] = {
+       {.name = "ssp0_mclk"}, {.name = "ssp1_mclk"}, {.name = "ssp2_mclk"},
+       {.name = "ssp3_mclk"}, {.name = "ssp4_mclk"}, {.name = "ssp5_mclk"},
+       {.name = "ssp0_sclk"}, {.name = "ssp1_sclk"}, {.name = "ssp2_sclk"},
+       {.name = "ssp3_sclk"}, {.name = "ssp4_sclk"}, {.name = "ssp5_sclk"},
+       {.name = "ssp0_sclkfs"}, {.name = "ssp1_sclkfs"},
+                                               {.name = "ssp2_sclkfs"},
+       {.name = "ssp3_sclkfs"}, {.name = "ssp4_sclkfs"},
+                                               {.name = "ssp5_sclkfs"},
+};
+
+static int skl_find_machine(struct skl *skl, void *driver_data)
 {
-       struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
-       struct platform_device *pdev;
        struct snd_soc_acpi_mach *mach = driver_data;
-       int ret;
+       struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+       struct skl_machine_pdata *pdata;
 
        mach = snd_soc_acpi_find_machine(mach);
        if (mach == NULL) {
                dev_err(bus->dev, "No matching machine driver found\n");
                return -ENODEV;
        }
+
+       skl->mach = mach;
        skl->fw_name = mach->fw_filename;
+       pdata = skl->mach->pdata;
+
+       if (mach->pdata)
+               skl->use_tplg_pcm = pdata->use_tplg_pcm;
+
+       return 0;
+}
+
+static int skl_machine_device_register(struct skl *skl)
+{
+       struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+       struct snd_soc_acpi_mach *mach = skl->mach;
+       struct platform_device *pdev;
+       int ret;
 
        pdev = platform_device_alloc(mach->drv_name, -1);
        if (pdev == NULL) {
@@ -462,11 +495,8 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data)
                return -EIO;
        }
 
-       if (mach->pdata) {
-               skl->use_tplg_pcm =
-                       ((struct skl_machine_pdata *)mach->pdata)->use_tplg_pcm;
+       if (mach->pdata)
                dev_set_drvdata(&pdev->dev, mach->pdata);
-       }
 
        skl->i2s_dev = pdev;
 
@@ -509,6 +539,74 @@ static void skl_dmic_device_unregister(struct skl *skl)
                platform_device_unregister(skl->dmic_dev);
 }
 
+static struct skl_clk_parent_src skl_clk_src[] = {
+       { .clk_id = SKL_XTAL, .name = "xtal" },
+       { .clk_id = SKL_CARDINAL, .name = "cardinal", .rate = 24576000 },
+       { .clk_id = SKL_PLL, .name = "pll", .rate = 96000000 },
+};
+
+struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(skl_clk_src); i++) {
+               if (skl_clk_src[i].clk_id == clk_id)
+                       return &skl_clk_src[i];
+       }
+
+       return NULL;
+}
+
+static void init_skl_xtal_rate(int pci_id)
+{
+       switch (pci_id) {
+       case 0x9d70:
+       case 0x9d71:
+               skl_clk_src[0].rate = 24000000;
+               return;
+
+       default:
+               skl_clk_src[0].rate = 19200000;
+               return;
+       }
+}
+
+static int skl_clock_device_register(struct skl *skl)
+{
+       struct platform_device_info pdevinfo = {NULL};
+       struct skl_clk_pdata *clk_pdata;
+
+       clk_pdata = devm_kzalloc(&skl->pci->dev, sizeof(*clk_pdata),
+                                                       GFP_KERNEL);
+       if (!clk_pdata)
+               return -ENOMEM;
+
+       init_skl_xtal_rate(skl->pci->device);
+
+       clk_pdata->parent_clks = skl_clk_src;
+       clk_pdata->ssp_clks = skl_ssp_clks;
+       clk_pdata->num_clks = ARRAY_SIZE(skl_ssp_clks);
+
+       /* Query NHLT to fill the rates and parent */
+       skl_get_clks(skl, clk_pdata->ssp_clks);
+       clk_pdata->pvt_data = skl;
+
+       /* Register Platform device */
+       pdevinfo.parent = &skl->pci->dev;
+       pdevinfo.id = -1;
+       pdevinfo.name = "skl-ssp-clk";
+       pdevinfo.data = clk_pdata;
+       pdevinfo.size_data = sizeof(*clk_pdata);
+       skl->clk_dev = platform_device_register_full(&pdevinfo);
+       return PTR_ERR_OR_ZERO(skl->clk_dev);
+}
+
+static void skl_clock_device_unregister(struct skl *skl)
+{
+       if (skl->clk_dev)
+               platform_device_unregister(skl->clk_dev);
+}
+
 /*
  * Probe the given codec address
  */
@@ -615,18 +713,30 @@ static void skl_probe_work(struct work_struct *work)
        /* create codec instances */
        skl_codec_create(ebus);
 
+       /* register platform dai and controls */
+       err = skl_platform_register(bus->dev);
+       if (err < 0) {
+               dev_err(bus->dev, "platform register failed: %d\n", err);
+               return;
+       }
+
+       if (bus->ppcap) {
+               err = skl_machine_device_register(skl);
+               if (err < 0) {
+                       dev_err(bus->dev, "machine register failed: %d\n", err);
+                       goto out_err;
+               }
+       }
+
        if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
                err = snd_hdac_display_power(bus, false);
                if (err < 0) {
                        dev_err(bus->dev, "Cannot turn off display power on i915\n");
+                       skl_machine_device_unregister(skl);
                        return;
                }
        }
 
-       /* register platform dai and controls */
-       err = skl_platform_register(bus->dev);
-       if (err < 0)
-               return;
        /*
         * we are done probing so decrement link counts
         */
@@ -791,18 +901,21 @@ static int skl_probe(struct pci_dev *pci,
 
        /* check if dsp is there */
        if (bus->ppcap) {
-               err = skl_machine_device_register(skl,
-                                 (void *)pci_id->driver_data);
+               /* create device for dsp clk */
+               err = skl_clock_device_register(skl);
+               if (err < 0)
+                       goto out_clk_free;
+
+               err = skl_find_machine(skl, (void *)pci_id->driver_data);
                if (err < 0)
                        goto out_nhlt_free;
 
                err = skl_init_dsp(skl);
                if (err < 0) {
                        dev_dbg(bus->dev, "error failed to register dsp\n");
-                       goto out_mach_free;
+                       goto out_nhlt_free;
                }
                skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
-
        }
        if (bus->mlcap)
                snd_hdac_ext_bus_get_ml_capabilities(ebus);
@@ -820,8 +933,8 @@ static int skl_probe(struct pci_dev *pci,
 
 out_dsp_free:
        skl_free_dsp(skl);
-out_mach_free:
-       skl_machine_device_unregister(skl);
+out_clk_free:
+       skl_clock_device_unregister(skl);
 out_nhlt_free:
        skl_nhlt_free(skl->nhlt);
 out_free:
@@ -872,6 +985,7 @@ static void skl_remove(struct pci_dev *pci)
        skl_free_dsp(skl);
        skl_machine_device_unregister(skl);
        skl_dmic_device_unregister(skl);
+       skl_clock_device_unregister(skl);
        skl_nhlt_remove_sysfs(skl);
        skl_nhlt_free(skl->nhlt);
        skl_free(ebus);
index e00cde8200ddd186cea76aeec8442891ad4107a9..f411579bc7138ac1fce813cf8914720862ede50d 100644 (file)
 #include <sound/hdaudio_ext.h>
 #include <sound/soc.h>
 #include "skl-nhlt.h"
+#include "skl-ssp-clk.h"
 
 #define SKL_SUSPEND_DELAY 2000
 
+#define SKL_MAX_ASTATE_CFG             3
+
 #define AZX_PCIREG_PGCTL               0x44
 #define AZX_PGCTL_LSRMD_MASK           (1 << 4)
 #define AZX_PCIREG_CGCTL               0x48
@@ -45,6 +48,20 @@ struct skl_dsp_resource {
 
 struct skl_debug;
 
+struct skl_astate_param {
+       u32 kcps;
+       u32 clk_src;
+};
+
+struct skl_astate_config {
+       u32 count;
+       struct skl_astate_param astate_table[0];
+};
+
+struct skl_fw_config {
+       struct skl_astate_config *astate_cfg;
+};
+
 struct skl {
        struct hdac_ext_bus ebus;
        struct pci_dev *pci;
@@ -52,6 +69,7 @@ struct skl {
        unsigned int init_done:1; /* delayed init status */
        struct platform_device *dmic_dev;
        struct platform_device *i2s_dev;
+       struct platform_device *clk_dev;
        struct snd_soc_platform *platform;
        struct snd_soc_dai_driver *dais;
 
@@ -75,6 +93,8 @@ struct skl {
        u8 nr_modules;
        struct skl_module **modules;
        bool use_tplg_pcm;
+       struct skl_fw_config cfg;
+       struct snd_soc_acpi_mach *mach;
 };
 
 #define skl_to_ebus(s) (&(s)->ebus)
@@ -125,6 +145,8 @@ const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id);
 void skl_update_d0i3c(struct device *dev, bool enable);
 int skl_nhlt_create_sysfs(struct skl *skl);
 void skl_nhlt_remove_sysfs(struct skl *skl);
+void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks);
+struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id);
 
 struct skl_module_cfg;