ASoC: Intel: Skylake: Add D0i3 mode ref counting
authorVinod Koul <vinod.koul@intel.com>
Thu, 3 Nov 2016 11:37:20 +0000 (17:07 +0530)
committerMark Brown <broonie@kernel.org>
Thu, 3 Nov 2016 17:14:42 +0000 (11:14 -0600)
For device opened/closed, we check the D0i3 capability for the device
and invoke skl_tplg_d0i3_get/put, which counts the use case based on the
mode supported.

These counters are then used to decide if the device can enter D0i3 mode
of streaming or non-streaming or no D0i3.

Signed-off-by: Jayachandran B <jayachandran.b@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/intel/skylake/bxt-sst.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-sst-ipc.c
sound/soc/intel/skylake/skl-sst-ipc.h
sound/soc/intel/skylake/skl-topology.c
sound/soc/intel/skylake/skl-topology.h

index fed818fe2e69a8809bf28bae58b9e55c07f4862f..1f9f33d34000b13f752c875680038383c48561a4 100644 (file)
@@ -610,10 +610,15 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
        if (ret)
                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);
        skl->is_first_boot = true;
+       INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
+       skl->d0i3.state = SKL_DSP_D0I3_NONE;
 
        if (dsp)
                *dsp = skl;
index b69e05ec6844ab289ce3ec376af47eb49c5a6c60..84b5101e6ca691df0e0896b59a95e07a55e3b5e7 100644 (file)
@@ -144,6 +144,8 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
        struct hdac_ext_stream *stream;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct skl_dma_params *dma_params;
+       struct skl *skl = get_skl_ctx(dai->dev);
+       struct skl_module_cfg *mconfig;
 
        dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
 
@@ -177,6 +179,9 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
        skl_set_suspend_active(substream, dai, true);
        snd_pcm_set_sync(substream);
 
+       mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
+       skl_tplg_d0i3_get(skl, mconfig->d0i3_caps);
+
        return 0;
 }
 
@@ -302,6 +307,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
        struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
        struct skl_dma_params *dma_params = NULL;
        struct skl *skl = ebus_to_skl(ebus);
+       struct skl_module_cfg *mconfig;
 
        dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
 
@@ -325,6 +331,9 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
                skl->skl_sst->miscbdcg_disabled = false;
        }
 
+       mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
+       skl_tplg_d0i3_put(skl, mconfig->d0i3_caps);
+
        kfree(dma_params);
 }
 
index 734408a34a240b1078fe915b20dd334e0a5304e7..594623a4b4cd3a72e7ccb546dcc6f7f8b035f01c 100644 (file)
@@ -306,6 +306,23 @@ static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
                header->primary | SKL_ADSP_REG_HIPCI_BUSY);
 }
 
+int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state)
+{
+       int ret;
+
+       /* check D0i3 support */
+       if (!dsp->fw_ops.set_state_D0i0)
+               return 0;
+
+       /* Attempt D0i0 or D0i3 based on state */
+       if (state)
+               ret = dsp->fw_ops.set_state_D0i0(dsp);
+       else
+               ret = dsp->fw_ops.set_state_D0i3(dsp);
+
+       return ret;
+}
+
 static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc,
                                u64 ipc_header)
 {
index 83bf1689f62e890150e47ea5f291454b57357dba..0568f2e8fc57bed1cac974566722fec4337f2954 100644 (file)
@@ -187,6 +187,8 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
 int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc,
                struct skl_ipc_d0ix_msg *msg);
 
+int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state);
+
 void skl_ipc_int_enable(struct sst_dsp *dsp);
 void skl_ipc_op_int_enable(struct sst_dsp *ctx);
 void skl_ipc_op_int_disable(struct sst_dsp *ctx);
index 86597d491982f7507224b2fec9cece24e431de1a..bd313c907b20df470a8c7727f8169c036fae25b9 100644 (file)
 #define SKL_IN_DIR_BIT_MASK            BIT(0)
 #define SKL_PIN_COUNT_MASK             GENMASK(7, 4)
 
+void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps)
+{
+       struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
+
+       switch (caps) {
+       case SKL_D0I3_NONE:
+               d0i3->non_d0i3++;
+               break;
+
+       case SKL_D0I3_STREAMING:
+               d0i3->streaming++;
+               break;
+
+       case SKL_D0I3_NON_STREAMING:
+               d0i3->non_streaming++;
+               break;
+       }
+}
+
+void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps)
+{
+       struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
+
+       switch (caps) {
+       case SKL_D0I3_NONE:
+               d0i3->non_d0i3--;
+               break;
+
+       case SKL_D0I3_STREAMING:
+               d0i3->streaming--;
+               break;
+
+       case SKL_D0I3_NON_STREAMING:
+               d0i3->non_streaming--;
+               break;
+       }
+}
+
 /*
  * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
  * ignore. This helpers checks if the SKL driver handles this widget type
index 38809f6d20d63c2e76f47c3e1c3188818360cc2d..3b962d84bcb839c108e3b3dcfa612f48489d1ee8 100644 (file)
@@ -369,6 +369,9 @@ struct skl_module_cfg *skl_tplg_fe_get_cpr_module(
 int skl_tplg_update_pipe_params(struct device *dev,
                struct skl_module_cfg *mconfig, struct skl_pipe_params *params);
 
+void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps);
+void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps);
+
 int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe);
 
 int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);