linux/sound/soc/sof/ops.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: (GPL-2.0 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#ifndef __SOUND_SOC_SOF_IO_H
  12#define __SOUND_SOC_SOF_IO_H
  13
  14#include <linux/device.h>
  15#include <linux/interrupt.h>
  16#include <linux/kernel.h>
  17#include <linux/types.h>
  18#include <sound/pcm.h>
  19#include "sof-priv.h"
  20
  21#define sof_ops(sdev) \
  22        ((sdev)->pdata->desc->ops)
  23
  24/* Mandatory operations are verified during probing */
  25
  26/* init */
  27static inline int snd_sof_probe(struct snd_sof_dev *sdev)
  28{
  29        return sof_ops(sdev)->probe(sdev);
  30}
  31
  32static inline int snd_sof_remove(struct snd_sof_dev *sdev)
  33{
  34        if (sof_ops(sdev)->remove)
  35                return sof_ops(sdev)->remove(sdev);
  36
  37        return 0;
  38}
  39
  40/* control */
  41
  42/*
  43 * snd_sof_dsp_run returns the core mask of the cores that are available
  44 * after successful fw boot
  45 */
  46static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev)
  47{
  48        return sof_ops(sdev)->run(sdev);
  49}
  50
  51static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev)
  52{
  53        if (sof_ops(sdev)->stall)
  54                return sof_ops(sdev)->stall(sdev);
  55
  56        return 0;
  57}
  58
  59static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev)
  60{
  61        if (sof_ops(sdev)->reset)
  62                return sof_ops(sdev)->reset(sdev);
  63
  64        return 0;
  65}
  66
  67/* dsp core power up/power down */
  68static inline int snd_sof_dsp_core_power_up(struct snd_sof_dev *sdev,
  69                                            unsigned int core_mask)
  70{
  71        if (sof_ops(sdev)->core_power_up)
  72                return sof_ops(sdev)->core_power_up(sdev, core_mask);
  73
  74        return 0;
  75}
  76
  77static inline int snd_sof_dsp_core_power_down(struct snd_sof_dev *sdev,
  78                                              unsigned int core_mask)
  79{
  80        if (sof_ops(sdev)->core_power_down)
  81                return sof_ops(sdev)->core_power_down(sdev, core_mask);
  82
  83        return 0;
  84}
  85
  86/* pre/post fw load */
  87static inline int snd_sof_dsp_pre_fw_run(struct snd_sof_dev *sdev)
  88{
  89        if (sof_ops(sdev)->pre_fw_run)
  90                return sof_ops(sdev)->pre_fw_run(sdev);
  91
  92        return 0;
  93}
  94
  95static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev)
  96{
  97        if (sof_ops(sdev)->post_fw_run)
  98                return sof_ops(sdev)->post_fw_run(sdev);
  99
 100        return 0;
 101}
 102
 103/* misc */
 104
 105/**
 106 * snd_sof_dsp_get_bar_index - Maps a section type with a BAR index
 107 *
 108 * @sdev: sof device
 109 * @type: section type as described by snd_sof_fw_blk_type
 110 *
 111 * Returns the corresponding BAR index (a positive integer) or -EINVAL
 112 * in case there is no mapping
 113 */
 114static inline int snd_sof_dsp_get_bar_index(struct snd_sof_dev *sdev, u32 type)
 115{
 116        if (sof_ops(sdev)->get_bar_index)
 117                return sof_ops(sdev)->get_bar_index(sdev, type);
 118
 119        return sdev->mmio_bar;
 120}
 121
 122static inline int snd_sof_dsp_get_mailbox_offset(struct snd_sof_dev *sdev)
 123{
 124        if (sof_ops(sdev)->get_mailbox_offset)
 125                return sof_ops(sdev)->get_mailbox_offset(sdev);
 126
 127        dev_err(sdev->dev, "error: %s not defined\n", __func__);
 128        return -ENOTSUPP;
 129}
 130
 131static inline int snd_sof_dsp_get_window_offset(struct snd_sof_dev *sdev,
 132                                                u32 id)
 133{
 134        if (sof_ops(sdev)->get_window_offset)
 135                return sof_ops(sdev)->get_window_offset(sdev, id);
 136
 137        dev_err(sdev->dev, "error: %s not defined\n", __func__);
 138        return -ENOTSUPP;
 139}
 140/* power management */
 141static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev)
 142{
 143        if (sof_ops(sdev)->resume)
 144                return sof_ops(sdev)->resume(sdev);
 145
 146        return 0;
 147}
 148
 149static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev)
 150{
 151        if (sof_ops(sdev)->suspend)
 152                return sof_ops(sdev)->suspend(sdev);
 153
 154        return 0;
 155}
 156
 157static inline int snd_sof_dsp_runtime_resume(struct snd_sof_dev *sdev)
 158{
 159        if (sof_ops(sdev)->runtime_resume)
 160                return sof_ops(sdev)->runtime_resume(sdev);
 161
 162        return 0;
 163}
 164
 165static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev)
 166{
 167        if (sof_ops(sdev)->runtime_suspend)
 168                return sof_ops(sdev)->runtime_suspend(sdev);
 169
 170        return 0;
 171}
 172
 173static inline int snd_sof_dsp_runtime_idle(struct snd_sof_dev *sdev)
 174{
 175        if (sof_ops(sdev)->runtime_idle)
 176                return sof_ops(sdev)->runtime_idle(sdev);
 177
 178        return 0;
 179}
 180
 181static inline int snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev)
 182{
 183        if (sof_ops(sdev)->set_hw_params_upon_resume)
 184                return sof_ops(sdev)->set_hw_params_upon_resume(sdev);
 185        return 0;
 186}
 187
 188static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq)
 189{
 190        if (sof_ops(sdev)->set_clk)
 191                return sof_ops(sdev)->set_clk(sdev, freq);
 192
 193        return 0;
 194}
 195
 196static inline int snd_sof_dsp_set_power_state(struct snd_sof_dev *sdev,
 197                                              enum sof_d0_substate substate)
 198{
 199        if (sof_ops(sdev)->set_power_state)
 200                return sof_ops(sdev)->set_power_state(sdev, substate);
 201
 202        /* D0 substate is not supported */
 203        return -ENOTSUPP;
 204}
 205
 206/* debug */
 207static inline void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags)
 208{
 209        if (sof_ops(sdev)->dbg_dump)
 210                return sof_ops(sdev)->dbg_dump(sdev, flags);
 211}
 212
 213static inline void snd_sof_ipc_dump(struct snd_sof_dev *sdev)
 214{
 215        if (sof_ops(sdev)->ipc_dump)
 216                return sof_ops(sdev)->ipc_dump(sdev);
 217}
 218
 219/* register IO */
 220static inline void snd_sof_dsp_write(struct snd_sof_dev *sdev, u32 bar,
 221                                     u32 offset, u32 value)
 222{
 223        if (sof_ops(sdev)->write) {
 224                sof_ops(sdev)->write(sdev, sdev->bar[bar] + offset, value);
 225                return;
 226        }
 227
 228        dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__);
 229}
 230
 231static inline void snd_sof_dsp_write64(struct snd_sof_dev *sdev, u32 bar,
 232                                       u32 offset, u64 value)
 233{
 234        if (sof_ops(sdev)->write64) {
 235                sof_ops(sdev)->write64(sdev, sdev->bar[bar] + offset, value);
 236                return;
 237        }
 238
 239        dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__);
 240}
 241
 242static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar,
 243                                   u32 offset)
 244{
 245        if (sof_ops(sdev)->read)
 246                return sof_ops(sdev)->read(sdev, sdev->bar[bar] + offset);
 247
 248        dev_err(sdev->dev, "error: %s not defined\n", __func__);
 249        return -ENOTSUPP;
 250}
 251
 252static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar,
 253                                     u32 offset)
 254{
 255        if (sof_ops(sdev)->read64)
 256                return sof_ops(sdev)->read64(sdev, sdev->bar[bar] + offset);
 257
 258        dev_err(sdev->dev, "error: %s not defined\n", __func__);
 259        return -ENOTSUPP;
 260}
 261
 262/* block IO */
 263static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, u32 bar,
 264                                          u32 offset, void *dest, size_t bytes)
 265{
 266        sof_ops(sdev)->block_read(sdev, bar, offset, dest, bytes);
 267}
 268
 269static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, u32 bar,
 270                                           u32 offset, void *src, size_t bytes)
 271{
 272        sof_ops(sdev)->block_write(sdev, bar, offset, src, bytes);
 273}
 274
 275/* ipc */
 276static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev,
 277                                       struct snd_sof_ipc_msg *msg)
 278{
 279        return sof_ops(sdev)->send_msg(sdev, msg);
 280}
 281
 282/* host DMA trace */
 283static inline int snd_sof_dma_trace_init(struct snd_sof_dev *sdev,
 284                                         u32 *stream_tag)
 285{
 286        if (sof_ops(sdev)->trace_init)
 287                return sof_ops(sdev)->trace_init(sdev, stream_tag);
 288
 289        return 0;
 290}
 291
 292static inline int snd_sof_dma_trace_release(struct snd_sof_dev *sdev)
 293{
 294        if (sof_ops(sdev)->trace_release)
 295                return sof_ops(sdev)->trace_release(sdev);
 296
 297        return 0;
 298}
 299
 300static inline int snd_sof_dma_trace_trigger(struct snd_sof_dev *sdev, int cmd)
 301{
 302        if (sof_ops(sdev)->trace_trigger)
 303                return sof_ops(sdev)->trace_trigger(sdev, cmd);
 304
 305        return 0;
 306}
 307
 308/* host PCM ops */
 309static inline int
 310snd_sof_pcm_platform_open(struct snd_sof_dev *sdev,
 311                          struct snd_pcm_substream *substream)
 312{
 313        if (sof_ops(sdev) && sof_ops(sdev)->pcm_open)
 314                return sof_ops(sdev)->pcm_open(sdev, substream);
 315
 316        return 0;
 317}
 318
 319/* disconnect pcm substream to a host stream */
 320static inline int
 321snd_sof_pcm_platform_close(struct snd_sof_dev *sdev,
 322                           struct snd_pcm_substream *substream)
 323{
 324        if (sof_ops(sdev) && sof_ops(sdev)->pcm_close)
 325                return sof_ops(sdev)->pcm_close(sdev, substream);
 326
 327        return 0;
 328}
 329
 330/* host stream hw params */
 331static inline int
 332snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev,
 333                               struct snd_pcm_substream *substream,
 334                               struct snd_pcm_hw_params *params,
 335                               struct sof_ipc_stream_params *ipc_params)
 336{
 337        if (sof_ops(sdev) && sof_ops(sdev)->pcm_hw_params)
 338                return sof_ops(sdev)->pcm_hw_params(sdev, substream,
 339                                                    params, ipc_params);
 340
 341        return 0;
 342}
 343
 344/* host stream hw free */
 345static inline int
 346snd_sof_pcm_platform_hw_free(struct snd_sof_dev *sdev,
 347                             struct snd_pcm_substream *substream)
 348{
 349        if (sof_ops(sdev) && sof_ops(sdev)->pcm_hw_free)
 350                return sof_ops(sdev)->pcm_hw_free(sdev, substream);
 351
 352        return 0;
 353}
 354
 355/* host stream trigger */
 356static inline int
 357snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev,
 358                             struct snd_pcm_substream *substream, int cmd)
 359{
 360        if (sof_ops(sdev) && sof_ops(sdev)->pcm_trigger)
 361                return sof_ops(sdev)->pcm_trigger(sdev, substream, cmd);
 362
 363        return 0;
 364}
 365
 366/* host DSP message data */
 367static inline void snd_sof_ipc_msg_data(struct snd_sof_dev *sdev,
 368                                        struct snd_pcm_substream *substream,
 369                                        void *p, size_t sz)
 370{
 371        sof_ops(sdev)->ipc_msg_data(sdev, substream, p, sz);
 372}
 373
 374/* host configure DSP HW parameters */
 375static inline int
 376snd_sof_ipc_pcm_params(struct snd_sof_dev *sdev,
 377                       struct snd_pcm_substream *substream,
 378                       const struct sof_ipc_pcm_params_reply *reply)
 379{
 380        return sof_ops(sdev)->ipc_pcm_params(sdev, substream, reply);
 381}
 382
 383/* host stream pointer */
 384static inline snd_pcm_uframes_t
 385snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev,
 386                             struct snd_pcm_substream *substream)
 387{
 388        if (sof_ops(sdev) && sof_ops(sdev)->pcm_pointer)
 389                return sof_ops(sdev)->pcm_pointer(sdev, substream);
 390
 391        return 0;
 392}
 393
 394static inline const struct snd_sof_dsp_ops
 395*sof_get_ops(const struct sof_dev_desc *d,
 396             const struct sof_ops_table mach_ops[], int asize)
 397{
 398        int i;
 399
 400        for (i = 0; i < asize; i++) {
 401                if (d == mach_ops[i].desc)
 402                        return mach_ops[i].ops;
 403        }
 404
 405        /* not found */
 406        return NULL;
 407}
 408
 409/**
 410 * snd_sof_dsp_register_poll_timeout - Periodically poll an address
 411 * until a condition is met or a timeout occurs
 412 * @op: accessor function (takes @addr as its only argument)
 413 * @addr: Address to poll
 414 * @val: Variable to read the value into
 415 * @cond: Break condition (usually involving @val)
 416 * @sleep_us: Maximum time to sleep between reads in us (0
 417 *            tight-loops).  Should be less than ~20ms since usleep_range
 418 *            is used (see Documentation/timers/timers-howto.rst).
 419 * @timeout_us: Timeout in us, 0 means never timeout
 420 *
 421 * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
 422 * case, the last read value at @addr is stored in @val. Must not
 423 * be called from atomic context if sleep_us or timeout_us are used.
 424 *
 425 * This is modelled after the readx_poll_timeout macros in linux/iopoll.h.
 426 */
 427#define snd_sof_dsp_read_poll_timeout(sdev, bar, offset, val, cond, sleep_us, timeout_us) \
 428({ \
 429        u64 __timeout_us = (timeout_us); \
 430        unsigned long __sleep_us = (sleep_us); \
 431        ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
 432        might_sleep_if((__sleep_us) != 0); \
 433        for (;;) {                                                      \
 434                (val) = snd_sof_dsp_read(sdev, bar, offset);            \
 435                if (cond) { \
 436                        dev_dbg(sdev->dev, \
 437                                "FW Poll Status: reg=%#x successful\n", (val)); \
 438                        break; \
 439                } \
 440                if (__timeout_us && \
 441                    ktime_compare(ktime_get(), __timeout) > 0) { \
 442                        (val) = snd_sof_dsp_read(sdev, bar, offset); \
 443                        dev_dbg(sdev->dev, \
 444                                "FW Poll Status: reg=%#x timedout\n", (val)); \
 445                        break; \
 446                } \
 447                if (__sleep_us) \
 448                        usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
 449        } \
 450        (cond) ? 0 : -ETIMEDOUT; \
 451})
 452
 453/* This is for registers bits with attribute RWC */
 454bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset,
 455                             u32 mask, u32 value);
 456
 457bool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar,
 458                                      u32 offset, u32 mask, u32 value);
 459
 460bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar,
 461                                        u32 offset, u64 mask, u64 value);
 462
 463bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset,
 464                             u32 mask, u32 value);
 465
 466bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar,
 467                               u32 offset, u64 mask, u64 value);
 468
 469void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar,
 470                                    u32 offset, u32 mask, u32 value);
 471
 472int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset,
 473                              u32 mask, u32 target, u32 timeout_ms,
 474                              u32 interval_us);
 475
 476void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset);
 477#endif
 478