linux/sound/soc/sof/topology.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
   2//
   3// This file is provided under a dual BSD/GPLv2 license.  When using or
   4// redistributing this file, you may do so under either license.
   5//
   6// Copyright(c) 2018 Intel Corporation. All rights reserved.
   7//
   8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
   9//
  10
  11#include <linux/bits.h>
  12#include <linux/device.h>
  13#include <linux/errno.h>
  14#include <linux/firmware.h>
  15#include <linux/workqueue.h>
  16#include <sound/tlv.h>
  17#include <sound/pcm_params.h>
  18#include <uapi/sound/sof/tokens.h>
  19#include "sof-priv.h"
  20#include "sof-audio.h"
  21#include "ops.h"
  22
  23#define COMP_ID_UNASSIGNED              0xffffffff
  24/*
  25 * Constants used in the computation of linear volume gain
  26 * from dB gain 20th root of 10 in Q1.16 fixed-point notation
  27 */
  28#define VOL_TWENTIETH_ROOT_OF_TEN       73533
  29/* 40th root of 10 in Q1.16 fixed-point notation*/
  30#define VOL_FORTIETH_ROOT_OF_TEN        69419
  31/*
  32 * Volume fractional word length define to 16 sets
  33 * the volume linear gain value to use Qx.16 format
  34 */
  35#define VOLUME_FWL      16
  36/* 0.5 dB step value in topology TLV */
  37#define VOL_HALF_DB_STEP        50
  38/* Full volume for default values */
  39#define VOL_ZERO_DB     BIT(VOLUME_FWL)
  40
  41/* TLV data items */
  42#define TLV_ITEMS       3
  43#define TLV_MIN         0
  44#define TLV_STEP        1
  45#define TLV_MUTE        2
  46
  47/* size of tplg abi in byte */
  48#define SOF_TPLG_ABI_SIZE 3
  49
  50struct sof_widget_data {
  51        int ctrl_type;
  52        int ipc_cmd;
  53        struct sof_abi_hdr *pdata;
  54        struct snd_sof_control *control;
  55};
  56
  57/* send pcm params ipc */
  58static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir)
  59{
  60        struct sof_ipc_pcm_params_reply ipc_params_reply;
  61        struct snd_soc_component *scomp = swidget->scomp;
  62        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
  63        struct sof_ipc_pcm_params pcm;
  64        struct snd_pcm_hw_params *params;
  65        struct snd_sof_pcm *spcm;
  66        int ret;
  67
  68        memset(&pcm, 0, sizeof(pcm));
  69
  70        /* get runtime PCM params using widget's stream name */
  71        spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
  72        if (!spcm) {
  73                dev_err(scomp->dev, "error: cannot find PCM for %s\n",
  74                        swidget->widget->name);
  75                return -EINVAL;
  76        }
  77
  78        params = &spcm->params[dir];
  79
  80        /* set IPC PCM params */
  81        pcm.hdr.size = sizeof(pcm);
  82        pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
  83        pcm.comp_id = swidget->comp_id;
  84        pcm.params.hdr.size = sizeof(pcm.params);
  85        pcm.params.direction = dir;
  86        pcm.params.sample_valid_bytes = params_width(params) >> 3;
  87        pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
  88        pcm.params.rate = params_rate(params);
  89        pcm.params.channels = params_channels(params);
  90        pcm.params.host_period_bytes = params_period_bytes(params);
  91
  92        /* set format */
  93        switch (params_format(params)) {
  94        case SNDRV_PCM_FORMAT_S16:
  95                pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
  96                break;
  97        case SNDRV_PCM_FORMAT_S24:
  98                pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
  99                break;
 100        case SNDRV_PCM_FORMAT_S32:
 101                pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
 102                break;
 103        default:
 104                return -EINVAL;
 105        }
 106
 107        /* send IPC to the DSP */
 108        ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
 109                                 &ipc_params_reply, sizeof(ipc_params_reply));
 110        if (ret < 0)
 111                dev_err(scomp->dev, "error: pcm params failed for %s\n",
 112                        swidget->widget->name);
 113
 114        return ret;
 115}
 116
 117 /* send stream trigger ipc */
 118static int ipc_trigger(struct snd_sof_widget *swidget, int cmd)
 119{
 120        struct snd_soc_component *scomp = swidget->scomp;
 121        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 122        struct sof_ipc_stream stream;
 123        struct sof_ipc_reply reply;
 124        int ret;
 125
 126        /* set IPC stream params */
 127        stream.hdr.size = sizeof(stream);
 128        stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | cmd;
 129        stream.comp_id = swidget->comp_id;
 130
 131        /* send IPC to the DSP */
 132        ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
 133                                 sizeof(stream), &reply, sizeof(reply));
 134        if (ret < 0)
 135                dev_err(scomp->dev, "error: failed to trigger %s\n",
 136                        swidget->widget->name);
 137
 138        return ret;
 139}
 140
 141static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w,
 142                                  struct snd_kcontrol *k, int event)
 143{
 144        struct snd_sof_widget *swidget = w->dobj.private;
 145        struct snd_soc_component *scomp;
 146        int stream = SNDRV_PCM_STREAM_CAPTURE;
 147        struct snd_sof_pcm *spcm;
 148        int ret = 0;
 149
 150        if (!swidget)
 151                return 0;
 152
 153        scomp = swidget->scomp;
 154
 155        dev_dbg(scomp->dev, "received event %d for widget %s\n",
 156                event, w->name);
 157
 158        /* get runtime PCM params using widget's stream name */
 159        spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
 160        if (!spcm) {
 161                dev_err(scomp->dev, "error: cannot find PCM for %s\n",
 162                        swidget->widget->name);
 163                return -EINVAL;
 164        }
 165
 166        /* process events */
 167        switch (event) {
 168        case SND_SOC_DAPM_PRE_PMU:
 169                if (spcm->stream[stream].suspend_ignored) {
 170                        dev_dbg(scomp->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n");
 171                        return 0;
 172                }
 173
 174                /* set pcm params */
 175                ret = ipc_pcm_params(swidget, stream);
 176                if (ret < 0) {
 177                        dev_err(scomp->dev,
 178                                "error: failed to set pcm params for widget %s\n",
 179                                swidget->widget->name);
 180                        break;
 181                }
 182
 183                /* start trigger */
 184                ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_START);
 185                if (ret < 0)
 186                        dev_err(scomp->dev,
 187                                "error: failed to trigger widget %s\n",
 188                                swidget->widget->name);
 189                break;
 190        case SND_SOC_DAPM_POST_PMD:
 191                if (spcm->stream[stream].suspend_ignored) {
 192                        dev_dbg(scomp->dev, "POST_PMD even ignored, KWD pipeline will remain RUNNING\n");
 193                        return 0;
 194                }
 195
 196                /* stop trigger */
 197                ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP);
 198                if (ret < 0)
 199                        dev_err(scomp->dev,
 200                                "error: failed to trigger widget %s\n",
 201                                swidget->widget->name);
 202
 203                /* pcm free */
 204                ret = ipc_trigger(swidget, SOF_IPC_STREAM_PCM_FREE);
 205                if (ret < 0)
 206                        dev_err(scomp->dev,
 207                                "error: failed to trigger widget %s\n",
 208                                swidget->widget->name);
 209                break;
 210        default:
 211                break;
 212        }
 213
 214        return ret;
 215}
 216
 217/* event handlers for keyword detect component */
 218static const struct snd_soc_tplg_widget_events sof_kwd_events[] = {
 219        {SOF_KEYWORD_DETECT_DAPM_EVENT, sof_keyword_dapm_event},
 220};
 221
 222static inline int get_tlv_data(const int *p, int tlv[TLV_ITEMS])
 223{
 224        /* we only support dB scale TLV type at the moment */
 225        if ((int)p[SNDRV_CTL_TLVO_TYPE] != SNDRV_CTL_TLVT_DB_SCALE)
 226                return -EINVAL;
 227
 228        /* min value in topology tlv data is multiplied by 100 */
 229        tlv[TLV_MIN] = (int)p[SNDRV_CTL_TLVO_DB_SCALE_MIN] / 100;
 230
 231        /* volume steps */
 232        tlv[TLV_STEP] = (int)(p[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] &
 233                                TLV_DB_SCALE_MASK);
 234
 235        /* mute ON/OFF */
 236        if ((p[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] &
 237                TLV_DB_SCALE_MUTE) == 0)
 238                tlv[TLV_MUTE] = 0;
 239        else
 240                tlv[TLV_MUTE] = 1;
 241
 242        return 0;
 243}
 244
 245/*
 246 * Function to truncate an unsigned 64-bit number
 247 * by x bits and return 32-bit unsigned number. This
 248 * function also takes care of rounding while truncating
 249 */
 250static inline u32 vol_shift_64(u64 i, u32 x)
 251{
 252        /* do not truncate more than 32 bits */
 253        if (x > 32)
 254                x = 32;
 255
 256        if (x == 0)
 257                return (u32)i;
 258
 259        return (u32)(((i >> (x - 1)) + 1) >> 1);
 260}
 261
 262/*
 263 * Function to compute a ^ exp where,
 264 * a is a fractional number represented by a fixed-point
 265 * integer with a fractional world length of "fwl"
 266 * exp is an integer
 267 * fwl is the fractional word length
 268 * Return value is a fractional number represented by a
 269 * fixed-point integer with a fractional word length of "fwl"
 270 */
 271static u32 vol_pow32(u32 a, int exp, u32 fwl)
 272{
 273        int i, iter;
 274        u32 power = 1 << fwl;
 275        u64 numerator;
 276
 277        /* if exponent is 0, return 1 */
 278        if (exp == 0)
 279                return power;
 280
 281        /* determine the number of iterations based on the exponent */
 282        if (exp < 0)
 283                iter = exp * -1;
 284        else
 285                iter = exp;
 286
 287        /* mutiply a "iter" times to compute power */
 288        for (i = 0; i < iter; i++) {
 289                /*
 290                 * Product of 2 Qx.fwl fixed-point numbers yields a Q2*x.2*fwl
 291                 * Truncate product back to fwl fractional bits with rounding
 292                 */
 293                power = vol_shift_64((u64)power * a, fwl);
 294        }
 295
 296        if (exp > 0) {
 297                /* if exp is positive, return the result */
 298                return power;
 299        }
 300
 301        /* if exp is negative, return the multiplicative inverse */
 302        numerator = (u64)1 << (fwl << 1);
 303        do_div(numerator, power);
 304
 305        return (u32)numerator;
 306}
 307
 308/*
 309 * Function to calculate volume gain from TLV data.
 310 * This function can only handle gain steps that are multiples of 0.5 dB
 311 */
 312static u32 vol_compute_gain(u32 value, int *tlv)
 313{
 314        int dB_gain;
 315        u32 linear_gain;
 316        int f_step;
 317
 318        /* mute volume */
 319        if (value == 0 && tlv[TLV_MUTE])
 320                return 0;
 321
 322        /*
 323         * compute dB gain from tlv. tlv_step
 324         * in topology is multiplied by 100
 325         */
 326        dB_gain = tlv[TLV_MIN] + (value * tlv[TLV_STEP]) / 100;
 327
 328        /*
 329         * compute linear gain represented by fixed-point
 330         * int with VOLUME_FWL fractional bits
 331         */
 332        linear_gain = vol_pow32(VOL_TWENTIETH_ROOT_OF_TEN, dB_gain, VOLUME_FWL);
 333
 334        /* extract the fractional part of volume step */
 335        f_step = tlv[TLV_STEP] - (tlv[TLV_STEP] / 100);
 336
 337        /* if volume step is an odd multiple of 0.5 dB */
 338        if (f_step == VOL_HALF_DB_STEP && (value & 1))
 339                linear_gain = vol_shift_64((u64)linear_gain *
 340                                                  VOL_FORTIETH_ROOT_OF_TEN,
 341                                                  VOLUME_FWL);
 342
 343        return linear_gain;
 344}
 345
 346/*
 347 * Set up volume table for kcontrols from tlv data
 348 * "size" specifies the number of entries in the table
 349 */
 350static int set_up_volume_table(struct snd_sof_control *scontrol,
 351                               int tlv[TLV_ITEMS], int size)
 352{
 353        int j;
 354
 355        /* init the volume table */
 356        scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
 357        if (!scontrol->volume_table)
 358                return -ENOMEM;
 359
 360        /* populate the volume table */
 361        for (j = 0; j < size ; j++)
 362                scontrol->volume_table[j] = vol_compute_gain(j, tlv);
 363
 364        return 0;
 365}
 366
 367struct sof_dai_types {
 368        const char *name;
 369        enum sof_ipc_dai_type type;
 370};
 371
 372static const struct sof_dai_types sof_dais[] = {
 373        {"SSP", SOF_DAI_INTEL_SSP},
 374        {"HDA", SOF_DAI_INTEL_HDA},
 375        {"DMIC", SOF_DAI_INTEL_DMIC},
 376        {"ALH", SOF_DAI_INTEL_ALH},
 377        {"SAI", SOF_DAI_IMX_SAI},
 378        {"ESAI", SOF_DAI_IMX_ESAI},
 379};
 380
 381static enum sof_ipc_dai_type find_dai(const char *name)
 382{
 383        int i;
 384
 385        for (i = 0; i < ARRAY_SIZE(sof_dais); i++) {
 386                if (strcmp(name, sof_dais[i].name) == 0)
 387                        return sof_dais[i].type;
 388        }
 389
 390        return SOF_DAI_INTEL_NONE;
 391}
 392
 393/*
 394 * Supported Frame format types and lookup, add new ones to end of list.
 395 */
 396
 397struct sof_frame_types {
 398        const char *name;
 399        enum sof_ipc_frame frame;
 400};
 401
 402static const struct sof_frame_types sof_frames[] = {
 403        {"s16le", SOF_IPC_FRAME_S16_LE},
 404        {"s24le", SOF_IPC_FRAME_S24_4LE},
 405        {"s32le", SOF_IPC_FRAME_S32_LE},
 406        {"float", SOF_IPC_FRAME_FLOAT},
 407};
 408
 409static enum sof_ipc_frame find_format(const char *name)
 410{
 411        int i;
 412
 413        for (i = 0; i < ARRAY_SIZE(sof_frames); i++) {
 414                if (strcmp(name, sof_frames[i].name) == 0)
 415                        return sof_frames[i].frame;
 416        }
 417
 418        /* use s32le if nothing is specified */
 419        return SOF_IPC_FRAME_S32_LE;
 420}
 421
 422struct sof_process_types {
 423        const char *name;
 424        enum sof_ipc_process_type type;
 425        enum sof_comp_type comp_type;
 426};
 427
 428static const struct sof_process_types sof_process[] = {
 429        {"EQFIR", SOF_PROCESS_EQFIR, SOF_COMP_EQ_FIR},
 430        {"EQIIR", SOF_PROCESS_EQIIR, SOF_COMP_EQ_IIR},
 431        {"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT, SOF_COMP_KEYWORD_DETECT},
 432        {"KPB", SOF_PROCESS_KPB, SOF_COMP_KPB},
 433        {"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR, SOF_COMP_SELECTOR},
 434        {"MUX", SOF_PROCESS_MUX, SOF_COMP_MUX},
 435        {"DEMUX", SOF_PROCESS_DEMUX, SOF_COMP_DEMUX},
 436        {"DCBLOCK", SOF_PROCESS_DCBLOCK, SOF_COMP_DCBLOCK},
 437        {"SMART_AMP", SOF_PROCESS_SMART_AMP, SOF_COMP_SMART_AMP},
 438};
 439
 440static enum sof_ipc_process_type find_process(const char *name)
 441{
 442        int i;
 443
 444        for (i = 0; i < ARRAY_SIZE(sof_process); i++) {
 445                if (strcmp(name, sof_process[i].name) == 0)
 446                        return sof_process[i].type;
 447        }
 448
 449        return SOF_PROCESS_NONE;
 450}
 451
 452static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type)
 453{
 454        int i;
 455
 456        for (i = 0; i < ARRAY_SIZE(sof_process); i++) {
 457                if (sof_process[i].type == type)
 458                        return sof_process[i].comp_type;
 459        }
 460
 461        return SOF_COMP_NONE;
 462}
 463
 464/*
 465 * Topology Token Parsing.
 466 * New tokens should be added to headers and parsing tables below.
 467 */
 468
 469struct sof_topology_token {
 470        u32 token;
 471        u32 type;
 472        int (*get_token)(void *elem, void *object, u32 offset, u32 size);
 473        u32 offset;
 474        u32 size;
 475};
 476
 477static int get_token_u32(void *elem, void *object, u32 offset, u32 size)
 478{
 479        struct snd_soc_tplg_vendor_value_elem *velem = elem;
 480        u32 *val = (u32 *)((u8 *)object + offset);
 481
 482        *val = le32_to_cpu(velem->value);
 483        return 0;
 484}
 485
 486static int get_token_u16(void *elem, void *object, u32 offset, u32 size)
 487{
 488        struct snd_soc_tplg_vendor_value_elem *velem = elem;
 489        u16 *val = (u16 *)((u8 *)object + offset);
 490
 491        *val = (u16)le32_to_cpu(velem->value);
 492        return 0;
 493}
 494
 495static int get_token_uuid(void *elem, void *object, u32 offset, u32 size)
 496{
 497        struct snd_soc_tplg_vendor_uuid_elem *velem = elem;
 498        u8 *dst = (u8 *)object + offset;
 499
 500        memcpy(dst, velem->uuid, UUID_SIZE);
 501
 502        return 0;
 503}
 504
 505static int get_token_comp_format(void *elem, void *object, u32 offset, u32 size)
 506{
 507        struct snd_soc_tplg_vendor_string_elem *velem = elem;
 508        u32 *val = (u32 *)((u8 *)object + offset);
 509
 510        *val = find_format(velem->string);
 511        return 0;
 512}
 513
 514static int get_token_dai_type(void *elem, void *object, u32 offset, u32 size)
 515{
 516        struct snd_soc_tplg_vendor_string_elem *velem = elem;
 517        u32 *val = (u32 *)((u8 *)object + offset);
 518
 519        *val = find_dai(velem->string);
 520        return 0;
 521}
 522
 523static int get_token_process_type(void *elem, void *object, u32 offset,
 524                                  u32 size)
 525{
 526        struct snd_soc_tplg_vendor_string_elem *velem = elem;
 527        u32 *val = (u32 *)((u8 *)object + offset);
 528
 529        *val = find_process(velem->string);
 530        return 0;
 531}
 532
 533/* Buffers */
 534static const struct sof_topology_token buffer_tokens[] = {
 535        {SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 536                offsetof(struct sof_ipc_buffer, size), 0},
 537        {SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 538                offsetof(struct sof_ipc_buffer, caps), 0},
 539};
 540
 541/* DAI */
 542static const struct sof_topology_token dai_tokens[] = {
 543        {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
 544                offsetof(struct sof_ipc_comp_dai, type), 0},
 545        {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 546                offsetof(struct sof_ipc_comp_dai, dai_index), 0},
 547        {SOF_TKN_DAI_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 548                offsetof(struct sof_ipc_comp_dai, direction), 0},
 549};
 550
 551/* BE DAI link */
 552static const struct sof_topology_token dai_link_tokens[] = {
 553        {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
 554                offsetof(struct sof_ipc_dai_config, type), 0},
 555        {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 556                offsetof(struct sof_ipc_dai_config, dai_index), 0},
 557};
 558
 559/* scheduling */
 560static const struct sof_topology_token sched_tokens[] = {
 561        {SOF_TKN_SCHED_PERIOD, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 562                offsetof(struct sof_ipc_pipe_new, period), 0},
 563        {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 564                offsetof(struct sof_ipc_pipe_new, priority), 0},
 565        {SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 566                offsetof(struct sof_ipc_pipe_new, period_mips), 0},
 567        {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 568                offsetof(struct sof_ipc_pipe_new, core), 0},
 569        {SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 570                offsetof(struct sof_ipc_pipe_new, frames_per_sched), 0},
 571        {SOF_TKN_SCHED_TIME_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 572                offsetof(struct sof_ipc_pipe_new, time_domain), 0},
 573};
 574
 575/* volume */
 576static const struct sof_topology_token volume_tokens[] = {
 577        {SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
 578                get_token_u32, offsetof(struct sof_ipc_comp_volume, ramp), 0},
 579        {SOF_TKN_VOLUME_RAMP_STEP_MS,
 580                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 581                offsetof(struct sof_ipc_comp_volume, initial_ramp), 0},
 582};
 583
 584/* SRC */
 585static const struct sof_topology_token src_tokens[] = {
 586        {SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 587                offsetof(struct sof_ipc_comp_src, source_rate), 0},
 588        {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 589                offsetof(struct sof_ipc_comp_src, sink_rate), 0},
 590};
 591
 592/* ASRC */
 593static const struct sof_topology_token asrc_tokens[] = {
 594        {SOF_TKN_ASRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 595                offsetof(struct sof_ipc_comp_asrc, source_rate), 0},
 596        {SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 597                offsetof(struct sof_ipc_comp_asrc, sink_rate), 0},
 598        {SOF_TKN_ASRC_ASYNCHRONOUS_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
 599                get_token_u32,
 600                offsetof(struct sof_ipc_comp_asrc, asynchronous_mode), 0},
 601        {SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
 602                get_token_u32,
 603                offsetof(struct sof_ipc_comp_asrc, operation_mode), 0},
 604};
 605
 606/* Tone */
 607static const struct sof_topology_token tone_tokens[] = {
 608};
 609
 610/* EFFECT */
 611static const struct sof_topology_token process_tokens[] = {
 612        {SOF_TKN_PROCESS_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING,
 613                get_token_process_type,
 614                offsetof(struct sof_ipc_comp_process, type), 0},
 615};
 616
 617/* PCM */
 618static const struct sof_topology_token pcm_tokens[] = {
 619        {SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 620                offsetof(struct sof_ipc_comp_host, dmac_config), 0},
 621};
 622
 623/* PCM */
 624static const struct sof_topology_token stream_tokens[] = {
 625        {SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3,
 626                SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
 627                offsetof(struct snd_sof_pcm, stream[0].d0i3_compatible), 0},
 628        {SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3,
 629                SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
 630                offsetof(struct snd_sof_pcm, stream[1].d0i3_compatible), 0},
 631};
 632
 633/* Generic components */
 634static const struct sof_topology_token comp_tokens[] = {
 635        {SOF_TKN_COMP_PERIOD_SINK_COUNT,
 636                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 637                offsetof(struct sof_ipc_comp_config, periods_sink), 0},
 638        {SOF_TKN_COMP_PERIOD_SOURCE_COUNT,
 639                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 640                offsetof(struct sof_ipc_comp_config, periods_source), 0},
 641        {SOF_TKN_COMP_FORMAT,
 642                SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format,
 643                offsetof(struct sof_ipc_comp_config, frame_fmt), 0},
 644};
 645
 646/* SSP */
 647static const struct sof_topology_token ssp_tokens[] = {
 648        {SOF_TKN_INTEL_SSP_CLKS_CONTROL,
 649                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 650                offsetof(struct sof_ipc_dai_ssp_params, clks_control), 0},
 651        {SOF_TKN_INTEL_SSP_MCLK_ID,
 652                SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
 653                offsetof(struct sof_ipc_dai_ssp_params, mclk_id), 0},
 654        {SOF_TKN_INTEL_SSP_SAMPLE_BITS, SND_SOC_TPLG_TUPLE_TYPE_WORD,
 655                get_token_u32,
 656                offsetof(struct sof_ipc_dai_ssp_params, sample_valid_bits), 0},
 657        {SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT,
 658                get_token_u16,
 659                offsetof(struct sof_ipc_dai_ssp_params, frame_pulse_width), 0},
 660        {SOF_TKN_INTEL_SSP_QUIRKS, SND_SOC_TPLG_TUPLE_TYPE_WORD,
 661                get_token_u32,
 662                offsetof(struct sof_ipc_dai_ssp_params, quirks), 0},
 663        {SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT, SND_SOC_TPLG_TUPLE_TYPE_BOOL,
 664                get_token_u16,
 665                offsetof(struct sof_ipc_dai_ssp_params,
 666                         tdm_per_slot_padding_flag), 0},
 667        {SOF_TKN_INTEL_SSP_BCLK_DELAY, SND_SOC_TPLG_TUPLE_TYPE_WORD,
 668                get_token_u32,
 669                offsetof(struct sof_ipc_dai_ssp_params, bclk_delay), 0},
 670
 671};
 672
 673/* ALH */
 674static const struct sof_topology_token alh_tokens[] = {
 675        {SOF_TKN_INTEL_ALH_RATE,
 676                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 677                offsetof(struct sof_ipc_dai_alh_params, rate), 0},
 678        {SOF_TKN_INTEL_ALH_CH,
 679                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 680                offsetof(struct sof_ipc_dai_alh_params, channels), 0},
 681};
 682
 683/* DMIC */
 684static const struct sof_topology_token dmic_tokens[] = {
 685        {SOF_TKN_INTEL_DMIC_DRIVER_VERSION,
 686                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 687                offsetof(struct sof_ipc_dai_dmic_params, driver_ipc_version),
 688                0},
 689        {SOF_TKN_INTEL_DMIC_CLK_MIN,
 690                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 691                offsetof(struct sof_ipc_dai_dmic_params, pdmclk_min), 0},
 692        {SOF_TKN_INTEL_DMIC_CLK_MAX,
 693                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 694                offsetof(struct sof_ipc_dai_dmic_params, pdmclk_max), 0},
 695        {SOF_TKN_INTEL_DMIC_SAMPLE_RATE,
 696                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 697                offsetof(struct sof_ipc_dai_dmic_params, fifo_fs), 0},
 698        {SOF_TKN_INTEL_DMIC_DUTY_MIN,
 699                SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
 700                offsetof(struct sof_ipc_dai_dmic_params, duty_min), 0},
 701        {SOF_TKN_INTEL_DMIC_DUTY_MAX,
 702                SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
 703                offsetof(struct sof_ipc_dai_dmic_params, duty_max), 0},
 704        {SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE,
 705                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 706                offsetof(struct sof_ipc_dai_dmic_params,
 707                         num_pdm_active), 0},
 708        {SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH,
 709                SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
 710                offsetof(struct sof_ipc_dai_dmic_params, fifo_bits), 0},
 711        {SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS,
 712                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 713                offsetof(struct sof_ipc_dai_dmic_params, unmute_ramp_time), 0},
 714
 715};
 716
 717/* ESAI */
 718static const struct sof_topology_token esai_tokens[] = {
 719        {SOF_TKN_IMX_ESAI_MCLK_ID,
 720                SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
 721                offsetof(struct sof_ipc_dai_esai_params, mclk_id), 0},
 722};
 723
 724/* SAI */
 725static const struct sof_topology_token sai_tokens[] = {
 726        {SOF_TKN_IMX_SAI_MCLK_ID,
 727                SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
 728                offsetof(struct sof_ipc_dai_sai_params, mclk_id), 0},
 729};
 730
 731/* Core tokens */
 732static const struct sof_topology_token core_tokens[] = {
 733        {SOF_TKN_COMP_CORE_ID,
 734                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 735                offsetof(struct sof_ipc_comp, core), 0},
 736};
 737
 738/* Component extended tokens */
 739static const struct sof_topology_token comp_ext_tokens[] = {
 740        {SOF_TKN_COMP_UUID,
 741                SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
 742                offsetof(struct sof_ipc_comp_ext, uuid), 0},
 743};
 744
 745/*
 746 * DMIC PDM Tokens
 747 * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token
 748 * as it increments the index while parsing the array of pdm tokens
 749 * and determines the correct offset
 750 */
 751static const struct sof_topology_token dmic_pdm_tokens[] = {
 752        {SOF_TKN_INTEL_DMIC_PDM_CTRL_ID,
 753                SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
 754                offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, id),
 755                0},
 756        {SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable,
 757                SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
 758                offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_a),
 759                0},
 760        {SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable,
 761                SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
 762                offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_b),
 763                0},
 764        {SOF_TKN_INTEL_DMIC_PDM_POLARITY_A,
 765                SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
 766                offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_a),
 767                0},
 768        {SOF_TKN_INTEL_DMIC_PDM_POLARITY_B,
 769                SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
 770                offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_b),
 771                0},
 772        {SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE,
 773                SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
 774                offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, clk_edge),
 775                0},
 776        {SOF_TKN_INTEL_DMIC_PDM_SKEW,
 777                SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
 778                offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, skew),
 779                0},
 780};
 781
 782/* HDA */
 783static const struct sof_topology_token hda_tokens[] = {
 784        {SOF_TKN_INTEL_HDA_RATE,
 785                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 786                offsetof(struct sof_ipc_dai_hda_params, rate), 0},
 787        {SOF_TKN_INTEL_HDA_CH,
 788                SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 789                offsetof(struct sof_ipc_dai_hda_params, channels), 0},
 790};
 791
 792/* Leds */
 793static const struct sof_topology_token led_tokens[] = {
 794        {SOF_TKN_MUTE_LED_USE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 795         offsetof(struct snd_sof_led_control, use_led), 0},
 796        {SOF_TKN_MUTE_LED_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD,
 797         get_token_u32, offsetof(struct snd_sof_led_control, direction), 0},
 798};
 799
 800static int sof_parse_uuid_tokens(struct snd_soc_component *scomp,
 801                                 void *object,
 802                                 const struct sof_topology_token *tokens,
 803                                 int count,
 804                                 struct snd_soc_tplg_vendor_array *array,
 805                                 size_t offset)
 806{
 807        struct snd_soc_tplg_vendor_uuid_elem *elem;
 808        int found = 0;
 809        int i, j;
 810
 811        /* parse element by element */
 812        for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
 813                elem = &array->uuid[i];
 814
 815                /* search for token */
 816                for (j = 0; j < count; j++) {
 817                        /* match token type */
 818                        if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_UUID)
 819                                continue;
 820
 821                        /* match token id */
 822                        if (tokens[j].token != le32_to_cpu(elem->token))
 823                                continue;
 824
 825                        /* matched - now load token */
 826                        tokens[j].get_token(elem, object,
 827                                            offset + tokens[j].offset,
 828                                            tokens[j].size);
 829
 830                        found++;
 831                }
 832        }
 833
 834        return found;
 835}
 836
 837static int sof_parse_string_tokens(struct snd_soc_component *scomp,
 838                                   void *object,
 839                                   const struct sof_topology_token *tokens,
 840                                   int count,
 841                                   struct snd_soc_tplg_vendor_array *array,
 842                                   size_t offset)
 843{
 844        struct snd_soc_tplg_vendor_string_elem *elem;
 845        int found = 0;
 846        int i, j;
 847
 848        /* parse element by element */
 849        for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
 850                elem = &array->string[i];
 851
 852                /* search for token */
 853                for (j = 0; j < count; j++) {
 854                        /* match token type */
 855                        if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_STRING)
 856                                continue;
 857
 858                        /* match token id */
 859                        if (tokens[j].token != le32_to_cpu(elem->token))
 860                                continue;
 861
 862                        /* matched - now load token */
 863                        tokens[j].get_token(elem, object,
 864                                            offset + tokens[j].offset,
 865                                            tokens[j].size);
 866
 867                        found++;
 868                }
 869        }
 870
 871        return found;
 872}
 873
 874static int sof_parse_word_tokens(struct snd_soc_component *scomp,
 875                                 void *object,
 876                                 const struct sof_topology_token *tokens,
 877                                 int count,
 878                                 struct snd_soc_tplg_vendor_array *array,
 879                                 size_t offset)
 880{
 881        struct snd_soc_tplg_vendor_value_elem *elem;
 882        int found = 0;
 883        int i, j;
 884
 885        /* parse element by element */
 886        for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
 887                elem = &array->value[i];
 888
 889                /* search for token */
 890                for (j = 0; j < count; j++) {
 891                        /* match token type */
 892                        if (!(tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_WORD ||
 893                              tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_SHORT ||
 894                              tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_BYTE ||
 895                              tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_BOOL))
 896                                continue;
 897
 898                        /* match token id */
 899                        if (tokens[j].token != le32_to_cpu(elem->token))
 900                                continue;
 901
 902                        /* load token */
 903                        tokens[j].get_token(elem, object,
 904                                            offset + tokens[j].offset,
 905                                            tokens[j].size);
 906
 907                        found++;
 908                }
 909        }
 910
 911        return found;
 912}
 913
 914/**
 915 * sof_parse_token_sets - Parse multiple sets of tokens
 916 * @scomp: pointer to soc component
 917 * @object: target ipc struct for parsed values
 918 * @tokens: token definition array describing what tokens to parse
 919 * @count: number of tokens in definition array
 920 * @array: source pointer to consecutive vendor arrays to be parsed
 921 * @priv_size: total size of the consecutive source arrays
 922 * @sets: number of similar token sets to be parsed, 1 set has count elements
 923 * @object_size: offset to next target ipc struct with multiple sets
 924 *
 925 * This function parses multiple sets of tokens in vendor arrays into
 926 * consecutive ipc structs.
 927 */
 928static int sof_parse_token_sets(struct snd_soc_component *scomp,
 929                                void *object,
 930                                const struct sof_topology_token *tokens,
 931                                int count,
 932                                struct snd_soc_tplg_vendor_array *array,
 933                                int priv_size, int sets, size_t object_size)
 934{
 935        size_t offset = 0;
 936        int found = 0;
 937        int total = 0;
 938        int asize;
 939
 940        while (priv_size > 0 && total < count * sets) {
 941                asize = le32_to_cpu(array->size);
 942
 943                /* validate asize */
 944                if (asize < 0) { /* FIXME: A zero-size array makes no sense */
 945                        dev_err(scomp->dev, "error: invalid array size 0x%x\n",
 946                                asize);
 947                        return -EINVAL;
 948                }
 949
 950                /* make sure there is enough data before parsing */
 951                priv_size -= asize;
 952                if (priv_size < 0) {
 953                        dev_err(scomp->dev, "error: invalid array size 0x%x\n",
 954                                asize);
 955                        return -EINVAL;
 956                }
 957
 958                /* call correct parser depending on type */
 959                switch (le32_to_cpu(array->type)) {
 960                case SND_SOC_TPLG_TUPLE_TYPE_UUID:
 961                        found += sof_parse_uuid_tokens(scomp, object, tokens,
 962                                                       count, array, offset);
 963                        break;
 964                case SND_SOC_TPLG_TUPLE_TYPE_STRING:
 965                        found += sof_parse_string_tokens(scomp, object, tokens,
 966                                                         count, array, offset);
 967                        break;
 968                case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
 969                case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
 970                case SND_SOC_TPLG_TUPLE_TYPE_WORD:
 971                case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
 972                        found += sof_parse_word_tokens(scomp, object, tokens,
 973                                                       count, array, offset);
 974                        break;
 975                default:
 976                        dev_err(scomp->dev, "error: unknown token type %d\n",
 977                                array->type);
 978                        return -EINVAL;
 979                }
 980
 981                /* next array */
 982                array = (struct snd_soc_tplg_vendor_array *)((u8 *)array
 983                        + asize);
 984
 985                /* move to next target struct */
 986                if (found >= count) {
 987                        offset += object_size;
 988                        total += found;
 989                        found = 0;
 990                }
 991        }
 992
 993        return 0;
 994}
 995
 996static int sof_parse_tokens(struct snd_soc_component *scomp,
 997                            void *object,
 998                            const struct sof_topology_token *tokens,
 999                            int count,
1000                            struct snd_soc_tplg_vendor_array *array,
1001                            int priv_size)
1002{
1003        /*
1004         * sof_parse_tokens is used when topology contains only a single set of
1005         * identical tuples arrays. So additional parameters to
1006         * sof_parse_token_sets are sets = 1 (only 1 set) and
1007         * object_size = 0 (irrelevant).
1008         */
1009        return sof_parse_token_sets(scomp, object, tokens, count, array,
1010                                    priv_size, 1, 0);
1011}
1012
1013static void sof_dbg_comp_config(struct snd_soc_component *scomp,
1014                                struct sof_ipc_comp_config *config)
1015{
1016        dev_dbg(scomp->dev, " config: periods snk %d src %d fmt %d\n",
1017                config->periods_sink, config->periods_source,
1018                config->frame_fmt);
1019}
1020
1021/*
1022 * Standard Kcontrols.
1023 */
1024
1025static int sof_control_load_volume(struct snd_soc_component *scomp,
1026                                   struct snd_sof_control *scontrol,
1027                                   struct snd_kcontrol_new *kc,
1028                                   struct snd_soc_tplg_ctl_hdr *hdr)
1029{
1030        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1031        struct snd_soc_tplg_mixer_control *mc =
1032                container_of(hdr, struct snd_soc_tplg_mixer_control, hdr);
1033        struct sof_ipc_ctrl_data *cdata;
1034        int tlv[TLV_ITEMS];
1035        unsigned int i;
1036        int ret;
1037
1038        /* validate topology data */
1039        if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) {
1040                ret = -EINVAL;
1041                goto out;
1042        }
1043
1044        /*
1045         * If control has more than 2 channels we need to override the info. This is because even if
1046         * ASoC layer has defined topology's max channel count to SND_SOC_TPLG_MAX_CHAN = 8, the
1047         * pre-defined dapm control types (and related functions) creating the actual control
1048         * restrict the channels only to mono or stereo.
1049         */
1050        if (le32_to_cpu(mc->num_channels) > 2)
1051                kc->info = snd_sof_volume_info;
1052
1053        /* init the volume get/put data */
1054        scontrol->size = struct_size(scontrol->control_data, chanv,
1055                                     le32_to_cpu(mc->num_channels));
1056        scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL);
1057        if (!scontrol->control_data) {
1058                ret = -ENOMEM;
1059                goto out;
1060        }
1061
1062        scontrol->comp_id = sdev->next_comp_id;
1063        scontrol->min_volume_step = le32_to_cpu(mc->min);
1064        scontrol->max_volume_step = le32_to_cpu(mc->max);
1065        scontrol->num_channels = le32_to_cpu(mc->num_channels);
1066
1067        /* set cmd for mixer control */
1068        if (le32_to_cpu(mc->max) == 1) {
1069                scontrol->cmd = SOF_CTRL_CMD_SWITCH;
1070                goto skip;
1071        }
1072
1073        scontrol->cmd = SOF_CTRL_CMD_VOLUME;
1074
1075        /* extract tlv data */
1076        if (!kc->tlv.p || get_tlv_data(kc->tlv.p, tlv) < 0) {
1077                dev_err(scomp->dev, "error: invalid TLV data\n");
1078                ret = -EINVAL;
1079                goto out_free;
1080        }
1081
1082        /* set up volume table */
1083        ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1);
1084        if (ret < 0) {
1085                dev_err(scomp->dev, "error: setting up volume table\n");
1086                goto out_free;
1087        }
1088
1089        /* set default volume values to 0dB in control */
1090        cdata = scontrol->control_data;
1091        for (i = 0; i < scontrol->num_channels; i++) {
1092                cdata->chanv[i].channel = i;
1093                cdata->chanv[i].value = VOL_ZERO_DB;
1094        }
1095
1096skip:
1097        /* set up possible led control from mixer private data */
1098        ret = sof_parse_tokens(scomp, &scontrol->led_ctl, led_tokens,
1099                               ARRAY_SIZE(led_tokens), mc->priv.array,
1100                               le32_to_cpu(mc->priv.size));
1101        if (ret != 0) {
1102                dev_err(scomp->dev, "error: parse led tokens failed %d\n",
1103                        le32_to_cpu(mc->priv.size));
1104                goto out_free_table;
1105        }
1106
1107        dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n",
1108                scontrol->comp_id, scontrol->num_channels);
1109
1110        return 0;
1111
1112out_free_table:
1113        if (le32_to_cpu(mc->max) > 1)
1114                kfree(scontrol->volume_table);
1115out_free:
1116        kfree(scontrol->control_data);
1117out:
1118        return ret;
1119}
1120
1121static int sof_control_load_enum(struct snd_soc_component *scomp,
1122                                 struct snd_sof_control *scontrol,
1123                                 struct snd_kcontrol_new *kc,
1124                                 struct snd_soc_tplg_ctl_hdr *hdr)
1125{
1126        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1127        struct snd_soc_tplg_enum_control *ec =
1128                container_of(hdr, struct snd_soc_tplg_enum_control, hdr);
1129
1130        /* validate topology data */
1131        if (le32_to_cpu(ec->num_channels) > SND_SOC_TPLG_MAX_CHAN)
1132                return -EINVAL;
1133
1134        /* init the enum get/put data */
1135        scontrol->size = struct_size(scontrol->control_data, chanv,
1136                                     le32_to_cpu(ec->num_channels));
1137        scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL);
1138        if (!scontrol->control_data)
1139                return -ENOMEM;
1140
1141        scontrol->comp_id = sdev->next_comp_id;
1142        scontrol->num_channels = le32_to_cpu(ec->num_channels);
1143
1144        scontrol->cmd = SOF_CTRL_CMD_ENUM;
1145
1146        dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n",
1147                scontrol->comp_id, scontrol->num_channels, scontrol->comp_id);
1148
1149        return 0;
1150}
1151
1152static int sof_control_load_bytes(struct snd_soc_component *scomp,
1153                                  struct snd_sof_control *scontrol,
1154                                  struct snd_kcontrol_new *kc,
1155                                  struct snd_soc_tplg_ctl_hdr *hdr)
1156{
1157        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1158        struct sof_ipc_ctrl_data *cdata;
1159        struct snd_soc_tplg_bytes_control *control =
1160                container_of(hdr, struct snd_soc_tplg_bytes_control, hdr);
1161        struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value;
1162        size_t max_size = sbe->max;
1163        size_t priv_size = le32_to_cpu(control->priv.size);
1164        int ret;
1165
1166        if (max_size < sizeof(struct sof_ipc_ctrl_data) ||
1167            max_size < sizeof(struct sof_abi_hdr)) {
1168                ret = -EINVAL;
1169                goto out;
1170        }
1171
1172        /* init the get/put bytes data */
1173        if (priv_size > max_size - sizeof(struct sof_ipc_ctrl_data)) {
1174                dev_err(scomp->dev, "err: bytes data size %zu exceeds max %zu.\n",
1175                        priv_size, max_size - sizeof(struct sof_ipc_ctrl_data));
1176                ret = -EINVAL;
1177                goto out;
1178        }
1179
1180        scontrol->size = sizeof(struct sof_ipc_ctrl_data) + priv_size;
1181
1182        scontrol->control_data = kzalloc(max_size, GFP_KERNEL);
1183        cdata = scontrol->control_data;
1184        if (!scontrol->control_data) {
1185                ret = -ENOMEM;
1186                goto out;
1187        }
1188
1189        scontrol->comp_id = sdev->next_comp_id;
1190        scontrol->cmd = SOF_CTRL_CMD_BINARY;
1191
1192        dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n",
1193                scontrol->comp_id, scontrol->num_channels);
1194
1195        if (le32_to_cpu(control->priv.size) > 0) {
1196                memcpy(cdata->data, control->priv.data,
1197                       le32_to_cpu(control->priv.size));
1198
1199                if (cdata->data->magic != SOF_ABI_MAGIC) {
1200                        dev_err(scomp->dev, "error: Wrong ABI magic 0x%08x.\n",
1201                                cdata->data->magic);
1202                        ret = -EINVAL;
1203                        goto out_free;
1204                }
1205                if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION,
1206                                                 cdata->data->abi)) {
1207                        dev_err(scomp->dev,
1208                                "error: Incompatible ABI version 0x%08x.\n",
1209                                cdata->data->abi);
1210                        ret = -EINVAL;
1211                        goto out_free;
1212                }
1213                if (cdata->data->size + sizeof(struct sof_abi_hdr) !=
1214                    le32_to_cpu(control->priv.size)) {
1215                        dev_err(scomp->dev,
1216                                "error: Conflict in bytes vs. priv size.\n");
1217                        ret = -EINVAL;
1218                        goto out_free;
1219                }
1220        }
1221
1222        return 0;
1223
1224out_free:
1225        kfree(scontrol->control_data);
1226out:
1227        return ret;
1228}
1229
1230/* external kcontrol init - used for any driver specific init */
1231static int sof_control_load(struct snd_soc_component *scomp, int index,
1232                            struct snd_kcontrol_new *kc,
1233                            struct snd_soc_tplg_ctl_hdr *hdr)
1234{
1235        struct soc_mixer_control *sm;
1236        struct soc_bytes_ext *sbe;
1237        struct soc_enum *se;
1238        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1239        struct snd_soc_dobj *dobj;
1240        struct snd_sof_control *scontrol;
1241        int ret;
1242
1243        dev_dbg(scomp->dev, "tplg: load control type %d name : %s\n",
1244                hdr->type, hdr->name);
1245
1246        scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
1247        if (!scontrol)
1248                return -ENOMEM;
1249
1250        scontrol->scomp = scomp;
1251
1252        switch (le32_to_cpu(hdr->ops.info)) {
1253        case SND_SOC_TPLG_CTL_VOLSW:
1254        case SND_SOC_TPLG_CTL_VOLSW_SX:
1255        case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1256                sm = (struct soc_mixer_control *)kc->private_value;
1257                dobj = &sm->dobj;
1258                ret = sof_control_load_volume(scomp, scontrol, kc, hdr);
1259                break;
1260        case SND_SOC_TPLG_CTL_BYTES:
1261                sbe = (struct soc_bytes_ext *)kc->private_value;
1262                dobj = &sbe->dobj;
1263                ret = sof_control_load_bytes(scomp, scontrol, kc, hdr);
1264                break;
1265        case SND_SOC_TPLG_CTL_ENUM:
1266        case SND_SOC_TPLG_CTL_ENUM_VALUE:
1267                se = (struct soc_enum *)kc->private_value;
1268                dobj = &se->dobj;
1269                ret = sof_control_load_enum(scomp, scontrol, kc, hdr);
1270                break;
1271        case SND_SOC_TPLG_CTL_RANGE:
1272        case SND_SOC_TPLG_CTL_STROBE:
1273        case SND_SOC_TPLG_DAPM_CTL_VOLSW:
1274        case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1275        case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1276        case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1277        case SND_SOC_TPLG_DAPM_CTL_PIN:
1278        default:
1279                dev_warn(scomp->dev, "control type not supported %d:%d:%d\n",
1280                         hdr->ops.get, hdr->ops.put, hdr->ops.info);
1281                kfree(scontrol);
1282                return 0;
1283        }
1284
1285        if (ret < 0) {
1286                kfree(scontrol);
1287                return ret;
1288        }
1289
1290        scontrol->led_ctl.led_value = -1;
1291
1292        dobj->private = scontrol;
1293        list_add(&scontrol->list, &sdev->kcontrol_list);
1294        return 0;
1295}
1296
1297static int sof_control_unload(struct snd_soc_component *scomp,
1298                              struct snd_soc_dobj *dobj)
1299{
1300        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1301        struct sof_ipc_free fcomp;
1302        struct snd_sof_control *scontrol = dobj->private;
1303
1304        dev_dbg(scomp->dev, "tplg: unload control name : %s\n", scomp->name);
1305
1306        fcomp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_FREE;
1307        fcomp.hdr.size = sizeof(fcomp);
1308        fcomp.id = scontrol->comp_id;
1309
1310        kfree(scontrol->control_data);
1311        list_del(&scontrol->list);
1312        kfree(scontrol);
1313        /* send IPC to the DSP */
1314        return sof_ipc_tx_message(sdev->ipc,
1315                                  fcomp.hdr.cmd, &fcomp, sizeof(fcomp),
1316                                  NULL, 0);
1317}
1318
1319/*
1320 * DAI Topology
1321 */
1322
1323/* Static DSP core power management so far, should be extended in the future */
1324static int sof_core_enable(struct snd_sof_dev *sdev, int core)
1325{
1326        struct sof_ipc_pm_core_config pm_core_config = {
1327                .hdr = {
1328                        .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
1329                        .size = sizeof(pm_core_config),
1330                },
1331                .enable_mask = sdev->enabled_cores_mask | BIT(core),
1332        };
1333        int ret;
1334
1335        if (sdev->enabled_cores_mask & BIT(core))
1336                return 0;
1337
1338        /* power up the core if it is host managed */
1339        ret = snd_sof_dsp_core_power_up(sdev, BIT(core));
1340        if (ret < 0) {
1341                dev_err(sdev->dev, "error: %d powering up core %d\n",
1342                        ret, core);
1343                return ret;
1344        }
1345
1346        /* Now notify DSP */
1347        ret = sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd,
1348                                 &pm_core_config, sizeof(pm_core_config),
1349                                 &pm_core_config, sizeof(pm_core_config));
1350        if (ret < 0) {
1351                dev_err(sdev->dev, "error: core %d enable ipc failure %d\n",
1352                        core, ret);
1353                goto err;
1354        }
1355        return ret;
1356err:
1357        /* power down core if it is host managed and return the original error if this fails too */
1358        if (snd_sof_dsp_core_power_down(sdev, BIT(core)) < 0)
1359                dev_err(sdev->dev, "error: powering down core %d\n", core);
1360
1361        return ret;
1362}
1363
1364int sof_pipeline_core_enable(struct snd_sof_dev *sdev,
1365                             const struct snd_sof_widget *swidget)
1366{
1367        const struct sof_ipc_pipe_new *pipeline;
1368        int ret;
1369
1370        if (swidget->id == snd_soc_dapm_scheduler) {
1371                pipeline = swidget->private;
1372        } else {
1373                pipeline = snd_sof_pipeline_find(sdev, swidget->pipeline_id);
1374                if (!pipeline)
1375                        return -ENOENT;
1376        }
1377
1378        /* First enable the pipeline core */
1379        ret = sof_core_enable(sdev, pipeline->core);
1380        if (ret < 0)
1381                return ret;
1382
1383        return sof_core_enable(sdev, swidget->core);
1384}
1385
1386static int sof_connect_dai_widget(struct snd_soc_component *scomp,
1387                                  struct snd_soc_dapm_widget *w,
1388                                  struct snd_soc_tplg_dapm_widget *tw,
1389                                  struct snd_sof_dai *dai)
1390{
1391        struct snd_soc_card *card = scomp->card;
1392        struct snd_soc_pcm_runtime *rtd;
1393        struct snd_soc_dai *cpu_dai;
1394        int i;
1395
1396        list_for_each_entry(rtd, &card->rtd_list, list) {
1397                dev_vdbg(scomp->dev, "tplg: check widget: %s stream: %s dai stream: %s\n",
1398                         w->name,  w->sname, rtd->dai_link->stream_name);
1399
1400                if (!w->sname || !rtd->dai_link->stream_name)
1401                        continue;
1402
1403                /* does stream match DAI link ? */
1404                if (strcmp(w->sname, rtd->dai_link->stream_name))
1405                        continue;
1406
1407                switch (w->id) {
1408                case snd_soc_dapm_dai_out:
1409                        for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
1410                                /*
1411                                 * Please create DAI widget in the right order
1412                                 * to ensure BE will connect to the right DAI
1413                                 * widget.
1414                                 */
1415                                if (!cpu_dai->capture_widget) {
1416                                        cpu_dai->capture_widget = w;
1417                                        break;
1418                                }
1419                        }
1420                        if (i == rtd->num_cpus) {
1421                                dev_err(scomp->dev, "error: can't find BE for DAI %s\n",
1422                                        w->name);
1423
1424                                return -EINVAL;
1425                        }
1426                        dai->name = rtd->dai_link->name;
1427                        dev_dbg(scomp->dev, "tplg: connected widget %s -> DAI link %s\n",
1428                                w->name, rtd->dai_link->name);
1429                        break;
1430                case snd_soc_dapm_dai_in:
1431                        for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
1432                                /*
1433                                 * Please create DAI widget in the right order
1434                                 * to ensure BE will connect to the right DAI
1435                                 * widget.
1436                                 */
1437                                if (!cpu_dai->playback_widget) {
1438                                        cpu_dai->playback_widget = w;
1439                                        break;
1440                                }
1441                        }
1442                        if (i == rtd->num_cpus) {
1443                                dev_err(scomp->dev, "error: can't find BE for DAI %s\n",
1444                                        w->name);
1445
1446                                return -EINVAL;
1447                        }
1448                        dai->name = rtd->dai_link->name;
1449                        dev_dbg(scomp->dev, "tplg: connected widget %s -> DAI link %s\n",
1450                                w->name, rtd->dai_link->name);
1451                        break;
1452                default:
1453                        break;
1454                }
1455        }
1456
1457        /* check we have a connection */
1458        if (!dai->name) {
1459                dev_err(scomp->dev, "error: can't connect DAI %s stream %s\n",
1460                        w->name, w->sname);
1461                return -EINVAL;
1462        }
1463
1464        return 0;
1465}
1466
1467/**
1468 * sof_comp_alloc - allocate and initialize buffer for a new component
1469 * @swidget: pointer to struct snd_sof_widget containing extended data
1470 * @ipc_size: IPC payload size that will be updated depending on valid
1471 *  extended data.
1472 * @index: ID of the pipeline the component belongs to
1473 *
1474 * Return: The pointer to the new allocated component, NULL if failed.
1475 */
1476static struct sof_ipc_comp *sof_comp_alloc(struct snd_sof_widget *swidget,
1477                                           size_t *ipc_size, int index)
1478{
1479        u8 nil_uuid[SOF_UUID_SIZE] = {0};
1480        struct sof_ipc_comp *comp;
1481        size_t total_size = *ipc_size;
1482
1483        /* only non-zero UUID is valid */
1484        if (memcmp(&swidget->comp_ext, nil_uuid, SOF_UUID_SIZE))
1485                total_size += sizeof(swidget->comp_ext);
1486
1487        comp = kzalloc(total_size, GFP_KERNEL);
1488        if (!comp)
1489                return NULL;
1490
1491        /* configure comp new IPC message */
1492        comp->hdr.size = total_size;
1493        comp->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
1494        comp->id = swidget->comp_id;
1495        comp->pipeline_id = index;
1496        comp->core = swidget->core;
1497
1498        /* handle the extended data if needed */
1499        if (total_size > *ipc_size) {
1500                /* append extended data to the end of the component */
1501                memcpy((u8 *)comp + *ipc_size, &swidget->comp_ext, sizeof(swidget->comp_ext));
1502                comp->ext_data_length = sizeof(swidget->comp_ext);
1503        }
1504
1505        /* update ipc_size and return */
1506        *ipc_size = total_size;
1507        return comp;
1508}
1509
1510static int sof_widget_load_dai(struct snd_soc_component *scomp, int index,
1511                               struct snd_sof_widget *swidget,
1512                               struct snd_soc_tplg_dapm_widget *tw,
1513                               struct sof_ipc_comp_reply *r,
1514                               struct snd_sof_dai *dai)
1515{
1516        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1517        struct snd_soc_tplg_private *private = &tw->priv;
1518        struct sof_ipc_comp_dai *comp_dai;
1519        size_t ipc_size = sizeof(*comp_dai);
1520        int ret;
1521
1522        comp_dai = (struct sof_ipc_comp_dai *)
1523                   sof_comp_alloc(swidget, &ipc_size, index);
1524        if (!comp_dai)
1525                return -ENOMEM;
1526
1527        /* configure dai IPC message */
1528        comp_dai->comp.type = SOF_COMP_DAI;
1529        comp_dai->config.hdr.size = sizeof(comp_dai->config);
1530
1531        ret = sof_parse_tokens(scomp, comp_dai, dai_tokens,
1532                               ARRAY_SIZE(dai_tokens), private->array,
1533                               le32_to_cpu(private->size));
1534        if (ret != 0) {
1535                dev_err(scomp->dev, "error: parse dai tokens failed %d\n",
1536                        le32_to_cpu(private->size));
1537                goto finish;
1538        }
1539
1540        ret = sof_parse_tokens(scomp, &comp_dai->config, comp_tokens,
1541                               ARRAY_SIZE(comp_tokens), private->array,
1542                               le32_to_cpu(private->size));
1543        if (ret != 0) {
1544                dev_err(scomp->dev, "error: parse dai.cfg tokens failed %d\n",
1545                        private->size);
1546                goto finish;
1547        }
1548
1549        dev_dbg(scomp->dev, "dai %s: type %d index %d\n",
1550                swidget->widget->name, comp_dai->type, comp_dai->dai_index);
1551        sof_dbg_comp_config(scomp, &comp_dai->config);
1552
1553        ret = sof_ipc_tx_message(sdev->ipc, comp_dai->comp.hdr.cmd,
1554                                 comp_dai, ipc_size, r, sizeof(*r));
1555
1556        if (ret == 0 && dai) {
1557                dai->scomp = scomp;
1558
1559                /*
1560                 * copy only the sof_ipc_comp_dai to avoid collapsing
1561                 * the snd_sof_dai, the extended data is kept in the
1562                 * snd_sof_widget.
1563                 */
1564                memcpy(&dai->comp_dai, comp_dai, sizeof(*comp_dai));
1565        }
1566
1567finish:
1568        kfree(comp_dai);
1569        return ret;
1570}
1571
1572/*
1573 * Buffer topology
1574 */
1575
1576static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index,
1577                                  struct snd_sof_widget *swidget,
1578                                  struct snd_soc_tplg_dapm_widget *tw,
1579                                  struct sof_ipc_comp_reply *r)
1580{
1581        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1582        struct snd_soc_tplg_private *private = &tw->priv;
1583        struct sof_ipc_buffer *buffer;
1584        int ret;
1585
1586        buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
1587        if (!buffer)
1588                return -ENOMEM;
1589
1590        /* configure dai IPC message */
1591        buffer->comp.hdr.size = sizeof(*buffer);
1592        buffer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_BUFFER_NEW;
1593        buffer->comp.id = swidget->comp_id;
1594        buffer->comp.type = SOF_COMP_BUFFER;
1595        buffer->comp.pipeline_id = index;
1596        buffer->comp.core = swidget->core;
1597
1598        ret = sof_parse_tokens(scomp, buffer, buffer_tokens,
1599                               ARRAY_SIZE(buffer_tokens), private->array,
1600                               le32_to_cpu(private->size));
1601        if (ret != 0) {
1602                dev_err(scomp->dev, "error: parse buffer tokens failed %d\n",
1603                        private->size);
1604                kfree(buffer);
1605                return ret;
1606        }
1607
1608        dev_dbg(scomp->dev, "buffer %s: size %d caps 0x%x\n",
1609                swidget->widget->name, buffer->size, buffer->caps);
1610
1611        swidget->private = buffer;
1612
1613        ret = sof_ipc_tx_message(sdev->ipc, buffer->comp.hdr.cmd, buffer,
1614                                 sizeof(*buffer), r, sizeof(*r));
1615        if (ret < 0) {
1616                dev_err(scomp->dev, "error: buffer %s load failed\n",
1617                        swidget->widget->name);
1618                kfree(buffer);
1619        }
1620
1621        return ret;
1622}
1623
1624/* bind PCM ID to host component ID */
1625static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm,
1626                     int dir)
1627{
1628        struct snd_sof_widget *host_widget;
1629
1630        host_widget = snd_sof_find_swidget_sname(scomp,
1631                                                 spcm->pcm.caps[dir].name,
1632                                                 dir);
1633        if (!host_widget) {
1634                dev_err(scomp->dev, "can't find host comp to bind pcm\n");
1635                return -EINVAL;
1636        }
1637
1638        spcm->stream[dir].comp_id = host_widget->comp_id;
1639
1640        return 0;
1641}
1642
1643/*
1644 * PCM Topology
1645 */
1646
1647static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index,
1648                               struct snd_sof_widget *swidget,
1649                               enum sof_ipc_stream_direction dir,
1650                               struct snd_soc_tplg_dapm_widget *tw,
1651                               struct sof_ipc_comp_reply *r)
1652{
1653        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1654        struct snd_soc_tplg_private *private = &tw->priv;
1655        struct sof_ipc_comp_host *host;
1656        size_t ipc_size = sizeof(*host);
1657        int ret;
1658
1659        host = (struct sof_ipc_comp_host *)
1660               sof_comp_alloc(swidget, &ipc_size, index);
1661        if (!host)
1662                return -ENOMEM;
1663
1664        /* configure host comp IPC message */
1665        host->comp.type = SOF_COMP_HOST;
1666        host->direction = dir;
1667        host->config.hdr.size = sizeof(host->config);
1668
1669        ret = sof_parse_tokens(scomp, host, pcm_tokens,
1670                               ARRAY_SIZE(pcm_tokens), private->array,
1671                               le32_to_cpu(private->size));
1672        if (ret != 0) {
1673                dev_err(scomp->dev, "error: parse host tokens failed %d\n",
1674                        private->size);
1675                goto err;
1676        }
1677
1678        ret = sof_parse_tokens(scomp, &host->config, comp_tokens,
1679                               ARRAY_SIZE(comp_tokens), private->array,
1680                               le32_to_cpu(private->size));
1681        if (ret != 0) {
1682                dev_err(scomp->dev, "error: parse host.cfg tokens failed %d\n",
1683                        le32_to_cpu(private->size));
1684                goto err;
1685        }
1686
1687        dev_dbg(scomp->dev, "loaded host %s\n", swidget->widget->name);
1688        sof_dbg_comp_config(scomp, &host->config);
1689
1690        swidget->private = host;
1691
1692        ret = sof_ipc_tx_message(sdev->ipc, host->comp.hdr.cmd, host,
1693                                 ipc_size, r, sizeof(*r));
1694        if (ret >= 0)
1695                return ret;
1696err:
1697        kfree(host);
1698        return ret;
1699}
1700
1701/*
1702 * Pipeline Topology
1703 */
1704int sof_load_pipeline_ipc(struct device *dev,
1705                          struct sof_ipc_pipe_new *pipeline,
1706                          struct sof_ipc_comp_reply *r)
1707{
1708        struct snd_sof_dev *sdev = dev_get_drvdata(dev);
1709        int ret = sof_core_enable(sdev, pipeline->core);
1710
1711        if (ret < 0)
1712                return ret;
1713
1714        ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
1715                                 sizeof(*pipeline), r, sizeof(*r));
1716        if (ret < 0)
1717                dev_err(dev, "error: load pipeline ipc failure\n");
1718
1719        return ret;
1720}
1721
1722static int sof_widget_load_pipeline(struct snd_soc_component *scomp, int index,
1723                                    struct snd_sof_widget *swidget,
1724                                    struct snd_soc_tplg_dapm_widget *tw,
1725                                    struct sof_ipc_comp_reply *r)
1726{
1727        struct snd_soc_tplg_private *private = &tw->priv;
1728        struct sof_ipc_pipe_new *pipeline;
1729        struct snd_sof_widget *comp_swidget;
1730        int ret;
1731
1732        pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
1733        if (!pipeline)
1734                return -ENOMEM;
1735
1736        /* configure dai IPC message */
1737        pipeline->hdr.size = sizeof(*pipeline);
1738        pipeline->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_NEW;
1739        pipeline->pipeline_id = index;
1740        pipeline->comp_id = swidget->comp_id;
1741
1742        /* component at start of pipeline is our stream id */
1743        comp_swidget = snd_sof_find_swidget(scomp, tw->sname);
1744        if (!comp_swidget) {
1745                dev_err(scomp->dev, "error: widget %s refers to non existent widget %s\n",
1746                        tw->name, tw->sname);
1747                ret = -EINVAL;
1748                goto err;
1749        }
1750
1751        pipeline->sched_id = comp_swidget->comp_id;
1752
1753        dev_dbg(scomp->dev, "tplg: pipeline id %d comp %d scheduling comp id %d\n",
1754                pipeline->pipeline_id, pipeline->comp_id, pipeline->sched_id);
1755
1756        ret = sof_parse_tokens(scomp, pipeline, sched_tokens,
1757                               ARRAY_SIZE(sched_tokens), private->array,
1758                               le32_to_cpu(private->size));
1759        if (ret != 0) {
1760                dev_err(scomp->dev, "error: parse pipeline tokens failed %d\n",
1761                        private->size);
1762                goto err;
1763        }
1764
1765        dev_dbg(scomp->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d\n",
1766                swidget->widget->name, pipeline->period, pipeline->priority,
1767                pipeline->period_mips, pipeline->core, pipeline->frames_per_sched);
1768
1769        swidget->private = pipeline;
1770
1771        /* send ipc's to create pipeline comp and power up schedule core */
1772        ret = sof_load_pipeline_ipc(scomp->dev, pipeline, r);
1773        if (ret >= 0)
1774                return ret;
1775err:
1776        kfree(pipeline);
1777        return ret;
1778}
1779
1780/*
1781 * Mixer topology
1782 */
1783
1784static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index,
1785                                 struct snd_sof_widget *swidget,
1786                                 struct snd_soc_tplg_dapm_widget *tw,
1787                                 struct sof_ipc_comp_reply *r)
1788{
1789        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1790        struct snd_soc_tplg_private *private = &tw->priv;
1791        struct sof_ipc_comp_mixer *mixer;
1792        size_t ipc_size = sizeof(*mixer);
1793        int ret;
1794
1795        mixer = (struct sof_ipc_comp_mixer *)
1796                sof_comp_alloc(swidget, &ipc_size, index);
1797        if (!mixer)
1798                return -ENOMEM;
1799
1800        /* configure mixer IPC message */
1801        mixer->comp.type = SOF_COMP_MIXER;
1802        mixer->config.hdr.size = sizeof(mixer->config);
1803
1804        ret = sof_parse_tokens(scomp, &mixer->config, comp_tokens,
1805                               ARRAY_SIZE(comp_tokens), private->array,
1806                               le32_to_cpu(private->size));
1807        if (ret != 0) {
1808                dev_err(scomp->dev, "error: parse mixer.cfg tokens failed %d\n",
1809                        private->size);
1810                kfree(mixer);
1811                return ret;
1812        }
1813
1814        sof_dbg_comp_config(scomp, &mixer->config);
1815
1816        swidget->private = mixer;
1817
1818        ret = sof_ipc_tx_message(sdev->ipc, mixer->comp.hdr.cmd, mixer,
1819                                 ipc_size, r, sizeof(*r));
1820        if (ret < 0)
1821                kfree(mixer);
1822
1823        return ret;
1824}
1825
1826/*
1827 * Mux topology
1828 */
1829static int sof_widget_load_mux(struct snd_soc_component *scomp, int index,
1830                               struct snd_sof_widget *swidget,
1831                               struct snd_soc_tplg_dapm_widget *tw,
1832                               struct sof_ipc_comp_reply *r)
1833{
1834        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1835        struct snd_soc_tplg_private *private = &tw->priv;
1836        struct sof_ipc_comp_mux *mux;
1837        size_t ipc_size = sizeof(*mux);
1838        int ret;
1839
1840        mux = (struct sof_ipc_comp_mux *)
1841              sof_comp_alloc(swidget, &ipc_size, index);
1842        if (!mux)
1843                return -ENOMEM;
1844
1845        /* configure mux IPC message */
1846        mux->comp.type = SOF_COMP_MUX;
1847        mux->config.hdr.size = sizeof(mux->config);
1848
1849        ret = sof_parse_tokens(scomp, &mux->config, comp_tokens,
1850                               ARRAY_SIZE(comp_tokens), private->array,
1851                               le32_to_cpu(private->size));
1852        if (ret != 0) {
1853                dev_err(scomp->dev, "error: parse mux.cfg tokens failed %d\n",
1854                        private->size);
1855                kfree(mux);
1856                return ret;
1857        }
1858
1859        sof_dbg_comp_config(scomp, &mux->config);
1860
1861        swidget->private = mux;
1862
1863        ret = sof_ipc_tx_message(sdev->ipc, mux->comp.hdr.cmd, mux,
1864                                 ipc_size, r, sizeof(*r));
1865        if (ret < 0)
1866                kfree(mux);
1867
1868        return ret;
1869}
1870
1871/*
1872 * PGA Topology
1873 */
1874
1875static int sof_widget_load_pga(struct snd_soc_component *scomp, int index,
1876                               struct snd_sof_widget *swidget,
1877                               struct snd_soc_tplg_dapm_widget *tw,
1878                               struct sof_ipc_comp_reply *r)
1879{
1880        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1881        struct snd_soc_tplg_private *private = &tw->priv;
1882        struct sof_ipc_comp_volume *volume;
1883        struct snd_sof_control *scontrol;
1884        size_t ipc_size = sizeof(*volume);
1885        int min_step;
1886        int max_step;
1887        int ret;
1888
1889        volume = (struct sof_ipc_comp_volume *)
1890                 sof_comp_alloc(swidget, &ipc_size, index);
1891        if (!volume)
1892                return -ENOMEM;
1893
1894        if (!le32_to_cpu(tw->num_kcontrols)) {
1895                dev_err(scomp->dev, "error: invalid kcontrol count %d for volume\n",
1896                        tw->num_kcontrols);
1897                ret = -EINVAL;
1898                goto err;
1899        }
1900
1901        /* configure volume IPC message */
1902        volume->comp.type = SOF_COMP_VOLUME;
1903        volume->config.hdr.size = sizeof(volume->config);
1904
1905        ret = sof_parse_tokens(scomp, volume, volume_tokens,
1906                               ARRAY_SIZE(volume_tokens), private->array,
1907                               le32_to_cpu(private->size));
1908        if (ret != 0) {
1909                dev_err(scomp->dev, "error: parse volume tokens failed %d\n",
1910                        private->size);
1911                goto err;
1912        }
1913        ret = sof_parse_tokens(scomp, &volume->config, comp_tokens,
1914                               ARRAY_SIZE(comp_tokens), private->array,
1915                               le32_to_cpu(private->size));
1916        if (ret != 0) {
1917                dev_err(scomp->dev, "error: parse volume.cfg tokens failed %d\n",
1918                        le32_to_cpu(private->size));
1919                goto err;
1920        }
1921
1922        sof_dbg_comp_config(scomp, &volume->config);
1923
1924        swidget->private = volume;
1925
1926        list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
1927                if (scontrol->comp_id == swidget->comp_id &&
1928                    scontrol->volume_table) {
1929                        min_step = scontrol->min_volume_step;
1930                        max_step = scontrol->max_volume_step;
1931                        volume->min_value = scontrol->volume_table[min_step];
1932                        volume->max_value = scontrol->volume_table[max_step];
1933                        volume->channels = scontrol->num_channels;
1934                        break;
1935                }
1936        }
1937
1938        ret = sof_ipc_tx_message(sdev->ipc, volume->comp.hdr.cmd, volume,
1939                                 ipc_size, r, sizeof(*r));
1940        if (ret >= 0)
1941                return ret;
1942err:
1943        kfree(volume);
1944        return ret;
1945}
1946
1947/*
1948 * SRC Topology
1949 */
1950
1951static int sof_widget_load_src(struct snd_soc_component *scomp, int index,
1952                               struct snd_sof_widget *swidget,
1953                               struct snd_soc_tplg_dapm_widget *tw,
1954                               struct sof_ipc_comp_reply *r)
1955{
1956        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1957        struct snd_soc_tplg_private *private = &tw->priv;
1958        struct sof_ipc_comp_src *src;
1959        size_t ipc_size = sizeof(*src);
1960        int ret;
1961
1962        src = (struct sof_ipc_comp_src *)
1963              sof_comp_alloc(swidget, &ipc_size, index);
1964        if (!src)
1965                return -ENOMEM;
1966
1967        /* configure src IPC message */
1968        src->comp.type = SOF_COMP_SRC;
1969        src->config.hdr.size = sizeof(src->config);
1970
1971        ret = sof_parse_tokens(scomp, src, src_tokens,
1972                               ARRAY_SIZE(src_tokens), private->array,
1973                               le32_to_cpu(private->size));
1974        if (ret != 0) {
1975                dev_err(scomp->dev, "error: parse src tokens failed %d\n",
1976                        private->size);
1977                goto err;
1978        }
1979
1980        ret = sof_parse_tokens(scomp, &src->config, comp_tokens,
1981                               ARRAY_SIZE(comp_tokens), private->array,
1982                               le32_to_cpu(private->size));
1983        if (ret != 0) {
1984                dev_err(scomp->dev, "error: parse src.cfg tokens failed %d\n",
1985                        le32_to_cpu(private->size));
1986                goto err;
1987        }
1988
1989        dev_dbg(scomp->dev, "src %s: source rate %d sink rate %d\n",
1990                swidget->widget->name, src->source_rate, src->sink_rate);
1991        sof_dbg_comp_config(scomp, &src->config);
1992
1993        swidget->private = src;
1994
1995        ret = sof_ipc_tx_message(sdev->ipc, src->comp.hdr.cmd, src,
1996                                 ipc_size, r, sizeof(*r));
1997        if (ret >= 0)
1998                return ret;
1999err:
2000        kfree(src);
2001        return ret;
2002}
2003
2004/*
2005 * ASRC Topology
2006 */
2007
2008static int sof_widget_load_asrc(struct snd_soc_component *scomp, int index,
2009                                struct snd_sof_widget *swidget,
2010                                struct snd_soc_tplg_dapm_widget *tw,
2011                                struct sof_ipc_comp_reply *r)
2012{
2013        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2014        struct snd_soc_tplg_private *private = &tw->priv;
2015        struct sof_ipc_comp_asrc *asrc;
2016        size_t ipc_size = sizeof(*asrc);
2017        int ret;
2018
2019        asrc = (struct sof_ipc_comp_asrc *)
2020               sof_comp_alloc(swidget, &ipc_size, index);
2021        if (!asrc)
2022                return -ENOMEM;
2023
2024        /* configure ASRC IPC message */
2025        asrc->comp.type = SOF_COMP_ASRC;
2026        asrc->config.hdr.size = sizeof(asrc->config);
2027
2028        ret = sof_parse_tokens(scomp, asrc, asrc_tokens,
2029                               ARRAY_SIZE(asrc_tokens), private->array,
2030                               le32_to_cpu(private->size));
2031        if (ret != 0) {
2032                dev_err(scomp->dev, "error: parse asrc tokens failed %d\n",
2033                        private->size);
2034                goto err;
2035        }
2036
2037        ret = sof_parse_tokens(scomp, &asrc->config, comp_tokens,
2038                               ARRAY_SIZE(comp_tokens), private->array,
2039                               le32_to_cpu(private->size));
2040        if (ret != 0) {
2041                dev_err(scomp->dev, "error: parse asrc.cfg tokens failed %d\n",
2042                        le32_to_cpu(private->size));
2043                goto err;
2044        }
2045
2046        dev_dbg(scomp->dev, "asrc %s: source rate %d sink rate %d "
2047                "asynch %d operation %d\n",
2048                swidget->widget->name, asrc->source_rate, asrc->sink_rate,
2049                asrc->asynchronous_mode, asrc->operation_mode);
2050        sof_dbg_comp_config(scomp, &asrc->config);
2051
2052        swidget->private = asrc;
2053
2054        ret = sof_ipc_tx_message(sdev->ipc, asrc->comp.hdr.cmd, asrc,
2055                                 ipc_size, r, sizeof(*r));
2056        if (ret >= 0)
2057                return ret;
2058err:
2059        kfree(asrc);
2060        return ret;
2061}
2062
2063/*
2064 * Signal Generator Topology
2065 */
2066
2067static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index,
2068                                  struct snd_sof_widget *swidget,
2069                                  struct snd_soc_tplg_dapm_widget *tw,
2070                                  struct sof_ipc_comp_reply *r)
2071{
2072        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2073        struct snd_soc_tplg_private *private = &tw->priv;
2074        struct sof_ipc_comp_tone *tone;
2075        size_t ipc_size = sizeof(*tone);
2076        int ret;
2077
2078        tone = (struct sof_ipc_comp_tone *)
2079               sof_comp_alloc(swidget, &ipc_size, index);
2080        if (!tone)
2081                return -ENOMEM;
2082
2083        /* configure siggen IPC message */
2084        tone->comp.type = SOF_COMP_TONE;
2085        tone->config.hdr.size = sizeof(tone->config);
2086
2087        ret = sof_parse_tokens(scomp, tone, tone_tokens,
2088                               ARRAY_SIZE(tone_tokens), private->array,
2089                               le32_to_cpu(private->size));
2090        if (ret != 0) {
2091                dev_err(scomp->dev, "error: parse tone tokens failed %d\n",
2092                        le32_to_cpu(private->size));
2093                goto err;
2094        }
2095
2096        ret = sof_parse_tokens(scomp, &tone->config, comp_tokens,
2097                               ARRAY_SIZE(comp_tokens), private->array,
2098                               le32_to_cpu(private->size));
2099        if (ret != 0) {
2100                dev_err(scomp->dev, "error: parse tone.cfg tokens failed %d\n",
2101                        le32_to_cpu(private->size));
2102                goto err;
2103        }
2104
2105        dev_dbg(scomp->dev, "tone %s: frequency %d amplitude %d\n",
2106                swidget->widget->name, tone->frequency, tone->amplitude);
2107        sof_dbg_comp_config(scomp, &tone->config);
2108
2109        swidget->private = tone;
2110
2111        ret = sof_ipc_tx_message(sdev->ipc, tone->comp.hdr.cmd, tone,
2112                                 ipc_size, r, sizeof(*r));
2113        if (ret >= 0)
2114                return ret;
2115err:
2116        kfree(tone);
2117        return ret;
2118}
2119
2120static int sof_get_control_data(struct snd_soc_component *scomp,
2121                                struct snd_soc_dapm_widget *widget,
2122                                struct sof_widget_data *wdata,
2123                                size_t *size)
2124{
2125        const struct snd_kcontrol_new *kc;
2126        struct soc_mixer_control *sm;
2127        struct soc_bytes_ext *sbe;
2128        struct soc_enum *se;
2129        int i;
2130
2131        *size = 0;
2132
2133        for (i = 0; i < widget->num_kcontrols; i++) {
2134                kc = &widget->kcontrol_news[i];
2135
2136                switch (widget->dobj.widget.kcontrol_type) {
2137                case SND_SOC_TPLG_TYPE_MIXER:
2138                        sm = (struct soc_mixer_control *)kc->private_value;
2139                        wdata[i].control = sm->dobj.private;
2140                        break;
2141                case SND_SOC_TPLG_TYPE_BYTES:
2142                        sbe = (struct soc_bytes_ext *)kc->private_value;
2143                        wdata[i].control = sbe->dobj.private;
2144                        break;
2145                case SND_SOC_TPLG_TYPE_ENUM:
2146                        se = (struct soc_enum *)kc->private_value;
2147                        wdata[i].control = se->dobj.private;
2148                        break;
2149                default:
2150                        dev_err(scomp->dev, "error: unknown kcontrol type %d in widget %s\n",
2151                                widget->dobj.widget.kcontrol_type,
2152                                widget->name);
2153                        return -EINVAL;
2154                }
2155
2156                if (!wdata[i].control) {
2157                        dev_err(scomp->dev, "error: no scontrol for widget %s\n",
2158                                widget->name);
2159                        return -EINVAL;
2160                }
2161
2162                wdata[i].pdata = wdata[i].control->control_data->data;
2163                if (!wdata[i].pdata)
2164                        return -EINVAL;
2165
2166                /* make sure data is valid - data can be updated at runtime */
2167                if (wdata[i].pdata->magic != SOF_ABI_MAGIC)
2168                        return -EINVAL;
2169
2170                *size += wdata[i].pdata->size;
2171
2172                /* get data type */
2173                switch (wdata[i].control->cmd) {
2174                case SOF_CTRL_CMD_VOLUME:
2175                case SOF_CTRL_CMD_ENUM:
2176                case SOF_CTRL_CMD_SWITCH:
2177                        wdata[i].ipc_cmd = SOF_IPC_COMP_SET_VALUE;
2178                        wdata[i].ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET;
2179                        break;
2180                case SOF_CTRL_CMD_BINARY:
2181                        wdata[i].ipc_cmd = SOF_IPC_COMP_SET_DATA;
2182                        wdata[i].ctrl_type = SOF_CTRL_TYPE_DATA_SET;
2183                        break;
2184                default:
2185                        break;
2186                }
2187        }
2188
2189        return 0;
2190}
2191
2192static int sof_process_load(struct snd_soc_component *scomp, int index,
2193                            struct snd_sof_widget *swidget,
2194                            struct snd_soc_tplg_dapm_widget *tw,
2195                            struct sof_ipc_comp_reply *r,
2196                            int type)
2197{
2198        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2199        struct snd_soc_dapm_widget *widget = swidget->widget;
2200        struct snd_soc_tplg_private *private = &tw->priv;
2201        struct sof_ipc_comp_process *process;
2202        struct sof_widget_data *wdata = NULL;
2203        size_t ipc_data_size = 0;
2204        size_t ipc_size;
2205        int offset = 0;
2206        int ret;
2207        int i;
2208
2209        /* allocate struct for widget control data sizes and types */
2210        if (widget->num_kcontrols) {
2211                wdata = kcalloc(widget->num_kcontrols,
2212                                sizeof(*wdata),
2213                                GFP_KERNEL);
2214
2215                if (!wdata)
2216                        return -ENOMEM;
2217
2218                /* get possible component controls and get size of all pdata */
2219                ret = sof_get_control_data(scomp, widget, wdata,
2220                                           &ipc_data_size);
2221
2222                if (ret < 0)
2223                        goto out;
2224        }
2225
2226        ipc_size = sizeof(struct sof_ipc_comp_process) + ipc_data_size;
2227
2228        /* we are exceeding max ipc size, config needs to be sent separately */
2229        if (ipc_size > SOF_IPC_MSG_MAX_SIZE) {
2230                ipc_size -= ipc_data_size;
2231                ipc_data_size = 0;
2232        }
2233
2234        process = (struct sof_ipc_comp_process *)
2235                  sof_comp_alloc(swidget, &ipc_size, index);
2236        if (!process) {
2237                ret = -ENOMEM;
2238                goto out;
2239        }
2240
2241        /* configure iir IPC message */
2242        process->comp.type = type;
2243        process->config.hdr.size = sizeof(process->config);
2244
2245        ret = sof_parse_tokens(scomp, &process->config, comp_tokens,
2246                               ARRAY_SIZE(comp_tokens), private->array,
2247                               le32_to_cpu(private->size));
2248        if (ret != 0) {
2249                dev_err(scomp->dev, "error: parse process.cfg tokens failed %d\n",
2250                        le32_to_cpu(private->size));
2251                goto err;
2252        }
2253
2254        sof_dbg_comp_config(scomp, &process->config);
2255
2256        /*
2257         * found private data in control, so copy it.
2258         * get possible component controls - get size of all pdata,
2259         * then memcpy with headers
2260         */
2261        if (ipc_data_size) {
2262                for (i = 0; i < widget->num_kcontrols; i++) {
2263                        memcpy(&process->data + offset,
2264                               wdata[i].pdata->data,
2265                               wdata[i].pdata->size);
2266                        offset += wdata[i].pdata->size;
2267                }
2268        }
2269
2270        process->size = ipc_data_size;
2271        swidget->private = process;
2272
2273        ret = sof_ipc_tx_message(sdev->ipc, process->comp.hdr.cmd, process,
2274                                 ipc_size, r, sizeof(*r));
2275
2276        if (ret < 0) {
2277                dev_err(scomp->dev, "error: create process failed\n");
2278                goto err;
2279        }
2280
2281        /* we sent the data in single message so return */
2282        if (ipc_data_size)
2283                goto out;
2284
2285        /* send control data with large message supported method */
2286        for (i = 0; i < widget->num_kcontrols; i++) {
2287                wdata[i].control->readback_offset = 0;
2288                ret = snd_sof_ipc_set_get_comp_data(wdata[i].control,
2289                                                    wdata[i].ipc_cmd,
2290                                                    wdata[i].ctrl_type,
2291                                                    wdata[i].control->cmd,
2292                                                    true);
2293                if (ret != 0) {
2294                        dev_err(scomp->dev, "error: send control failed\n");
2295                        break;
2296                }
2297        }
2298
2299err:
2300        if (ret < 0)
2301                kfree(process);
2302out:
2303        kfree(wdata);
2304        return ret;
2305}
2306
2307/*
2308 * Processing Component Topology - can be "effect", "codec", or general
2309 * "processing".
2310 */
2311
2312static int sof_widget_load_process(struct snd_soc_component *scomp, int index,
2313                                   struct snd_sof_widget *swidget,
2314                                   struct snd_soc_tplg_dapm_widget *tw,
2315                                   struct sof_ipc_comp_reply *r)
2316{
2317        struct snd_soc_tplg_private *private = &tw->priv;
2318        struct sof_ipc_comp_process config;
2319        int ret;
2320
2321        /* check we have some tokens - we need at least process type */
2322        if (le32_to_cpu(private->size) == 0) {
2323                dev_err(scomp->dev, "error: process tokens not found\n");
2324                return -EINVAL;
2325        }
2326
2327        memset(&config, 0, sizeof(config));
2328        config.comp.core = swidget->core;
2329
2330        /* get the process token */
2331        ret = sof_parse_tokens(scomp, &config, process_tokens,
2332                               ARRAY_SIZE(process_tokens), private->array,
2333                               le32_to_cpu(private->size));
2334        if (ret != 0) {
2335                dev_err(scomp->dev, "error: parse process tokens failed %d\n",
2336                        le32_to_cpu(private->size));
2337                return ret;
2338        }
2339
2340        /* now load process specific data and send IPC */
2341        ret = sof_process_load(scomp, index, swidget, tw, r,
2342                               find_process_comp_type(config.type));
2343        if (ret < 0) {
2344                dev_err(scomp->dev, "error: process loading failed\n");
2345                return ret;
2346        }
2347
2348        return 0;
2349}
2350
2351static int sof_widget_bind_event(struct snd_soc_component *scomp,
2352                                 struct snd_sof_widget *swidget,
2353                                 u16 event_type)
2354{
2355        struct sof_ipc_comp *ipc_comp;
2356
2357        /* validate widget event type */
2358        switch (event_type) {
2359        case SOF_KEYWORD_DETECT_DAPM_EVENT:
2360                /* only KEYWORD_DETECT comps should handle this */
2361                if (swidget->id != snd_soc_dapm_effect)
2362                        break;
2363
2364                ipc_comp = swidget->private;
2365                if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT)
2366                        break;
2367
2368                /* bind event to keyword detect comp */
2369                return snd_soc_tplg_widget_bind_event(swidget->widget,
2370                                                      sof_kwd_events,
2371                                                      ARRAY_SIZE(sof_kwd_events),
2372                                                      event_type);
2373        default:
2374                break;
2375        }
2376
2377        dev_err(scomp->dev,
2378                "error: invalid event type %d for widget %s\n",
2379                event_type, swidget->widget->name);
2380        return -EINVAL;
2381}
2382
2383/* external widget init - used for any driver specific init */
2384static int sof_widget_ready(struct snd_soc_component *scomp, int index,
2385                            struct snd_soc_dapm_widget *w,
2386                            struct snd_soc_tplg_dapm_widget *tw)
2387{
2388        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2389        struct snd_sof_widget *swidget;
2390        struct snd_sof_dai *dai;
2391        struct sof_ipc_comp_reply reply;
2392        struct snd_sof_control *scontrol;
2393        struct sof_ipc_comp comp = {
2394                .core = SOF_DSP_PRIMARY_CORE,
2395        };
2396        int ret = 0;
2397
2398        swidget = kzalloc(sizeof(*swidget), GFP_KERNEL);
2399        if (!swidget)
2400                return -ENOMEM;
2401
2402        swidget->scomp = scomp;
2403        swidget->widget = w;
2404        swidget->comp_id = sdev->next_comp_id++;
2405        swidget->complete = 0;
2406        swidget->id = w->id;
2407        swidget->pipeline_id = index;
2408        swidget->private = NULL;
2409        memset(&reply, 0, sizeof(reply));
2410
2411        dev_dbg(scomp->dev, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n",
2412                swidget->comp_id, index, swidget->id, tw->name,
2413                strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0
2414                        ? tw->sname : "none");
2415
2416        ret = sof_parse_tokens(scomp, &comp, core_tokens,
2417                               ARRAY_SIZE(core_tokens), tw->priv.array,
2418                               le32_to_cpu(tw->priv.size));
2419        if (ret != 0) {
2420                dev_err(scomp->dev, "error: parsing core tokens failed %d\n",
2421                        ret);
2422                kfree(swidget);
2423                return ret;
2424        }
2425
2426        swidget->core = comp.core;
2427
2428        /* default is primary core, safe to call for already enabled cores */
2429        ret = sof_core_enable(sdev, comp.core);
2430        if (ret < 0) {
2431                dev_err(scomp->dev, "error: enable core: %d\n", ret);
2432                kfree(swidget);
2433                return ret;
2434        }
2435
2436        ret = sof_parse_tokens(scomp, &swidget->comp_ext, comp_ext_tokens,
2437                               ARRAY_SIZE(comp_ext_tokens), tw->priv.array,
2438                               le32_to_cpu(tw->priv.size));
2439        if (ret != 0) {
2440                dev_err(scomp->dev, "error: parsing comp_ext_tokens failed %d\n",
2441                        ret);
2442                kfree(swidget);
2443                return ret;
2444        }
2445
2446        /* handle any special case widgets */
2447        switch (w->id) {
2448        case snd_soc_dapm_dai_in:
2449        case snd_soc_dapm_dai_out:
2450                dai = kzalloc(sizeof(*dai), GFP_KERNEL);
2451                if (!dai) {
2452                        kfree(swidget);
2453                        return -ENOMEM;
2454                }
2455
2456                ret = sof_widget_load_dai(scomp, index, swidget, tw, &reply, dai);
2457                if (ret == 0) {
2458                        sof_connect_dai_widget(scomp, w, tw, dai);
2459                        list_add(&dai->list, &sdev->dai_list);
2460                        swidget->private = dai;
2461                } else {
2462                        kfree(dai);
2463                }
2464                break;
2465        case snd_soc_dapm_mixer:
2466                ret = sof_widget_load_mixer(scomp, index, swidget, tw, &reply);
2467                break;
2468        case snd_soc_dapm_pga:
2469                ret = sof_widget_load_pga(scomp, index, swidget, tw, &reply);
2470                /* Find scontrol for this pga and set readback offset*/
2471                list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
2472                        if (scontrol->comp_id == swidget->comp_id) {
2473                                scontrol->readback_offset = reply.offset;
2474                                break;
2475                        }
2476                }
2477                break;
2478        case snd_soc_dapm_buffer:
2479                ret = sof_widget_load_buffer(scomp, index, swidget, tw, &reply);
2480                break;
2481        case snd_soc_dapm_scheduler:
2482                ret = sof_widget_load_pipeline(scomp, index, swidget, tw, &reply);
2483                break;
2484        case snd_soc_dapm_aif_out:
2485                ret = sof_widget_load_pcm(scomp, index, swidget,
2486                                          SOF_IPC_STREAM_CAPTURE, tw, &reply);
2487                break;
2488        case snd_soc_dapm_aif_in:
2489                ret = sof_widget_load_pcm(scomp, index, swidget,
2490                                          SOF_IPC_STREAM_PLAYBACK, tw, &reply);
2491                break;
2492        case snd_soc_dapm_src:
2493                ret = sof_widget_load_src(scomp, index, swidget, tw, &reply);
2494                break;
2495        case snd_soc_dapm_asrc:
2496                ret = sof_widget_load_asrc(scomp, index, swidget, tw, &reply);
2497                break;
2498        case snd_soc_dapm_siggen:
2499                ret = sof_widget_load_siggen(scomp, index, swidget, tw, &reply);
2500                break;
2501        case snd_soc_dapm_effect:
2502                ret = sof_widget_load_process(scomp, index, swidget, tw, &reply);
2503                break;
2504        case snd_soc_dapm_mux:
2505        case snd_soc_dapm_demux:
2506                ret = sof_widget_load_mux(scomp, index, swidget, tw, &reply);
2507                break;
2508        case snd_soc_dapm_switch:
2509        case snd_soc_dapm_dai_link:
2510        case snd_soc_dapm_kcontrol:
2511        default:
2512                dev_dbg(scomp->dev, "widget type %d name %s not handled\n", swidget->id, tw->name);
2513                break;
2514        }
2515
2516        /* check IPC reply */
2517        if (ret < 0 || reply.rhdr.error < 0) {
2518                dev_err(scomp->dev,
2519                        "error: DSP failed to add widget id %d type %d name : %s stream %s reply %d\n",
2520                        tw->shift, swidget->id, tw->name,
2521                        strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0
2522                                ? tw->sname : "none", reply.rhdr.error);
2523                kfree(swidget);
2524                return ret;
2525        }
2526
2527        /* bind widget to external event */
2528        if (tw->event_type) {
2529                ret = sof_widget_bind_event(scomp, swidget,
2530                                            le16_to_cpu(tw->event_type));
2531                if (ret) {
2532                        dev_err(scomp->dev, "error: widget event binding failed\n");
2533                        kfree(swidget->private);
2534                        kfree(swidget);
2535                        return ret;
2536                }
2537        }
2538
2539        w->dobj.private = swidget;
2540        list_add(&swidget->list, &sdev->widget_list);
2541        return ret;
2542}
2543
2544static int sof_route_unload(struct snd_soc_component *scomp,
2545                            struct snd_soc_dobj *dobj)
2546{
2547        struct snd_sof_route *sroute;
2548
2549        sroute = dobj->private;
2550        if (!sroute)
2551                return 0;
2552
2553        /* free sroute and its private data */
2554        kfree(sroute->private);
2555        list_del(&sroute->list);
2556        kfree(sroute);
2557
2558        return 0;
2559}
2560
2561static int sof_widget_unload(struct snd_soc_component *scomp,
2562                             struct snd_soc_dobj *dobj)
2563{
2564        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2565        const struct snd_kcontrol_new *kc;
2566        struct snd_soc_dapm_widget *widget;
2567        struct sof_ipc_pipe_new *pipeline;
2568        struct snd_sof_control *scontrol;
2569        struct snd_sof_widget *swidget;
2570        struct soc_mixer_control *sm;
2571        struct soc_bytes_ext *sbe;
2572        struct snd_sof_dai *dai;
2573        struct soc_enum *se;
2574        int ret = 0;
2575        int i;
2576
2577        swidget = dobj->private;
2578        if (!swidget)
2579                return 0;
2580
2581        widget = swidget->widget;
2582
2583        switch (swidget->id) {
2584        case snd_soc_dapm_dai_in:
2585        case snd_soc_dapm_dai_out:
2586                dai = swidget->private;
2587
2588                if (dai) {
2589                        /* free dai config */
2590                        kfree(dai->dai_config);
2591                        list_del(&dai->list);
2592                }
2593                break;
2594        case snd_soc_dapm_scheduler:
2595
2596                /* power down the pipeline schedule core */
2597                pipeline = swidget->private;
2598                ret = snd_sof_dsp_core_power_down(sdev, 1 << pipeline->core);
2599                if (ret < 0)
2600                        dev_err(scomp->dev, "error: powering down pipeline schedule core %d\n",
2601                                pipeline->core);
2602                break;
2603        default:
2604                break;
2605        }
2606        for (i = 0; i < widget->num_kcontrols; i++) {
2607                kc = &widget->kcontrol_news[i];
2608                switch (dobj->widget.kcontrol_type) {
2609                case SND_SOC_TPLG_TYPE_MIXER:
2610                        sm = (struct soc_mixer_control *)kc->private_value;
2611                        scontrol = sm->dobj.private;
2612                        if (sm->max > 1)
2613                                kfree(scontrol->volume_table);
2614                        break;
2615                case SND_SOC_TPLG_TYPE_ENUM:
2616                        se = (struct soc_enum *)kc->private_value;
2617                        scontrol = se->dobj.private;
2618                        break;
2619                case SND_SOC_TPLG_TYPE_BYTES:
2620                        sbe = (struct soc_bytes_ext *)kc->private_value;
2621                        scontrol = sbe->dobj.private;
2622                        break;
2623                default:
2624                        dev_warn(scomp->dev, "unsupported kcontrol_type\n");
2625                        goto out;
2626                }
2627                kfree(scontrol->control_data);
2628                list_del(&scontrol->list);
2629                kfree(scontrol);
2630        }
2631
2632out:
2633        /* free private value */
2634        kfree(swidget->private);
2635
2636        /* remove and free swidget object */
2637        list_del(&swidget->list);
2638        kfree(swidget);
2639
2640        return ret;
2641}
2642
2643/*
2644 * DAI HW configuration.
2645 */
2646
2647/* FE DAI - used for any driver specific init */
2648static int sof_dai_load(struct snd_soc_component *scomp, int index,
2649                        struct snd_soc_dai_driver *dai_drv,
2650                        struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai)
2651{
2652        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2653        struct snd_soc_tplg_stream_caps *caps;
2654        struct snd_soc_tplg_private *private = &pcm->priv;
2655        struct snd_sof_pcm *spcm;
2656        int stream;
2657        int ret;
2658
2659        /* nothing to do for BEs atm */
2660        if (!pcm)
2661                return 0;
2662
2663        spcm = kzalloc(sizeof(*spcm), GFP_KERNEL);
2664        if (!spcm)
2665                return -ENOMEM;
2666
2667        spcm->scomp = scomp;
2668
2669        for_each_pcm_streams(stream) {
2670                spcm->stream[stream].comp_id = COMP_ID_UNASSIGNED;
2671                INIT_WORK(&spcm->stream[stream].period_elapsed_work,
2672                          snd_sof_pcm_period_elapsed_work);
2673        }
2674
2675        spcm->pcm = *pcm;
2676        dev_dbg(scomp->dev, "tplg: load pcm %s\n", pcm->dai_name);
2677
2678        dai_drv->dobj.private = spcm;
2679        list_add(&spcm->list, &sdev->pcm_list);
2680
2681        ret = sof_parse_tokens(scomp, spcm, stream_tokens,
2682                               ARRAY_SIZE(stream_tokens), private->array,
2683                               le32_to_cpu(private->size));
2684        if (ret) {
2685                dev_err(scomp->dev, "error: parse stream tokens failed %d\n",
2686                        le32_to_cpu(private->size));
2687                return ret;
2688        }
2689
2690        /* do we need to allocate playback PCM DMA pages */
2691        if (!spcm->pcm.playback)
2692                goto capture;
2693
2694        stream = SNDRV_PCM_STREAM_PLAYBACK;
2695
2696        dev_vdbg(scomp->dev, "tplg: pcm %s stream tokens: playback d0i3:%d\n",
2697                 spcm->pcm.pcm_name, spcm->stream[stream].d0i3_compatible);
2698
2699        caps = &spcm->pcm.caps[stream];
2700
2701        /* allocate playback page table buffer */
2702        ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev,
2703                                  PAGE_SIZE, &spcm->stream[stream].page_table);
2704        if (ret < 0) {
2705                dev_err(scomp->dev, "error: can't alloc page table for %s %d\n",
2706                        caps->name, ret);
2707
2708                return ret;
2709        }
2710
2711        /* bind pcm to host comp */
2712        ret = spcm_bind(scomp, spcm, stream);
2713        if (ret) {
2714                dev_err(scomp->dev,
2715                        "error: can't bind pcm to host\n");
2716                goto free_playback_tables;
2717        }
2718
2719capture:
2720        stream = SNDRV_PCM_STREAM_CAPTURE;
2721
2722        /* do we need to allocate capture PCM DMA pages */
2723        if (!spcm->pcm.capture)
2724                return ret;
2725
2726        dev_vdbg(scomp->dev, "tplg: pcm %s stream tokens: capture d0i3:%d\n",
2727                 spcm->pcm.pcm_name, spcm->stream[stream].d0i3_compatible);
2728
2729        caps = &spcm->pcm.caps[stream];
2730
2731        /* allocate capture page table buffer */
2732        ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev,
2733                                  PAGE_SIZE, &spcm->stream[stream].page_table);
2734        if (ret < 0) {
2735                dev_err(scomp->dev, "error: can't alloc page table for %s %d\n",
2736                        caps->name, ret);
2737                goto free_playback_tables;
2738        }
2739
2740        /* bind pcm to host comp */
2741        ret = spcm_bind(scomp, spcm, stream);
2742        if (ret) {
2743                dev_err(scomp->dev,
2744                        "error: can't bind pcm to host\n");
2745                snd_dma_free_pages(&spcm->stream[stream].page_table);
2746                goto free_playback_tables;
2747        }
2748
2749        return ret;
2750
2751free_playback_tables:
2752        if (spcm->pcm.playback)
2753                snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table);
2754
2755        return ret;
2756}
2757
2758static int sof_dai_unload(struct snd_soc_component *scomp,
2759                          struct snd_soc_dobj *dobj)
2760{
2761        struct snd_sof_pcm *spcm = dobj->private;
2762
2763        /* free PCM DMA pages */
2764        if (spcm->pcm.playback)
2765                snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table);
2766
2767        if (spcm->pcm.capture)
2768                snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_CAPTURE].page_table);
2769
2770        /* remove from list and free spcm */
2771        list_del(&spcm->list);
2772        kfree(spcm);
2773
2774        return 0;
2775}
2776
2777static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config,
2778                               struct sof_ipc_dai_config *config)
2779{
2780        /* clock directions wrt codec */
2781        if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CP) {
2782                /* codec is bclk provider */
2783                if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
2784                        config->format |= SOF_DAI_FMT_CBP_CFP;
2785                else
2786                        config->format |= SOF_DAI_FMT_CBP_CFC;
2787        } else {
2788                /* codec is bclk consumer */
2789                if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
2790                        config->format |= SOF_DAI_FMT_CBC_CFP;
2791                else
2792                        config->format |= SOF_DAI_FMT_CBC_CFC;
2793        }
2794
2795        /* inverted clocks ? */
2796        if (hw_config->invert_bclk) {
2797                if (hw_config->invert_fsync)
2798                        config->format |= SOF_DAI_FMT_IB_IF;
2799                else
2800                        config->format |= SOF_DAI_FMT_IB_NF;
2801        } else {
2802                if (hw_config->invert_fsync)
2803                        config->format |= SOF_DAI_FMT_NB_IF;
2804                else
2805                        config->format |= SOF_DAI_FMT_NB_NF;
2806        }
2807}
2808
2809/*
2810 * Send IPC and set the same config for all DAIs with name matching the link
2811 * name. Note that the function can only be used for the case that all DAIs
2812 * have a common DAI config for now.
2813 */
2814static int sof_set_dai_config_multi(struct snd_sof_dev *sdev, u32 size,
2815                                    struct snd_soc_dai_link *link,
2816                                    struct sof_ipc_dai_config *config,
2817                                    int num_conf, int curr_conf)
2818{
2819        struct snd_sof_dai *dai;
2820        int found = 0;
2821        int i;
2822
2823        list_for_each_entry(dai, &sdev->dai_list, list) {
2824                if (!dai->name)
2825                        continue;
2826
2827                if (strcmp(link->name, dai->name) == 0) {
2828                        struct sof_ipc_reply reply;
2829                        int ret;
2830
2831                        /*
2832                         * the same dai config will be applied to all DAIs in
2833                         * the same dai link. We have to ensure that the ipc
2834                         * dai config's dai_index match to the component's
2835                         * dai_index.
2836                         */
2837                        for (i = 0; i < num_conf; i++)
2838                                config[i].dai_index = dai->comp_dai.dai_index;
2839
2840                        dev_dbg(sdev->dev, "set DAI config for %s index %d\n",
2841                                dai->name, config[curr_conf].dai_index);
2842                        /* send message to DSP */
2843                        ret = sof_ipc_tx_message(sdev->ipc,
2844                                                 config[curr_conf].hdr.cmd,
2845                                                 &config[curr_conf], size,
2846                                                 &reply, sizeof(reply));
2847
2848                        if (ret < 0) {
2849                                dev_err(sdev->dev,
2850                                        "error: failed to set DAI config for %s index %d\n",
2851                                        dai->name, config[curr_conf].dai_index);
2852                                return ret;
2853                        }
2854
2855                        dai->number_configs = num_conf;
2856                        dai->current_config = curr_conf;
2857                        dai->dai_config = kmemdup(config, size * num_conf, GFP_KERNEL);
2858                        if (!dai->dai_config)
2859                                return -ENOMEM;
2860
2861                        /* set cpu_dai_name */
2862                        dai->cpu_dai_name = link->cpus->dai_name;
2863
2864                        found = 1;
2865                }
2866        }
2867
2868        /*
2869         * machine driver may define a dai link with playback and capture
2870         * dai enabled, but the dai link in topology would support both, one
2871         * or none of them. Here print a warning message to notify user
2872         */
2873        if (!found) {
2874                dev_warn(sdev->dev, "warning: failed to find dai for dai link %s",
2875                         link->name);
2876        }
2877
2878        return 0;
2879}
2880
2881static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size,
2882                              struct snd_soc_dai_link *link,
2883                              struct sof_ipc_dai_config *config)
2884{
2885        return sof_set_dai_config_multi(sdev, size, link, config, 1, 0);
2886}
2887
2888static int sof_link_ssp_load(struct snd_soc_component *scomp, int index,
2889                             struct snd_soc_dai_link *link,
2890                             struct snd_soc_tplg_link_config *cfg,
2891                             struct snd_soc_tplg_hw_config *hw_config,
2892                             struct sof_ipc_dai_config *config, int curr_conf)
2893{
2894        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2895        struct snd_soc_tplg_private *private = &cfg->priv;
2896        int num_conf = le32_to_cpu(cfg->num_hw_configs);
2897        u32 size = sizeof(*config);
2898        int ret;
2899        int i;
2900
2901        /*
2902         * Parse common data, we should have 1 common data per hw_config.
2903         */
2904        ret = sof_parse_token_sets(scomp, &config->ssp, ssp_tokens,
2905                                   ARRAY_SIZE(ssp_tokens), private->array,
2906                                   le32_to_cpu(private->size),
2907                                   num_conf, size);
2908
2909        if (ret != 0) {
2910                dev_err(scomp->dev, "error: parse ssp tokens failed %d\n",
2911                        le32_to_cpu(private->size));
2912                return ret;
2913        }
2914
2915        /* process all possible hw configs */
2916        for (i = 0; i < num_conf; i++) {
2917
2918                /* handle master/slave and inverted clocks */
2919                sof_dai_set_format(&hw_config[i], &config[i]);
2920
2921                config[i].hdr.size = size;
2922
2923                /* copy differentiating hw configs to ipc structs */
2924                config[i].ssp.mclk_rate = le32_to_cpu(hw_config[i].mclk_rate);
2925                config[i].ssp.bclk_rate = le32_to_cpu(hw_config[i].bclk_rate);
2926                config[i].ssp.fsync_rate = le32_to_cpu(hw_config[i].fsync_rate);
2927                config[i].ssp.tdm_slots = le32_to_cpu(hw_config[i].tdm_slots);
2928                config[i].ssp.tdm_slot_width = le32_to_cpu(hw_config[i].tdm_slot_width);
2929                config[i].ssp.mclk_direction = hw_config[i].mclk_direction;
2930                config[i].ssp.rx_slots = le32_to_cpu(hw_config[i].rx_slots);
2931                config[i].ssp.tx_slots = le32_to_cpu(hw_config[i].tx_slots);
2932
2933                dev_dbg(scomp->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d\n",
2934                        config[i].dai_index, config[i].format,
2935                        config[i].ssp.mclk_rate, config[i].ssp.bclk_rate,
2936                        config[i].ssp.fsync_rate, config[i].ssp.sample_valid_bits,
2937                        config[i].ssp.tdm_slot_width, config[i].ssp.tdm_slots,
2938                        config[i].ssp.mclk_id, config[i].ssp.quirks);
2939
2940                /* validate SSP fsync rate and channel count */
2941                if (config[i].ssp.fsync_rate < 8000 || config[i].ssp.fsync_rate > 192000) {
2942                        dev_err(scomp->dev, "error: invalid fsync rate for SSP%d\n",
2943                                config[i].dai_index);
2944                        return -EINVAL;
2945                }
2946
2947                if (config[i].ssp.tdm_slots < 1 || config[i].ssp.tdm_slots > 8) {
2948                        dev_err(scomp->dev, "error: invalid channel count for SSP%d\n",
2949                                config[i].dai_index);
2950                        return -EINVAL;
2951                }
2952        }
2953
2954        /* set config for all DAI's with name matching the link name */
2955        ret = sof_set_dai_config_multi(sdev, size, link, config, num_conf, curr_conf);
2956        if (ret < 0)
2957                dev_err(scomp->dev, "error: failed to save DAI config for SSP%d\n",
2958                        config->dai_index);
2959
2960        return ret;
2961}
2962
2963static int sof_link_sai_load(struct snd_soc_component *scomp, int index,
2964                             struct snd_soc_dai_link *link,
2965                             struct snd_soc_tplg_link_config *cfg,
2966                             struct snd_soc_tplg_hw_config *hw_config,
2967                             struct sof_ipc_dai_config *config)
2968{
2969        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2970        struct snd_soc_tplg_private *private = &cfg->priv;
2971        u32 size = sizeof(*config);
2972        int ret;
2973
2974        /* handle master/slave and inverted clocks */
2975        sof_dai_set_format(hw_config, config);
2976
2977        /* init IPC */
2978        memset(&config->sai, 0, sizeof(struct sof_ipc_dai_sai_params));
2979        config->hdr.size = size;
2980
2981        ret = sof_parse_tokens(scomp, &config->sai, sai_tokens,
2982                               ARRAY_SIZE(sai_tokens), private->array,
2983                               le32_to_cpu(private->size));
2984        if (ret != 0) {
2985                dev_err(scomp->dev, "error: parse sai tokens failed %d\n",
2986                        le32_to_cpu(private->size));
2987                return ret;
2988        }
2989
2990        config->sai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
2991        config->sai.bclk_rate = le32_to_cpu(hw_config->bclk_rate);
2992        config->sai.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
2993        config->sai.mclk_direction = hw_config->mclk_direction;
2994
2995        config->sai.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
2996        config->sai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
2997        config->sai.rx_slots = le32_to_cpu(hw_config->rx_slots);
2998        config->sai.tx_slots = le32_to_cpu(hw_config->tx_slots);
2999
3000        dev_info(scomp->dev,
3001                 "tplg: config SAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
3002                config->dai_index, config->format,
3003                config->sai.mclk_rate, config->sai.tdm_slot_width,
3004                config->sai.tdm_slots, config->sai.mclk_id);
3005
3006        if (config->sai.tdm_slots < 1 || config->sai.tdm_slots > 8) {
3007                dev_err(scomp->dev, "error: invalid channel count for SAI%d\n",
3008                        config->dai_index);
3009                return -EINVAL;
3010        }
3011
3012        /* set config for all DAI's with name matching the link name */
3013        ret = sof_set_dai_config(sdev, size, link, config);
3014        if (ret < 0)
3015                dev_err(scomp->dev, "error: failed to save DAI config for SAI%d\n",
3016                        config->dai_index);
3017
3018        return ret;
3019}
3020
3021static int sof_link_esai_load(struct snd_soc_component *scomp, int index,
3022                              struct snd_soc_dai_link *link,
3023                              struct snd_soc_tplg_link_config *cfg,
3024                              struct snd_soc_tplg_hw_config *hw_config,
3025                              struct sof_ipc_dai_config *config)
3026{
3027        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
3028        struct snd_soc_tplg_private *private = &cfg->priv;
3029        u32 size = sizeof(*config);
3030        int ret;
3031
3032        /* handle master/slave and inverted clocks */
3033        sof_dai_set_format(hw_config, config);
3034
3035        /* init IPC */
3036        memset(&config->esai, 0, sizeof(struct sof_ipc_dai_esai_params));
3037        config->hdr.size = size;
3038
3039        ret = sof_parse_tokens(scomp, &config->esai, esai_tokens,
3040                               ARRAY_SIZE(esai_tokens), private->array,
3041                               le32_to_cpu(private->size));
3042        if (ret != 0) {
3043                dev_err(scomp->dev, "error: parse esai tokens failed %d\n",
3044                        le32_to_cpu(private->size));
3045                return ret;
3046        }
3047
3048        config->esai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
3049        config->esai.bclk_rate = le32_to_cpu(hw_config->bclk_rate);
3050        config->esai.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
3051        config->esai.mclk_direction = hw_config->mclk_direction;
3052        config->esai.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
3053        config->esai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
3054        config->esai.rx_slots = le32_to_cpu(hw_config->rx_slots);
3055        config->esai.tx_slots = le32_to_cpu(hw_config->tx_slots);
3056
3057        dev_info(scomp->dev,
3058                 "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
3059                config->dai_index, config->format,
3060                config->esai.mclk_rate, config->esai.tdm_slot_width,
3061                config->esai.tdm_slots, config->esai.mclk_id);
3062
3063        if (config->esai.tdm_slots < 1 || config->esai.tdm_slots > 8) {
3064                dev_err(scomp->dev, "error: invalid channel count for ESAI%d\n",
3065                        config->dai_index);
3066                return -EINVAL;
3067        }
3068
3069        /* set config for all DAI's with name matching the link name */
3070        ret = sof_set_dai_config(sdev, size, link, config);
3071        if (ret < 0)
3072                dev_err(scomp->dev, "error: failed to save DAI config for ESAI%d\n",
3073                        config->dai_index);
3074
3075        return ret;
3076}
3077
3078static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
3079                              struct snd_soc_dai_link *link,
3080                              struct snd_soc_tplg_link_config *cfg,
3081                              struct snd_soc_tplg_hw_config *hw_config,
3082                              struct sof_ipc_dai_config *config)
3083{
3084        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
3085        struct snd_soc_tplg_private *private = &cfg->priv;
3086        struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
3087        struct sof_ipc_fw_version *v = &ready->version;
3088        size_t size = sizeof(*config);
3089        int ret, j;
3090
3091        /* Ensure the entire DMIC config struct is zeros */
3092        memset(&config->dmic, 0, sizeof(struct sof_ipc_dai_dmic_params));
3093
3094        /* get DMIC tokens */
3095        ret = sof_parse_tokens(scomp, &config->dmic, dmic_tokens,
3096                               ARRAY_SIZE(dmic_tokens), private->array,
3097                               le32_to_cpu(private->size));
3098        if (ret != 0) {
3099                dev_err(scomp->dev, "error: parse dmic tokens failed %d\n",
3100                        le32_to_cpu(private->size));
3101                return ret;
3102        }
3103
3104        /* get DMIC PDM tokens */
3105        ret = sof_parse_token_sets(scomp, &config->dmic.pdm[0], dmic_pdm_tokens,
3106                               ARRAY_SIZE(dmic_pdm_tokens), private->array,
3107                               le32_to_cpu(private->size),
3108                               config->dmic.num_pdm_active,
3109                               sizeof(struct sof_ipc_dai_dmic_pdm_ctrl));
3110
3111        if (ret != 0) {
3112                dev_err(scomp->dev, "error: parse dmic pdm tokens failed %d\n",
3113                        le32_to_cpu(private->size));
3114                return ret;
3115        }
3116
3117        /* set IPC header size */
3118        config->hdr.size = size;
3119
3120        /* debug messages */
3121        dev_dbg(scomp->dev, "tplg: config DMIC%d driver version %d\n",
3122                config->dai_index, config->dmic.driver_ipc_version);
3123        dev_dbg(scomp->dev, "pdmclk_min %d pdm_clkmax %d duty_min %hd\n",
3124                config->dmic.pdmclk_min, config->dmic.pdmclk_max,
3125                config->dmic.duty_min);
3126        dev_dbg(scomp->dev, "duty_max %hd fifo_fs %d num_pdms active %d\n",
3127                config->dmic.duty_max, config->dmic.fifo_fs,
3128                config->dmic.num_pdm_active);
3129        dev_dbg(scomp->dev, "fifo word length %hd\n", config->dmic.fifo_bits);
3130
3131        for (j = 0; j < config->dmic.num_pdm_active; j++) {
3132                dev_dbg(scomp->dev, "pdm %hd mic a %hd mic b %hd\n",
3133                        config->dmic.pdm[j].id,
3134                        config->dmic.pdm[j].enable_mic_a,
3135                        config->dmic.pdm[j].enable_mic_b);
3136                dev_dbg(scomp->dev, "pdm %hd polarity a %hd polarity b %hd\n",
3137                        config->dmic.pdm[j].id,
3138                        config->dmic.pdm[j].polarity_mic_a,
3139                        config->dmic.pdm[j].polarity_mic_b);
3140                dev_dbg(scomp->dev, "pdm %hd clk_edge %hd skew %hd\n",
3141                        config->dmic.pdm[j].id,
3142                        config->dmic.pdm[j].clk_edge,
3143                        config->dmic.pdm[j].skew);
3144        }
3145
3146        /*
3147         * this takes care of backwards compatible handling of fifo_bits_b.
3148         * It is deprecated since firmware ABI version 3.0.1.
3149         */
3150        if (SOF_ABI_VER(v->major, v->minor, v->micro) < SOF_ABI_VER(3, 0, 1))
3151                config->dmic.fifo_bits_b = config->dmic.fifo_bits;
3152
3153        /* set config for all DAI's with name matching the link name */
3154        ret = sof_set_dai_config(sdev, size, link, config);
3155        if (ret < 0)
3156                dev_err(scomp->dev, "error: failed to save DAI config for DMIC%d\n",
3157                        config->dai_index);
3158
3159        return ret;
3160}
3161
3162static int sof_link_hda_load(struct snd_soc_component *scomp, int index,
3163                             struct snd_soc_dai_link *link,
3164                             struct snd_soc_tplg_link_config *cfg,
3165                             struct snd_soc_tplg_hw_config *hw_config,
3166                             struct sof_ipc_dai_config *config)
3167{
3168        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
3169        struct snd_soc_tplg_private *private = &cfg->priv;
3170        struct snd_soc_dai *dai;
3171        u32 size = sizeof(*config);
3172        int ret;
3173
3174        /* init IPC */
3175        memset(&config->hda, 0, sizeof(struct sof_ipc_dai_hda_params));
3176        config->hdr.size = size;
3177
3178        /* get any bespoke DAI tokens */
3179        ret = sof_parse_tokens(scomp, &config->hda, hda_tokens,
3180                               ARRAY_SIZE(hda_tokens), private->array,
3181                               le32_to_cpu(private->size));
3182        if (ret != 0) {
3183                dev_err(scomp->dev, "error: parse hda tokens failed %d\n",
3184                        le32_to_cpu(private->size));
3185                return ret;
3186        }
3187
3188        dev_dbg(scomp->dev, "HDA config rate %d channels %d\n",
3189                config->hda.rate, config->hda.channels);
3190
3191        dai = snd_soc_find_dai(link->cpus);
3192        if (!dai) {
3193                dev_err(scomp->dev, "error: failed to find dai %s in %s",
3194                        link->cpus->dai_name, __func__);
3195                return -EINVAL;
3196        }
3197
3198        config->hda.link_dma_ch = DMA_CHAN_INVALID;
3199
3200        ret = sof_set_dai_config(sdev, size, link, config);
3201        if (ret < 0)
3202                dev_err(scomp->dev, "error: failed to process hda dai link %s",
3203                        link->name);
3204
3205        return ret;
3206}
3207
3208static int sof_link_alh_load(struct snd_soc_component *scomp, int index,
3209                             struct snd_soc_dai_link *link,
3210                             struct snd_soc_tplg_link_config *cfg,
3211                             struct snd_soc_tplg_hw_config *hw_config,
3212                             struct sof_ipc_dai_config *config)
3213{
3214        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
3215        struct snd_soc_tplg_private *private = &cfg->priv;
3216        u32 size = sizeof(*config);
3217        int ret;
3218
3219        ret = sof_parse_tokens(scomp, &config->alh, alh_tokens,
3220                               ARRAY_SIZE(alh_tokens), private->array,
3221                               le32_to_cpu(private->size));
3222        if (ret != 0) {
3223                dev_err(scomp->dev, "error: parse alh tokens failed %d\n",
3224                        le32_to_cpu(private->size));
3225                return ret;
3226        }
3227
3228        /* init IPC */
3229        config->hdr.size = size;
3230
3231        /* set config for all DAI's with name matching the link name */
3232        ret = sof_set_dai_config(sdev, size, link, config);
3233        if (ret < 0)
3234                dev_err(scomp->dev, "error: failed to save DAI config for ALH %d\n",
3235                        config->dai_index);
3236
3237        return ret;
3238}
3239
3240/* DAI link - used for any driver specific init */
3241static int sof_link_load(struct snd_soc_component *scomp, int index,
3242                         struct snd_soc_dai_link *link,
3243                         struct snd_soc_tplg_link_config *cfg)
3244{
3245        struct snd_soc_tplg_private *private = &cfg->priv;
3246        struct snd_soc_tplg_hw_config *hw_config;
3247        struct sof_ipc_dai_config common_config;
3248        struct sof_ipc_dai_config *config;
3249        int curr_conf;
3250        int num_conf;
3251        int ret;
3252        int i;
3253
3254        if (!link->platforms) {
3255                dev_err(scomp->dev, "error: no platforms\n");
3256                return -EINVAL;
3257        }
3258        link->platforms->name = dev_name(scomp->dev);
3259
3260        /*
3261         * Set nonatomic property for FE dai links as their trigger action
3262         * involves IPC's.
3263         */
3264        if (!link->no_pcm) {
3265                link->nonatomic = true;
3266
3267                /*
3268                 * set default trigger order for all links. Exceptions to
3269                 * the rule will be handled in sof_pcm_dai_link_fixup()
3270                 * For playback, the sequence is the following: start FE,
3271                 * start BE, stop BE, stop FE; for Capture the sequence is
3272                 * inverted start BE, start FE, stop FE, stop BE
3273                 */
3274                link->trigger[SNDRV_PCM_STREAM_PLAYBACK] =
3275                                        SND_SOC_DPCM_TRIGGER_PRE;
3276                link->trigger[SNDRV_PCM_STREAM_CAPTURE] =
3277                                        SND_SOC_DPCM_TRIGGER_POST;
3278
3279                /* nothing more to do for FE dai links */
3280                return 0;
3281        }
3282
3283        /* check we have some tokens - we need at least DAI type */
3284        if (le32_to_cpu(private->size) == 0) {
3285                dev_err(scomp->dev, "error: expected tokens for DAI, none found\n");
3286                return -EINVAL;
3287        }
3288
3289        memset(&common_config, 0, sizeof(common_config));
3290
3291        /* get any common DAI tokens */
3292        ret = sof_parse_tokens(scomp, &common_config, dai_link_tokens, ARRAY_SIZE(dai_link_tokens),
3293                               private->array, le32_to_cpu(private->size));
3294        if (ret != 0) {
3295                dev_err(scomp->dev, "error: parse link tokens failed %d\n",
3296                        le32_to_cpu(private->size));
3297                return ret;
3298        }
3299
3300        /*
3301         * DAI links are expected to have at least 1 hw_config.
3302         * But some older topologies might have no hw_config for HDA dai links.
3303         */
3304        hw_config = cfg->hw_config;
3305        num_conf = le32_to_cpu(cfg->num_hw_configs);
3306        if (!num_conf) {
3307                if (common_config.type != SOF_DAI_INTEL_HDA) {
3308                        dev_err(scomp->dev, "error: unexpected DAI config count %d!\n",
3309                                le32_to_cpu(cfg->num_hw_configs));
3310                        return -EINVAL;
3311                }
3312                num_conf = 1;
3313                curr_conf = 0;
3314        } else {
3315                dev_dbg(scomp->dev, "tplg: %d hw_configs found, default id: %d!\n",
3316                        cfg->num_hw_configs, le32_to_cpu(cfg->default_hw_config_id));
3317
3318                for (curr_conf = 0; curr_conf < num_conf; curr_conf++) {
3319                        if (hw_config[curr_conf].id == cfg->default_hw_config_id)
3320                                break;
3321                }
3322
3323                if (curr_conf == num_conf) {
3324                        dev_err(scomp->dev, "error: default hw_config id: %d not found!\n",
3325                                le32_to_cpu(cfg->default_hw_config_id));
3326                        return -EINVAL;
3327                }
3328        }
3329
3330        /* Reserve memory for all hw configs, eventually freed by widget */
3331        config = kcalloc(num_conf, sizeof(*config), GFP_KERNEL);
3332        if (!config)
3333                return -ENOMEM;
3334
3335        /* Copy common data to all config ipc structs */
3336        for (i = 0; i < num_conf; i++) {
3337                config[i].hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG;
3338                config[i].format = le32_to_cpu(hw_config[i].fmt);
3339                config[i].type = common_config.type;
3340                config[i].dai_index = common_config.dai_index;
3341        }
3342
3343        /* now load DAI specific data and send IPC - type comes from token */
3344        switch (common_config.type) {
3345        case SOF_DAI_INTEL_SSP:
3346                ret = sof_link_ssp_load(scomp, index, link, cfg, hw_config, config, curr_conf);
3347                break;
3348        case SOF_DAI_INTEL_DMIC:
3349                ret = sof_link_dmic_load(scomp, index, link, cfg, hw_config + curr_conf, config);
3350                break;
3351        case SOF_DAI_INTEL_HDA:
3352                ret = sof_link_hda_load(scomp, index, link, cfg, hw_config + curr_conf, config);
3353                break;
3354        case SOF_DAI_INTEL_ALH:
3355                ret = sof_link_alh_load(scomp, index, link, cfg, hw_config + curr_conf, config);
3356                break;
3357        case SOF_DAI_IMX_SAI:
3358                ret = sof_link_sai_load(scomp, index, link, cfg, hw_config + curr_conf, config);
3359                break;
3360        case SOF_DAI_IMX_ESAI:
3361                ret = sof_link_esai_load(scomp, index, link, cfg, hw_config + curr_conf, config);
3362                break;
3363        default:
3364                dev_err(scomp->dev, "error: invalid DAI type %d\n", common_config.type);
3365                ret = -EINVAL;
3366                break;
3367        }
3368
3369        kfree(config);
3370
3371        return ret;
3372}
3373
3374/* DAI link - used for any driver specific init */
3375static int sof_route_load(struct snd_soc_component *scomp, int index,
3376                          struct snd_soc_dapm_route *route)
3377{
3378        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
3379        struct sof_ipc_pipe_comp_connect *connect;
3380        struct snd_sof_widget *source_swidget, *sink_swidget;
3381        struct snd_soc_dobj *dobj = &route->dobj;
3382        struct snd_sof_route *sroute;
3383        struct sof_ipc_reply reply;
3384        int ret = 0;
3385
3386        /* allocate memory for sroute and connect */
3387        sroute = kzalloc(sizeof(*sroute), GFP_KERNEL);
3388        if (!sroute)
3389                return -ENOMEM;
3390
3391        sroute->scomp = scomp;
3392
3393        connect = kzalloc(sizeof(*connect), GFP_KERNEL);
3394        if (!connect) {
3395                kfree(sroute);
3396                return -ENOMEM;
3397        }
3398
3399        connect->hdr.size = sizeof(*connect);
3400        connect->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT;
3401
3402        dev_dbg(scomp->dev, "sink %s control %s source %s\n",
3403                route->sink, route->control ? route->control : "none",
3404                route->source);
3405
3406        /* source component */
3407        source_swidget = snd_sof_find_swidget(scomp, (char *)route->source);
3408        if (!source_swidget) {
3409                dev_err(scomp->dev, "error: source %s not found\n",
3410                        route->source);
3411                ret = -EINVAL;
3412                goto err;
3413        }
3414
3415        /*
3416         * Virtual widgets of type output/out_drv may be added in topology
3417         * for compatibility. These are not handled by the FW.
3418         * So, don't send routes whose source/sink widget is of such types
3419         * to the DSP.
3420         */
3421        if (source_swidget->id == snd_soc_dapm_out_drv ||
3422            source_swidget->id == snd_soc_dapm_output)
3423                goto err;
3424
3425        connect->source_id = source_swidget->comp_id;
3426
3427        /* sink component */
3428        sink_swidget = snd_sof_find_swidget(scomp, (char *)route->sink);
3429        if (!sink_swidget) {
3430                dev_err(scomp->dev, "error: sink %s not found\n",
3431                        route->sink);
3432                ret = -EINVAL;
3433                goto err;
3434        }
3435
3436        /*
3437         * Don't send routes whose sink widget is of type
3438         * output or out_drv to the DSP
3439         */
3440        if (sink_swidget->id == snd_soc_dapm_out_drv ||
3441            sink_swidget->id == snd_soc_dapm_output)
3442                goto err;
3443
3444        connect->sink_id = sink_swidget->comp_id;
3445
3446        /*
3447         * For virtual routes, both sink and source are not
3448         * buffer. Since only buffer linked to component is supported by
3449         * FW, others are reported as error, add check in route function,
3450         * do not send it to FW when both source and sink are not buffer
3451         */
3452        if (source_swidget->id != snd_soc_dapm_buffer &&
3453            sink_swidget->id != snd_soc_dapm_buffer) {
3454                dev_dbg(scomp->dev, "warning: neither Linked source component %s nor sink component %s is of buffer type, ignoring link\n",
3455                        route->source, route->sink);
3456                goto err;
3457        } else {
3458                ret = sof_ipc_tx_message(sdev->ipc,
3459                                         connect->hdr.cmd,
3460                                         connect, sizeof(*connect),
3461                                         &reply, sizeof(reply));
3462
3463                /* check IPC return value */
3464                if (ret < 0) {
3465                        dev_err(scomp->dev, "error: failed to add route sink %s control %s source %s\n",
3466                                route->sink,
3467                                route->control ? route->control : "none",
3468                                route->source);
3469                        goto err;
3470                }
3471
3472                /* check IPC reply */
3473                if (reply.error < 0) {
3474                        dev_err(scomp->dev, "error: DSP failed to add route sink %s control %s source %s result %d\n",
3475                                route->sink,
3476                                route->control ? route->control : "none",
3477                                route->source, reply.error);
3478                        ret = reply.error;
3479                        goto err;
3480                }
3481
3482                sroute->route = route;
3483                dobj->private = sroute;
3484                sroute->private = connect;
3485
3486                /* add route to route list */
3487                list_add(&sroute->list, &sdev->route_list);
3488
3489                return 0;
3490        }
3491
3492err:
3493        kfree(connect);
3494        kfree(sroute);
3495        return ret;
3496}
3497
3498/* Function to set the initial value of SOF kcontrols.
3499 * The value will be stored in scontrol->control_data
3500 */
3501static int snd_sof_cache_kcontrol_val(struct snd_soc_component *scomp)
3502{
3503        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
3504        struct snd_sof_control *scontrol = NULL;
3505        int ipc_cmd, ctrl_type;
3506        int ret = 0;
3507
3508        list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
3509
3510                /* notify DSP of kcontrol values */
3511                switch (scontrol->cmd) {
3512                case SOF_CTRL_CMD_VOLUME:
3513                case SOF_CTRL_CMD_ENUM:
3514                case SOF_CTRL_CMD_SWITCH:
3515                        ipc_cmd = SOF_IPC_COMP_GET_VALUE;
3516                        ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_GET;
3517                        break;
3518                case SOF_CTRL_CMD_BINARY:
3519                        ipc_cmd = SOF_IPC_COMP_GET_DATA;
3520                        ctrl_type = SOF_CTRL_TYPE_DATA_GET;
3521                        break;
3522                default:
3523                        dev_err(scomp->dev,
3524                                "error: Invalid scontrol->cmd: %d\n",
3525                                scontrol->cmd);
3526                        return -EINVAL;
3527                }
3528                ret = snd_sof_ipc_set_get_comp_data(scontrol,
3529                                                    ipc_cmd, ctrl_type,
3530                                                    scontrol->cmd,
3531                                                    false);
3532                if (ret < 0) {
3533                        dev_warn(scomp->dev,
3534                                 "error: kcontrol value get for widget: %d\n",
3535                                 scontrol->comp_id);
3536                }
3537        }
3538
3539        return ret;
3540}
3541
3542int snd_sof_complete_pipeline(struct device *dev,
3543                              struct snd_sof_widget *swidget)
3544{
3545        struct snd_sof_dev *sdev = dev_get_drvdata(dev);
3546        struct sof_ipc_pipe_ready ready;
3547        struct sof_ipc_reply reply;
3548        int ret;
3549
3550        dev_dbg(dev, "tplg: complete pipeline %s id %d\n",
3551                swidget->widget->name, swidget->comp_id);
3552
3553        memset(&ready, 0, sizeof(ready));
3554        ready.hdr.size = sizeof(ready);
3555        ready.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_COMPLETE;
3556        ready.comp_id = swidget->comp_id;
3557
3558        ret = sof_ipc_tx_message(sdev->ipc,
3559                                 ready.hdr.cmd, &ready, sizeof(ready), &reply,
3560                                 sizeof(reply));
3561        if (ret < 0)
3562                return ret;
3563        return 1;
3564}
3565
3566/* completion - called at completion of firmware loading */
3567static void sof_complete(struct snd_soc_component *scomp)
3568{
3569        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
3570        struct snd_sof_widget *swidget;
3571
3572        /* some widget types require completion notificattion */
3573        list_for_each_entry(swidget, &sdev->widget_list, list) {
3574                if (swidget->complete)
3575                        continue;
3576
3577                switch (swidget->id) {
3578                case snd_soc_dapm_scheduler:
3579                        swidget->complete =
3580                                snd_sof_complete_pipeline(scomp->dev, swidget);
3581                        break;
3582                default:
3583                        break;
3584                }
3585        }
3586        /*
3587         * cache initial values of SOF kcontrols by reading DSP value over
3588         * IPC. It may be overwritten by alsa-mixer after booting up
3589         */
3590        snd_sof_cache_kcontrol_val(scomp);
3591}
3592
3593/* manifest - optional to inform component of manifest */
3594static int sof_manifest(struct snd_soc_component *scomp, int index,
3595                        struct snd_soc_tplg_manifest *man)
3596{
3597        u32 size;
3598        u32 abi_version;
3599
3600        size = le32_to_cpu(man->priv.size);
3601
3602        /* backward compatible with tplg without ABI info */
3603        if (!size) {
3604                dev_dbg(scomp->dev, "No topology ABI info\n");
3605                return 0;
3606        }
3607
3608        if (size != SOF_TPLG_ABI_SIZE) {
3609                dev_err(scomp->dev, "error: invalid topology ABI size\n");
3610                return -EINVAL;
3611        }
3612
3613        dev_info(scomp->dev,
3614                 "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
3615                 man->priv.data[0], man->priv.data[1],
3616                 man->priv.data[2], SOF_ABI_MAJOR, SOF_ABI_MINOR,
3617                 SOF_ABI_PATCH);
3618
3619        abi_version = SOF_ABI_VER(man->priv.data[0],
3620                                  man->priv.data[1],
3621                                  man->priv.data[2]);
3622
3623        if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
3624                dev_err(scomp->dev, "error: incompatible topology ABI version\n");
3625                return -EINVAL;
3626        }
3627
3628        if (SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
3629                if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
3630                        dev_warn(scomp->dev, "warn: topology ABI is more recent than kernel\n");
3631                } else {
3632                        dev_err(scomp->dev, "error: topology ABI is more recent than kernel\n");
3633                        return -EINVAL;
3634                }
3635        }
3636
3637        return 0;
3638}
3639
3640/* vendor specific kcontrol handlers available for binding */
3641static const struct snd_soc_tplg_kcontrol_ops sof_io_ops[] = {
3642        {SOF_TPLG_KCTL_VOL_ID, snd_sof_volume_get, snd_sof_volume_put},
3643        {SOF_TPLG_KCTL_BYTES_ID, snd_sof_bytes_get, snd_sof_bytes_put},
3644        {SOF_TPLG_KCTL_ENUM_ID, snd_sof_enum_get, snd_sof_enum_put},
3645        {SOF_TPLG_KCTL_SWITCH_ID, snd_sof_switch_get, snd_sof_switch_put},
3646};
3647
3648/* vendor specific bytes ext handlers available for binding */
3649static const struct snd_soc_tplg_bytes_ext_ops sof_bytes_ext_ops[] = {
3650        {SOF_TPLG_KCTL_BYTES_ID, snd_sof_bytes_ext_get, snd_sof_bytes_ext_put},
3651        {SOF_TPLG_KCTL_BYTES_VOLATILE_RO, snd_sof_bytes_ext_volatile_get},
3652};
3653
3654static struct snd_soc_tplg_ops sof_tplg_ops = {
3655        /* external kcontrol init - used for any driver specific init */
3656        .control_load   = sof_control_load,
3657        .control_unload = sof_control_unload,
3658
3659        /* external kcontrol init - used for any driver specific init */
3660        .dapm_route_load        = sof_route_load,
3661        .dapm_route_unload      = sof_route_unload,
3662
3663        /* external widget init - used for any driver specific init */
3664        /* .widget_load is not currently used */
3665        .widget_ready   = sof_widget_ready,
3666        .widget_unload  = sof_widget_unload,
3667
3668        /* FE DAI - used for any driver specific init */
3669        .dai_load       = sof_dai_load,
3670        .dai_unload     = sof_dai_unload,
3671
3672        /* DAI link - used for any driver specific init */
3673        .link_load      = sof_link_load,
3674
3675        /* completion - called at completion of firmware loading */
3676        .complete       = sof_complete,
3677
3678        /* manifest - optional to inform component of manifest */
3679        .manifest       = sof_manifest,
3680
3681        /* vendor specific kcontrol handlers available for binding */
3682        .io_ops         = sof_io_ops,
3683        .io_ops_count   = ARRAY_SIZE(sof_io_ops),
3684
3685        /* vendor specific bytes ext handlers available for binding */
3686        .bytes_ext_ops  = sof_bytes_ext_ops,
3687        .bytes_ext_ops_count    = ARRAY_SIZE(sof_bytes_ext_ops),
3688};
3689
3690int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
3691{
3692        const struct firmware *fw;
3693        int ret;
3694
3695        dev_dbg(scomp->dev, "loading topology:%s\n", file);
3696
3697        ret = request_firmware(&fw, file, scomp->dev);
3698        if (ret < 0) {
3699                dev_err(scomp->dev, "error: tplg request firmware %s failed err: %d\n",
3700                        file, ret);
3701                dev_err(scomp->dev,
3702                        "you may need to download the firmware from https://github.com/thesofproject/sof-bin/\n");
3703                return ret;
3704        }
3705
3706        ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw);
3707        if (ret < 0) {
3708                dev_err(scomp->dev, "error: tplg component load failed %d\n",
3709                        ret);
3710                ret = -EINVAL;
3711        }
3712
3713        release_firmware(fw);
3714        return ret;
3715}
3716EXPORT_SYMBOL(snd_sof_load_topology);
3717