linux/sound/soc/intel/skylake/skl-sst-ipc.c
<<
>>
Prefs
   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
 164enum skl_ipc_msg_target {
 165        IPC_FW_GEN_MSG = 0,
 166        IPC_MOD_MSG = 1
 167};
 168
 169enum skl_ipc_msg_direction {
 170        IPC_MSG_REQUEST = 0,
 171        IPC_MSG_REPLY = 1
 172};
 173
 174/* Global Message Types */
 175enum 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
 190enum 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
 227enum 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 */
 240enum 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
 251static 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
 258static 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 */
 267static 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
 279static 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
 293out:
 294        return msg;
 295
 296}
 297
 298static 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
 330static 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
 375irqreturn_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
 444void 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
 450void 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
 456void 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
 467bool skl_ipc_int_status(struct sst_dsp *ctx)
 468{
 469        return sst_dsp_shim_read_unlocked(ctx,
 470                        SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC;
 471}
 472
 473int skl_ipc_init(struct device *dev, struct skl_sst *skl)
 474{
 475        struct sst_generic_ipc *ipc;
 476        int err;
 477
 478        ipc = &skl->ipc;
 479        ipc->dsp = skl->dsp;
 480        ipc->dev = dev;
 481
 482        ipc->tx_data_max_size = SKL_ADSP_W1_SZ;
 483        ipc->rx_data_max_size = SKL_ADSP_W0_UP_SZ;
 484
 485        err = sst_ipc_init(ipc);
 486        if (err)
 487                return err;
 488
 489        ipc->ops.tx_msg = skl_ipc_tx_msg;
 490        ipc->ops.tx_data_copy = skl_ipc_tx_data_copy;
 491        ipc->ops.is_dsp_busy = skl_ipc_is_dsp_busy;
 492
 493        return 0;
 494}
 495
 496void skl_ipc_free(struct sst_generic_ipc *ipc)
 497{
 498        /* Disable IPC DONE interrupt */
 499        sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL,
 500                SKL_ADSP_REG_HIPCCTL_DONE, 0);
 501
 502        /* Disable IPC BUSY interrupt */
 503        sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL,
 504                SKL_ADSP_REG_HIPCCTL_BUSY, 0);
 505
 506        sst_ipc_fini(ipc);
 507}
 508
 509int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc,
 510                u16 ppl_mem_size, u8 ppl_type, u8 instance_id)
 511{
 512        struct skl_ipc_header header = {0};
 513        u64 *ipc_header = (u64 *)(&header);
 514        int ret;
 515
 516        header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
 517        header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
 518        header.primary |= IPC_GLB_TYPE(IPC_GLB_CREATE_PPL);
 519        header.primary |= IPC_INSTANCE_ID(instance_id);
 520        header.primary |= IPC_PPL_TYPE(ppl_type);
 521        header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size);
 522
 523        dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
 524        ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
 525        if (ret < 0) {
 526                dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret);
 527                return ret;
 528        }
 529
 530        return ret;
 531}
 532EXPORT_SYMBOL_GPL(skl_ipc_create_pipeline);
 533
 534int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id)
 535{
 536        struct skl_ipc_header header = {0};
 537        u64 *ipc_header = (u64 *)(&header);
 538        int ret;
 539
 540        header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
 541        header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
 542        header.primary |= IPC_GLB_TYPE(IPC_GLB_DELETE_PPL);
 543        header.primary |= IPC_INSTANCE_ID(instance_id);
 544
 545        dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
 546        ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
 547        if (ret < 0) {
 548                dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret);
 549                return ret;
 550        }
 551
 552        return 0;
 553}
 554EXPORT_SYMBOL_GPL(skl_ipc_delete_pipeline);
 555
 556int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc,
 557                u8 instance_id, enum skl_ipc_pipeline_state state)
 558{
 559        struct skl_ipc_header header = {0};
 560        u64 *ipc_header = (u64 *)(&header);
 561        int ret;
 562
 563        header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
 564        header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
 565        header.primary |= IPC_GLB_TYPE(IPC_GLB_SET_PPL_STATE);
 566        header.primary |= IPC_INSTANCE_ID(instance_id);
 567        header.primary |= IPC_PPL_STATE(state);
 568
 569        dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
 570        ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
 571        if (ret < 0) {
 572                dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret);
 573                return ret;
 574        }
 575        return ret;
 576}
 577EXPORT_SYMBOL_GPL(skl_ipc_set_pipeline_state);
 578
 579int
 580skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id)
 581{
 582        struct skl_ipc_header header = {0};
 583        u64 *ipc_header = (u64 *)(&header);
 584        int ret;
 585
 586        header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
 587        header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
 588        header.primary |= IPC_GLB_TYPE(IPC_GLB_SAVE_PPL);
 589        header.primary |= IPC_INSTANCE_ID(instance_id);
 590
 591        header.extension = IPC_DMA_ID(dma_id);
 592        dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
 593        ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
 594        if (ret < 0) {
 595                dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret);
 596                return ret;
 597        }
 598
 599        return ret;
 600}
 601EXPORT_SYMBOL_GPL(skl_ipc_save_pipeline);
 602
 603int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id)
 604{
 605        struct skl_ipc_header header = {0};
 606        u64 *ipc_header = (u64 *)(&header);
 607        int ret;
 608
 609        header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
 610        header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
 611        header.primary |= IPC_GLB_TYPE(IPC_GLB_RESTORE_PPL);
 612        header.primary |= IPC_INSTANCE_ID(instance_id);
 613
 614        dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
 615        ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
 616        if (ret < 0) {
 617                dev_err(ipc->dev, "ipc: restore  pipeline failed, err: %d\n", ret);
 618                return ret;
 619        }
 620
 621        return ret;
 622}
 623EXPORT_SYMBOL_GPL(skl_ipc_restore_pipeline);
 624
 625int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id,
 626                u16 module_id, struct skl_ipc_dxstate_info *dx)
 627{
 628        struct skl_ipc_header header = {0};
 629        u64 *ipc_header = (u64 *)(&header);
 630        int ret;
 631
 632        header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
 633        header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
 634        header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_DX);
 635        header.primary |= IPC_MOD_INSTANCE_ID(instance_id);
 636        header.primary |= IPC_MOD_ID(module_id);
 637
 638        dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
 639                         header.primary, header.extension);
 640        ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
 641                                dx, sizeof(dx), NULL, 0);
 642        if (ret < 0) {
 643                dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret);
 644                return ret;
 645        }
 646
 647        return ret;
 648}
 649EXPORT_SYMBOL_GPL(skl_ipc_set_dx);
 650
 651int skl_ipc_init_instance(struct sst_generic_ipc *ipc,
 652                struct skl_ipc_init_instance_msg *msg, void *param_data)
 653{
 654        struct skl_ipc_header header = {0};
 655        u64 *ipc_header = (u64 *)(&header);
 656        int ret;
 657        u32 *buffer = (u32 *)param_data;
 658         /* param_block_size must be in dwords */
 659        u16 param_block_size = msg->param_data_size / sizeof(u32);
 660
 661        print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE,
 662                16, 4, buffer, param_block_size, false);
 663
 664        header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
 665        header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
 666        header.primary |= IPC_GLB_TYPE(IPC_MOD_INIT_INSTANCE);
 667        header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
 668        header.primary |= IPC_MOD_ID(msg->module_id);
 669
 670        header.extension = IPC_CORE_ID(msg->core_id);
 671        header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id);
 672        header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size);
 673
 674        dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
 675                         header.primary, header.extension);
 676        ret = sst_ipc_tx_message_wait(ipc, *ipc_header, param_data,
 677                        msg->param_data_size, NULL, 0);
 678
 679        if (ret < 0) {
 680                dev_err(ipc->dev, "ipc: init instance failed\n");
 681                return ret;
 682        }
 683
 684        return ret;
 685}
 686EXPORT_SYMBOL_GPL(skl_ipc_init_instance);
 687
 688int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc,
 689                struct skl_ipc_bind_unbind_msg *msg)
 690{
 691        struct skl_ipc_header header = {0};
 692        u64 *ipc_header = (u64 *)(&header);
 693        u8 bind_unbind = msg->bind ? IPC_MOD_BIND : IPC_MOD_UNBIND;
 694        int ret;
 695
 696        header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
 697        header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
 698        header.primary |= IPC_GLB_TYPE(bind_unbind);
 699        header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
 700        header.primary |= IPC_MOD_ID(msg->module_id);
 701
 702        header.extension = IPC_DST_MOD_ID(msg->dst_module_id);
 703        header.extension |= IPC_DST_MOD_INSTANCE_ID(msg->dst_instance_id);
 704        header.extension |= IPC_DST_QUEUE(msg->dst_queue);
 705        header.extension |= IPC_SRC_QUEUE(msg->src_queue);
 706
 707        dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary,
 708                         header.extension);
 709        ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
 710        if (ret < 0) {
 711                dev_err(ipc->dev, "ipc: bind/unbind faileden");
 712                return ret;
 713        }
 714
 715        return ret;
 716}
 717EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind);
 718
 719int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
 720                struct skl_ipc_large_config_msg *msg, u32 *param)
 721{
 722        struct skl_ipc_header header = {0};
 723        u64 *ipc_header = (u64 *)(&header);
 724        int ret = 0;
 725        size_t sz_remaining, tx_size, data_offset;
 726
 727        header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
 728        header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
 729        header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_SET);
 730        header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
 731        header.primary |= IPC_MOD_ID(msg->module_id);
 732
 733        header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size);
 734        header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id);
 735        header.extension |= IPC_FINAL_BLOCK(0);
 736        header.extension |= IPC_INITIAL_BLOCK(1);
 737
 738        sz_remaining = msg->param_data_size;
 739        data_offset = 0;
 740        while (sz_remaining != 0) {
 741                tx_size = sz_remaining > SKL_ADSP_W1_SZ
 742                                ? SKL_ADSP_W1_SZ : sz_remaining;
 743                if (tx_size == sz_remaining)
 744                        header.extension |= IPC_FINAL_BLOCK(1);
 745
 746                dev_dbg(ipc->dev, "In %s primary=%#x ext=%#x\n", __func__,
 747                        header.primary, header.extension);
 748                dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n",
 749                        (unsigned)data_offset, (unsigned)tx_size);
 750                ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
 751                                          ((char *)param) + data_offset,
 752                                          tx_size, NULL, 0);
 753                if (ret < 0) {
 754                        dev_err(ipc->dev,
 755                                "ipc: set large config fail, err: %d\n", ret);
 756                        return ret;
 757                }
 758                sz_remaining -= tx_size;
 759                data_offset = msg->param_data_size - sz_remaining;
 760
 761                /* clear the fields */
 762                header.extension &= IPC_INITIAL_BLOCK_CLEAR;
 763                header.extension &= IPC_DATA_OFFSET_SZ_CLEAR;
 764                /* fill the fields */
 765                header.extension |= IPC_INITIAL_BLOCK(0);
 766                header.extension |= IPC_DATA_OFFSET_SZ(data_offset);
 767        }
 768
 769        return ret;
 770}
 771EXPORT_SYMBOL_GPL(skl_ipc_set_large_config);
 772