ASoC: Intel: Skylake: Add D0iX IPCs
authorPardha Saradhi K <pardha.saradhi.kesapragada@intel.com>
Thu, 3 Nov 2016 11:37:15 +0000 (17:07 +0530)
committerMark Brown <broonie@kernel.org>
Thu, 3 Nov 2016 17:14:10 +0000 (11:14 -0600)
The audio DSP supports intermediate power states between D0 and D3
states. These states are D0i0 and D0i3 states.

Collectively we refer these two states as D0iX states.

To set or wake up from these states, driver also needs to send an IPC "Set D0iX
IPC" before doing anything else.

Add support for this new IPC messages.

Signed-off-by: Pardha Saradhi K <pardha.saradhi.kesapragada@intel.com>
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/skl-sst-ipc.c
sound/soc/intel/skylake/skl-sst-ipc.h

index 797cf40532352c22a1adc573dd1aa1db292e726e..087b8d6e7186870cf800f45915c40c74635fed9b 100644 (file)
                                        << IPC_INITIAL_BLOCK_SHIFT)
 #define IPC_INITIAL_BLOCK_CLEAR                ~(IPC_INITIAL_BLOCK_MASK \
                                          << IPC_INITIAL_BLOCK_SHIFT)
+/* Set D0ix IPC extension register */
+#define IPC_D0IX_WAKE_SHIFT            0
+#define IPC_D0IX_WAKE_MASK             0x1
+#define IPC_D0IX_WAKE(x)               (((x) & IPC_D0IX_WAKE_MASK) \
+                                       << IPC_D0IX_WAKE_SHIFT)
+
+#define IPC_D0IX_STREAMING_SHIFT       1
+#define IPC_D0IX_STREAMING_MASK                0x1
+#define IPC_D0IX_STREAMING(x)          (((x) & IPC_D0IX_STREAMING_MASK) \
+                                       << IPC_D0IX_STREAMING_SHIFT)
+
 
 enum skl_ipc_msg_target {
        IPC_FW_GEN_MSG = 0,
@@ -258,7 +269,8 @@ enum skl_ipc_module_msg {
        IPC_MOD_LARGE_CONFIG_SET = 4,
        IPC_MOD_BIND = 5,
        IPC_MOD_UNBIND = 6,
-       IPC_MOD_SET_DX = 7
+       IPC_MOD_SET_DX = 7,
+       IPC_MOD_SET_D0IX = 8
 };
 
 static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
@@ -931,3 +943,32 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
        return ret;
 }
 EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library);
+
+int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg)
+{
+       struct skl_ipc_header header = {0};
+       u64 *ipc_header = (u64 *)(&header);
+       int ret;
+
+       header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
+       header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+       header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_D0IX);
+       header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
+       header.primary |= IPC_MOD_ID(msg->module_id);
+
+       header.extension = IPC_D0IX_WAKE(msg->wake);
+       header.extension |= IPC_D0IX_STREAMING(msg->streaming);
+
+       dev_dbg(ipc->dev, "In %s primary=%x ext=%x\n", __func__,
+                       header.primary, header.extension);
+
+       /*
+        * Use the nopm IPC here as we dont want it checking for D0iX
+        */
+       ret = sst_ipc_tx_message_nopm(ipc, *ipc_header, NULL, 0, NULL, 0);
+       if (ret < 0)
+               dev_err(ipc->dev, "ipc: set d0ix failed, err %d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_set_d0ix);
index 0334ed4af0312a89eef15a09f05a67c88465272b..1ae265d8ee084ed17e274d3bbbfb8505b707920c 100644 (file)
@@ -111,6 +111,13 @@ struct skl_ipc_large_config_msg {
        u32 param_data_size;
 };
 
+struct skl_ipc_d0ix_msg {
+       u32 module_id;
+       u32 instance_id;
+       u8 streaming;
+       u8 wake;
+};
+
 #define SKL_IPC_BOOT_MSECS             3000
 
 #define SKL_IPC_D3_MASK        0
@@ -155,6 +162,9 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
 int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
                        u8 dma_id, u8 table_id);
 
+int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc,
+               struct skl_ipc_d0ix_msg *msg);
+
 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);