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