1b81fd263SSubhransu S. Prusty /* 2b81fd263SSubhransu S. Prusty * skl-sst-ipc.c - Intel skl IPC Support 3b81fd263SSubhransu S. Prusty * 4b81fd263SSubhransu S. Prusty * Copyright (C) 2014-15, Intel Corporation. 5b81fd263SSubhransu S. Prusty * 6b81fd263SSubhransu S. Prusty * This program is free software; you can redistribute it and/or modify 7b81fd263SSubhransu S. Prusty * it under the terms of the GNU General Public License as version 2, as 8b81fd263SSubhransu S. Prusty * published by the Free Software Foundation. 9b81fd263SSubhransu S. Prusty * 10b81fd263SSubhransu S. Prusty * This program is distributed in the hope that it will be useful, but 11b81fd263SSubhransu S. Prusty * WITHOUT ANY WARRANTY; without even the implied warranty of 12b81fd263SSubhransu S. Prusty * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13b81fd263SSubhransu S. Prusty * General Public License for more details. 14b81fd263SSubhransu S. Prusty */ 15b81fd263SSubhransu S. Prusty #include <linux/device.h> 16b81fd263SSubhransu S. Prusty 17b81fd263SSubhransu S. Prusty #include "../common/sst-dsp.h" 18b81fd263SSubhransu S. Prusty #include "../common/sst-dsp-priv.h" 19b81fd263SSubhransu S. Prusty #include "skl-sst-dsp.h" 20b81fd263SSubhransu S. Prusty #include "skl-sst-ipc.h" 21b81fd263SSubhransu S. Prusty 22b81fd263SSubhransu S. Prusty 23b81fd263SSubhransu S. Prusty #define IPC_IXC_STATUS_BITS 24 24b81fd263SSubhransu S. Prusty 25b81fd263SSubhransu S. Prusty /* Global Message - Generic */ 26b81fd263SSubhransu S. Prusty #define IPC_GLB_TYPE_SHIFT 24 27b81fd263SSubhransu S. Prusty #define IPC_GLB_TYPE_MASK (0xf << IPC_GLB_TYPE_SHIFT) 28b81fd263SSubhransu S. Prusty #define IPC_GLB_TYPE(x) ((x) << IPC_GLB_TYPE_SHIFT) 29b81fd263SSubhransu S. Prusty 30b81fd263SSubhransu S. Prusty /* Global Message - Reply */ 31b81fd263SSubhransu S. Prusty #define IPC_GLB_REPLY_STATUS_SHIFT 24 32b81fd263SSubhransu S. Prusty #define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1) 33b81fd263SSubhransu S. Prusty #define IPC_GLB_REPLY_STATUS(x) ((x) << IPC_GLB_REPLY_STATUS_SHIFT) 34b81fd263SSubhransu S. Prusty 35b81fd263SSubhransu S. Prusty #define IPC_TIMEOUT_MSECS 3000 36b81fd263SSubhransu S. Prusty 37b81fd263SSubhransu S. Prusty #define IPC_EMPTY_LIST_SIZE 8 38b81fd263SSubhransu S. Prusty 39b81fd263SSubhransu S. Prusty #define IPC_MSG_TARGET_SHIFT 30 40b81fd263SSubhransu S. Prusty #define IPC_MSG_TARGET_MASK 0x1 41b81fd263SSubhransu S. Prusty #define IPC_MSG_TARGET(x) (((x) & IPC_MSG_TARGET_MASK) \ 42b81fd263SSubhransu S. Prusty << IPC_MSG_TARGET_SHIFT) 43b81fd263SSubhransu S. Prusty 44b81fd263SSubhransu S. Prusty #define IPC_MSG_DIR_SHIFT 29 45b81fd263SSubhransu S. Prusty #define IPC_MSG_DIR_MASK 0x1 46b81fd263SSubhransu S. Prusty #define IPC_MSG_DIR(x) (((x) & IPC_MSG_DIR_MASK) \ 47b81fd263SSubhransu S. Prusty << IPC_MSG_DIR_SHIFT) 48b81fd263SSubhransu S. Prusty /* Global Notification Message */ 49b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_TYPE_SHIFT 16 50b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_TYPE_MASK 0xFF 51b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_TYPE(x) (((x) >> IPC_GLB_NOTIFY_TYPE_SHIFT) \ 52b81fd263SSubhransu S. Prusty & IPC_GLB_NOTIFY_TYPE_MASK) 53b81fd263SSubhransu S. Prusty 54b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_MSG_TYPE_SHIFT 24 55b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_MSG_TYPE_MASK 0x1F 56b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_MSG_TYPE(x) (((x) >> IPC_GLB_NOTIFY_MSG_TYPE_SHIFT) \ 57b81fd263SSubhransu S. Prusty & IPC_GLB_NOTIFY_MSG_TYPE_MASK) 58b81fd263SSubhransu S. Prusty 59b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_RSP_SHIFT 29 60b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_RSP_MASK 0x1 61b81fd263SSubhransu S. Prusty #define IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> IPC_GLB_NOTIFY_RSP_SHIFT) \ 62b81fd263SSubhransu S. Prusty & IPC_GLB_NOTIFY_RSP_MASK) 63b81fd263SSubhransu S. Prusty 64b81fd263SSubhransu S. Prusty /* Pipeline operations */ 65b81fd263SSubhransu S. Prusty 66b81fd263SSubhransu S. Prusty /* Create pipeline message */ 67b81fd263SSubhransu S. Prusty #define IPC_PPL_MEM_SIZE_SHIFT 0 68b81fd263SSubhransu S. Prusty #define IPC_PPL_MEM_SIZE_MASK 0x7FF 69b81fd263SSubhransu S. Prusty #define IPC_PPL_MEM_SIZE(x) (((x) & IPC_PPL_MEM_SIZE_MASK) \ 70b81fd263SSubhransu S. Prusty << IPC_PPL_MEM_SIZE_SHIFT) 71b81fd263SSubhransu S. Prusty 72b81fd263SSubhransu S. Prusty #define IPC_PPL_TYPE_SHIFT 11 73b81fd263SSubhransu S. Prusty #define IPC_PPL_TYPE_MASK 0x1F 74b81fd263SSubhransu S. Prusty #define IPC_PPL_TYPE(x) (((x) & IPC_PPL_TYPE_MASK) \ 75b81fd263SSubhransu S. Prusty << IPC_PPL_TYPE_SHIFT) 76b81fd263SSubhransu S. Prusty 77b81fd263SSubhransu S. Prusty #define IPC_INSTANCE_ID_SHIFT 16 78b81fd263SSubhransu S. Prusty #define IPC_INSTANCE_ID_MASK 0xFF 79b81fd263SSubhransu S. Prusty #define IPC_INSTANCE_ID(x) (((x) & IPC_INSTANCE_ID_MASK) \ 80b81fd263SSubhransu S. Prusty << IPC_INSTANCE_ID_SHIFT) 81b81fd263SSubhransu S. Prusty 82b81fd263SSubhransu S. Prusty /* Set pipeline state message */ 83b81fd263SSubhransu S. Prusty #define IPC_PPL_STATE_SHIFT 0 84b81fd263SSubhransu S. Prusty #define IPC_PPL_STATE_MASK 0x1F 85b81fd263SSubhransu S. Prusty #define IPC_PPL_STATE(x) (((x) & IPC_PPL_STATE_MASK) \ 86b81fd263SSubhransu S. Prusty << IPC_PPL_STATE_SHIFT) 87b81fd263SSubhransu S. Prusty 88b81fd263SSubhransu S. Prusty /* Module operations primary register */ 89b81fd263SSubhransu S. Prusty #define IPC_MOD_ID_SHIFT 0 90b81fd263SSubhransu S. Prusty #define IPC_MOD_ID_MASK 0xFFFF 91b81fd263SSubhransu S. Prusty #define IPC_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ 92b81fd263SSubhransu S. Prusty << IPC_MOD_ID_SHIFT) 93b81fd263SSubhransu S. Prusty 94b81fd263SSubhransu S. Prusty #define IPC_MOD_INSTANCE_ID_SHIFT 16 95b81fd263SSubhransu S. Prusty #define IPC_MOD_INSTANCE_ID_MASK 0xFF 96b81fd263SSubhransu S. Prusty #define IPC_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ 97b81fd263SSubhransu S. Prusty << IPC_MOD_INSTANCE_ID_SHIFT) 98b81fd263SSubhransu S. Prusty 99b81fd263SSubhransu S. Prusty /* Init instance message extension register */ 100b81fd263SSubhransu S. Prusty #define IPC_PARAM_BLOCK_SIZE_SHIFT 0 101b81fd263SSubhransu S. Prusty #define IPC_PARAM_BLOCK_SIZE_MASK 0xFFFF 102b81fd263SSubhransu S. Prusty #define IPC_PARAM_BLOCK_SIZE(x) (((x) & IPC_PARAM_BLOCK_SIZE_MASK) \ 103b81fd263SSubhransu S. Prusty << IPC_PARAM_BLOCK_SIZE_SHIFT) 104b81fd263SSubhransu S. Prusty 105b81fd263SSubhransu S. Prusty #define IPC_PPL_INSTANCE_ID_SHIFT 16 106b81fd263SSubhransu S. Prusty #define IPC_PPL_INSTANCE_ID_MASK 0xFF 107b81fd263SSubhransu S. Prusty #define IPC_PPL_INSTANCE_ID(x) (((x) & IPC_PPL_INSTANCE_ID_MASK) \ 108b81fd263SSubhransu S. Prusty << IPC_PPL_INSTANCE_ID_SHIFT) 109b81fd263SSubhransu S. Prusty 110b81fd263SSubhransu S. Prusty #define IPC_CORE_ID_SHIFT 24 111b81fd263SSubhransu S. Prusty #define IPC_CORE_ID_MASK 0x1F 112b81fd263SSubhransu S. Prusty #define IPC_CORE_ID(x) (((x) & IPC_CORE_ID_MASK) \ 113b81fd263SSubhransu S. Prusty << IPC_CORE_ID_SHIFT) 114b81fd263SSubhransu S. Prusty 115b81fd263SSubhransu S. Prusty /* Bind/Unbind message extension register */ 116b81fd263SSubhransu S. Prusty #define IPC_DST_MOD_ID_SHIFT 0 117b81fd263SSubhransu S. Prusty #define IPC_DST_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ 118b81fd263SSubhransu S. Prusty << IPC_DST_MOD_ID_SHIFT) 119b81fd263SSubhransu S. Prusty 120b81fd263SSubhransu S. Prusty #define IPC_DST_MOD_INSTANCE_ID_SHIFT 16 121b81fd263SSubhransu S. Prusty #define IPC_DST_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ 122b81fd263SSubhransu S. Prusty << IPC_DST_MOD_INSTANCE_ID_SHIFT) 123b81fd263SSubhransu S. Prusty 124b81fd263SSubhransu S. Prusty #define IPC_DST_QUEUE_SHIFT 24 125b81fd263SSubhransu S. Prusty #define IPC_DST_QUEUE_MASK 0x7 126b81fd263SSubhransu S. Prusty #define IPC_DST_QUEUE(x) (((x) & IPC_DST_QUEUE_MASK) \ 127b81fd263SSubhransu S. Prusty << IPC_DST_QUEUE_SHIFT) 128b81fd263SSubhransu S. Prusty 129b81fd263SSubhransu S. Prusty #define IPC_SRC_QUEUE_SHIFT 27 130b81fd263SSubhransu S. Prusty #define IPC_SRC_QUEUE_MASK 0x7 131b81fd263SSubhransu S. Prusty #define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \ 132b81fd263SSubhransu S. Prusty << IPC_SRC_QUEUE_SHIFT) 133b81fd263SSubhransu S. Prusty 134b81fd263SSubhransu S. Prusty /* Save pipeline messgae extension register */ 135b81fd263SSubhransu S. Prusty #define IPC_DMA_ID_SHIFT 0 136b81fd263SSubhransu S. Prusty #define IPC_DMA_ID_MASK 0x1F 137b81fd263SSubhransu S. Prusty #define IPC_DMA_ID(x) (((x) & IPC_DMA_ID_MASK) \ 138b81fd263SSubhransu S. Prusty << IPC_DMA_ID_SHIFT) 139b81fd263SSubhransu S. Prusty /* Large Config message extension register */ 140b81fd263SSubhransu S. Prusty #define IPC_DATA_OFFSET_SZ_SHIFT 0 141b81fd263SSubhransu S. Prusty #define IPC_DATA_OFFSET_SZ_MASK 0xFFFFF 142b81fd263SSubhransu S. Prusty #define IPC_DATA_OFFSET_SZ(x) (((x) & IPC_DATA_OFFSET_SZ_MASK) \ 143b81fd263SSubhransu S. Prusty << IPC_DATA_OFFSET_SZ_SHIFT) 144b81fd263SSubhransu S. Prusty #define IPC_DATA_OFFSET_SZ_CLEAR ~(IPC_DATA_OFFSET_SZ_MASK \ 145b81fd263SSubhransu S. Prusty << IPC_DATA_OFFSET_SZ_SHIFT) 146b81fd263SSubhransu S. Prusty 147b81fd263SSubhransu S. Prusty #define IPC_LARGE_PARAM_ID_SHIFT 20 148b81fd263SSubhransu S. Prusty #define IPC_LARGE_PARAM_ID_MASK 0xFF 149b81fd263SSubhransu S. Prusty #define IPC_LARGE_PARAM_ID(x) (((x) & IPC_LARGE_PARAM_ID_MASK) \ 150b81fd263SSubhransu S. Prusty << IPC_LARGE_PARAM_ID_SHIFT) 151b81fd263SSubhransu S. Prusty 152b81fd263SSubhransu S. Prusty #define IPC_FINAL_BLOCK_SHIFT 28 153b81fd263SSubhransu S. Prusty #define IPC_FINAL_BLOCK_MASK 0x1 154b81fd263SSubhransu S. Prusty #define IPC_FINAL_BLOCK(x) (((x) & IPC_FINAL_BLOCK_MASK) \ 155b81fd263SSubhransu S. Prusty << IPC_FINAL_BLOCK_SHIFT) 156b81fd263SSubhransu S. Prusty 157b81fd263SSubhransu S. Prusty #define IPC_INITIAL_BLOCK_SHIFT 29 158b81fd263SSubhransu S. Prusty #define IPC_INITIAL_BLOCK_MASK 0x1 159b81fd263SSubhransu S. Prusty #define IPC_INITIAL_BLOCK(x) (((x) & IPC_INITIAL_BLOCK_MASK) \ 160b81fd263SSubhransu S. Prusty << IPC_INITIAL_BLOCK_SHIFT) 161b81fd263SSubhransu S. Prusty #define IPC_INITIAL_BLOCK_CLEAR ~(IPC_INITIAL_BLOCK_MASK \ 162b81fd263SSubhransu S. Prusty << IPC_INITIAL_BLOCK_SHIFT) 163b81fd263SSubhransu S. Prusty 164b81fd263SSubhransu S. Prusty enum skl_ipc_msg_target { 165b81fd263SSubhransu S. Prusty IPC_FW_GEN_MSG = 0, 166b81fd263SSubhransu S. Prusty IPC_MOD_MSG = 1 167b81fd263SSubhransu S. Prusty }; 168b81fd263SSubhransu S. Prusty 169b81fd263SSubhransu S. Prusty enum skl_ipc_msg_direction { 170b81fd263SSubhransu S. Prusty IPC_MSG_REQUEST = 0, 171b81fd263SSubhransu S. Prusty IPC_MSG_REPLY = 1 172b81fd263SSubhransu S. Prusty }; 173b81fd263SSubhransu S. Prusty 174b81fd263SSubhransu S. Prusty /* Global Message Types */ 175b81fd263SSubhransu S. Prusty enum skl_ipc_glb_type { 176b81fd263SSubhransu S. Prusty IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */ 177b81fd263SSubhransu S. Prusty IPC_GLB_LOAD_MULTIPLE_MODS = 15, 178b81fd263SSubhransu S. Prusty IPC_GLB_UNLOAD_MULTIPLE_MODS = 16, 179b81fd263SSubhransu S. Prusty IPC_GLB_CREATE_PPL = 17, 180b81fd263SSubhransu S. Prusty IPC_GLB_DELETE_PPL = 18, 181b81fd263SSubhransu S. Prusty IPC_GLB_SET_PPL_STATE = 19, 182b81fd263SSubhransu S. Prusty IPC_GLB_GET_PPL_STATE = 20, 183b81fd263SSubhransu S. Prusty IPC_GLB_GET_PPL_CONTEXT_SIZE = 21, 184b81fd263SSubhransu S. Prusty IPC_GLB_SAVE_PPL = 22, 185b81fd263SSubhransu S. Prusty IPC_GLB_RESTORE_PPL = 23, 186b81fd263SSubhransu S. Prusty IPC_GLB_NOTIFY = 26, 187b81fd263SSubhransu S. Prusty IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */ 188b81fd263SSubhransu S. Prusty }; 189b81fd263SSubhransu S. Prusty 190b81fd263SSubhransu S. Prusty enum skl_ipc_glb_reply { 191b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_SUCCESS = 0, 192b81fd263SSubhransu S. Prusty 193b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_UNKNOWN_MSG_TYPE = 1, 194b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_ERROR_INVALID_PARAM = 2, 195b81fd263SSubhransu S. Prusty 196b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_BUSY = 3, 197b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_PENDING = 4, 198b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_FAILURE = 5, 199b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_INVALID_REQUEST = 6, 200b81fd263SSubhransu S. Prusty 201b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_OUT_OF_MEMORY = 7, 202b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_OUT_OF_MIPS = 8, 203b81fd263SSubhransu S. Prusty 204b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_INVALID_RESOURCE_ID = 9, 205b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_INVALID_RESOURCE_STATE = 10, 206b81fd263SSubhransu S. Prusty 207b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_MOD_MGMT_ERROR = 100, 208b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_MOD_LOAD_CL_FAILED = 101, 209b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_MOD_LOAD_INVALID_HASH = 102, 210b81fd263SSubhransu S. Prusty 211b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_MOD_UNLOAD_INST_EXIST = 103, 212b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_MOD_NOT_INITIALIZED = 104, 213b81fd263SSubhransu S. Prusty 214b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_INVALID_CONFIG_PARAM_ID = 120, 215b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121, 216b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140, 217b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141, 218b81fd263SSubhransu S. Prusty 219b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160, 220b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_PPL_NOT_EXIST = 161, 221b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_PPL_SAVE_FAILED = 162, 222b81fd263SSubhransu S. Prusty IPC_GLB_REPLY_PPL_RESTORE_FAILED = 163, 223b81fd263SSubhransu S. Prusty 224b81fd263SSubhransu S. Prusty IPC_MAX_STATUS = ((1<<IPC_IXC_STATUS_BITS)-1) 225b81fd263SSubhransu S. Prusty }; 226b81fd263SSubhransu S. Prusty 227b81fd263SSubhransu S. Prusty enum skl_ipc_notification_type { 228b81fd263SSubhransu S. Prusty IPC_GLB_NOTIFY_GLITCH = 0, 229b81fd263SSubhransu S. Prusty IPC_GLB_NOTIFY_OVERRUN = 1, 230b81fd263SSubhransu S. Prusty IPC_GLB_NOTIFY_UNDERRUN = 2, 231b81fd263SSubhransu S. Prusty IPC_GLB_NOTIFY_END_STREAM = 3, 232b81fd263SSubhransu S. Prusty IPC_GLB_NOTIFY_PHRASE_DETECTED = 4, 233b81fd263SSubhransu S. Prusty IPC_GLB_NOTIFY_RESOURCE_EVENT = 5, 234b81fd263SSubhransu S. Prusty IPC_GLB_NOTIFY_LOG_BUFFER_STATUS = 6, 235b81fd263SSubhransu S. Prusty IPC_GLB_NOTIFY_TIMESTAMP_CAPTURED = 7, 236b81fd263SSubhransu S. Prusty IPC_GLB_NOTIFY_FW_READY = 8 237b81fd263SSubhransu S. Prusty }; 238b81fd263SSubhransu S. Prusty 239b81fd263SSubhransu S. Prusty /* Module Message Types */ 240b81fd263SSubhransu S. Prusty enum skl_ipc_module_msg { 241b81fd263SSubhransu S. Prusty IPC_MOD_INIT_INSTANCE = 0, 242b81fd263SSubhransu S. Prusty IPC_MOD_CONFIG_GET = 1, 243b81fd263SSubhransu S. Prusty IPC_MOD_CONFIG_SET = 2, 244b81fd263SSubhransu S. Prusty IPC_MOD_LARGE_CONFIG_GET = 3, 245b81fd263SSubhransu S. Prusty IPC_MOD_LARGE_CONFIG_SET = 4, 246b81fd263SSubhransu S. Prusty IPC_MOD_BIND = 5, 247b81fd263SSubhransu S. Prusty IPC_MOD_UNBIND = 6, 248b81fd263SSubhransu S. Prusty IPC_MOD_SET_DX = 7 249b81fd263SSubhransu S. Prusty }; 250b81fd263SSubhransu S. Prusty 251b81fd263SSubhransu S. Prusty static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data, 252b81fd263SSubhransu S. Prusty size_t tx_size) 253b81fd263SSubhransu S. Prusty { 254b81fd263SSubhransu S. Prusty if (tx_size) 255b81fd263SSubhransu S. Prusty memcpy(msg->tx_data, tx_data, tx_size); 256b81fd263SSubhransu S. Prusty } 257b81fd263SSubhransu S. Prusty 258b81fd263SSubhransu S. Prusty static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp) 259b81fd263SSubhransu S. Prusty { 260b81fd263SSubhransu S. Prusty u32 hipci; 261b81fd263SSubhransu S. Prusty 262b81fd263SSubhransu S. Prusty hipci = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCI); 263b81fd263SSubhransu S. Prusty return (hipci & SKL_ADSP_REG_HIPCI_BUSY); 264b81fd263SSubhransu S. Prusty } 265b81fd263SSubhransu S. Prusty 266b81fd263SSubhransu S. Prusty /* Lock to be held by caller */ 267b81fd263SSubhransu S. Prusty static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) 268b81fd263SSubhransu S. Prusty { 269b81fd263SSubhransu S. Prusty struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header); 270b81fd263SSubhransu S. Prusty 271b81fd263SSubhransu S. Prusty if (msg->tx_size) 272b81fd263SSubhransu S. Prusty sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); 273b81fd263SSubhransu S. Prusty sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCIE, 274b81fd263SSubhransu S. Prusty header->extension); 275b81fd263SSubhransu S. Prusty sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCI, 276b81fd263SSubhransu S. Prusty header->primary | SKL_ADSP_REG_HIPCI_BUSY); 277b81fd263SSubhransu S. Prusty } 278b81fd263SSubhransu S. Prusty 279b81fd263SSubhransu S. Prusty static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc, 280b81fd263SSubhransu S. Prusty u64 ipc_header) 281b81fd263SSubhransu S. Prusty { 282b81fd263SSubhransu S. Prusty struct ipc_message *msg = NULL; 283b81fd263SSubhransu S. Prusty struct skl_ipc_header *header = (struct skl_ipc_header *)(&ipc_header); 284b81fd263SSubhransu S. Prusty 285b81fd263SSubhransu S. Prusty if (list_empty(&ipc->rx_list)) { 286b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "ipc: rx list is empty but received 0x%x\n", 287b81fd263SSubhransu S. Prusty header->primary); 288b81fd263SSubhransu S. Prusty goto out; 289b81fd263SSubhransu S. Prusty } 290b81fd263SSubhransu S. Prusty 291b81fd263SSubhransu S. Prusty msg = list_first_entry(&ipc->rx_list, struct ipc_message, list); 292b81fd263SSubhransu S. Prusty 293b81fd263SSubhransu S. Prusty out: 294b81fd263SSubhransu S. Prusty return msg; 295b81fd263SSubhransu S. Prusty 296b81fd263SSubhransu S. Prusty } 297b81fd263SSubhransu S. Prusty 298b81fd263SSubhransu S. Prusty static int skl_ipc_process_notification(struct sst_generic_ipc *ipc, 299b81fd263SSubhransu S. Prusty struct skl_ipc_header header) 300b81fd263SSubhransu S. Prusty { 301b81fd263SSubhransu S. Prusty struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); 302b81fd263SSubhransu S. Prusty 303b81fd263SSubhransu S. Prusty if (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { 304b81fd263SSubhransu S. Prusty switch (IPC_GLB_NOTIFY_TYPE(header.primary)) { 305b81fd263SSubhransu S. Prusty 306b81fd263SSubhransu S. Prusty case IPC_GLB_NOTIFY_UNDERRUN: 307b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "FW Underrun %x\n", header.primary); 308b81fd263SSubhransu S. Prusty break; 309b81fd263SSubhransu S. Prusty 310b81fd263SSubhransu S. Prusty case IPC_GLB_NOTIFY_RESOURCE_EVENT: 311b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "MCPS Budget Violation: %x\n", 312b81fd263SSubhransu S. Prusty header.primary); 313b81fd263SSubhransu S. Prusty break; 314b81fd263SSubhransu S. Prusty 315b81fd263SSubhransu S. Prusty case IPC_GLB_NOTIFY_FW_READY: 316b81fd263SSubhransu S. Prusty skl->boot_complete = true; 317b81fd263SSubhransu S. Prusty wake_up(&skl->boot_wait); 318b81fd263SSubhransu S. Prusty break; 319b81fd263SSubhransu S. Prusty 320b81fd263SSubhransu S. Prusty default: 321b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "ipc: Unhandled error msg=%x", 322b81fd263SSubhransu S. Prusty header.primary); 323b81fd263SSubhransu S. Prusty break; 324b81fd263SSubhransu S. Prusty } 325b81fd263SSubhransu S. Prusty } 326b81fd263SSubhransu S. Prusty 327b81fd263SSubhransu S. Prusty return 0; 328b81fd263SSubhransu S. Prusty } 329b81fd263SSubhransu S. Prusty 330b81fd263SSubhransu S. Prusty static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, 331b81fd263SSubhransu S. Prusty struct skl_ipc_header header) 332b81fd263SSubhransu S. Prusty { 333b81fd263SSubhransu S. Prusty struct ipc_message *msg; 334b81fd263SSubhransu S. Prusty u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; 335b81fd263SSubhransu S. Prusty u64 *ipc_header = (u64 *)(&header); 336b81fd263SSubhransu S. Prusty 337b81fd263SSubhransu S. Prusty msg = skl_ipc_reply_get_msg(ipc, *ipc_header); 338b81fd263SSubhransu S. Prusty if (msg == NULL) { 339b81fd263SSubhransu S. Prusty dev_dbg(ipc->dev, "ipc: rx list is empty\n"); 340b81fd263SSubhransu S. Prusty return; 341b81fd263SSubhransu S. Prusty } 342b81fd263SSubhransu S. Prusty 343b81fd263SSubhransu S. Prusty /* first process the header */ 344b81fd263SSubhransu S. Prusty switch (reply) { 345b81fd263SSubhransu S. Prusty case IPC_GLB_REPLY_SUCCESS: 346b81fd263SSubhransu S. Prusty dev_info(ipc->dev, "ipc FW reply %x: success\n", header.primary); 347b81fd263SSubhransu S. Prusty break; 348b81fd263SSubhransu S. Prusty 349b81fd263SSubhransu S. Prusty case IPC_GLB_REPLY_OUT_OF_MEMORY: 350b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "ipc fw reply: %x: no memory\n", header.primary); 351b81fd263SSubhransu S. Prusty msg->errno = -ENOMEM; 352b81fd263SSubhransu S. Prusty break; 353b81fd263SSubhransu S. Prusty 354b81fd263SSubhransu S. Prusty case IPC_GLB_REPLY_BUSY: 355b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "ipc fw reply: %x: Busy\n", header.primary); 356b81fd263SSubhransu S. Prusty msg->errno = -EBUSY; 357b81fd263SSubhransu S. Prusty break; 358b81fd263SSubhransu S. Prusty 359b81fd263SSubhransu S. Prusty default: 360b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "Unknown ipc reply: 0x%x", reply); 361b81fd263SSubhransu S. Prusty msg->errno = -EINVAL; 362b81fd263SSubhransu S. Prusty break; 363b81fd263SSubhransu S. Prusty } 364b81fd263SSubhransu S. Prusty 36528f3b6f1SOmair M Abdullah if (reply != IPC_GLB_REPLY_SUCCESS) { 36628f3b6f1SOmair M Abdullah dev_err(ipc->dev, "ipc FW reply: reply=%d", reply); 36728f3b6f1SOmair M Abdullah dev_err(ipc->dev, "FW Error Code: %u\n", 36828f3b6f1SOmair M Abdullah ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); 36928f3b6f1SOmair M Abdullah } 37028f3b6f1SOmair M Abdullah 371b81fd263SSubhransu S. Prusty list_del(&msg->list); 372b81fd263SSubhransu S. Prusty sst_ipc_tx_msg_reply_complete(ipc, msg); 373b81fd263SSubhransu S. Prusty } 374b81fd263SSubhransu S. Prusty 375b81fd263SSubhransu S. Prusty irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) 376b81fd263SSubhransu S. Prusty { 377b81fd263SSubhransu S. Prusty struct sst_dsp *dsp = context; 378b81fd263SSubhransu S. Prusty struct skl_sst *skl = sst_dsp_get_thread_context(dsp); 379b81fd263SSubhransu S. Prusty struct sst_generic_ipc *ipc = &skl->ipc; 380b81fd263SSubhransu S. Prusty struct skl_ipc_header header = {0}; 381b81fd263SSubhransu S. Prusty u32 hipcie, hipct, hipcte; 382b81fd263SSubhransu S. Prusty int ipc_irq = 0; 383b81fd263SSubhransu S. Prusty 3846cb00333SSubhransu S. Prusty if (dsp->intr_status & SKL_ADSPIS_CL_DMA) 3856cb00333SSubhransu S. Prusty skl_cldma_process_intr(dsp); 3866cb00333SSubhransu S. Prusty 387b81fd263SSubhransu S. Prusty /* Here we handle IPC interrupts only */ 388b81fd263SSubhransu S. Prusty if (!(dsp->intr_status & SKL_ADSPIS_IPC)) 389b81fd263SSubhransu S. Prusty return IRQ_NONE; 390b81fd263SSubhransu S. Prusty 391b81fd263SSubhransu S. Prusty hipcie = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCIE); 392b81fd263SSubhransu S. Prusty hipct = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCT); 393b81fd263SSubhransu S. Prusty 394b81fd263SSubhransu S. Prusty /* reply message from DSP */ 395b81fd263SSubhransu S. Prusty if (hipcie & SKL_ADSP_REG_HIPCIE_DONE) { 396b81fd263SSubhransu S. Prusty sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, 397b81fd263SSubhransu S. Prusty SKL_ADSP_REG_HIPCCTL_DONE, 0); 398b81fd263SSubhransu S. Prusty 399b81fd263SSubhransu S. Prusty /* clear DONE bit - tell DSP we have completed the operation */ 400b81fd263SSubhransu S. Prusty sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCIE, 401b81fd263SSubhransu S. Prusty SKL_ADSP_REG_HIPCIE_DONE, SKL_ADSP_REG_HIPCIE_DONE); 402b81fd263SSubhransu S. Prusty 403b81fd263SSubhransu S. Prusty ipc_irq = 1; 404b81fd263SSubhransu S. Prusty 405b81fd263SSubhransu S. Prusty /* unmask Done interrupt */ 406b81fd263SSubhransu S. Prusty sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, 407b81fd263SSubhransu S. Prusty SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); 408b81fd263SSubhransu S. Prusty } 409b81fd263SSubhransu S. Prusty 410b81fd263SSubhransu S. Prusty /* New message from DSP */ 411b81fd263SSubhransu S. Prusty if (hipct & SKL_ADSP_REG_HIPCT_BUSY) { 412b81fd263SSubhransu S. Prusty hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE); 413b81fd263SSubhransu S. Prusty header.primary = hipct; 414b81fd263SSubhransu S. Prusty header.extension = hipcte; 415b81fd263SSubhransu S. Prusty dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x", 416b81fd263SSubhransu S. Prusty header.primary); 417b81fd263SSubhransu S. Prusty dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x", 418b81fd263SSubhransu S. Prusty header.extension); 419b81fd263SSubhransu S. Prusty 420b81fd263SSubhransu S. Prusty if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { 421b81fd263SSubhransu S. Prusty /* Handle Immediate reply from DSP Core */ 422b81fd263SSubhransu S. Prusty skl_ipc_process_reply(ipc, header); 423b81fd263SSubhransu S. Prusty } else { 424b81fd263SSubhransu S. Prusty dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n"); 425b81fd263SSubhransu S. Prusty skl_ipc_process_notification(ipc, header); 426b81fd263SSubhransu S. Prusty } 427b81fd263SSubhransu S. Prusty /* clear busy interrupt */ 428b81fd263SSubhransu S. Prusty sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCT, 429b81fd263SSubhransu S. Prusty SKL_ADSP_REG_HIPCT_BUSY, SKL_ADSP_REG_HIPCT_BUSY); 430b81fd263SSubhransu S. Prusty ipc_irq = 1; 431b81fd263SSubhransu S. Prusty } 432b81fd263SSubhransu S. Prusty 433b81fd263SSubhransu S. Prusty if (ipc_irq == 0) 434b81fd263SSubhransu S. Prusty return IRQ_NONE; 435b81fd263SSubhransu S. Prusty 436b81fd263SSubhransu S. Prusty skl_ipc_int_enable(dsp); 437b81fd263SSubhransu S. Prusty 438b81fd263SSubhransu S. Prusty /* continue to send any remaining messages... */ 439b81fd263SSubhransu S. Prusty queue_kthread_work(&ipc->kworker, &ipc->kwork); 440b81fd263SSubhransu S. Prusty 441b81fd263SSubhransu S. Prusty return IRQ_HANDLED; 442b81fd263SSubhransu S. Prusty } 443b81fd263SSubhransu S. Prusty 444b81fd263SSubhransu S. Prusty void skl_ipc_int_enable(struct sst_dsp *ctx) 445b81fd263SSubhransu S. Prusty { 446b81fd263SSubhransu S. Prusty sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_ADSPIC, 447b81fd263SSubhransu S. Prusty SKL_ADSPIC_IPC, SKL_ADSPIC_IPC); 448b81fd263SSubhransu S. Prusty } 449b81fd263SSubhransu S. Prusty 450b81fd263SSubhransu S. Prusty void skl_ipc_int_disable(struct sst_dsp *ctx) 451b81fd263SSubhransu S. Prusty { 452b81fd263SSubhransu S. Prusty sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC, 453b81fd263SSubhransu S. Prusty SKL_ADSPIC_IPC, 0); 454b81fd263SSubhransu S. Prusty } 455b81fd263SSubhransu S. Prusty 456b81fd263SSubhransu S. Prusty void skl_ipc_op_int_enable(struct sst_dsp *ctx) 457b81fd263SSubhransu S. Prusty { 458b81fd263SSubhransu S. Prusty /* enable IPC DONE interrupt */ 459b81fd263SSubhransu S. Prusty sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, 460b81fd263SSubhransu S. Prusty SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); 461b81fd263SSubhransu S. Prusty 462b81fd263SSubhransu S. Prusty /* Enable IPC BUSY interrupt */ 463b81fd263SSubhransu S. Prusty sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, 464b81fd263SSubhransu S. Prusty SKL_ADSP_REG_HIPCCTL_BUSY, SKL_ADSP_REG_HIPCCTL_BUSY); 465b81fd263SSubhransu S. Prusty } 466b81fd263SSubhransu S. Prusty 46784c9e283SJeeja KP void skl_ipc_op_int_disable(struct sst_dsp *ctx) 46884c9e283SJeeja KP { 46984c9e283SJeeja KP /* disable IPC DONE interrupt */ 47084c9e283SJeeja KP sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL, 47184c9e283SJeeja KP SKL_ADSP_REG_HIPCCTL_DONE, 0); 47284c9e283SJeeja KP 47384c9e283SJeeja KP /* Disable IPC BUSY interrupt */ 47484c9e283SJeeja KP sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL, 47584c9e283SJeeja KP SKL_ADSP_REG_HIPCCTL_BUSY, 0); 47684c9e283SJeeja KP 47784c9e283SJeeja KP } 47884c9e283SJeeja KP 479b81fd263SSubhransu S. Prusty bool skl_ipc_int_status(struct sst_dsp *ctx) 480b81fd263SSubhransu S. Prusty { 481b81fd263SSubhransu S. Prusty return sst_dsp_shim_read_unlocked(ctx, 482b81fd263SSubhransu S. Prusty SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC; 483b81fd263SSubhransu S. Prusty } 484b81fd263SSubhransu S. Prusty 485b81fd263SSubhransu S. Prusty int skl_ipc_init(struct device *dev, struct skl_sst *skl) 486b81fd263SSubhransu S. Prusty { 487b81fd263SSubhransu S. Prusty struct sst_generic_ipc *ipc; 488b81fd263SSubhransu S. Prusty int err; 489b81fd263SSubhransu S. Prusty 490b81fd263SSubhransu S. Prusty ipc = &skl->ipc; 491b81fd263SSubhransu S. Prusty ipc->dsp = skl->dsp; 492b81fd263SSubhransu S. Prusty ipc->dev = dev; 493b81fd263SSubhransu S. Prusty 494b81fd263SSubhransu S. Prusty ipc->tx_data_max_size = SKL_ADSP_W1_SZ; 495b81fd263SSubhransu S. Prusty ipc->rx_data_max_size = SKL_ADSP_W0_UP_SZ; 496b81fd263SSubhransu S. Prusty 497b81fd263SSubhransu S. Prusty err = sst_ipc_init(ipc); 498b81fd263SSubhransu S. Prusty if (err) 499b81fd263SSubhransu S. Prusty return err; 500b81fd263SSubhransu S. Prusty 501b81fd263SSubhransu S. Prusty ipc->ops.tx_msg = skl_ipc_tx_msg; 502b81fd263SSubhransu S. Prusty ipc->ops.tx_data_copy = skl_ipc_tx_data_copy; 503b81fd263SSubhransu S. Prusty ipc->ops.is_dsp_busy = skl_ipc_is_dsp_busy; 504b81fd263SSubhransu S. Prusty 505b81fd263SSubhransu S. Prusty return 0; 506b81fd263SSubhransu S. Prusty } 507b81fd263SSubhransu S. Prusty 508b81fd263SSubhransu S. Prusty void skl_ipc_free(struct sst_generic_ipc *ipc) 509b81fd263SSubhransu S. Prusty { 510b81fd263SSubhransu S. Prusty /* Disable IPC DONE interrupt */ 511b81fd263SSubhransu S. Prusty sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, 512b81fd263SSubhransu S. Prusty SKL_ADSP_REG_HIPCCTL_DONE, 0); 513b81fd263SSubhransu S. Prusty 514b81fd263SSubhransu S. Prusty /* Disable IPC BUSY interrupt */ 515b81fd263SSubhransu S. Prusty sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, 516b81fd263SSubhransu S. Prusty SKL_ADSP_REG_HIPCCTL_BUSY, 0); 517a750ba5fSSubhransu S. Prusty 518a750ba5fSSubhransu S. Prusty sst_ipc_fini(ipc); 519b81fd263SSubhransu S. Prusty } 520b81fd263SSubhransu S. Prusty 521b81fd263SSubhransu S. Prusty int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, 522b81fd263SSubhransu S. Prusty u16 ppl_mem_size, u8 ppl_type, u8 instance_id) 523b81fd263SSubhransu S. Prusty { 524b81fd263SSubhransu S. Prusty struct skl_ipc_header header = {0}; 525b81fd263SSubhransu S. Prusty u64 *ipc_header = (u64 *)(&header); 526b81fd263SSubhransu S. Prusty int ret; 527b81fd263SSubhransu S. Prusty 528b81fd263SSubhransu S. Prusty header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); 529b81fd263SSubhransu S. Prusty header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 530b81fd263SSubhransu S. Prusty header.primary |= IPC_GLB_TYPE(IPC_GLB_CREATE_PPL); 531b81fd263SSubhransu S. Prusty header.primary |= IPC_INSTANCE_ID(instance_id); 532b81fd263SSubhransu S. Prusty header.primary |= IPC_PPL_TYPE(ppl_type); 533b81fd263SSubhransu S. Prusty header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size); 534b81fd263SSubhransu S. Prusty 535b81fd263SSubhransu S. Prusty dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); 536b81fd263SSubhransu S. Prusty ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); 537b81fd263SSubhransu S. Prusty if (ret < 0) { 538b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret); 539b81fd263SSubhransu S. Prusty return ret; 540b81fd263SSubhransu S. Prusty } 541b81fd263SSubhransu S. Prusty 542b81fd263SSubhransu S. Prusty return ret; 543b81fd263SSubhransu S. Prusty } 544b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_create_pipeline); 545b81fd263SSubhransu S. Prusty 546b81fd263SSubhransu S. Prusty int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) 547b81fd263SSubhransu S. Prusty { 548b81fd263SSubhransu S. Prusty struct skl_ipc_header header = {0}; 549b81fd263SSubhransu S. Prusty u64 *ipc_header = (u64 *)(&header); 550b81fd263SSubhransu S. Prusty int ret; 551b81fd263SSubhransu S. Prusty 552b81fd263SSubhransu S. Prusty header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); 553b81fd263SSubhransu S. Prusty header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 554b81fd263SSubhransu S. Prusty header.primary |= IPC_GLB_TYPE(IPC_GLB_DELETE_PPL); 555b81fd263SSubhransu S. Prusty header.primary |= IPC_INSTANCE_ID(instance_id); 556b81fd263SSubhransu S. Prusty 557b81fd263SSubhransu S. Prusty dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); 558b81fd263SSubhransu S. Prusty ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); 559b81fd263SSubhransu S. Prusty if (ret < 0) { 560b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret); 561b81fd263SSubhransu S. Prusty return ret; 562b81fd263SSubhransu S. Prusty } 563b81fd263SSubhransu S. Prusty 564b81fd263SSubhransu S. Prusty return 0; 565b81fd263SSubhransu S. Prusty } 566b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_delete_pipeline); 567b81fd263SSubhransu S. Prusty 568b81fd263SSubhransu S. Prusty int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, 569b81fd263SSubhransu S. Prusty u8 instance_id, enum skl_ipc_pipeline_state state) 570b81fd263SSubhransu S. Prusty { 571b81fd263SSubhransu S. Prusty struct skl_ipc_header header = {0}; 572b81fd263SSubhransu S. Prusty u64 *ipc_header = (u64 *)(&header); 573b81fd263SSubhransu S. Prusty int ret; 574b81fd263SSubhransu S. Prusty 575b81fd263SSubhransu S. Prusty header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); 576b81fd263SSubhransu S. Prusty header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 577b81fd263SSubhransu S. Prusty header.primary |= IPC_GLB_TYPE(IPC_GLB_SET_PPL_STATE); 578b81fd263SSubhransu S. Prusty header.primary |= IPC_INSTANCE_ID(instance_id); 579b81fd263SSubhransu S. Prusty header.primary |= IPC_PPL_STATE(state); 580b81fd263SSubhransu S. Prusty 581b81fd263SSubhransu S. Prusty dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); 582b81fd263SSubhransu S. Prusty ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); 583b81fd263SSubhransu S. Prusty if (ret < 0) { 584b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret); 585b81fd263SSubhransu S. Prusty return ret; 586b81fd263SSubhransu S. Prusty } 587b81fd263SSubhransu S. Prusty return ret; 588b81fd263SSubhransu S. Prusty } 589b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_set_pipeline_state); 590b81fd263SSubhransu S. Prusty 591b81fd263SSubhransu S. Prusty int 592b81fd263SSubhransu S. Prusty skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id) 593b81fd263SSubhransu S. Prusty { 594b81fd263SSubhransu S. Prusty struct skl_ipc_header header = {0}; 595b81fd263SSubhransu S. Prusty u64 *ipc_header = (u64 *)(&header); 596b81fd263SSubhransu S. Prusty int ret; 597b81fd263SSubhransu S. Prusty 598b81fd263SSubhransu S. Prusty header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); 599b81fd263SSubhransu S. Prusty header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 600b81fd263SSubhransu S. Prusty header.primary |= IPC_GLB_TYPE(IPC_GLB_SAVE_PPL); 601b81fd263SSubhransu S. Prusty header.primary |= IPC_INSTANCE_ID(instance_id); 602b81fd263SSubhransu S. Prusty 603b81fd263SSubhransu S. Prusty header.extension = IPC_DMA_ID(dma_id); 604b81fd263SSubhransu S. Prusty dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); 605b81fd263SSubhransu S. Prusty ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); 606b81fd263SSubhransu S. Prusty if (ret < 0) { 607b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret); 608b81fd263SSubhransu S. Prusty return ret; 609b81fd263SSubhransu S. Prusty } 610b81fd263SSubhransu S. Prusty 611b81fd263SSubhransu S. Prusty return ret; 612b81fd263SSubhransu S. Prusty } 613b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_save_pipeline); 614b81fd263SSubhransu S. Prusty 615b81fd263SSubhransu S. Prusty int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) 616b81fd263SSubhransu S. Prusty { 617b81fd263SSubhransu S. Prusty struct skl_ipc_header header = {0}; 618b81fd263SSubhransu S. Prusty u64 *ipc_header = (u64 *)(&header); 619b81fd263SSubhransu S. Prusty int ret; 620b81fd263SSubhransu S. Prusty 621b81fd263SSubhransu S. Prusty header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); 622b81fd263SSubhransu S. Prusty header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 623b81fd263SSubhransu S. Prusty header.primary |= IPC_GLB_TYPE(IPC_GLB_RESTORE_PPL); 624b81fd263SSubhransu S. Prusty header.primary |= IPC_INSTANCE_ID(instance_id); 625b81fd263SSubhransu S. Prusty 626b81fd263SSubhransu S. Prusty dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); 627b81fd263SSubhransu S. Prusty ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); 628b81fd263SSubhransu S. Prusty if (ret < 0) { 629b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "ipc: restore pipeline failed, err: %d\n", ret); 630b81fd263SSubhransu S. Prusty return ret; 631b81fd263SSubhransu S. Prusty } 632b81fd263SSubhransu S. Prusty 633b81fd263SSubhransu S. Prusty return ret; 634b81fd263SSubhransu S. Prusty } 635b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_restore_pipeline); 636b81fd263SSubhransu S. Prusty 637b81fd263SSubhransu S. Prusty int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, 638b81fd263SSubhransu S. Prusty u16 module_id, struct skl_ipc_dxstate_info *dx) 639b81fd263SSubhransu S. Prusty { 640b81fd263SSubhransu S. Prusty struct skl_ipc_header header = {0}; 641b81fd263SSubhransu S. Prusty u64 *ipc_header = (u64 *)(&header); 642b81fd263SSubhransu S. Prusty int ret; 643b81fd263SSubhransu S. Prusty 644b81fd263SSubhransu S. Prusty header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); 645b81fd263SSubhransu S. Prusty header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 646b81fd263SSubhransu S. Prusty header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_DX); 647b81fd263SSubhransu S. Prusty header.primary |= IPC_MOD_INSTANCE_ID(instance_id); 648b81fd263SSubhransu S. Prusty header.primary |= IPC_MOD_ID(module_id); 649b81fd263SSubhransu S. Prusty 650b81fd263SSubhransu S. Prusty dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, 651b81fd263SSubhransu S. Prusty header.primary, header.extension); 652b81fd263SSubhransu S. Prusty ret = sst_ipc_tx_message_wait(ipc, *ipc_header, 653b81fd263SSubhransu S. Prusty dx, sizeof(dx), NULL, 0); 654b81fd263SSubhransu S. Prusty if (ret < 0) { 655b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret); 656b81fd263SSubhransu S. Prusty return ret; 657b81fd263SSubhransu S. Prusty } 658b81fd263SSubhransu S. Prusty 659b81fd263SSubhransu S. Prusty return ret; 660b81fd263SSubhransu S. Prusty } 661b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_set_dx); 662b81fd263SSubhransu S. Prusty 663b81fd263SSubhransu S. Prusty int skl_ipc_init_instance(struct sst_generic_ipc *ipc, 664b81fd263SSubhransu S. Prusty struct skl_ipc_init_instance_msg *msg, void *param_data) 665b81fd263SSubhransu S. Prusty { 666b81fd263SSubhransu S. Prusty struct skl_ipc_header header = {0}; 667b81fd263SSubhransu S. Prusty u64 *ipc_header = (u64 *)(&header); 668b81fd263SSubhransu S. Prusty int ret; 669b81fd263SSubhransu S. Prusty u32 *buffer = (u32 *)param_data; 670b81fd263SSubhransu S. Prusty /* param_block_size must be in dwords */ 671b81fd263SSubhransu S. Prusty u16 param_block_size = msg->param_data_size / sizeof(u32); 672b81fd263SSubhransu S. Prusty 673b81fd263SSubhransu S. Prusty print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE, 674b81fd263SSubhransu S. Prusty 16, 4, buffer, param_block_size, false); 675b81fd263SSubhransu S. Prusty 676b81fd263SSubhransu S. Prusty header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); 677b81fd263SSubhransu S. Prusty header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 678b81fd263SSubhransu S. Prusty header.primary |= IPC_GLB_TYPE(IPC_MOD_INIT_INSTANCE); 679b81fd263SSubhransu S. Prusty header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); 680b81fd263SSubhransu S. Prusty header.primary |= IPC_MOD_ID(msg->module_id); 681b81fd263SSubhransu S. Prusty 682b81fd263SSubhransu S. Prusty header.extension = IPC_CORE_ID(msg->core_id); 683b81fd263SSubhransu S. Prusty header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id); 684b81fd263SSubhransu S. Prusty header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size); 685b81fd263SSubhransu S. Prusty 686b81fd263SSubhransu S. Prusty dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, 687b81fd263SSubhransu S. Prusty header.primary, header.extension); 688b81fd263SSubhransu S. Prusty ret = sst_ipc_tx_message_wait(ipc, *ipc_header, param_data, 689b81fd263SSubhransu S. Prusty msg->param_data_size, NULL, 0); 690b81fd263SSubhransu S. Prusty 691b81fd263SSubhransu S. Prusty if (ret < 0) { 692b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "ipc: init instance failed\n"); 693b81fd263SSubhransu S. Prusty return ret; 694b81fd263SSubhransu S. Prusty } 695b81fd263SSubhransu S. Prusty 696b81fd263SSubhransu S. Prusty return ret; 697b81fd263SSubhransu S. Prusty } 698b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_init_instance); 699b81fd263SSubhransu S. Prusty 700b81fd263SSubhransu S. Prusty int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, 701b81fd263SSubhransu S. Prusty struct skl_ipc_bind_unbind_msg *msg) 702b81fd263SSubhransu S. Prusty { 703b81fd263SSubhransu S. Prusty struct skl_ipc_header header = {0}; 704b81fd263SSubhransu S. Prusty u64 *ipc_header = (u64 *)(&header); 705b81fd263SSubhransu S. Prusty u8 bind_unbind = msg->bind ? IPC_MOD_BIND : IPC_MOD_UNBIND; 706b81fd263SSubhransu S. Prusty int ret; 707b81fd263SSubhransu S. Prusty 708b81fd263SSubhransu S. Prusty header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); 709b81fd263SSubhransu S. Prusty header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 710b81fd263SSubhransu S. Prusty header.primary |= IPC_GLB_TYPE(bind_unbind); 711b81fd263SSubhransu S. Prusty header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); 712b81fd263SSubhransu S. Prusty header.primary |= IPC_MOD_ID(msg->module_id); 713b81fd263SSubhransu S. Prusty 714b81fd263SSubhransu S. Prusty header.extension = IPC_DST_MOD_ID(msg->dst_module_id); 715b81fd263SSubhransu S. Prusty header.extension |= IPC_DST_MOD_INSTANCE_ID(msg->dst_instance_id); 716b81fd263SSubhransu S. Prusty header.extension |= IPC_DST_QUEUE(msg->dst_queue); 717b81fd263SSubhransu S. Prusty header.extension |= IPC_SRC_QUEUE(msg->src_queue); 718b81fd263SSubhransu S. Prusty 719b81fd263SSubhransu S. Prusty dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary, 720b81fd263SSubhransu S. Prusty header.extension); 721b81fd263SSubhransu S. Prusty ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); 722b81fd263SSubhransu S. Prusty if (ret < 0) { 723b81fd263SSubhransu S. Prusty dev_err(ipc->dev, "ipc: bind/unbind faileden"); 724b81fd263SSubhransu S. Prusty return ret; 725b81fd263SSubhransu S. Prusty } 726b81fd263SSubhransu S. Prusty 727b81fd263SSubhransu S. Prusty return ret; 728b81fd263SSubhransu S. Prusty } 729b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind); 730b81fd263SSubhransu S. Prusty 731b81fd263SSubhransu S. Prusty int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, 732b81fd263SSubhransu S. Prusty struct skl_ipc_large_config_msg *msg, u32 *param) 733b81fd263SSubhransu S. Prusty { 734b81fd263SSubhransu S. Prusty struct skl_ipc_header header = {0}; 735b81fd263SSubhransu S. Prusty u64 *ipc_header = (u64 *)(&header); 736b81fd263SSubhransu S. Prusty int ret = 0; 737b81fd263SSubhransu S. Prusty size_t sz_remaining, tx_size, data_offset; 738b81fd263SSubhransu S. Prusty 739b81fd263SSubhransu S. Prusty header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); 740b81fd263SSubhransu S. Prusty header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 741b81fd263SSubhransu S. Prusty header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_SET); 742b81fd263SSubhransu S. Prusty header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); 743b81fd263SSubhransu S. Prusty header.primary |= IPC_MOD_ID(msg->module_id); 744b81fd263SSubhransu S. Prusty 745b81fd263SSubhransu S. Prusty header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size); 746b81fd263SSubhransu S. Prusty header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id); 747b81fd263SSubhransu S. Prusty header.extension |= IPC_FINAL_BLOCK(0); 748b81fd263SSubhransu S. Prusty header.extension |= IPC_INITIAL_BLOCK(1); 749b81fd263SSubhransu S. Prusty 750b81fd263SSubhransu S. Prusty sz_remaining = msg->param_data_size; 751b81fd263SSubhransu S. Prusty data_offset = 0; 752b81fd263SSubhransu S. Prusty while (sz_remaining != 0) { 753b81fd263SSubhransu S. Prusty tx_size = sz_remaining > SKL_ADSP_W1_SZ 754b81fd263SSubhransu S. Prusty ? SKL_ADSP_W1_SZ : sz_remaining; 755b81fd263SSubhransu S. Prusty if (tx_size == sz_remaining) 756b81fd263SSubhransu S. Prusty header.extension |= IPC_FINAL_BLOCK(1); 757b81fd263SSubhransu S. Prusty 758b81fd263SSubhransu S. Prusty dev_dbg(ipc->dev, "In %s primary=%#x ext=%#x\n", __func__, 759b81fd263SSubhransu S. Prusty header.primary, header.extension); 760b81fd263SSubhransu S. Prusty dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n", 761b81fd263SSubhransu S. Prusty (unsigned)data_offset, (unsigned)tx_size); 762b81fd263SSubhransu S. Prusty ret = sst_ipc_tx_message_wait(ipc, *ipc_header, 763b81fd263SSubhransu S. Prusty ((char *)param) + data_offset, 764b81fd263SSubhransu S. Prusty tx_size, NULL, 0); 765b81fd263SSubhransu S. Prusty if (ret < 0) { 766b81fd263SSubhransu S. Prusty dev_err(ipc->dev, 767b81fd263SSubhransu S. Prusty "ipc: set large config fail, err: %d\n", ret); 768b81fd263SSubhransu S. Prusty return ret; 769b81fd263SSubhransu S. Prusty } 770b81fd263SSubhransu S. Prusty sz_remaining -= tx_size; 771b81fd263SSubhransu S. Prusty data_offset = msg->param_data_size - sz_remaining; 772b81fd263SSubhransu S. Prusty 773b81fd263SSubhransu S. Prusty /* clear the fields */ 774b81fd263SSubhransu S. Prusty header.extension &= IPC_INITIAL_BLOCK_CLEAR; 775b81fd263SSubhransu S. Prusty header.extension &= IPC_DATA_OFFSET_SZ_CLEAR; 776b81fd263SSubhransu S. Prusty /* fill the fields */ 777b81fd263SSubhransu S. Prusty header.extension |= IPC_INITIAL_BLOCK(0); 778b81fd263SSubhransu S. Prusty header.extension |= IPC_DATA_OFFSET_SZ(data_offset); 779b81fd263SSubhransu S. Prusty } 780b81fd263SSubhransu S. Prusty 781b81fd263SSubhransu S. Prusty return ret; 782b81fd263SSubhransu S. Prusty } 783b81fd263SSubhransu S. Prusty EXPORT_SYMBOL_GPL(skl_ipc_set_large_config); 784