1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * skl-sst-ipc.c - Intel skl IPC Support 4 * 5 * Copyright (C) 2014-15, Intel Corporation. 6 */ 7 #include <linux/device.h> 8 9 #include "../common/sst-dsp.h" 10 #include "../common/sst-dsp-priv.h" 11 #include "skl.h" 12 #include "skl-sst-dsp.h" 13 #include "skl-sst-ipc.h" 14 #include "sound/hdaudio_ext.h" 15 16 17 #define IPC_IXC_STATUS_BITS 24 18 19 /* Global Message - Generic */ 20 #define IPC_GLB_TYPE_SHIFT 24 21 #define IPC_GLB_TYPE_MASK (0xf << IPC_GLB_TYPE_SHIFT) 22 #define IPC_GLB_TYPE(x) ((x) << IPC_GLB_TYPE_SHIFT) 23 24 /* Global Message - Reply */ 25 #define IPC_GLB_REPLY_STATUS_SHIFT 24 26 #define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1) 27 #define IPC_GLB_REPLY_STATUS(x) ((x) << IPC_GLB_REPLY_STATUS_SHIFT) 28 29 #define IPC_GLB_REPLY_TYPE_SHIFT 29 30 #define IPC_GLB_REPLY_TYPE_MASK 0x1F 31 #define IPC_GLB_REPLY_TYPE(x) (((x) >> IPC_GLB_REPLY_TYPE_SHIFT) \ 32 & IPC_GLB_RPLY_TYPE_MASK) 33 34 #define IPC_TIMEOUT_MSECS 3000 35 36 #define IPC_EMPTY_LIST_SIZE 8 37 38 #define IPC_MSG_TARGET_SHIFT 30 39 #define IPC_MSG_TARGET_MASK 0x1 40 #define IPC_MSG_TARGET(x) (((x) & IPC_MSG_TARGET_MASK) \ 41 << IPC_MSG_TARGET_SHIFT) 42 43 #define IPC_MSG_DIR_SHIFT 29 44 #define IPC_MSG_DIR_MASK 0x1 45 #define IPC_MSG_DIR(x) (((x) & IPC_MSG_DIR_MASK) \ 46 << IPC_MSG_DIR_SHIFT) 47 /* Global Notification Message */ 48 #define IPC_GLB_NOTIFY_TYPE_SHIFT 16 49 #define IPC_GLB_NOTIFY_TYPE_MASK 0xFF 50 #define IPC_GLB_NOTIFY_TYPE(x) (((x) >> IPC_GLB_NOTIFY_TYPE_SHIFT) \ 51 & IPC_GLB_NOTIFY_TYPE_MASK) 52 53 #define IPC_GLB_NOTIFY_MSG_TYPE_SHIFT 24 54 #define IPC_GLB_NOTIFY_MSG_TYPE_MASK 0x1F 55 #define IPC_GLB_NOTIFY_MSG_TYPE(x) (((x) >> IPC_GLB_NOTIFY_MSG_TYPE_SHIFT) \ 56 & IPC_GLB_NOTIFY_MSG_TYPE_MASK) 57 58 #define IPC_GLB_NOTIFY_RSP_SHIFT 29 59 #define IPC_GLB_NOTIFY_RSP_MASK 0x1 60 #define IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> IPC_GLB_NOTIFY_RSP_SHIFT) \ 61 & IPC_GLB_NOTIFY_RSP_MASK) 62 63 /* Pipeline operations */ 64 65 /* Create pipeline message */ 66 #define IPC_PPL_MEM_SIZE_SHIFT 0 67 #define IPC_PPL_MEM_SIZE_MASK 0x7FF 68 #define IPC_PPL_MEM_SIZE(x) (((x) & IPC_PPL_MEM_SIZE_MASK) \ 69 << IPC_PPL_MEM_SIZE_SHIFT) 70 71 #define IPC_PPL_TYPE_SHIFT 11 72 #define IPC_PPL_TYPE_MASK 0x1F 73 #define IPC_PPL_TYPE(x) (((x) & IPC_PPL_TYPE_MASK) \ 74 << IPC_PPL_TYPE_SHIFT) 75 76 #define IPC_INSTANCE_ID_SHIFT 16 77 #define IPC_INSTANCE_ID_MASK 0xFF 78 #define IPC_INSTANCE_ID(x) (((x) & IPC_INSTANCE_ID_MASK) \ 79 << IPC_INSTANCE_ID_SHIFT) 80 81 #define IPC_PPL_LP_MODE_SHIFT 0 82 #define IPC_PPL_LP_MODE_MASK 0x1 83 #define IPC_PPL_LP_MODE(x) (((x) & IPC_PPL_LP_MODE_MASK) \ 84 << IPC_PPL_LP_MODE_SHIFT) 85 86 /* Set pipeline state message */ 87 #define IPC_PPL_STATE_SHIFT 0 88 #define IPC_PPL_STATE_MASK 0x1F 89 #define IPC_PPL_STATE(x) (((x) & IPC_PPL_STATE_MASK) \ 90 << IPC_PPL_STATE_SHIFT) 91 92 /* Module operations primary register */ 93 #define IPC_MOD_ID_SHIFT 0 94 #define IPC_MOD_ID_MASK 0xFFFF 95 #define IPC_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ 96 << IPC_MOD_ID_SHIFT) 97 98 #define IPC_MOD_INSTANCE_ID_SHIFT 16 99 #define IPC_MOD_INSTANCE_ID_MASK 0xFF 100 #define IPC_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ 101 << IPC_MOD_INSTANCE_ID_SHIFT) 102 103 /* Init instance message extension register */ 104 #define IPC_PARAM_BLOCK_SIZE_SHIFT 0 105 #define IPC_PARAM_BLOCK_SIZE_MASK 0xFFFF 106 #define IPC_PARAM_BLOCK_SIZE(x) (((x) & IPC_PARAM_BLOCK_SIZE_MASK) \ 107 << IPC_PARAM_BLOCK_SIZE_SHIFT) 108 109 #define IPC_PPL_INSTANCE_ID_SHIFT 16 110 #define IPC_PPL_INSTANCE_ID_MASK 0xFF 111 #define IPC_PPL_INSTANCE_ID(x) (((x) & IPC_PPL_INSTANCE_ID_MASK) \ 112 << IPC_PPL_INSTANCE_ID_SHIFT) 113 114 #define IPC_CORE_ID_SHIFT 24 115 #define IPC_CORE_ID_MASK 0x1F 116 #define IPC_CORE_ID(x) (((x) & IPC_CORE_ID_MASK) \ 117 << IPC_CORE_ID_SHIFT) 118 119 #define IPC_DOMAIN_SHIFT 28 120 #define IPC_DOMAIN_MASK 0x1 121 #define IPC_DOMAIN(x) (((x) & IPC_DOMAIN_MASK) \ 122 << IPC_DOMAIN_SHIFT) 123 124 /* Bind/Unbind message extension register */ 125 #define IPC_DST_MOD_ID_SHIFT 0 126 #define IPC_DST_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ 127 << IPC_DST_MOD_ID_SHIFT) 128 129 #define IPC_DST_MOD_INSTANCE_ID_SHIFT 16 130 #define IPC_DST_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ 131 << IPC_DST_MOD_INSTANCE_ID_SHIFT) 132 133 #define IPC_DST_QUEUE_SHIFT 24 134 #define IPC_DST_QUEUE_MASK 0x7 135 #define IPC_DST_QUEUE(x) (((x) & IPC_DST_QUEUE_MASK) \ 136 << IPC_DST_QUEUE_SHIFT) 137 138 #define IPC_SRC_QUEUE_SHIFT 27 139 #define IPC_SRC_QUEUE_MASK 0x7 140 #define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \ 141 << IPC_SRC_QUEUE_SHIFT) 142 /* Load Module count */ 143 #define IPC_LOAD_MODULE_SHIFT 0 144 #define IPC_LOAD_MODULE_MASK 0xFF 145 #define IPC_LOAD_MODULE_CNT(x) (((x) & IPC_LOAD_MODULE_MASK) \ 146 << IPC_LOAD_MODULE_SHIFT) 147 148 /* Save pipeline messgae extension register */ 149 #define IPC_DMA_ID_SHIFT 0 150 #define IPC_DMA_ID_MASK 0x1F 151 #define IPC_DMA_ID(x) (((x) & IPC_DMA_ID_MASK) \ 152 << IPC_DMA_ID_SHIFT) 153 /* Large Config message extension register */ 154 #define IPC_DATA_OFFSET_SZ_SHIFT 0 155 #define IPC_DATA_OFFSET_SZ_MASK 0xFFFFF 156 #define IPC_DATA_OFFSET_SZ(x) (((x) & IPC_DATA_OFFSET_SZ_MASK) \ 157 << IPC_DATA_OFFSET_SZ_SHIFT) 158 #define IPC_DATA_OFFSET_SZ_CLEAR ~(IPC_DATA_OFFSET_SZ_MASK \ 159 << IPC_DATA_OFFSET_SZ_SHIFT) 160 161 #define IPC_LARGE_PARAM_ID_SHIFT 20 162 #define IPC_LARGE_PARAM_ID_MASK 0xFF 163 #define IPC_LARGE_PARAM_ID(x) (((x) & IPC_LARGE_PARAM_ID_MASK) \ 164 << IPC_LARGE_PARAM_ID_SHIFT) 165 166 #define IPC_FINAL_BLOCK_SHIFT 28 167 #define IPC_FINAL_BLOCK_MASK 0x1 168 #define IPC_FINAL_BLOCK(x) (((x) & IPC_FINAL_BLOCK_MASK) \ 169 << IPC_FINAL_BLOCK_SHIFT) 170 171 #define IPC_INITIAL_BLOCK_SHIFT 29 172 #define IPC_INITIAL_BLOCK_MASK 0x1 173 #define IPC_INITIAL_BLOCK(x) (((x) & IPC_INITIAL_BLOCK_MASK) \ 174 << IPC_INITIAL_BLOCK_SHIFT) 175 #define IPC_INITIAL_BLOCK_CLEAR ~(IPC_INITIAL_BLOCK_MASK \ 176 << IPC_INITIAL_BLOCK_SHIFT) 177 /* Set D0ix IPC extension register */ 178 #define IPC_D0IX_WAKE_SHIFT 0 179 #define IPC_D0IX_WAKE_MASK 0x1 180 #define IPC_D0IX_WAKE(x) (((x) & IPC_D0IX_WAKE_MASK) \ 181 << IPC_D0IX_WAKE_SHIFT) 182 183 #define IPC_D0IX_STREAMING_SHIFT 1 184 #define IPC_D0IX_STREAMING_MASK 0x1 185 #define IPC_D0IX_STREAMING(x) (((x) & IPC_D0IX_STREAMING_MASK) \ 186 << IPC_D0IX_STREAMING_SHIFT) 187 188 189 enum skl_ipc_msg_target { 190 IPC_FW_GEN_MSG = 0, 191 IPC_MOD_MSG = 1 192 }; 193 194 enum skl_ipc_msg_direction { 195 IPC_MSG_REQUEST = 0, 196 IPC_MSG_REPLY = 1 197 }; 198 199 /* Global Message Types */ 200 enum skl_ipc_glb_type { 201 IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */ 202 IPC_GLB_LOAD_MULTIPLE_MODS = 15, 203 IPC_GLB_UNLOAD_MULTIPLE_MODS = 16, 204 IPC_GLB_CREATE_PPL = 17, 205 IPC_GLB_DELETE_PPL = 18, 206 IPC_GLB_SET_PPL_STATE = 19, 207 IPC_GLB_GET_PPL_STATE = 20, 208 IPC_GLB_GET_PPL_CONTEXT_SIZE = 21, 209 IPC_GLB_SAVE_PPL = 22, 210 IPC_GLB_RESTORE_PPL = 23, 211 IPC_GLB_LOAD_LIBRARY = 24, 212 IPC_GLB_NOTIFY = 26, 213 IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */ 214 }; 215 216 enum skl_ipc_glb_reply { 217 IPC_GLB_REPLY_SUCCESS = 0, 218 219 IPC_GLB_REPLY_UNKNOWN_MSG_TYPE = 1, 220 IPC_GLB_REPLY_ERROR_INVALID_PARAM = 2, 221 222 IPC_GLB_REPLY_BUSY = 3, 223 IPC_GLB_REPLY_PENDING = 4, 224 IPC_GLB_REPLY_FAILURE = 5, 225 IPC_GLB_REPLY_INVALID_REQUEST = 6, 226 227 IPC_GLB_REPLY_OUT_OF_MEMORY = 7, 228 IPC_GLB_REPLY_OUT_OF_MIPS = 8, 229 230 IPC_GLB_REPLY_INVALID_RESOURCE_ID = 9, 231 IPC_GLB_REPLY_INVALID_RESOURCE_STATE = 10, 232 233 IPC_GLB_REPLY_MOD_MGMT_ERROR = 100, 234 IPC_GLB_REPLY_MOD_LOAD_CL_FAILED = 101, 235 IPC_GLB_REPLY_MOD_LOAD_INVALID_HASH = 102, 236 237 IPC_GLB_REPLY_MOD_UNLOAD_INST_EXIST = 103, 238 IPC_GLB_REPLY_MOD_NOT_INITIALIZED = 104, 239 240 IPC_GLB_REPLY_INVALID_CONFIG_PARAM_ID = 120, 241 IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121, 242 IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140, 243 IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141, 244 IPC_GLB_REPLY_SCLK_ALREADY_RUNNING = 150, 245 IPC_GLB_REPLY_MCLK_ALREADY_RUNNING = 151, 246 247 IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160, 248 IPC_GLB_REPLY_PPL_NOT_EXIST = 161, 249 IPC_GLB_REPLY_PPL_SAVE_FAILED = 162, 250 IPC_GLB_REPLY_PPL_RESTORE_FAILED = 163, 251 252 IPC_MAX_STATUS = ((1<<IPC_IXC_STATUS_BITS)-1) 253 }; 254 255 enum skl_ipc_notification_type { 256 IPC_GLB_NOTIFY_GLITCH = 0, 257 IPC_GLB_NOTIFY_OVERRUN = 1, 258 IPC_GLB_NOTIFY_UNDERRUN = 2, 259 IPC_GLB_NOTIFY_END_STREAM = 3, 260 IPC_GLB_NOTIFY_PHRASE_DETECTED = 4, 261 IPC_GLB_NOTIFY_RESOURCE_EVENT = 5, 262 IPC_GLB_NOTIFY_LOG_BUFFER_STATUS = 6, 263 IPC_GLB_NOTIFY_TIMESTAMP_CAPTURED = 7, 264 IPC_GLB_NOTIFY_FW_READY = 8 265 }; 266 267 /* Module Message Types */ 268 enum skl_ipc_module_msg { 269 IPC_MOD_INIT_INSTANCE = 0, 270 IPC_MOD_CONFIG_GET = 1, 271 IPC_MOD_CONFIG_SET = 2, 272 IPC_MOD_LARGE_CONFIG_GET = 3, 273 IPC_MOD_LARGE_CONFIG_SET = 4, 274 IPC_MOD_BIND = 5, 275 IPC_MOD_UNBIND = 6, 276 IPC_MOD_SET_DX = 7, 277 IPC_MOD_SET_D0IX = 8 278 }; 279 280 void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data, 281 size_t tx_size) 282 { 283 if (tx_size) 284 memcpy(msg->tx.data, tx_data, tx_size); 285 } 286 287 static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp) 288 { 289 u32 hipci; 290 291 hipci = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCI); 292 return (hipci & SKL_ADSP_REG_HIPCI_BUSY); 293 } 294 295 /* Lock to be held by caller */ 296 static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) 297 { 298 struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header); 299 300 if (msg->tx.size) 301 sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); 302 sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCIE, 303 header->extension); 304 sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCI, 305 header->primary | SKL_ADSP_REG_HIPCI_BUSY); 306 } 307 308 int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state) 309 { 310 int ret; 311 312 /* check D0i3 support */ 313 if (!dsp->fw_ops.set_state_D0i0) 314 return 0; 315 316 /* Attempt D0i0 or D0i3 based on state */ 317 if (state) 318 ret = dsp->fw_ops.set_state_D0i0(dsp); 319 else 320 ret = dsp->fw_ops.set_state_D0i3(dsp); 321 322 return ret; 323 } 324 325 static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc, 326 u64 ipc_header) 327 { 328 struct ipc_message *msg = NULL; 329 struct skl_ipc_header *header = (struct skl_ipc_header *)(&ipc_header); 330 331 if (list_empty(&ipc->rx_list)) { 332 dev_err(ipc->dev, "ipc: rx list is empty but received 0x%x\n", 333 header->primary); 334 goto out; 335 } 336 337 msg = list_first_entry(&ipc->rx_list, struct ipc_message, list); 338 339 list_del(&msg->list); 340 out: 341 return msg; 342 343 } 344 345 int skl_ipc_process_notification(struct sst_generic_ipc *ipc, 346 struct skl_ipc_header header) 347 { 348 struct skl_dev *skl = container_of(ipc, struct skl_dev, ipc); 349 350 if (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { 351 switch (IPC_GLB_NOTIFY_TYPE(header.primary)) { 352 353 case IPC_GLB_NOTIFY_UNDERRUN: 354 dev_err(ipc->dev, "FW Underrun %x\n", header.primary); 355 break; 356 357 case IPC_GLB_NOTIFY_RESOURCE_EVENT: 358 dev_err(ipc->dev, "MCPS Budget Violation: %x\n", 359 header.primary); 360 break; 361 362 case IPC_GLB_NOTIFY_FW_READY: 363 skl->boot_complete = true; 364 wake_up(&skl->boot_wait); 365 break; 366 367 case IPC_GLB_NOTIFY_PHRASE_DETECTED: 368 dev_dbg(ipc->dev, "***** Phrase Detected **********\n"); 369 370 /* 371 * Per HW recomendation, After phrase detection, 372 * clear the CGCTL.MISCBDCGE. 373 * 374 * This will be set back on stream closure 375 */ 376 skl->enable_miscbdcge(ipc->dev, false); 377 skl->miscbdcg_disabled = true; 378 break; 379 380 default: 381 dev_err(ipc->dev, "ipc: Unhandled error msg=%x\n", 382 header.primary); 383 break; 384 } 385 } 386 387 return 0; 388 } 389 390 struct skl_ipc_err_map { 391 const char *msg; 392 enum skl_ipc_glb_reply reply; 393 int err; 394 }; 395 396 static struct skl_ipc_err_map skl_err_map[] = { 397 {"DSP out of memory", IPC_GLB_REPLY_OUT_OF_MEMORY, -ENOMEM}, 398 {"DSP busy", IPC_GLB_REPLY_BUSY, -EBUSY}, 399 {"SCLK already running", IPC_GLB_REPLY_SCLK_ALREADY_RUNNING, 400 IPC_GLB_REPLY_SCLK_ALREADY_RUNNING}, 401 {"MCLK already running", IPC_GLB_REPLY_MCLK_ALREADY_RUNNING, 402 IPC_GLB_REPLY_MCLK_ALREADY_RUNNING}, 403 }; 404 405 static int skl_ipc_set_reply_error_code(struct sst_generic_ipc *ipc, u32 reply) 406 { 407 int i; 408 409 for (i = 0; i < ARRAY_SIZE(skl_err_map); i++) { 410 if (skl_err_map[i].reply == reply) 411 break; 412 } 413 414 if (i == ARRAY_SIZE(skl_err_map)) { 415 dev_err(ipc->dev, "ipc FW reply: %d FW Error Code: %u\n", 416 reply, 417 ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); 418 return -EINVAL; 419 } 420 421 if (skl_err_map[i].err < 0) 422 dev_err(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n", 423 skl_err_map[i].msg, 424 ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); 425 else 426 dev_info(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n", 427 skl_err_map[i].msg, 428 ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); 429 430 return skl_err_map[i].err; 431 } 432 433 void skl_ipc_process_reply(struct sst_generic_ipc *ipc, 434 struct skl_ipc_header header) 435 { 436 struct ipc_message *msg; 437 u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; 438 u64 *ipc_header = (u64 *)(&header); 439 struct skl_dev *skl = container_of(ipc, struct skl_dev, ipc); 440 unsigned long flags; 441 442 spin_lock_irqsave(&ipc->dsp->spinlock, flags); 443 msg = skl_ipc_reply_get_msg(ipc, *ipc_header); 444 spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); 445 if (msg == NULL) { 446 dev_dbg(ipc->dev, "ipc: rx list is empty\n"); 447 return; 448 } 449 450 msg->rx.header = *ipc_header; 451 /* first process the header */ 452 if (reply == IPC_GLB_REPLY_SUCCESS) { 453 dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary); 454 /* copy the rx data from the mailbox */ 455 sst_dsp_inbox_read(ipc->dsp, msg->rx.data, msg->rx.size); 456 switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { 457 case IPC_GLB_LOAD_MULTIPLE_MODS: 458 case IPC_GLB_LOAD_LIBRARY: 459 skl->mod_load_complete = true; 460 skl->mod_load_status = true; 461 wake_up(&skl->mod_load_wait); 462 break; 463 464 default: 465 break; 466 467 } 468 } else { 469 msg->errno = skl_ipc_set_reply_error_code(ipc, reply); 470 switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { 471 case IPC_GLB_LOAD_MULTIPLE_MODS: 472 case IPC_GLB_LOAD_LIBRARY: 473 skl->mod_load_complete = true; 474 skl->mod_load_status = false; 475 wake_up(&skl->mod_load_wait); 476 break; 477 478 default: 479 break; 480 481 } 482 } 483 484 spin_lock_irqsave(&ipc->dsp->spinlock, flags); 485 sst_ipc_tx_msg_reply_complete(ipc, msg); 486 spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); 487 } 488 489 irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) 490 { 491 struct sst_dsp *dsp = context; 492 struct skl_dev *skl = dsp->thread_context; 493 struct sst_generic_ipc *ipc = &skl->ipc; 494 struct skl_ipc_header header = {0}; 495 u32 hipcie, hipct, hipcte; 496 int ipc_irq = 0; 497 498 if (dsp->intr_status & SKL_ADSPIS_CL_DMA) 499 skl_cldma_process_intr(dsp); 500 501 /* Here we handle IPC interrupts only */ 502 if (!(dsp->intr_status & SKL_ADSPIS_IPC)) 503 return IRQ_NONE; 504 505 hipcie = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCIE); 506 hipct = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCT); 507 hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE); 508 509 /* reply message from DSP */ 510 if (hipcie & SKL_ADSP_REG_HIPCIE_DONE) { 511 sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, 512 SKL_ADSP_REG_HIPCCTL_DONE, 0); 513 514 /* clear DONE bit - tell DSP we have completed the operation */ 515 sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCIE, 516 SKL_ADSP_REG_HIPCIE_DONE, SKL_ADSP_REG_HIPCIE_DONE); 517 518 ipc_irq = 1; 519 520 /* unmask Done interrupt */ 521 sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, 522 SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); 523 } 524 525 /* New message from DSP */ 526 if (hipct & SKL_ADSP_REG_HIPCT_BUSY) { 527 header.primary = hipct; 528 header.extension = hipcte; 529 dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x\n", 530 header.primary); 531 dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x\n", 532 header.extension); 533 534 if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { 535 /* Handle Immediate reply from DSP Core */ 536 skl_ipc_process_reply(ipc, header); 537 } else { 538 dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n"); 539 skl_ipc_process_notification(ipc, header); 540 } 541 /* clear busy interrupt */ 542 sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCT, 543 SKL_ADSP_REG_HIPCT_BUSY, SKL_ADSP_REG_HIPCT_BUSY); 544 ipc_irq = 1; 545 } 546 547 if (ipc_irq == 0) 548 return IRQ_NONE; 549 550 skl_ipc_int_enable(dsp); 551 552 /* continue to send any remaining messages... */ 553 schedule_work(&ipc->kwork); 554 555 return IRQ_HANDLED; 556 } 557 558 void skl_ipc_int_enable(struct sst_dsp *ctx) 559 { 560 sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_ADSPIC, 561 SKL_ADSPIC_IPC, SKL_ADSPIC_IPC); 562 } 563 564 void skl_ipc_int_disable(struct sst_dsp *ctx) 565 { 566 sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC, 567 SKL_ADSPIC_IPC, 0); 568 } 569 570 void skl_ipc_op_int_enable(struct sst_dsp *ctx) 571 { 572 /* enable IPC DONE interrupt */ 573 sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, 574 SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); 575 576 /* Enable IPC BUSY interrupt */ 577 sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, 578 SKL_ADSP_REG_HIPCCTL_BUSY, SKL_ADSP_REG_HIPCCTL_BUSY); 579 } 580 581 void skl_ipc_op_int_disable(struct sst_dsp *ctx) 582 { 583 /* disable IPC DONE interrupt */ 584 sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL, 585 SKL_ADSP_REG_HIPCCTL_DONE, 0); 586 587 /* Disable IPC BUSY interrupt */ 588 sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL, 589 SKL_ADSP_REG_HIPCCTL_BUSY, 0); 590 591 } 592 593 bool skl_ipc_int_status(struct sst_dsp *ctx) 594 { 595 return sst_dsp_shim_read_unlocked(ctx, 596 SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC; 597 } 598 599 int skl_ipc_init(struct device *dev, struct skl_dev *skl) 600 { 601 struct sst_generic_ipc *ipc; 602 int err; 603 604 ipc = &skl->ipc; 605 ipc->dsp = skl->dsp; 606 ipc->dev = dev; 607 608 ipc->tx_data_max_size = SKL_ADSP_W1_SZ; 609 ipc->rx_data_max_size = SKL_ADSP_W0_UP_SZ; 610 611 err = sst_ipc_init(ipc); 612 if (err) 613 return err; 614 615 ipc->ops.tx_msg = skl_ipc_tx_msg; 616 ipc->ops.tx_data_copy = skl_ipc_tx_data_copy; 617 ipc->ops.is_dsp_busy = skl_ipc_is_dsp_busy; 618 619 return 0; 620 } 621 622 void skl_ipc_free(struct sst_generic_ipc *ipc) 623 { 624 /* Disable IPC DONE interrupt */ 625 sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, 626 SKL_ADSP_REG_HIPCCTL_DONE, 0); 627 628 /* Disable IPC BUSY interrupt */ 629 sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, 630 SKL_ADSP_REG_HIPCCTL_BUSY, 0); 631 632 sst_ipc_fini(ipc); 633 } 634 635 int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, 636 u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode) 637 { 638 struct skl_ipc_header header = {0}; 639 struct sst_ipc_message request = {0}; 640 int ret; 641 642 header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); 643 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 644 header.primary |= IPC_GLB_TYPE(IPC_GLB_CREATE_PPL); 645 header.primary |= IPC_INSTANCE_ID(instance_id); 646 header.primary |= IPC_PPL_TYPE(ppl_type); 647 header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size); 648 649 header.extension = IPC_PPL_LP_MODE(lp_mode); 650 request.header = *(u64 *)(&header); 651 652 dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); 653 ret = sst_ipc_tx_message_wait(ipc, request, NULL); 654 if (ret < 0) { 655 dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret); 656 return ret; 657 } 658 659 return ret; 660 } 661 EXPORT_SYMBOL_GPL(skl_ipc_create_pipeline); 662 663 int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) 664 { 665 struct skl_ipc_header header = {0}; 666 struct sst_ipc_message request = {0}; 667 int ret; 668 669 header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); 670 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 671 header.primary |= IPC_GLB_TYPE(IPC_GLB_DELETE_PPL); 672 header.primary |= IPC_INSTANCE_ID(instance_id); 673 request.header = *(u64 *)(&header); 674 675 dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); 676 ret = sst_ipc_tx_message_wait(ipc, request, NULL); 677 if (ret < 0) { 678 dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret); 679 return ret; 680 } 681 682 return 0; 683 } 684 EXPORT_SYMBOL_GPL(skl_ipc_delete_pipeline); 685 686 int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, 687 u8 instance_id, enum skl_ipc_pipeline_state state) 688 { 689 struct skl_ipc_header header = {0}; 690 struct sst_ipc_message request = {0}; 691 int ret; 692 693 header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); 694 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 695 header.primary |= IPC_GLB_TYPE(IPC_GLB_SET_PPL_STATE); 696 header.primary |= IPC_INSTANCE_ID(instance_id); 697 header.primary |= IPC_PPL_STATE(state); 698 request.header = *(u64 *)(&header); 699 700 dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); 701 ret = sst_ipc_tx_message_wait(ipc, request, NULL); 702 if (ret < 0) { 703 dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret); 704 return ret; 705 } 706 return ret; 707 } 708 EXPORT_SYMBOL_GPL(skl_ipc_set_pipeline_state); 709 710 int 711 skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id) 712 { 713 struct skl_ipc_header header = {0}; 714 struct sst_ipc_message request = {0}; 715 int ret; 716 717 header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); 718 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 719 header.primary |= IPC_GLB_TYPE(IPC_GLB_SAVE_PPL); 720 header.primary |= IPC_INSTANCE_ID(instance_id); 721 722 header.extension = IPC_DMA_ID(dma_id); 723 request.header = *(u64 *)(&header); 724 725 dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); 726 ret = sst_ipc_tx_message_wait(ipc, request, NULL); 727 if (ret < 0) { 728 dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret); 729 return ret; 730 } 731 732 return ret; 733 } 734 EXPORT_SYMBOL_GPL(skl_ipc_save_pipeline); 735 736 int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) 737 { 738 struct skl_ipc_header header = {0}; 739 struct sst_ipc_message request = {0}; 740 int ret; 741 742 header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); 743 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 744 header.primary |= IPC_GLB_TYPE(IPC_GLB_RESTORE_PPL); 745 header.primary |= IPC_INSTANCE_ID(instance_id); 746 request.header = *(u64 *)(&header); 747 748 dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); 749 ret = sst_ipc_tx_message_wait(ipc, request, NULL); 750 if (ret < 0) { 751 dev_err(ipc->dev, "ipc: restore pipeline failed, err: %d\n", ret); 752 return ret; 753 } 754 755 return ret; 756 } 757 EXPORT_SYMBOL_GPL(skl_ipc_restore_pipeline); 758 759 int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, 760 u16 module_id, struct skl_ipc_dxstate_info *dx) 761 { 762 struct skl_ipc_header header = {0}; 763 struct sst_ipc_message request; 764 int ret; 765 766 header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); 767 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 768 header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_DX); 769 header.primary |= IPC_MOD_INSTANCE_ID(instance_id); 770 header.primary |= IPC_MOD_ID(module_id); 771 772 request.header = *(u64 *)(&header); 773 request.data = dx; 774 request.size = sizeof(*dx); 775 776 dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, 777 header.primary, header.extension); 778 ret = sst_ipc_tx_message_wait(ipc, request, NULL); 779 if (ret < 0) { 780 dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret); 781 return ret; 782 } 783 784 return ret; 785 } 786 EXPORT_SYMBOL_GPL(skl_ipc_set_dx); 787 788 int skl_ipc_init_instance(struct sst_generic_ipc *ipc, 789 struct skl_ipc_init_instance_msg *msg, void *param_data) 790 { 791 struct skl_ipc_header header = {0}; 792 struct sst_ipc_message request; 793 int ret; 794 u32 *buffer = (u32 *)param_data; 795 /* param_block_size must be in dwords */ 796 u16 param_block_size = msg->param_data_size / sizeof(u32); 797 798 print_hex_dump_debug("Param data:", DUMP_PREFIX_NONE, 799 16, 4, buffer, param_block_size, false); 800 801 header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); 802 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 803 header.primary |= IPC_GLB_TYPE(IPC_MOD_INIT_INSTANCE); 804 header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); 805 header.primary |= IPC_MOD_ID(msg->module_id); 806 807 header.extension = IPC_CORE_ID(msg->core_id); 808 header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id); 809 header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size); 810 header.extension |= IPC_DOMAIN(msg->domain); 811 812 request.header = *(u64 *)(&header); 813 request.data = param_data; 814 request.size = msg->param_data_size; 815 816 dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, 817 header.primary, header.extension); 818 ret = sst_ipc_tx_message_wait(ipc, request, NULL); 819 820 if (ret < 0) { 821 dev_err(ipc->dev, "ipc: init instance failed\n"); 822 return ret; 823 } 824 825 return ret; 826 } 827 EXPORT_SYMBOL_GPL(skl_ipc_init_instance); 828 829 int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, 830 struct skl_ipc_bind_unbind_msg *msg) 831 { 832 struct skl_ipc_header header = {0}; 833 struct sst_ipc_message request = {0}; 834 u8 bind_unbind = msg->bind ? IPC_MOD_BIND : IPC_MOD_UNBIND; 835 int ret; 836 837 header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); 838 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 839 header.primary |= IPC_GLB_TYPE(bind_unbind); 840 header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); 841 header.primary |= IPC_MOD_ID(msg->module_id); 842 843 header.extension = IPC_DST_MOD_ID(msg->dst_module_id); 844 header.extension |= IPC_DST_MOD_INSTANCE_ID(msg->dst_instance_id); 845 header.extension |= IPC_DST_QUEUE(msg->dst_queue); 846 header.extension |= IPC_SRC_QUEUE(msg->src_queue); 847 request.header = *(u64 *)(&header); 848 849 dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary, 850 header.extension); 851 ret = sst_ipc_tx_message_wait(ipc, request, NULL); 852 if (ret < 0) { 853 dev_err(ipc->dev, "ipc: bind/unbind failed\n"); 854 return ret; 855 } 856 857 return ret; 858 } 859 EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind); 860 861 /* 862 * In order to load a module we need to send IPC to initiate that. DMA will 863 * performed to load the module memory. The FW supports multiple module load 864 * at single shot, so we can send IPC with N modules represented by 865 * module_cnt 866 */ 867 int skl_ipc_load_modules(struct sst_generic_ipc *ipc, 868 u8 module_cnt, void *data) 869 { 870 struct skl_ipc_header header = {0}; 871 struct sst_ipc_message request; 872 int ret; 873 874 header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); 875 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 876 header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS); 877 header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); 878 879 request.header = *(u64 *)(&header); 880 request.data = data; 881 request.size = sizeof(u16) * module_cnt; 882 883 ret = sst_ipc_tx_message_nowait(ipc, request); 884 if (ret < 0) 885 dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret); 886 887 return ret; 888 } 889 EXPORT_SYMBOL_GPL(skl_ipc_load_modules); 890 891 int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt, 892 void *data) 893 { 894 struct skl_ipc_header header = {0}; 895 struct sst_ipc_message request; 896 int ret; 897 898 header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); 899 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 900 header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS); 901 header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); 902 903 request.header = *(u64 *)(&header); 904 request.data = data; 905 request.size = sizeof(u16) * module_cnt; 906 907 ret = sst_ipc_tx_message_wait(ipc, request, NULL); 908 if (ret < 0) 909 dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret); 910 911 return ret; 912 } 913 EXPORT_SYMBOL_GPL(skl_ipc_unload_modules); 914 915 int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, 916 struct skl_ipc_large_config_msg *msg, u32 *param) 917 { 918 struct skl_ipc_header header = {0}; 919 struct sst_ipc_message request; 920 int ret = 0; 921 size_t sz_remaining, tx_size, data_offset; 922 923 header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); 924 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 925 header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_SET); 926 header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); 927 header.primary |= IPC_MOD_ID(msg->module_id); 928 929 header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size); 930 header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id); 931 header.extension |= IPC_FINAL_BLOCK(0); 932 header.extension |= IPC_INITIAL_BLOCK(1); 933 934 sz_remaining = msg->param_data_size; 935 data_offset = 0; 936 while (sz_remaining != 0) { 937 tx_size = sz_remaining > SKL_ADSP_W1_SZ 938 ? SKL_ADSP_W1_SZ : sz_remaining; 939 if (tx_size == sz_remaining) 940 header.extension |= IPC_FINAL_BLOCK(1); 941 942 dev_dbg(ipc->dev, "In %s primary=%#x ext=%#x\n", __func__, 943 header.primary, header.extension); 944 dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n", 945 (unsigned)data_offset, (unsigned)tx_size); 946 947 request.header = *(u64 *)(&header); 948 request.data = ((char *)param) + data_offset; 949 request.size = tx_size; 950 ret = sst_ipc_tx_message_wait(ipc, request, NULL); 951 if (ret < 0) { 952 dev_err(ipc->dev, 953 "ipc: set large config fail, err: %d\n", ret); 954 return ret; 955 } 956 sz_remaining -= tx_size; 957 data_offset = msg->param_data_size - sz_remaining; 958 959 /* clear the fields */ 960 header.extension &= IPC_INITIAL_BLOCK_CLEAR; 961 header.extension &= IPC_DATA_OFFSET_SZ_CLEAR; 962 /* fill the fields */ 963 header.extension |= IPC_INITIAL_BLOCK(0); 964 header.extension |= IPC_DATA_OFFSET_SZ(data_offset); 965 } 966 967 return ret; 968 } 969 EXPORT_SYMBOL_GPL(skl_ipc_set_large_config); 970 971 int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, 972 struct skl_ipc_large_config_msg *msg, 973 u32 **payload, size_t *bytes) 974 { 975 struct skl_ipc_header header = {0}; 976 struct sst_ipc_message request, reply = {0}; 977 unsigned int *buf; 978 int ret; 979 980 reply.data = kzalloc(SKL_ADSP_W1_SZ, GFP_KERNEL); 981 if (!reply.data) 982 return -ENOMEM; 983 984 header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); 985 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 986 header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_GET); 987 header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); 988 header.primary |= IPC_MOD_ID(msg->module_id); 989 990 header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size); 991 header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id); 992 header.extension |= IPC_FINAL_BLOCK(1); 993 header.extension |= IPC_INITIAL_BLOCK(1); 994 995 request.header = *(u64 *)&header; 996 request.data = *payload; 997 request.size = *bytes; 998 reply.size = SKL_ADSP_W1_SZ; 999 1000 ret = sst_ipc_tx_message_wait(ipc, request, &reply); 1001 if (ret < 0) 1002 dev_err(ipc->dev, "ipc: get large config fail, err: %d\n", ret); 1003 1004 reply.size = (reply.header >> 32) & IPC_DATA_OFFSET_SZ_MASK; 1005 buf = krealloc(reply.data, reply.size, GFP_KERNEL); 1006 if (!buf) { 1007 kfree(reply.data); 1008 return -ENOMEM; 1009 } 1010 *payload = buf; 1011 *bytes = reply.size; 1012 1013 return ret; 1014 } 1015 EXPORT_SYMBOL_GPL(skl_ipc_get_large_config); 1016 1017 int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, 1018 u8 dma_id, u8 table_id, bool wait) 1019 { 1020 struct skl_ipc_header header = {0}; 1021 struct sst_ipc_message request = {0}; 1022 int ret = 0; 1023 1024 header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); 1025 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 1026 header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_LIBRARY); 1027 header.primary |= IPC_MOD_INSTANCE_ID(table_id); 1028 header.primary |= IPC_MOD_ID(dma_id); 1029 request.header = *(u64 *)(&header); 1030 1031 if (wait) 1032 ret = sst_ipc_tx_message_wait(ipc, request, NULL); 1033 else 1034 ret = sst_ipc_tx_message_nowait(ipc, request); 1035 1036 if (ret < 0) 1037 dev_err(ipc->dev, "ipc: load lib failed\n"); 1038 1039 return ret; 1040 } 1041 EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library); 1042 1043 int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg) 1044 { 1045 struct skl_ipc_header header = {0}; 1046 struct sst_ipc_message request = {0}; 1047 int ret; 1048 1049 header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); 1050 header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); 1051 header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_D0IX); 1052 header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); 1053 header.primary |= IPC_MOD_ID(msg->module_id); 1054 1055 header.extension = IPC_D0IX_WAKE(msg->wake); 1056 header.extension |= IPC_D0IX_STREAMING(msg->streaming); 1057 request.header = *(u64 *)(&header); 1058 1059 dev_dbg(ipc->dev, "In %s primary=%x ext=%x\n", __func__, 1060 header.primary, header.extension); 1061 1062 /* 1063 * Use the nopm IPC here as we dont want it checking for D0iX 1064 */ 1065 ret = sst_ipc_tx_message_nopm(ipc, request, NULL); 1066 if (ret < 0) 1067 dev_err(ipc->dev, "ipc: set d0ix failed, err %d\n", ret); 1068 1069 return ret; 1070 } 1071 EXPORT_SYMBOL_GPL(skl_ipc_set_d0ix); 1072
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.