linux/sound/soc/codecs/wm_adsp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * wm_adsp.c  --  Wolfson ADSP support
   4 *
   5 * Copyright 2012 Wolfson Microelectronics plc
   6 *
   7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   8 */
   9
  10#include <linux/ctype.h>
  11#include <linux/module.h>
  12#include <linux/moduleparam.h>
  13#include <linux/init.h>
  14#include <linux/delay.h>
  15#include <linux/firmware.h>
  16#include <linux/list.h>
  17#include <linux/pm.h>
  18#include <linux/pm_runtime.h>
  19#include <linux/regmap.h>
  20#include <linux/regulator/consumer.h>
  21#include <linux/slab.h>
  22#include <linux/vmalloc.h>
  23#include <linux/workqueue.h>
  24#include <linux/debugfs.h>
  25#include <sound/core.h>
  26#include <sound/pcm.h>
  27#include <sound/pcm_params.h>
  28#include <sound/soc.h>
  29#include <sound/jack.h>
  30#include <sound/initval.h>
  31#include <sound/tlv.h>
  32
  33#include "wm_adsp.h"
  34
  35#define adsp_crit(_dsp, fmt, ...) \
  36        dev_crit(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  37#define adsp_err(_dsp, fmt, ...) \
  38        dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  39#define adsp_warn(_dsp, fmt, ...) \
  40        dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  41#define adsp_info(_dsp, fmt, ...) \
  42        dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  43#define adsp_dbg(_dsp, fmt, ...) \
  44        dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  45
  46#define compr_err(_obj, fmt, ...) \
  47        adsp_err(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
  48                 ##__VA_ARGS__)
  49#define compr_dbg(_obj, fmt, ...) \
  50        adsp_dbg(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
  51                 ##__VA_ARGS__)
  52
  53#define ADSP1_CONTROL_1                   0x00
  54#define ADSP1_CONTROL_2                   0x02
  55#define ADSP1_CONTROL_3                   0x03
  56#define ADSP1_CONTROL_4                   0x04
  57#define ADSP1_CONTROL_5                   0x06
  58#define ADSP1_CONTROL_6                   0x07
  59#define ADSP1_CONTROL_7                   0x08
  60#define ADSP1_CONTROL_8                   0x09
  61#define ADSP1_CONTROL_9                   0x0A
  62#define ADSP1_CONTROL_10                  0x0B
  63#define ADSP1_CONTROL_11                  0x0C
  64#define ADSP1_CONTROL_12                  0x0D
  65#define ADSP1_CONTROL_13                  0x0F
  66#define ADSP1_CONTROL_14                  0x10
  67#define ADSP1_CONTROL_15                  0x11
  68#define ADSP1_CONTROL_16                  0x12
  69#define ADSP1_CONTROL_17                  0x13
  70#define ADSP1_CONTROL_18                  0x14
  71#define ADSP1_CONTROL_19                  0x16
  72#define ADSP1_CONTROL_20                  0x17
  73#define ADSP1_CONTROL_21                  0x18
  74#define ADSP1_CONTROL_22                  0x1A
  75#define ADSP1_CONTROL_23                  0x1B
  76#define ADSP1_CONTROL_24                  0x1C
  77#define ADSP1_CONTROL_25                  0x1E
  78#define ADSP1_CONTROL_26                  0x20
  79#define ADSP1_CONTROL_27                  0x21
  80#define ADSP1_CONTROL_28                  0x22
  81#define ADSP1_CONTROL_29                  0x23
  82#define ADSP1_CONTROL_30                  0x24
  83#define ADSP1_CONTROL_31                  0x26
  84
  85/*
  86 * ADSP1 Control 19
  87 */
  88#define ADSP1_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
  89#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
  90#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
  91
  92
  93/*
  94 * ADSP1 Control 30
  95 */
  96#define ADSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
  97#define ADSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
  98#define ADSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
  99#define ADSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
 100#define ADSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
 101#define ADSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
 102#define ADSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
 103#define ADSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
 104#define ADSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
 105#define ADSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
 106#define ADSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
 107#define ADSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
 108#define ADSP1_START                       0x0001  /* DSP1_START */
 109#define ADSP1_START_MASK                  0x0001  /* DSP1_START */
 110#define ADSP1_START_SHIFT                      0  /* DSP1_START */
 111#define ADSP1_START_WIDTH                      1  /* DSP1_START */
 112
 113/*
 114 * ADSP1 Control 31
 115 */
 116#define ADSP1_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
 117#define ADSP1_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
 118#define ADSP1_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
 119
 120#define ADSP2_CONTROL                     0x0
 121#define ADSP2_CLOCKING                    0x1
 122#define ADSP2V2_CLOCKING                  0x2
 123#define ADSP2_STATUS1                     0x4
 124#define ADSP2_WDMA_CONFIG_1               0x30
 125#define ADSP2_WDMA_CONFIG_2               0x31
 126#define ADSP2V2_WDMA_CONFIG_2             0x32
 127#define ADSP2_RDMA_CONFIG_1               0x34
 128
 129#define ADSP2_SCRATCH0                    0x40
 130#define ADSP2_SCRATCH1                    0x41
 131#define ADSP2_SCRATCH2                    0x42
 132#define ADSP2_SCRATCH3                    0x43
 133
 134#define ADSP2V2_SCRATCH0_1                0x40
 135#define ADSP2V2_SCRATCH2_3                0x42
 136
 137/*
 138 * ADSP2 Control
 139 */
 140
 141#define ADSP2_MEM_ENA                     0x0010  /* DSP1_MEM_ENA */
 142#define ADSP2_MEM_ENA_MASK                0x0010  /* DSP1_MEM_ENA */
 143#define ADSP2_MEM_ENA_SHIFT                    4  /* DSP1_MEM_ENA */
 144#define ADSP2_MEM_ENA_WIDTH                    1  /* DSP1_MEM_ENA */
 145#define ADSP2_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
 146#define ADSP2_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
 147#define ADSP2_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
 148#define ADSP2_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
 149#define ADSP2_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
 150#define ADSP2_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
 151#define ADSP2_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
 152#define ADSP2_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
 153#define ADSP2_START                       0x0001  /* DSP1_START */
 154#define ADSP2_START_MASK                  0x0001  /* DSP1_START */
 155#define ADSP2_START_SHIFT                      0  /* DSP1_START */
 156#define ADSP2_START_WIDTH                      1  /* DSP1_START */
 157
 158/*
 159 * ADSP2 clocking
 160 */
 161#define ADSP2_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
 162#define ADSP2_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
 163#define ADSP2_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
 164
 165/*
 166 * ADSP2V2 clocking
 167 */
 168#define ADSP2V2_CLK_SEL_MASK             0x70000  /* CLK_SEL_ENA */
 169#define ADSP2V2_CLK_SEL_SHIFT                 16  /* CLK_SEL_ENA */
 170#define ADSP2V2_CLK_SEL_WIDTH                  3  /* CLK_SEL_ENA */
 171
 172#define ADSP2V2_RATE_MASK                 0x7800  /* DSP_RATE */
 173#define ADSP2V2_RATE_SHIFT                    11  /* DSP_RATE */
 174#define ADSP2V2_RATE_WIDTH                     4  /* DSP_RATE */
 175
 176/*
 177 * ADSP2 Status 1
 178 */
 179#define ADSP2_RAM_RDY                     0x0001
 180#define ADSP2_RAM_RDY_MASK                0x0001
 181#define ADSP2_RAM_RDY_SHIFT                    0
 182#define ADSP2_RAM_RDY_WIDTH                    1
 183
 184/*
 185 * ADSP2 Lock support
 186 */
 187#define ADSP2_LOCK_CODE_0                    0x5555
 188#define ADSP2_LOCK_CODE_1                    0xAAAA
 189
 190#define ADSP2_WATCHDOG                       0x0A
 191#define ADSP2_BUS_ERR_ADDR                   0x52
 192#define ADSP2_REGION_LOCK_STATUS             0x64
 193#define ADSP2_LOCK_REGION_1_LOCK_REGION_0    0x66
 194#define ADSP2_LOCK_REGION_3_LOCK_REGION_2    0x68
 195#define ADSP2_LOCK_REGION_5_LOCK_REGION_4    0x6A
 196#define ADSP2_LOCK_REGION_7_LOCK_REGION_6    0x6C
 197#define ADSP2_LOCK_REGION_9_LOCK_REGION_8    0x6E
 198#define ADSP2_LOCK_REGION_CTRL               0x7A
 199#define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR    0x7C
 200
 201#define ADSP2_REGION_LOCK_ERR_MASK           0x8000
 202#define ADSP2_SLAVE_ERR_MASK                 0x4000
 203#define ADSP2_WDT_TIMEOUT_STS_MASK           0x2000
 204#define ADSP2_CTRL_ERR_PAUSE_ENA             0x0002
 205#define ADSP2_CTRL_ERR_EINT                  0x0001
 206
 207#define ADSP2_BUS_ERR_ADDR_MASK              0x00FFFFFF
 208#define ADSP2_XMEM_ERR_ADDR_MASK             0x0000FFFF
 209#define ADSP2_PMEM_ERR_ADDR_MASK             0x7FFF0000
 210#define ADSP2_PMEM_ERR_ADDR_SHIFT            16
 211#define ADSP2_WDT_ENA_MASK                   0xFFFFFFFD
 212
 213#define ADSP2_LOCK_REGION_SHIFT              16
 214
 215#define ADSP_MAX_STD_CTRL_SIZE               512
 216
 217#define WM_ADSP_ACKED_CTL_TIMEOUT_MS         100
 218#define WM_ADSP_ACKED_CTL_N_QUICKPOLLS       10
 219#define WM_ADSP_ACKED_CTL_MIN_VALUE          0
 220#define WM_ADSP_ACKED_CTL_MAX_VALUE          0xFFFFFF
 221
 222/*
 223 * Event control messages
 224 */
 225#define WM_ADSP_FW_EVENT_SHUTDOWN            0x000001
 226
 227/*
 228 * HALO system info
 229 */
 230#define HALO_AHBM_WINDOW_DEBUG_0             0x02040
 231#define HALO_AHBM_WINDOW_DEBUG_1             0x02044
 232
 233/*
 234 * HALO core
 235 */
 236#define HALO_SCRATCH1                        0x005c0
 237#define HALO_SCRATCH2                        0x005c8
 238#define HALO_SCRATCH3                        0x005d0
 239#define HALO_SCRATCH4                        0x005d8
 240#define HALO_CCM_CORE_CONTROL                0x41000
 241#define HALO_CORE_SOFT_RESET                 0x00010
 242#define HALO_WDT_CONTROL                     0x47000
 243
 244/*
 245 * HALO MPU banks
 246 */
 247#define HALO_MPU_XMEM_ACCESS_0               0x43000
 248#define HALO_MPU_YMEM_ACCESS_0               0x43004
 249#define HALO_MPU_WINDOW_ACCESS_0             0x43008
 250#define HALO_MPU_XREG_ACCESS_0               0x4300C
 251#define HALO_MPU_YREG_ACCESS_0               0x43014
 252#define HALO_MPU_XMEM_ACCESS_1               0x43018
 253#define HALO_MPU_YMEM_ACCESS_1               0x4301C
 254#define HALO_MPU_WINDOW_ACCESS_1             0x43020
 255#define HALO_MPU_XREG_ACCESS_1               0x43024
 256#define HALO_MPU_YREG_ACCESS_1               0x4302C
 257#define HALO_MPU_XMEM_ACCESS_2               0x43030
 258#define HALO_MPU_YMEM_ACCESS_2               0x43034
 259#define HALO_MPU_WINDOW_ACCESS_2             0x43038
 260#define HALO_MPU_XREG_ACCESS_2               0x4303C
 261#define HALO_MPU_YREG_ACCESS_2               0x43044
 262#define HALO_MPU_XMEM_ACCESS_3               0x43048
 263#define HALO_MPU_YMEM_ACCESS_3               0x4304C
 264#define HALO_MPU_WINDOW_ACCESS_3             0x43050
 265#define HALO_MPU_XREG_ACCESS_3               0x43054
 266#define HALO_MPU_YREG_ACCESS_3               0x4305C
 267#define HALO_MPU_XM_VIO_ADDR                 0x43100
 268#define HALO_MPU_XM_VIO_STATUS               0x43104
 269#define HALO_MPU_YM_VIO_ADDR                 0x43108
 270#define HALO_MPU_YM_VIO_STATUS               0x4310C
 271#define HALO_MPU_PM_VIO_ADDR                 0x43110
 272#define HALO_MPU_PM_VIO_STATUS               0x43114
 273#define HALO_MPU_LOCK_CONFIG                 0x43140
 274
 275/*
 276 * HALO_AHBM_WINDOW_DEBUG_1
 277 */
 278#define HALO_AHBM_CORE_ERR_ADDR_MASK         0x0fffff00
 279#define HALO_AHBM_CORE_ERR_ADDR_SHIFT                 8
 280#define HALO_AHBM_FLAGS_ERR_MASK             0x000000ff
 281
 282/*
 283 * HALO_CCM_CORE_CONTROL
 284 */
 285#define HALO_CORE_EN                        0x00000001
 286
 287/*
 288 * HALO_CORE_SOFT_RESET
 289 */
 290#define HALO_CORE_SOFT_RESET_MASK           0x00000001
 291
 292/*
 293 * HALO_WDT_CONTROL
 294 */
 295#define HALO_WDT_EN_MASK                    0x00000001
 296
 297/*
 298 * HALO_MPU_?M_VIO_STATUS
 299 */
 300#define HALO_MPU_VIO_STS_MASK               0x007e0000
 301#define HALO_MPU_VIO_STS_SHIFT                      17
 302#define HALO_MPU_VIO_ERR_WR_MASK            0x00008000
 303#define HALO_MPU_VIO_ERR_SRC_MASK           0x00007fff
 304#define HALO_MPU_VIO_ERR_SRC_SHIFT                   0
 305
 306static struct wm_adsp_ops wm_adsp1_ops;
 307static struct wm_adsp_ops wm_adsp2_ops[];
 308static struct wm_adsp_ops wm_halo_ops;
 309
 310struct wm_adsp_buf {
 311        struct list_head list;
 312        void *buf;
 313};
 314
 315static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
 316                                             struct list_head *list)
 317{
 318        struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
 319
 320        if (buf == NULL)
 321                return NULL;
 322
 323        buf->buf = vmalloc(len);
 324        if (!buf->buf) {
 325                kfree(buf);
 326                return NULL;
 327        }
 328        memcpy(buf->buf, src, len);
 329
 330        if (list)
 331                list_add_tail(&buf->list, list);
 332
 333        return buf;
 334}
 335
 336static void wm_adsp_buf_free(struct list_head *list)
 337{
 338        while (!list_empty(list)) {
 339                struct wm_adsp_buf *buf = list_first_entry(list,
 340                                                           struct wm_adsp_buf,
 341                                                           list);
 342                list_del(&buf->list);
 343                vfree(buf->buf);
 344                kfree(buf);
 345        }
 346}
 347
 348#define WM_ADSP_FW_MBC_VSS  0
 349#define WM_ADSP_FW_HIFI     1
 350#define WM_ADSP_FW_TX       2
 351#define WM_ADSP_FW_TX_SPK   3
 352#define WM_ADSP_FW_RX       4
 353#define WM_ADSP_FW_RX_ANC   5
 354#define WM_ADSP_FW_CTRL     6
 355#define WM_ADSP_FW_ASR      7
 356#define WM_ADSP_FW_TRACE    8
 357#define WM_ADSP_FW_SPK_PROT 9
 358#define WM_ADSP_FW_MISC     10
 359
 360#define WM_ADSP_NUM_FW      11
 361
 362static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
 363        [WM_ADSP_FW_MBC_VSS] =  "MBC/VSS",
 364        [WM_ADSP_FW_HIFI] =     "MasterHiFi",
 365        [WM_ADSP_FW_TX] =       "Tx",
 366        [WM_ADSP_FW_TX_SPK] =   "Tx Speaker",
 367        [WM_ADSP_FW_RX] =       "Rx",
 368        [WM_ADSP_FW_RX_ANC] =   "Rx ANC",
 369        [WM_ADSP_FW_CTRL] =     "Voice Ctrl",
 370        [WM_ADSP_FW_ASR] =      "ASR Assist",
 371        [WM_ADSP_FW_TRACE] =    "Dbg Trace",
 372        [WM_ADSP_FW_SPK_PROT] = "Protection",
 373        [WM_ADSP_FW_MISC] =     "Misc",
 374};
 375
 376struct wm_adsp_system_config_xm_hdr {
 377        __be32 sys_enable;
 378        __be32 fw_id;
 379        __be32 fw_rev;
 380        __be32 boot_status;
 381        __be32 watchdog;
 382        __be32 dma_buffer_size;
 383        __be32 rdma[6];
 384        __be32 wdma[8];
 385        __be32 build_job_name[3];
 386        __be32 build_job_number;
 387};
 388
 389struct wm_halo_system_config_xm_hdr {
 390        __be32 halo_heartbeat;
 391        __be32 build_job_name[3];
 392        __be32 build_job_number;
 393};
 394
 395struct wm_adsp_alg_xm_struct {
 396        __be32 magic;
 397        __be32 smoothing;
 398        __be32 threshold;
 399        __be32 host_buf_ptr;
 400        __be32 start_seq;
 401        __be32 high_water_mark;
 402        __be32 low_water_mark;
 403        __be64 smoothed_power;
 404};
 405
 406struct wm_adsp_host_buf_coeff_v1 {
 407        __be32 host_buf_ptr;            /* Host buffer pointer */
 408        __be32 versions;                /* Version numbers */
 409        __be32 name[4];                 /* The buffer name */
 410};
 411
 412struct wm_adsp_buffer {
 413        __be32 buf1_base;               /* Base addr of first buffer area */
 414        __be32 buf1_size;               /* Size of buf1 area in DSP words */
 415        __be32 buf2_base;               /* Base addr of 2nd buffer area */
 416        __be32 buf1_buf2_size;          /* Size of buf1+buf2 in DSP words */
 417        __be32 buf3_base;               /* Base addr of buf3 area */
 418        __be32 buf_total_size;          /* Size of buf1+buf2+buf3 in DSP words */
 419        __be32 high_water_mark;         /* Point at which IRQ is asserted */
 420        __be32 irq_count;               /* bits 1-31 count IRQ assertions */
 421        __be32 irq_ack;                 /* acked IRQ count, bit 0 enables IRQ */
 422        __be32 next_write_index;        /* word index of next write */
 423        __be32 next_read_index;         /* word index of next read */
 424        __be32 error;                   /* error if any */
 425        __be32 oldest_block_index;      /* word index of oldest surviving */
 426        __be32 requested_rewind;        /* how many blocks rewind was done */
 427        __be32 reserved_space;          /* internal */
 428        __be32 min_free;                /* min free space since stream start */
 429        __be32 blocks_written[2];       /* total blocks written (64 bit) */
 430        __be32 words_written[2];        /* total words written (64 bit) */
 431};
 432
 433struct wm_adsp_compr;
 434
 435struct wm_adsp_compr_buf {
 436        struct list_head list;
 437        struct wm_adsp *dsp;
 438        struct wm_adsp_compr *compr;
 439
 440        struct wm_adsp_buffer_region *regions;
 441        u32 host_buf_ptr;
 442
 443        u32 error;
 444        u32 irq_count;
 445        int read_index;
 446        int avail;
 447        int host_buf_mem_type;
 448
 449        char *name;
 450};
 451
 452struct wm_adsp_compr {
 453        struct list_head list;
 454        struct wm_adsp *dsp;
 455        struct wm_adsp_compr_buf *buf;
 456
 457        struct snd_compr_stream *stream;
 458        struct snd_compressed_buffer size;
 459
 460        u32 *raw_buf;
 461        unsigned int copied_total;
 462
 463        unsigned int sample_rate;
 464
 465        const char *name;
 466};
 467
 468#define WM_ADSP_DATA_WORD_SIZE         3
 469
 470#define WM_ADSP_MIN_FRAGMENTS          1
 471#define WM_ADSP_MAX_FRAGMENTS          256
 472#define WM_ADSP_MIN_FRAGMENT_SIZE      (64 * WM_ADSP_DATA_WORD_SIZE)
 473#define WM_ADSP_MAX_FRAGMENT_SIZE      (4096 * WM_ADSP_DATA_WORD_SIZE)
 474
 475#define WM_ADSP_ALG_XM_STRUCT_MAGIC    0x49aec7
 476
 477#define HOST_BUFFER_FIELD(field) \
 478        (offsetof(struct wm_adsp_buffer, field) / sizeof(__be32))
 479
 480#define ALG_XM_FIELD(field) \
 481        (offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32))
 482
 483#define HOST_BUF_COEFF_SUPPORTED_COMPAT_VER     1
 484
 485#define HOST_BUF_COEFF_COMPAT_VER_MASK          0xFF00
 486#define HOST_BUF_COEFF_COMPAT_VER_SHIFT         8
 487
 488static int wm_adsp_buffer_init(struct wm_adsp *dsp);
 489static int wm_adsp_buffer_free(struct wm_adsp *dsp);
 490
 491struct wm_adsp_buffer_region {
 492        unsigned int offset;
 493        unsigned int cumulative_size;
 494        unsigned int mem_type;
 495        unsigned int base_addr;
 496};
 497
 498struct wm_adsp_buffer_region_def {
 499        unsigned int mem_type;
 500        unsigned int base_offset;
 501        unsigned int size_offset;
 502};
 503
 504static const struct wm_adsp_buffer_region_def default_regions[] = {
 505        {
 506                .mem_type = WMFW_ADSP2_XM,
 507                .base_offset = HOST_BUFFER_FIELD(buf1_base),
 508                .size_offset = HOST_BUFFER_FIELD(buf1_size),
 509        },
 510        {
 511                .mem_type = WMFW_ADSP2_XM,
 512                .base_offset = HOST_BUFFER_FIELD(buf2_base),
 513                .size_offset = HOST_BUFFER_FIELD(buf1_buf2_size),
 514        },
 515        {
 516                .mem_type = WMFW_ADSP2_YM,
 517                .base_offset = HOST_BUFFER_FIELD(buf3_base),
 518                .size_offset = HOST_BUFFER_FIELD(buf_total_size),
 519        },
 520};
 521
 522struct wm_adsp_fw_caps {
 523        u32 id;
 524        struct snd_codec_desc desc;
 525        int num_regions;
 526        const struct wm_adsp_buffer_region_def *region_defs;
 527};
 528
 529static const struct wm_adsp_fw_caps ctrl_caps[] = {
 530        {
 531                .id = SND_AUDIOCODEC_BESPOKE,
 532                .desc = {
 533                        .max_ch = 8,
 534                        .sample_rates = { 16000 },
 535                        .num_sample_rates = 1,
 536                        .formats = SNDRV_PCM_FMTBIT_S16_LE,
 537                },
 538                .num_regions = ARRAY_SIZE(default_regions),
 539                .region_defs = default_regions,
 540        },
 541};
 542
 543static const struct wm_adsp_fw_caps trace_caps[] = {
 544        {
 545                .id = SND_AUDIOCODEC_BESPOKE,
 546                .desc = {
 547                        .max_ch = 8,
 548                        .sample_rates = {
 549                                4000, 8000, 11025, 12000, 16000, 22050,
 550                                24000, 32000, 44100, 48000, 64000, 88200,
 551                                96000, 176400, 192000
 552                        },
 553                        .num_sample_rates = 15,
 554                        .formats = SNDRV_PCM_FMTBIT_S16_LE,
 555                },
 556                .num_regions = ARRAY_SIZE(default_regions),
 557                .region_defs = default_regions,
 558        },
 559};
 560
 561static const struct {
 562        const char *file;
 563        int compr_direction;
 564        int num_caps;
 565        const struct wm_adsp_fw_caps *caps;
 566        bool voice_trigger;
 567} wm_adsp_fw[WM_ADSP_NUM_FW] = {
 568        [WM_ADSP_FW_MBC_VSS] =  { .file = "mbc-vss" },
 569        [WM_ADSP_FW_HIFI] =     { .file = "hifi" },
 570        [WM_ADSP_FW_TX] =       { .file = "tx" },
 571        [WM_ADSP_FW_TX_SPK] =   { .file = "tx-spk" },
 572        [WM_ADSP_FW_RX] =       { .file = "rx" },
 573        [WM_ADSP_FW_RX_ANC] =   { .file = "rx-anc" },
 574        [WM_ADSP_FW_CTRL] =     {
 575                .file = "ctrl",
 576                .compr_direction = SND_COMPRESS_CAPTURE,
 577                .num_caps = ARRAY_SIZE(ctrl_caps),
 578                .caps = ctrl_caps,
 579                .voice_trigger = true,
 580        },
 581        [WM_ADSP_FW_ASR] =      { .file = "asr" },
 582        [WM_ADSP_FW_TRACE] =    {
 583                .file = "trace",
 584                .compr_direction = SND_COMPRESS_CAPTURE,
 585                .num_caps = ARRAY_SIZE(trace_caps),
 586                .caps = trace_caps,
 587        },
 588        [WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" },
 589        [WM_ADSP_FW_MISC] =     { .file = "misc" },
 590};
 591
 592struct wm_coeff_ctl_ops {
 593        int (*xget)(struct snd_kcontrol *kcontrol,
 594                    struct snd_ctl_elem_value *ucontrol);
 595        int (*xput)(struct snd_kcontrol *kcontrol,
 596                    struct snd_ctl_elem_value *ucontrol);
 597};
 598
 599struct wm_coeff_ctl {
 600        const char *name;
 601        const char *fw_name;
 602        /* Subname is needed to match with firmware */
 603        const char *subname;
 604        unsigned int subname_len;
 605        struct wm_adsp_alg_region alg_region;
 606        struct wm_coeff_ctl_ops ops;
 607        struct wm_adsp *dsp;
 608        unsigned int enabled:1;
 609        struct list_head list;
 610        void *cache;
 611        unsigned int offset;
 612        size_t len;
 613        unsigned int set:1;
 614        struct soc_bytes_ext bytes_ext;
 615        unsigned int flags;
 616        unsigned int type;
 617};
 618
 619static const char *wm_adsp_mem_region_name(unsigned int type)
 620{
 621        switch (type) {
 622        case WMFW_ADSP1_PM:
 623                return "PM";
 624        case WMFW_HALO_PM_PACKED:
 625                return "PM_PACKED";
 626        case WMFW_ADSP1_DM:
 627                return "DM";
 628        case WMFW_ADSP2_XM:
 629                return "XM";
 630        case WMFW_HALO_XM_PACKED:
 631                return "XM_PACKED";
 632        case WMFW_ADSP2_YM:
 633                return "YM";
 634        case WMFW_HALO_YM_PACKED:
 635                return "YM_PACKED";
 636        case WMFW_ADSP1_ZM:
 637                return "ZM";
 638        default:
 639                return NULL;
 640        }
 641}
 642
 643#ifdef CONFIG_DEBUG_FS
 644static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s)
 645{
 646        char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
 647
 648        kfree(dsp->wmfw_file_name);
 649        dsp->wmfw_file_name = tmp;
 650}
 651
 652static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s)
 653{
 654        char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
 655
 656        kfree(dsp->bin_file_name);
 657        dsp->bin_file_name = tmp;
 658}
 659
 660static void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
 661{
 662        kfree(dsp->wmfw_file_name);
 663        kfree(dsp->bin_file_name);
 664        dsp->wmfw_file_name = NULL;
 665        dsp->bin_file_name = NULL;
 666}
 667
 668static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
 669                                         char __user *user_buf,
 670                                         size_t count, loff_t *ppos)
 671{
 672        struct wm_adsp *dsp = file->private_data;
 673        ssize_t ret;
 674
 675        mutex_lock(&dsp->pwr_lock);
 676
 677        if (!dsp->wmfw_file_name || !dsp->booted)
 678                ret = 0;
 679        else
 680                ret = simple_read_from_buffer(user_buf, count, ppos,
 681                                              dsp->wmfw_file_name,
 682                                              strlen(dsp->wmfw_file_name));
 683
 684        mutex_unlock(&dsp->pwr_lock);
 685        return ret;
 686}
 687
 688static ssize_t wm_adsp_debugfs_bin_read(struct file *file,
 689                                        char __user *user_buf,
 690                                        size_t count, loff_t *ppos)
 691{
 692        struct wm_adsp *dsp = file->private_data;
 693        ssize_t ret;
 694
 695        mutex_lock(&dsp->pwr_lock);
 696
 697        if (!dsp->bin_file_name || !dsp->booted)
 698                ret = 0;
 699        else
 700                ret = simple_read_from_buffer(user_buf, count, ppos,
 701                                              dsp->bin_file_name,
 702                                              strlen(dsp->bin_file_name));
 703
 704        mutex_unlock(&dsp->pwr_lock);
 705        return ret;
 706}
 707
 708static const struct {
 709        const char *name;
 710        const struct file_operations fops;
 711} wm_adsp_debugfs_fops[] = {
 712        {
 713                .name = "wmfw_file_name",
 714                .fops = {
 715                        .open = simple_open,
 716                        .read = wm_adsp_debugfs_wmfw_read,
 717                },
 718        },
 719        {
 720                .name = "bin_file_name",
 721                .fops = {
 722                        .open = simple_open,
 723                        .read = wm_adsp_debugfs_bin_read,
 724                },
 725        },
 726};
 727
 728static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
 729                                  struct snd_soc_component *component)
 730{
 731        struct dentry *root = NULL;
 732        int i;
 733
 734        root = debugfs_create_dir(dsp->name, component->debugfs_root);
 735
 736        debugfs_create_bool("booted", 0444, root, &dsp->booted);
 737        debugfs_create_bool("running", 0444, root, &dsp->running);
 738        debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id);
 739        debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version);
 740
 741        for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i)
 742                debugfs_create_file(wm_adsp_debugfs_fops[i].name, 0444, root,
 743                                    dsp, &wm_adsp_debugfs_fops[i].fops);
 744
 745        dsp->debugfs_root = root;
 746}
 747
 748static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
 749{
 750        wm_adsp_debugfs_clear(dsp);
 751        debugfs_remove_recursive(dsp->debugfs_root);
 752}
 753#else
 754static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
 755                                         struct snd_soc_component *component)
 756{
 757}
 758
 759static inline void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
 760{
 761}
 762
 763static inline void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp,
 764                                                 const char *s)
 765{
 766}
 767
 768static inline void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp,
 769                                                const char *s)
 770{
 771}
 772
 773static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
 774{
 775}
 776#endif
 777
 778int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
 779                   struct snd_ctl_elem_value *ucontrol)
 780{
 781        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 782        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 783        struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
 784
 785        ucontrol->value.enumerated.item[0] = dsp[e->shift_l].fw;
 786
 787        return 0;
 788}
 789EXPORT_SYMBOL_GPL(wm_adsp_fw_get);
 790
 791int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
 792                   struct snd_ctl_elem_value *ucontrol)
 793{
 794        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 795        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 796        struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
 797        int ret = 0;
 798
 799        if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw)
 800                return 0;
 801
 802        if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW)
 803                return -EINVAL;
 804
 805        mutex_lock(&dsp[e->shift_l].pwr_lock);
 806
 807        if (dsp[e->shift_l].booted || !list_empty(&dsp[e->shift_l].compr_list))
 808                ret = -EBUSY;
 809        else
 810                dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0];
 811
 812        mutex_unlock(&dsp[e->shift_l].pwr_lock);
 813
 814        return ret;
 815}
 816EXPORT_SYMBOL_GPL(wm_adsp_fw_put);
 817
 818const struct soc_enum wm_adsp_fw_enum[] = {
 819        SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 820        SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 821        SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 822        SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 823        SOC_ENUM_SINGLE(0, 4, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 824        SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 825        SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 826};
 827EXPORT_SYMBOL_GPL(wm_adsp_fw_enum);
 828
 829static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
 830                                                        int type)
 831{
 832        int i;
 833
 834        for (i = 0; i < dsp->num_mems; i++)
 835                if (dsp->mem[i].type == type)
 836                        return &dsp->mem[i];
 837
 838        return NULL;
 839}
 840
 841static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
 842                                          unsigned int offset)
 843{
 844        switch (mem->type) {
 845        case WMFW_ADSP1_PM:
 846                return mem->base + (offset * 3);
 847        case WMFW_ADSP1_DM:
 848        case WMFW_ADSP2_XM:
 849        case WMFW_ADSP2_YM:
 850        case WMFW_ADSP1_ZM:
 851                return mem->base + (offset * 2);
 852        default:
 853                WARN(1, "Unknown memory region type");
 854                return offset;
 855        }
 856}
 857
 858static unsigned int wm_halo_region_to_reg(struct wm_adsp_region const *mem,
 859                                          unsigned int offset)
 860{
 861        switch (mem->type) {
 862        case WMFW_ADSP2_XM:
 863        case WMFW_ADSP2_YM:
 864                return mem->base + (offset * 4);
 865        case WMFW_HALO_XM_PACKED:
 866        case WMFW_HALO_YM_PACKED:
 867                return (mem->base + (offset * 3)) & ~0x3;
 868        case WMFW_HALO_PM_PACKED:
 869                return mem->base + (offset * 5);
 870        default:
 871                WARN(1, "Unknown memory region type");
 872                return offset;
 873        }
 874}
 875
 876static void wm_adsp_read_fw_status(struct wm_adsp *dsp,
 877                                   int noffs, unsigned int *offs)
 878{
 879        unsigned int i;
 880        int ret;
 881
 882        for (i = 0; i < noffs; ++i) {
 883                ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]);
 884                if (ret) {
 885                        adsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret);
 886                        return;
 887                }
 888        }
 889}
 890
 891static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
 892{
 893        unsigned int offs[] = {
 894                ADSP2_SCRATCH0, ADSP2_SCRATCH1, ADSP2_SCRATCH2, ADSP2_SCRATCH3,
 895        };
 896
 897        wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
 898
 899        adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
 900                 offs[0], offs[1], offs[2], offs[3]);
 901}
 902
 903static void wm_adsp2v2_show_fw_status(struct wm_adsp *dsp)
 904{
 905        unsigned int offs[] = { ADSP2V2_SCRATCH0_1, ADSP2V2_SCRATCH2_3 };
 906
 907        wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
 908
 909        adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
 910                 offs[0] & 0xFFFF, offs[0] >> 16,
 911                 offs[1] & 0xFFFF, offs[1] >> 16);
 912}
 913
 914static void wm_halo_show_fw_status(struct wm_adsp *dsp)
 915{
 916        unsigned int offs[] = {
 917                HALO_SCRATCH1, HALO_SCRATCH2, HALO_SCRATCH3, HALO_SCRATCH4,
 918        };
 919
 920        wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
 921
 922        adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
 923                 offs[0], offs[1], offs[2], offs[3]);
 924}
 925
 926static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
 927{
 928        return container_of(ext, struct wm_coeff_ctl, bytes_ext);
 929}
 930
 931static int wm_coeff_base_reg(struct wm_coeff_ctl *ctl, unsigned int *reg)
 932{
 933        const struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
 934        struct wm_adsp *dsp = ctl->dsp;
 935        const struct wm_adsp_region *mem;
 936
 937        mem = wm_adsp_find_region(dsp, alg_region->type);
 938        if (!mem) {
 939                adsp_err(dsp, "No base for region %x\n",
 940                         alg_region->type);
 941                return -EINVAL;
 942        }
 943
 944        *reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset);
 945
 946        return 0;
 947}
 948
 949static int wm_coeff_info(struct snd_kcontrol *kctl,
 950                         struct snd_ctl_elem_info *uinfo)
 951{
 952        struct soc_bytes_ext *bytes_ext =
 953                (struct soc_bytes_ext *)kctl->private_value;
 954        struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 955
 956        switch (ctl->type) {
 957        case WMFW_CTL_TYPE_ACKED:
 958                uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 959                uinfo->value.integer.min = WM_ADSP_ACKED_CTL_MIN_VALUE;
 960                uinfo->value.integer.max = WM_ADSP_ACKED_CTL_MAX_VALUE;
 961                uinfo->value.integer.step = 1;
 962                uinfo->count = 1;
 963                break;
 964        default:
 965                uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
 966                uinfo->count = ctl->len;
 967                break;
 968        }
 969
 970        return 0;
 971}
 972
 973static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl,
 974                                        unsigned int event_id)
 975{
 976        struct wm_adsp *dsp = ctl->dsp;
 977        u32 val = cpu_to_be32(event_id);
 978        unsigned int reg;
 979        int i, ret;
 980
 981        ret = wm_coeff_base_reg(ctl, &reg);
 982        if (ret)
 983                return ret;
 984
 985        adsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n",
 986                 event_id, ctl->alg_region.alg,
 987                 wm_adsp_mem_region_name(ctl->alg_region.type), ctl->offset);
 988
 989        ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
 990        if (ret) {
 991                adsp_err(dsp, "Failed to write %x: %d\n", reg, ret);
 992                return ret;
 993        }
 994
 995        /*
 996         * Poll for ack, we initially poll at ~1ms intervals for firmwares
 997         * that respond quickly, then go to ~10ms polls. A firmware is unlikely
 998         * to ack instantly so we do the first 1ms delay before reading the
 999         * control to avoid a pointless bus transaction
1000         */
1001        for (i = 0; i < WM_ADSP_ACKED_CTL_TIMEOUT_MS;) {
1002                switch (i) {
1003                case 0 ... WM_ADSP_ACKED_CTL_N_QUICKPOLLS - 1:
1004                        usleep_range(1000, 2000);
1005                        i++;
1006                        break;
1007                default:
1008                        usleep_range(10000, 20000);
1009                        i += 10;
1010                        break;
1011                }
1012
1013                ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
1014                if (ret) {
1015                        adsp_err(dsp, "Failed to read %x: %d\n", reg, ret);
1016                        return ret;
1017                }
1018
1019                if (val == 0) {
1020                        adsp_dbg(dsp, "Acked control ACKED at poll %u\n", i);
1021                        return 0;
1022                }
1023        }
1024
1025        adsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n",
1026                  reg, ctl->alg_region.alg,
1027                  wm_adsp_mem_region_name(ctl->alg_region.type),
1028                  ctl->offset);
1029
1030        return -ETIMEDOUT;
1031}
1032
1033static int wm_coeff_write_ctrl_raw(struct wm_coeff_ctl *ctl,
1034                                   const void *buf, size_t len)
1035{
1036        struct wm_adsp *dsp = ctl->dsp;
1037        void *scratch;
1038        int ret;
1039        unsigned int reg;
1040
1041        ret = wm_coeff_base_reg(ctl, &reg);
1042        if (ret)
1043                return ret;
1044
1045        scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);
1046        if (!scratch)
1047                return -ENOMEM;
1048
1049        ret = regmap_raw_write(dsp->regmap, reg, scratch,
1050                               len);
1051        if (ret) {
1052                adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
1053                         len, reg, ret);
1054                kfree(scratch);
1055                return ret;
1056        }
1057        adsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg);
1058
1059        kfree(scratch);
1060
1061        return 0;
1062}
1063
1064static int wm_coeff_write_ctrl(struct wm_coeff_ctl *ctl,
1065                               const void *buf, size_t len)
1066{
1067        int ret = 0;
1068
1069        if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
1070                ret = -EPERM;
1071        else if (buf != ctl->cache)
1072                memcpy(ctl->cache, buf, len);
1073
1074        ctl->set = 1;
1075        if (ctl->enabled && ctl->dsp->running)
1076                ret = wm_coeff_write_ctrl_raw(ctl, buf, len);
1077
1078        return ret;
1079}
1080
1081static int wm_coeff_put(struct snd_kcontrol *kctl,
1082                        struct snd_ctl_elem_value *ucontrol)
1083{
1084        struct soc_bytes_ext *bytes_ext =
1085                (struct soc_bytes_ext *)kctl->private_value;
1086        struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1087        char *p = ucontrol->value.bytes.data;
1088        int ret = 0;
1089
1090        mutex_lock(&ctl->dsp->pwr_lock);
1091        ret = wm_coeff_write_ctrl(ctl, p, ctl->len);
1092        mutex_unlock(&ctl->dsp->pwr_lock);
1093
1094        return ret;
1095}
1096
1097static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
1098                            const unsigned int __user *bytes, unsigned int size)
1099{
1100        struct soc_bytes_ext *bytes_ext =
1101                (struct soc_bytes_ext *)kctl->private_value;
1102        struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1103        int ret = 0;
1104
1105        mutex_lock(&ctl->dsp->pwr_lock);
1106
1107        if (copy_from_user(ctl->cache, bytes, size))
1108                ret = -EFAULT;
1109        else
1110                ret = wm_coeff_write_ctrl(ctl, ctl->cache, size);
1111
1112        mutex_unlock(&ctl->dsp->pwr_lock);
1113
1114        return ret;
1115}
1116
1117static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
1118                              struct snd_ctl_elem_value *ucontrol)
1119{
1120        struct soc_bytes_ext *bytes_ext =
1121                (struct soc_bytes_ext *)kctl->private_value;
1122        struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1123        unsigned int val = ucontrol->value.integer.value[0];
1124        int ret;
1125
1126        if (val == 0)
1127                return 0;       /* 0 means no event */
1128
1129        mutex_lock(&ctl->dsp->pwr_lock);
1130
1131        if (ctl->enabled && ctl->dsp->running)
1132                ret = wm_coeff_write_acked_control(ctl, val);
1133        else
1134                ret = -EPERM;
1135
1136        mutex_unlock(&ctl->dsp->pwr_lock);
1137
1138        return ret;
1139}
1140
1141static int wm_coeff_read_ctrl_raw(struct wm_coeff_ctl *ctl,
1142                                  void *buf, size_t len)
1143{
1144        struct wm_adsp *dsp = ctl->dsp;
1145        void *scratch;
1146        int ret;
1147        unsigned int reg;
1148
1149        ret = wm_coeff_base_reg(ctl, &reg);
1150        if (ret)
1151                return ret;
1152
1153        scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);
1154        if (!scratch)
1155                return -ENOMEM;
1156
1157        ret = regmap_raw_read(dsp->regmap, reg, scratch, len);
1158        if (ret) {
1159                adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
1160                         len, reg, ret);
1161                kfree(scratch);
1162                return ret;
1163        }
1164        adsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg);
1165
1166        memcpy(buf, scratch, len);
1167        kfree(scratch);
1168
1169        return 0;
1170}
1171
1172static int wm_coeff_read_ctrl(struct wm_coeff_ctl *ctl, void *buf, size_t len)
1173{
1174        int ret = 0;
1175
1176        if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
1177                if (ctl->enabled && ctl->dsp->running)
1178                        return wm_coeff_read_ctrl_raw(ctl, buf, len);
1179                else
1180                        return -EPERM;
1181        } else {
1182                if (!ctl->flags && ctl->enabled && ctl->dsp->running)
1183                        ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len);
1184
1185                if (buf != ctl->cache)
1186                        memcpy(buf, ctl->cache, len);
1187        }
1188
1189        return ret;
1190}
1191
1192static int wm_coeff_get(struct snd_kcontrol *kctl,
1193                        struct snd_ctl_elem_value *ucontrol)
1194{
1195        struct soc_bytes_ext *bytes_ext =
1196                (struct soc_bytes_ext *)kctl->private_value;
1197        struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1198        char *p = ucontrol->value.bytes.data;
1199        int ret;
1200
1201        mutex_lock(&ctl->dsp->pwr_lock);
1202        ret = wm_coeff_read_ctrl(ctl, p, ctl->len);
1203        mutex_unlock(&ctl->dsp->pwr_lock);
1204
1205        return ret;
1206}
1207
1208static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
1209                            unsigned int __user *bytes, unsigned int size)
1210{
1211        struct soc_bytes_ext *bytes_ext =
1212                (struct soc_bytes_ext *)kctl->private_value;
1213        struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1214        int ret = 0;
1215
1216        mutex_lock(&ctl->dsp->pwr_lock);
1217
1218        ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, size);
1219
1220        if (!ret && copy_to_user(bytes, ctl->cache, size))
1221                ret = -EFAULT;
1222
1223        mutex_unlock(&ctl->dsp->pwr_lock);
1224
1225        return ret;
1226}
1227
1228static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol,
1229                              struct snd_ctl_elem_value *ucontrol)
1230{
1231        /*
1232         * Although it's not useful to read an acked control, we must satisfy
1233         * user-side assumptions that all controls are readable and that a
1234         * write of the same value should be filtered out (it's valid to send
1235         * the same event number again to the firmware). We therefore return 0,
1236         * meaning "no event" so valid event numbers will always be a change
1237         */
1238        ucontrol->value.integer.value[0] = 0;
1239
1240        return 0;
1241}
1242
1243struct wmfw_ctl_work {
1244        struct wm_adsp *dsp;
1245        struct wm_coeff_ctl *ctl;
1246        struct work_struct work;
1247};
1248
1249static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len)
1250{
1251        unsigned int out, rd, wr, vol;
1252
1253        if (len > ADSP_MAX_STD_CTRL_SIZE) {
1254                rd = SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1255                wr = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE;
1256                vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
1257
1258                out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
1259        } else {
1260                rd = SNDRV_CTL_ELEM_ACCESS_READ;
1261                wr = SNDRV_CTL_ELEM_ACCESS_WRITE;
1262                vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
1263
1264                out = 0;
1265        }
1266
1267        if (in) {
1268                out |= rd;
1269                if (in & WMFW_CTL_FLAG_WRITEABLE)
1270                        out |= wr;
1271                if (in & WMFW_CTL_FLAG_VOLATILE)
1272                        out |= vol;
1273        } else {
1274                out |= rd | wr | vol;
1275        }
1276
1277        return out;
1278}
1279
1280static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
1281{
1282        struct snd_kcontrol_new *kcontrol;
1283        int ret;
1284
1285        if (!ctl || !ctl->name)
1286                return -EINVAL;
1287
1288        kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
1289        if (!kcontrol)
1290                return -ENOMEM;
1291
1292        kcontrol->name = ctl->name;
1293        kcontrol->info = wm_coeff_info;
1294        kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1295        kcontrol->tlv.c = snd_soc_bytes_tlv_callback;
1296        kcontrol->private_value = (unsigned long)&ctl->bytes_ext;
1297        kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len);
1298
1299        switch (ctl->type) {
1300        case WMFW_CTL_TYPE_ACKED:
1301                kcontrol->get = wm_coeff_get_acked;
1302                kcontrol->put = wm_coeff_put_acked;
1303                break;
1304        default:
1305                if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
1306                        ctl->bytes_ext.max = ctl->len;
1307                        ctl->bytes_ext.get = wm_coeff_tlv_get;
1308                        ctl->bytes_ext.put = wm_coeff_tlv_put;
1309                } else {
1310                        kcontrol->get = wm_coeff_get;
1311                        kcontrol->put = wm_coeff_put;
1312                }
1313                break;
1314        }
1315
1316        ret = snd_soc_add_component_controls(dsp->component, kcontrol, 1);
1317        if (ret < 0)
1318                goto err_kcontrol;
1319
1320        kfree(kcontrol);
1321
1322        return 0;
1323
1324err_kcontrol:
1325        kfree(kcontrol);
1326        return ret;
1327}
1328
1329static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
1330{
1331        struct wm_coeff_ctl *ctl;
1332        int ret;
1333
1334        list_for_each_entry(ctl, &dsp->ctl_list, list) {
1335                if (!ctl->enabled || ctl->set)
1336                        continue;
1337                if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
1338                        continue;
1339
1340                /*
1341                 * For readable controls populate the cache from the DSP memory.
1342                 * For non-readable controls the cache was zero-filled when
1343                 * created so we don't need to do anything.
1344                 */
1345                if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) {
1346                        ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len);
1347                        if (ret < 0)
1348                                return ret;
1349                }
1350        }
1351
1352        return 0;
1353}
1354
1355static int wm_coeff_sync_controls(struct wm_adsp *dsp)
1356{
1357        struct wm_coeff_ctl *ctl;
1358        int ret;
1359
1360        list_for_each_entry(ctl, &dsp->ctl_list, list) {
1361                if (!ctl->enabled)
1362                        continue;
1363                if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
1364                        ret = wm_coeff_write_ctrl_raw(ctl, ctl->cache,
1365                                                      ctl->len);
1366                        if (ret < 0)
1367                                return ret;
1368                }
1369        }
1370
1371        return 0;
1372}
1373
1374static void wm_adsp_signal_event_controls(struct wm_adsp *dsp,
1375                                          unsigned int event)
1376{
1377        struct wm_coeff_ctl *ctl;
1378        int ret;
1379
1380        list_for_each_entry(ctl, &dsp->ctl_list, list) {
1381                if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT)
1382                        continue;
1383
1384                if (!ctl->enabled)
1385                        continue;
1386
1387                ret = wm_coeff_write_acked_control(ctl, event);
1388                if (ret)
1389                        adsp_warn(dsp,
1390                                  "Failed to send 0x%x event to alg 0x%x (%d)\n",
1391                                  event, ctl->alg_region.alg, ret);
1392        }
1393}
1394
1395static void wm_adsp_ctl_work(struct work_struct *work)
1396{
1397        struct wmfw_ctl_work *ctl_work = container_of(work,
1398                                                      struct wmfw_ctl_work,
1399                                                      work);
1400
1401        wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl);
1402        kfree(ctl_work);
1403}
1404
1405static void wm_adsp_free_ctl_blk(struct wm_coeff_ctl *ctl)
1406{
1407        kfree(ctl->cache);
1408        kfree(ctl->name);
1409        kfree(ctl->subname);
1410        kfree(ctl);
1411}
1412
1413static int wm_adsp_create_control(struct wm_adsp *dsp,
1414                                  const struct wm_adsp_alg_region *alg_region,
1415                                  unsigned int offset, unsigned int len,
1416                                  const char *subname, unsigned int subname_len,
1417                                  unsigned int flags, unsigned int type)
1418{
1419        struct wm_coeff_ctl *ctl;
1420        struct wmfw_ctl_work *ctl_work;
1421        char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
1422        const char *region_name;
1423        int ret;
1424
1425        region_name = wm_adsp_mem_region_name(alg_region->type);
1426        if (!region_name) {
1427                adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);
1428                return -EINVAL;
1429        }
1430
1431        switch (dsp->fw_ver) {
1432        case 0:
1433        case 1:
1434                snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x",
1435                         dsp->name, region_name, alg_region->alg);
1436                subname = NULL; /* don't append subname */
1437                break;
1438        case 2:
1439                ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
1440                                "%s%c %.12s %x", dsp->name, *region_name,
1441                                wm_adsp_fw_text[dsp->fw], alg_region->alg);
1442                break;
1443        default:
1444                ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
1445                                "%s %.12s %x", dsp->name,
1446                                wm_adsp_fw_text[dsp->fw], alg_region->alg);
1447                break;
1448        }
1449
1450        if (subname) {
1451                int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
1452                int skip = 0;
1453
1454                if (dsp->component->name_prefix)
1455                        avail -= strlen(dsp->component->name_prefix) + 1;
1456
1457                /* Truncate the subname from the start if it is too long */
1458                if (subname_len > avail)
1459                        skip = subname_len - avail;
1460
1461                snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret,
1462                         " %.*s", subname_len - skip, subname + skip);
1463        }
1464
1465        list_for_each_entry(ctl, &dsp->ctl_list, list) {
1466                if (!strcmp(ctl->name, name)) {
1467                        if (!ctl->enabled)
1468                                ctl->enabled = 1;
1469                        return 0;
1470                }
1471        }
1472
1473        ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
1474        if (!ctl)
1475                return -ENOMEM;
1476        ctl->fw_name = wm_adsp_fw_text[dsp->fw];
1477        ctl->alg_region = *alg_region;
1478        ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
1479        if (!ctl->name) {
1480                ret = -ENOMEM;
1481                goto err_ctl;
1482        }
1483        if (subname) {
1484                ctl->subname_len = subname_len;
1485                ctl->subname = kmemdup(subname,
1486                                       strlen(subname) + 1, GFP_KERNEL);
1487                if (!ctl->subname) {
1488                        ret = -ENOMEM;
1489                        goto err_ctl_name;
1490                }
1491        }
1492        ctl->enabled = 1;
1493        ctl->set = 0;
1494        ctl->ops.xget = wm_coeff_get;
1495        ctl->ops.xput = wm_coeff_put;
1496        ctl->dsp = dsp;
1497
1498        ctl->flags = flags;
1499        ctl->type = type;
1500        ctl->offset = offset;
1501        ctl->len = len;
1502        ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
1503        if (!ctl->cache) {
1504                ret = -ENOMEM;
1505                goto err_ctl_subname;
1506        }
1507
1508        list_add(&ctl->list, &dsp->ctl_list);
1509
1510        if (flags & WMFW_CTL_FLAG_SYS)
1511                return 0;
1512
1513        ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
1514        if (!ctl_work) {
1515                ret = -ENOMEM;
1516                goto err_ctl_cache;
1517        }
1518
1519        ctl_work->dsp = dsp;
1520        ctl_work->ctl = ctl;
1521        INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
1522        schedule_work(&ctl_work->work);
1523
1524        return 0;
1525
1526err_ctl_cache:
1527        kfree(ctl->cache);
1528err_ctl_subname:
1529        kfree(ctl->subname);
1530err_ctl_name:
1531        kfree(ctl->name);
1532err_ctl:
1533        kfree(ctl);
1534
1535        return ret;
1536}
1537
1538struct wm_coeff_parsed_alg {
1539        int id;
1540        const u8 *name;
1541        int name_len;
1542        int ncoeff;
1543};
1544
1545struct wm_coeff_parsed_coeff {
1546        int offset;
1547        int mem_type;
1548        const u8 *name;
1549        int name_len;
1550        int ctl_type;
1551        int flags;
1552        int len;
1553};
1554
1555static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
1556{
1557        int length;
1558
1559        switch (bytes) {
1560        case 1:
1561                length = **pos;
1562                break;
1563        case 2:
1564                length = le16_to_cpu(*((__le16 *)*pos));
1565                break;
1566        default:
1567                return 0;
1568        }
1569
1570        if (str)
1571                *str = *pos + bytes;
1572
1573        *pos += ((length + bytes) + 3) & ~0x03;
1574
1575        return length;
1576}
1577
1578static int wm_coeff_parse_int(int bytes, const u8 **pos)
1579{
1580        int val = 0;
1581
1582        switch (bytes) {
1583        case 2:
1584                val = le16_to_cpu(*((__le16 *)*pos));
1585                break;
1586        case 4:
1587                val = le32_to_cpu(*((__le32 *)*pos));
1588                break;
1589        default:
1590                break;
1591        }
1592
1593        *pos += bytes;
1594
1595        return val;
1596}
1597
1598static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data,
1599                                      struct wm_coeff_parsed_alg *blk)
1600{
1601        const struct wmfw_adsp_alg_data *raw;
1602
1603        switch (dsp->fw_ver) {
1604        case 0:
1605        case 1:
1606                raw = (const struct wmfw_adsp_alg_data *)*data;
1607                *data = raw->data;
1608
1609                blk->id = le32_to_cpu(raw->id);
1610                blk->name = raw->name;
1611                blk->name_len = strlen(raw->name);
1612                blk->ncoeff = le32_to_cpu(raw->ncoeff);
1613                break;
1614        default:
1615                blk->id = wm_coeff_parse_int(sizeof(raw->id), data);
1616                blk->name_len = wm_coeff_parse_string(sizeof(u8), data,
1617                                                      &blk->name);
1618                wm_coeff_parse_string(sizeof(u16), data, NULL);
1619                blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data);
1620                break;
1621        }
1622
1623        adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
1624        adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
1625        adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
1626}
1627
1628static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
1629                                        struct wm_coeff_parsed_coeff *blk)
1630{
1631        const struct wmfw_adsp_coeff_data *raw;
1632        const u8 *tmp;
1633        int length;
1634
1635        switch (dsp->fw_ver) {
1636        case 0:
1637        case 1:
1638                raw = (const struct wmfw_adsp_coeff_data *)*data;
1639                *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
1640
1641                blk->offset = le16_to_cpu(raw->hdr.offset);
1642                blk->mem_type = le16_to_cpu(raw->hdr.type);
1643                blk->name = raw->name;
1644                blk->name_len = strlen(raw->name);
1645                blk->ctl_type = le16_to_cpu(raw->ctl_type);
1646                blk->flags = le16_to_cpu(raw->flags);
1647                blk->len = le32_to_cpu(raw->len);
1648                break;
1649        default:
1650                tmp = *data;
1651                blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
1652                blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
1653                length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
1654                blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp,
1655                                                      &blk->name);
1656                wm_coeff_parse_string(sizeof(u8), &tmp, NULL);
1657                wm_coeff_parse_string(sizeof(u16), &tmp, NULL);
1658                blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
1659                blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp);
1660                blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp);
1661
1662                *data = *data + sizeof(raw->hdr) + length;
1663                break;
1664        }
1665
1666        adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
1667        adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
1668        adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
1669        adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
1670        adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
1671        adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
1672}
1673
1674static int wm_adsp_check_coeff_flags(struct wm_adsp *dsp,
1675                                const struct wm_coeff_parsed_coeff *coeff_blk,
1676                                unsigned int f_required,
1677                                unsigned int f_illegal)
1678{
1679        if ((coeff_blk->flags & f_illegal) ||
1680            ((coeff_blk->flags & f_required) != f_required)) {
1681                adsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n",
1682                         coeff_blk->flags, coeff_blk->ctl_type);
1683                return -EINVAL;
1684        }
1685
1686        return 0;
1687}
1688
1689static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
1690                               const struct wmfw_region *region)
1691{
1692        struct wm_adsp_alg_region alg_region = {};
1693        struct wm_coeff_parsed_alg alg_blk;
1694        struct wm_coeff_parsed_coeff coeff_blk;
1695        const u8 *data = region->data;
1696        int i, ret;
1697
1698        wm_coeff_parse_alg(dsp, &data, &alg_blk);
1699        for (i = 0; i < alg_blk.ncoeff; i++) {
1700                wm_coeff_parse_coeff(dsp, &data, &coeff_blk);
1701
1702                switch (coeff_blk.ctl_type) {
1703                case SNDRV_CTL_ELEM_TYPE_BYTES:
1704                        break;
1705                case WMFW_CTL_TYPE_ACKED:
1706                        if (coeff_blk.flags & WMFW_CTL_FLAG_SYS)
1707                                continue;       /* ignore */
1708
1709                        ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
1710                                                WMFW_CTL_FLAG_VOLATILE |
1711                                                WMFW_CTL_FLAG_WRITEABLE |
1712                                                WMFW_CTL_FLAG_READABLE,
1713                                                0);
1714                        if (ret)
1715                                return -EINVAL;
1716                        break;
1717                case WMFW_CTL_TYPE_HOSTEVENT:
1718                        ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
1719                                                WMFW_CTL_FLAG_SYS |
1720                                                WMFW_CTL_FLAG_VOLATILE |
1721                                                WMFW_CTL_FLAG_WRITEABLE |
1722                                                WMFW_CTL_FLAG_READABLE,
1723                                                0);
1724                        if (ret)
1725                                return -EINVAL;
1726                        break;
1727                case WMFW_CTL_TYPE_HOST_BUFFER:
1728                        ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
1729                                                WMFW_CTL_FLAG_SYS |
1730                                                WMFW_CTL_FLAG_VOLATILE |
1731                                                WMFW_CTL_FLAG_READABLE,
1732                                                0);
1733                        if (ret)
1734                                return -EINVAL;
1735                        break;
1736                default:
1737                        adsp_err(dsp, "Unknown control type: %d\n",
1738                                 coeff_blk.ctl_type);
1739                        return -EINVAL;
1740                }
1741
1742                alg_region.type = coeff_blk.mem_type;
1743                alg_region.alg = alg_blk.id;
1744
1745                ret = wm_adsp_create_control(dsp, &alg_region,
1746                                             coeff_blk.offset,
1747                                             coeff_blk.len,
1748                                             coeff_blk.name,
1749                                             coeff_blk.name_len,
1750                                             coeff_blk.flags,
1751                                             coeff_blk.ctl_type);
1752                if (ret < 0)
1753                        adsp_err(dsp, "Failed to create control: %.*s, %d\n",
1754                                 coeff_blk.name_len, coeff_blk.name, ret);
1755        }
1756
1757        return 0;
1758}
1759
1760static unsigned int wm_adsp1_parse_sizes(struct wm_adsp *dsp,
1761                                         const char * const file,
1762                                         unsigned int pos,
1763                                         const struct firmware *firmware)
1764{
1765        const struct wmfw_adsp1_sizes *adsp1_sizes;
1766
1767        adsp1_sizes = (void *)&firmware->data[pos];
1768
1769        adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file,
1770                 le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm),
1771                 le32_to_cpu(adsp1_sizes->zm));
1772
1773        return pos + sizeof(*adsp1_sizes);
1774}
1775
1776static unsigned int wm_adsp2_parse_sizes(struct wm_adsp *dsp,
1777                                         const char * const file,
1778                                         unsigned int pos,
1779                                         const struct firmware *firmware)
1780{
1781        const struct wmfw_adsp2_sizes *adsp2_sizes;
1782
1783        adsp2_sizes = (void *)&firmware->data[pos];
1784
1785        adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file,
1786                 le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym),
1787                 le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm));
1788
1789        return pos + sizeof(*adsp2_sizes);
1790}
1791
1792static bool wm_adsp_validate_version(struct wm_adsp *dsp, unsigned int version)
1793{
1794        switch (version) {
1795        case 0:
1796                adsp_warn(dsp, "Deprecated file format %d\n", version);
1797                return true;
1798        case 1:
1799        case 2:
1800                return true;
1801        default:
1802                return false;
1803        }
1804}
1805
1806static bool wm_halo_validate_version(struct wm_adsp *dsp, unsigned int version)
1807{
1808        switch (version) {
1809        case 3:
1810                return true;
1811        default:
1812                return false;
1813        }
1814}
1815
1816static int wm_adsp_load(struct wm_adsp *dsp)
1817{
1818        LIST_HEAD(buf_list);
1819        const struct firmware *firmware;
1820        struct regmap *regmap = dsp->regmap;
1821        unsigned int pos = 0;
1822        const struct wmfw_header *header;
1823        const struct wmfw_adsp1_sizes *adsp1_sizes;
1824        const struct wmfw_footer *footer;
1825        const struct wmfw_region *region;
1826        const struct wm_adsp_region *mem;
1827        const char *region_name;
1828        char *file, *text = NULL;
1829        struct wm_adsp_buf *buf;
1830        unsigned int reg;
1831        int regions = 0;
1832        int ret, offset, type;
1833
1834        file = kzalloc(PAGE_SIZE, GFP_KERNEL);
1835        if (file == NULL)
1836                return -ENOMEM;
1837
1838        snprintf(file, PAGE_SIZE, "%s-%s-%s.wmfw", dsp->part, dsp->fwf_name,
1839                 wm_adsp_fw[dsp->fw].file);
1840        file[PAGE_SIZE - 1] = '\0';
1841
1842        ret = request_firmware(&firmware, file, dsp->dev);
1843        if (ret != 0) {
1844                adsp_err(dsp, "Failed to request '%s'\n", file);
1845                goto out;
1846        }
1847        ret = -EINVAL;
1848
1849        pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
1850        if (pos >= firmware->size) {
1851                adsp_err(dsp, "%s: file too short, %zu bytes\n",
1852                         file, firmware->size);
1853                goto out_fw;
1854        }
1855
1856        header = (void *)&firmware->data[0];
1857
1858        if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
1859                adsp_err(dsp, "%s: invalid magic\n", file);
1860                goto out_fw;
1861        }
1862
1863        if (!dsp->ops->validate_version(dsp, header->ver)) {
1864                adsp_err(dsp, "%s: unknown file format %d\n",
1865                         file, header->ver);
1866                goto out_fw;
1867        }
1868
1869        adsp_info(dsp, "Firmware version: %d\n", header->ver);
1870        dsp->fw_ver = header->ver;
1871
1872        if (header->core != dsp->type) {
1873                adsp_err(dsp, "%s: invalid core %d != %d\n",
1874                         file, header->core, dsp->type);
1875                goto out_fw;
1876        }
1877
1878        pos = sizeof(*header);
1879        pos = dsp->ops->parse_sizes(dsp, file, pos, firmware);
1880
1881        footer = (void *)&firmware->data[pos];
1882        pos += sizeof(*footer);
1883
1884        if (le32_to_cpu(header->len) != pos) {
1885                adsp_err(dsp, "%s: unexpected header length %d\n",
1886                         file, le32_to_cpu(header->len));
1887                goto out_fw;
1888        }
1889
1890        adsp_dbg(dsp, "%s: timestamp %llu\n", file,
1891                 le64_to_cpu(footer->timestamp));
1892
1893        while (pos < firmware->size &&
1894               sizeof(*region) < firmware->size - pos) {
1895                region = (void *)&(firmware->data[pos]);
1896                region_name = "Unknown";
1897                reg = 0;
1898                text = NULL;
1899                offset = le32_to_cpu(region->offset) & 0xffffff;
1900                type = be32_to_cpu(region->type) & 0xff;
1901
1902                switch (type) {
1903                case WMFW_NAME_TEXT:
1904                        region_name = "Firmware name";
1905                        text = kzalloc(le32_to_cpu(region->len) + 1,
1906                                       GFP_KERNEL);
1907                        break;
1908                case WMFW_ALGORITHM_DATA:
1909                        region_name = "Algorithm";
1910                        ret = wm_adsp_parse_coeff(dsp, region);
1911                        if (ret != 0)
1912                                goto out_fw;
1913                        break;
1914                case WMFW_INFO_TEXT:
1915                        region_name = "Information";
1916                        text = kzalloc(le32_to_cpu(region->len) + 1,
1917                                       GFP_KERNEL);
1918                        break;
1919                case WMFW_ABSOLUTE:
1920                        region_name = "Absolute";
1921                        reg = offset;
1922                        break;
1923                case WMFW_ADSP1_PM:
1924                case WMFW_ADSP1_DM:
1925                case WMFW_ADSP2_XM:
1926                case WMFW_ADSP2_YM:
1927                case WMFW_ADSP1_ZM:
1928                case WMFW_HALO_PM_PACKED:
1929                case WMFW_HALO_XM_PACKED:
1930                case WMFW_HALO_YM_PACKED:
1931                        mem = wm_adsp_find_region(dsp, type);
1932                        if (!mem) {
1933                                adsp_err(dsp, "No region of type: %x\n", type);
1934                                goto out_fw;
1935                        }
1936
1937                        region_name = wm_adsp_mem_region_name(type);
1938                        reg = dsp->ops->region_to_reg(mem, offset);
1939                        break;
1940                default:
1941                        adsp_warn(dsp,
1942                                  "%s.%d: Unknown region type %x at %d(%x)\n",
1943                                  file, regions, type, pos, pos);
1944                        break;
1945                }
1946
1947                adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
1948                         regions, le32_to_cpu(region->len), offset,
1949                         region_name);
1950
1951                if (le32_to_cpu(region->len) >
1952                    firmware->size - pos - sizeof(*region)) {
1953                        adsp_err(dsp,
1954                                 "%s.%d: %s region len %d bytes exceeds file length %zu\n",
1955                                 file, regions, region_name,
1956                                 le32_to_cpu(region->len), firmware->size);
1957                        ret = -EINVAL;
1958                        goto out_fw;
1959                }
1960
1961                if (text) {
1962                        memcpy(text, region->data, le32_to_cpu(region->len));
1963                        adsp_info(dsp, "%s: %s\n", file, text);
1964                        kfree(text);
1965                        text = NULL;
1966                }
1967
1968                if (reg) {
1969                        buf = wm_adsp_buf_alloc(region->data,
1970                                                le32_to_cpu(region->len),
1971                                                &buf_list);
1972                        if (!buf) {
1973                                adsp_err(dsp, "Out of memory\n");
1974                                ret = -ENOMEM;
1975                                goto out_fw;
1976                        }
1977
1978                        ret = regmap_raw_write_async(regmap, reg, buf->buf,
1979                                                     le32_to_cpu(region->len));
1980                        if (ret != 0) {
1981                                adsp_err(dsp,
1982                                        "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
1983                                        file, regions,
1984                                        le32_to_cpu(region->len), offset,
1985                                        region_name, ret);
1986                                goto out_fw;
1987                        }
1988                }
1989
1990                pos += le32_to_cpu(region->len) + sizeof(*region);
1991                regions++;
1992        }
1993
1994        ret = regmap_async_complete(regmap);
1995        if (ret != 0) {
1996                adsp_err(dsp, "Failed to complete async write: %d\n", ret);
1997                goto out_fw;
1998        }
1999
2000        if (pos > firmware->size)
2001                adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
2002                          file, regions, pos - firmware->size);
2003
2004        wm_adsp_debugfs_save_wmfwname(dsp, file);
2005
2006out_fw:
2007        regmap_async_complete(regmap);
2008        wm_adsp_buf_free(&buf_list);
2009        release_firmware(firmware);
2010        kfree(text);
2011out:
2012        kfree(file);
2013
2014        return ret;
2015}
2016
2017/*
2018 * Find wm_coeff_ctl with input name as its subname
2019 * If not found, return NULL
2020 */
2021static struct wm_coeff_ctl *wm_adsp_get_ctl(struct wm_adsp *dsp,
2022                                             const char *name, int type,
2023                                             unsigned int alg)
2024{
2025        struct wm_coeff_ctl *pos, *rslt = NULL;
2026
2027        list_for_each_entry(pos, &dsp->ctl_list, list) {
2028                if (!pos->subname)
2029                        continue;
2030                if (strncmp(pos->subname, name, pos->subname_len) == 0 &&
2031                                pos->alg_region.alg == alg &&
2032                                pos->alg_region.type == type) {
2033                        rslt = pos;
2034                        break;
2035                }
2036        }
2037
2038        return rslt;
2039}
2040
2041int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
2042                      unsigned int alg, void *buf, size_t len)
2043{
2044        struct wm_coeff_ctl *ctl;
2045        struct snd_kcontrol *kcontrol;
2046        int ret;
2047
2048        ctl = wm_adsp_get_ctl(dsp, name, type, alg);
2049        if (!ctl)
2050                return -EINVAL;
2051
2052        if (len > ctl->len)
2053                return -EINVAL;
2054
2055        ret = wm_coeff_write_ctrl(ctl, buf, len);
2056
2057        kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl->name);
2058        snd_ctl_notify(dsp->component->card->snd_card,
2059                       SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id);
2060
2061        return ret;
2062}
2063EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
2064
2065int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
2066                     unsigned int alg, void *buf, size_t len)
2067{
2068        struct wm_coeff_ctl *ctl;
2069
2070        ctl = wm_adsp_get_ctl(dsp, name, type, alg);
2071        if (!ctl)
2072                return -EINVAL;
2073
2074        if (len > ctl->len)
2075                return -EINVAL;
2076
2077        return wm_coeff_read_ctrl(ctl, buf, len);
2078}
2079EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
2080
2081static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
2082                                  const struct wm_adsp_alg_region *alg_region)
2083{
2084        struct wm_coeff_ctl *ctl;
2085
2086        list_for_each_entry(ctl, &dsp->ctl_list, list) {
2087                if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
2088                    alg_region->alg == ctl->alg_region.alg &&
2089                    alg_region->type == ctl->alg_region.type) {
2090                        ctl->alg_region.base = alg_region->base;
2091                }
2092        }
2093}
2094
2095static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
2096                               const struct wm_adsp_region *mem,
2097                               unsigned int pos, unsigned int len)
2098{
2099        void *alg;
2100        unsigned int reg;
2101        int ret;
2102        __be32 val;
2103
2104        if (n_algs == 0) {
2105                adsp_err(dsp, "No algorithms\n");
2106                return ERR_PTR(-EINVAL);
2107        }
2108
2109        if (n_algs > 1024) {
2110                adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
2111                return ERR_PTR(-EINVAL);
2112        }
2113
2114        /* Read the terminator first to validate the length */
2115        reg = dsp->ops->region_to_reg(mem, pos + len);
2116
2117        ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
2118        if (ret != 0) {
2119                adsp_err(dsp, "Failed to read algorithm list end: %d\n",
2120                        ret);
2121                return ERR_PTR(ret);
2122        }
2123
2124        if (be32_to_cpu(val) != 0xbedead)
2125                adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
2126                          reg, be32_to_cpu(val));
2127
2128        /* Convert length from DSP words to bytes */
2129        len *= sizeof(u32);
2130
2131        alg = kzalloc(len, GFP_KERNEL | GFP_DMA);
2132        if (!alg)
2133                return ERR_PTR(-ENOMEM);
2134
2135        reg = dsp->ops->region_to_reg(mem, pos);
2136
2137        ret = regmap_raw_read(dsp->regmap, reg, alg, len);
2138        if (ret != 0) {
2139                adsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
2140                kfree(alg);
2141                return ERR_PTR(ret);
2142        }
2143
2144        return alg;
2145}
2146
2147static struct wm_adsp_alg_region *
2148        wm_adsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id)
2149{
2150        struct wm_adsp_alg_region *alg_region;
2151
2152        list_for_each_entry(alg_region, &dsp->alg_regions, list) {
2153                if (id == alg_region->alg && type == alg_region->type)
2154                        return alg_region;
2155        }
2156
2157        return NULL;
2158}
2159
2160static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
2161                                                        int type, __be32 id,
2162                                                        __be32 base)
2163{
2164        struct wm_adsp_alg_region *alg_region;
2165
2166        alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
2167        if (!alg_region)
2168                return ERR_PTR(-ENOMEM);
2169
2170        alg_region->type = type;
2171        alg_region->alg = be32_to_cpu(id);
2172        alg_region->base = be32_to_cpu(base);
2173
2174        list_add_tail(&alg_region->list, &dsp->alg_regions);
2175
2176        if (dsp->fw_ver > 0)
2177                wm_adsp_ctl_fixup_base(dsp, alg_region);
2178
2179        return alg_region;
2180}
2181
2182static void wm_adsp_free_alg_regions(struct wm_adsp *dsp)
2183{
2184        struct wm_adsp_alg_region *alg_region;
2185
2186        while (!list_empty(&dsp->alg_regions)) {
2187                alg_region = list_first_entry(&dsp->alg_regions,
2188                                              struct wm_adsp_alg_region,
2189                                              list);
2190                list_del(&alg_region->list);
2191                kfree(alg_region);
2192        }
2193}
2194
2195static void wmfw_parse_id_header(struct wm_adsp *dsp,
2196                                 struct wmfw_id_hdr *fw, int nalgs)
2197{
2198        dsp->fw_id = be32_to_cpu(fw->id);
2199        dsp->fw_id_version = be32_to_cpu(fw->ver);
2200
2201        adsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n",
2202                  dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16,
2203                  (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
2204                  nalgs);
2205}
2206
2207static void wmfw_v3_parse_id_header(struct wm_adsp *dsp,
2208                                    struct wmfw_v3_id_hdr *fw, int nalgs)
2209{
2210        dsp->fw_id = be32_to_cpu(fw->id);
2211        dsp->fw_id_version = be32_to_cpu(fw->ver);
2212        dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id);
2213
2214        adsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n",
2215                  dsp->fw_id, dsp->fw_vendor_id,
2216                  (dsp->fw_id_version & 0xff0000) >> 16,
2217                  (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
2218                  nalgs);
2219}
2220
2221static int wm_adsp_create_regions(struct wm_adsp *dsp, __be32 id, int nregions,
2222                                int *type, __be32 *base)
2223{
2224        struct wm_adsp_alg_region *alg_region;
2225        int i;
2226
2227        for (i = 0; i < nregions; i++) {
2228                alg_region = wm_adsp_create_region(dsp, type[i], id, base[i]);
2229                if (IS_ERR(alg_region))
2230                        return PTR_ERR(alg_region);
2231        }
2232
2233        return 0;
2234}
2235
2236static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
2237{
2238        struct wmfw_adsp1_id_hdr adsp1_id;
2239        struct wmfw_adsp1_alg_hdr *adsp1_alg;
2240        struct wm_adsp_alg_region *alg_region;
2241        const struct wm_adsp_region *mem;
2242        unsigned int pos, len;
2243        size_t n_algs;
2244        int i, ret;
2245
2246        mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
2247        if (WARN_ON(!mem))
2248                return -EINVAL;
2249
2250        ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
2251                              sizeof(adsp1_id));
2252        if (ret != 0) {
2253                adsp_err(dsp, "Failed to read algorithm info: %d\n",
2254                         ret);
2255                return ret;
2256        }
2257
2258        n_algs = be32_to_cpu(adsp1_id.n_algs);
2259
2260        wmfw_parse_id_header(dsp, &adsp1_id.fw, n_algs);
2261
2262        alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
2263                                           adsp1_id.fw.id, adsp1_id.zm);
2264        if (IS_ERR(alg_region))
2265                return PTR_ERR(alg_region);
2266
2267        alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
2268                                           adsp1_id.fw.id, adsp1_id.dm);
2269        if (IS_ERR(alg_region))
2270                return PTR_ERR(alg_region);
2271
2272        /* Calculate offset and length in DSP words */
2273        pos = sizeof(adsp1_id) / sizeof(u32);
2274        len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32);
2275
2276        adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
2277        if (IS_ERR(adsp1_alg))
2278                return PTR_ERR(adsp1_alg);
2279
2280        for (i = 0; i < n_algs; i++) {
2281                adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
2282                          i, be32_to_cpu(adsp1_alg[i].alg.id),
2283                          (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
2284                          (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
2285                          be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
2286                          be32_to_cpu(adsp1_alg[i].dm),
2287                          be32_to_cpu(adsp1_alg[i].zm));
2288
2289                alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
2290                                                   adsp1_alg[i].alg.id,
2291                                                   adsp1_alg[i].dm);
2292                if (IS_ERR(alg_region)) {
2293                        ret = PTR_ERR(alg_region);
2294                        goto out;
2295                }
2296                if (dsp->fw_ver == 0) {
2297                        if (i + 1 < n_algs) {
2298                                len = be32_to_cpu(adsp1_alg[i + 1].dm);
2299                                len -= be32_to_cpu(adsp1_alg[i].dm);
2300                                len *= 4;
2301                                wm_adsp_create_control(dsp, alg_region, 0,
2302                                                     len, NULL, 0, 0,
2303                                                     SNDRV_CTL_ELEM_TYPE_BYTES);
2304                        } else {
2305                                adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
2306                                          be32_to_cpu(adsp1_alg[i].alg.id));
2307                        }
2308                }
2309
2310                alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
2311                                                   adsp1_alg[i].alg.id,
2312                                                   adsp1_alg[i].zm);
2313                if (IS_ERR(alg_region)) {
2314                        ret = PTR_ERR(alg_region);
2315                        goto out;
2316                }
2317                if (dsp->fw_ver == 0) {
2318                        if (i + 1 < n_algs) {
2319                                len = be32_to_cpu(adsp1_alg[i + 1].zm);
2320                                len -= be32_to_cpu(adsp1_alg[i].zm);
2321                                len *= 4;
2322                                wm_adsp_create_control(dsp, alg_region, 0,
2323                                                     len, NULL, 0, 0,
2324                                                     SNDRV_CTL_ELEM_TYPE_BYTES);
2325                        } else {
2326                                adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
2327                                          be32_to_cpu(adsp1_alg[i].alg.id));
2328                        }
2329                }
2330        }
2331
2332out:
2333        kfree(adsp1_alg);
2334        return ret;
2335}
2336
2337static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
2338{
2339        struct wmfw_adsp2_id_hdr adsp2_id;
2340        struct wmfw_adsp2_alg_hdr *adsp2_alg;
2341        struct wm_adsp_alg_region *alg_region;
2342        const struct wm_adsp_region *mem;
2343        unsigned int pos, len;
2344        size_t n_algs;
2345        int i, ret;
2346
2347        mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
2348        if (WARN_ON(!mem))
2349                return -EINVAL;
2350
2351        ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
2352                              sizeof(adsp2_id));
2353        if (ret != 0) {
2354                adsp_err(dsp, "Failed to read algorithm info: %d\n",
2355                         ret);
2356                return ret;
2357        }
2358
2359        n_algs = be32_to_cpu(adsp2_id.n_algs);
2360
2361        wmfw_parse_id_header(dsp, &adsp2_id.fw, n_algs);
2362
2363        alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
2364                                           adsp2_id.fw.id, adsp2_id.xm);
2365        if (IS_ERR(alg_region))
2366                return PTR_ERR(alg_region);
2367
2368        alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
2369                                           adsp2_id.fw.id, adsp2_id.ym);
2370        if (IS_ERR(alg_region))
2371                return PTR_ERR(alg_region);
2372
2373        alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
2374                                           adsp2_id.fw.id, adsp2_id.zm);
2375        if (IS_ERR(alg_region))
2376                return PTR_ERR(alg_region);
2377
2378        /* Calculate offset and length in DSP words */
2379        pos = sizeof(adsp2_id) / sizeof(u32);
2380        len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32);
2381
2382        adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
2383        if (IS_ERR(adsp2_alg))
2384                return PTR_ERR(adsp2_alg);
2385
2386        for (i = 0; i < n_algs; i++) {
2387                adsp_info(dsp,
2388                          "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
2389                          i, be32_to_cpu(adsp2_alg[i].alg.id),
2390                          (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
2391                          (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
2392                          be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
2393                          be32_to_cpu(adsp2_alg[i].xm),
2394                          be32_to_cpu(adsp2_alg[i].ym),
2395                          be32_to_cpu(adsp2_alg[i].zm));
2396
2397                alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
2398                                                   adsp2_alg[i].alg.id,
2399                                                   adsp2_alg[i].xm);
2400                if (IS_ERR(alg_region)) {
2401                        ret = PTR_ERR(alg_region);
2402                        goto out;
2403                }
2404                if (dsp->fw_ver == 0) {
2405                        if (i + 1 < n_algs) {
2406                                len = be32_to_cpu(adsp2_alg[i + 1].xm);
2407                                len -= be32_to_cpu(adsp2_alg[i].xm);
2408                                len *= 4;
2409                                wm_adsp_create_control(dsp, alg_region, 0,
2410                                                     len, NULL, 0, 0,
2411                                                     SNDRV_CTL_ELEM_TYPE_BYTES);
2412                        } else {
2413                                adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
2414                                          be32_to_cpu(adsp2_alg[i].alg.id));
2415                        }
2416                }
2417
2418                alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
2419                                                   adsp2_alg[i].alg.id,
2420                                                   adsp2_alg[i].ym);
2421                if (IS_ERR(alg_region)) {
2422                        ret = PTR_ERR(alg_region);
2423                        goto out;
2424                }
2425                if (dsp->fw_ver == 0) {
2426                        if (i + 1 < n_algs) {
2427                                len = be32_to_cpu(adsp2_alg[i + 1].ym);
2428                                len -= be32_to_cpu(adsp2_alg[i].ym);
2429                                len *= 4;
2430                                wm_adsp_create_control(dsp, alg_region, 0,
2431                                                     len, NULL, 0, 0,
2432                                                     SNDRV_CTL_ELEM_TYPE_BYTES);
2433                        } else {
2434                                adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
2435                                          be32_to_cpu(adsp2_alg[i].alg.id));
2436                        }
2437                }
2438
2439                alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
2440                                                   adsp2_alg[i].alg.id,
2441                                                   adsp2_alg[i].zm);
2442                if (IS_ERR(alg_region)) {
2443                        ret = PTR_ERR(alg_region);
2444                        goto out;
2445                }
2446                if (dsp->fw_ver == 0) {
2447                        if (i + 1 < n_algs) {
2448                                len = be32_to_cpu(adsp2_alg[i + 1].zm);
2449                                len -= be32_to_cpu(adsp2_alg[i].zm);
2450                                len *= 4;
2451                                wm_adsp_create_control(dsp, alg_region, 0,
2452                                                     len, NULL, 0, 0,
2453                                                     SNDRV_CTL_ELEM_TYPE_BYTES);
2454                        } else {
2455                                adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
2456                                          be32_to_cpu(adsp2_alg[i].alg.id));
2457                        }
2458                }
2459        }
2460
2461out:
2462        kfree(adsp2_alg);
2463        return ret;
2464}
2465
2466static int wm_halo_create_regions(struct wm_adsp *dsp, __be32 id,
2467                                  __be32 xm_base, __be32 ym_base)
2468{
2469        int types[] = {
2470                WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED,
2471                WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED
2472        };
2473        __be32 bases[] = { xm_base, xm_base, ym_base, ym_base };
2474
2475        return wm_adsp_create_regions(dsp, id, ARRAY_SIZE(types), types, bases);
2476}
2477
2478static int wm_halo_setup_algs(struct wm_adsp *dsp)
2479{
2480        struct wmfw_halo_id_hdr halo_id;
2481        struct wmfw_halo_alg_hdr *halo_alg;
2482        const struct wm_adsp_region *mem;
2483        unsigned int pos, len;
2484        size_t n_algs;
2485        int i, ret;
2486
2487        mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
2488        if (WARN_ON(!mem))
2489                return -EINVAL;
2490
2491        ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id,
2492                              sizeof(halo_id));
2493        if (ret != 0) {
2494                adsp_err(dsp, "Failed to read algorithm info: %d\n",
2495                         ret);
2496                return ret;
2497        }
2498
2499        n_algs = be32_to_cpu(halo_id.n_algs);
2500
2501        wmfw_v3_parse_id_header(dsp, &halo_id.fw, n_algs);
2502
2503        ret = wm_halo_create_regions(dsp, halo_id.fw.id,
2504                                     halo_id.xm_base, halo_id.ym_base);
2505        if (ret)
2506                return ret;
2507
2508        /* Calculate offset and length in DSP words */
2509        pos = sizeof(halo_id) / sizeof(u32);
2510        len = (sizeof(*halo_alg) * n_algs) / sizeof(u32);
2511
2512        halo_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
2513        if (IS_ERR(halo_alg))
2514                return PTR_ERR(halo_alg);
2515
2516        for (i = 0; i < n_algs; i++) {
2517                adsp_info(dsp,
2518                          "%d: ID %x v%d.%d.%d XM@%x YM@%x\n",
2519                          i, be32_to_cpu(halo_alg[i].alg.id),
2520                          (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16,
2521                          (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8,
2522                          be32_to_cpu(halo_alg[i].alg.ver) & 0xff,
2523                          be32_to_cpu(halo_alg[i].xm_base),
2524                          be32_to_cpu(halo_alg[i].ym_base));
2525
2526                ret = wm_halo_create_regions(dsp, halo_alg[i].alg.id,
2527                                             halo_alg[i].xm_base,
2528                                             halo_alg[i].ym_base);
2529                if (ret)
2530                        goto out;
2531        }
2532
2533out:
2534        kfree(halo_alg);
2535        return ret;
2536}
2537
2538static int wm_adsp_load_coeff(struct wm_adsp *dsp)
2539{
2540        LIST_HEAD(buf_list);
2541        struct regmap *regmap = dsp->regmap;
2542        struct wmfw_coeff_hdr *hdr;
2543        struct wmfw_coeff_item *blk;
2544        const struct firmware *firmware;
2545        const struct wm_adsp_region *mem;
2546        struct wm_adsp_alg_region *alg_region;
2547        const char *region_name;
2548        int ret, pos, blocks, type, offset, reg;
2549        char *file;
2550        struct wm_adsp_buf *buf;
2551
2552        file = kzalloc(PAGE_SIZE, GFP_KERNEL);
2553        if (file == NULL)
2554                return -ENOMEM;
2555
2556        snprintf(file, PAGE_SIZE, "%s-%s-%s.bin", dsp->part, dsp->fwf_name,
2557                 wm_adsp_fw[dsp->fw].file);
2558        file[PAGE_SIZE - 1] = '\0';
2559
2560        ret = request_firmware(&firmware, file, dsp->dev);
2561        if (ret != 0) {
2562                adsp_warn(dsp, "Failed to request '%s'\n", file);
2563                ret = 0;
2564                goto out;
2565        }
2566        ret = -EINVAL;
2567
2568        if (sizeof(*hdr) >= firmware->size) {
2569                adsp_err(dsp, "%s: file too short, %zu bytes\n",
2570                        file, firmware->size);
2571                goto out_fw;
2572        }
2573
2574        hdr = (void *)&firmware->data[0];
2575        if (memcmp(hdr->magic, "WMDR", 4) != 0) {
2576                adsp_err(dsp, "%s: invalid magic\n", file);
2577                goto out_fw;
2578        }
2579
2580        switch (be32_to_cpu(hdr->rev) & 0xff) {
2581        case 1:
2582                break;
2583        default:
2584                adsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
2585                         file, be32_to_cpu(hdr->rev) & 0xff);
2586                ret = -EINVAL;
2587                goto out_fw;
2588        }
2589
2590        adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
2591                (le32_to_cpu(hdr->ver) >> 16) & 0xff,
2592                (le32_to_cpu(hdr->ver) >>  8) & 0xff,
2593                le32_to_cpu(hdr->ver) & 0xff);
2594
2595        pos = le32_to_cpu(hdr->len);
2596
2597        blocks = 0;
2598        while (pos < firmware->size &&
2599               sizeof(*blk) < firmware->size - pos) {
2600                blk = (void *)(&firmware->data[pos]);
2601
2602                type = le16_to_cpu(blk->type);
2603                offset = le16_to_cpu(blk->offset);
2604
2605                adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
2606                         file, blocks, le32_to_cpu(blk->id),
2607                         (le32_to_cpu(blk->ver) >> 16) & 0xff,
2608                         (le32_to_cpu(blk->ver) >>  8) & 0xff,
2609                         le32_to_cpu(blk->ver) & 0xff);
2610                adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
2611                         file, blocks, le32_to_cpu(blk->len), offset, type);
2612
2613                reg = 0;
2614                region_name = "Unknown";
2615                switch (type) {
2616                case (WMFW_NAME_TEXT << 8):
2617                case (WMFW_INFO_TEXT << 8):
2618                        break;
2619                case (WMFW_ABSOLUTE << 8):
2620                        /*
2621                         * Old files may use this for global
2622                         * coefficients.
2623                         */
2624                        if (le32_to_cpu(blk->id) == dsp->fw_id &&
2625                            offset == 0) {
2626                                region_name = "global coefficients";
2627                                mem = wm_adsp_find_region(dsp, type);
2628                                if (!mem) {
2629                                        adsp_err(dsp, "No ZM\n");
2630                                        break;
2631                                }
2632                                reg = dsp->ops->region_to_reg(mem, 0);
2633
2634                        } else {
2635                                region_name = "register";
2636                                reg = offset;
2637                        }
2638                        break;
2639
2640                case WMFW_ADSP1_DM:
2641                case WMFW_ADSP1_ZM:
2642                case WMFW_ADSP2_XM:
2643                case WMFW_ADSP2_YM:
2644                case WMFW_HALO_XM_PACKED:
2645                case WMFW_HALO_YM_PACKED:
2646                case WMFW_HALO_PM_PACKED:
2647                        adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
2648                                 file, blocks, le32_to_cpu(blk->len),
2649                                 type, le32_to_cpu(blk->id));
2650
2651                        mem = wm_adsp_find_region(dsp, type);
2652                        if (!mem) {
2653                                adsp_err(dsp, "No base for region %x\n", type);
2654                                break;
2655                        }
2656
2657                        alg_region = wm_adsp_find_alg_region(dsp, type,
2658                                                le32_to_cpu(blk->id));
2659                        if (alg_region) {
2660                                reg = alg_region->base;
2661                                reg = dsp->ops->region_to_reg(mem, reg);
2662                                reg += offset;
2663                        } else {
2664                                adsp_err(dsp, "No %x for algorithm %x\n",
2665                                         type, le32_to_cpu(blk->id));
2666                        }
2667                        break;
2668
2669                default:
2670                        adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
2671                                 file, blocks, type, pos);
2672                        break;
2673                }
2674
2675                if (reg) {
2676                        if (le32_to_cpu(blk->len) >
2677                            firmware->size - pos - sizeof(*blk)) {
2678                                adsp_err(dsp,
2679                                         "%s.%d: %s region len %d bytes exceeds file length %zu\n",
2680                                         file, blocks, region_name,
2681                                         le32_to_cpu(blk->len),
2682                                         firmware->size);
2683                                ret = -EINVAL;
2684                                goto out_fw;
2685                        }
2686
2687                        buf = wm_adsp_buf_alloc(blk->data,
2688                                                le32_to_cpu(blk->len),
2689                                                &buf_list);
2690                        if (!buf) {
2691                                adsp_err(dsp, "Out of memory\n");
2692                                ret = -ENOMEM;
2693                                goto out_fw;
2694                        }
2695
2696                        adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
2697                                 file, blocks, le32_to_cpu(blk->len),
2698                                 reg);
2699                        ret = regmap_raw_write_async(regmap, reg, buf->buf,
2700                                                     le32_to_cpu(blk->len));
2701                        if (ret != 0) {
2702                                adsp_err(dsp,
2703                                        "%s.%d: Failed to write to %x in %s: %d\n",
2704                                        file, blocks, reg, region_name, ret);
2705                        }
2706                }
2707
2708                pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
2709                blocks++;
2710        }
2711
2712        ret = regmap_async_complete(regmap);
2713        if (ret != 0)
2714                adsp_err(dsp, "Failed to complete async write: %d\n", ret);
2715
2716        if (pos > firmware->size)
2717                adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
2718                          file, blocks, pos - firmware->size);
2719
2720        wm_adsp_debugfs_save_binname(dsp, file);
2721
2722out_fw:
2723        regmap_async_complete(regmap);
2724        release_firmware(firmware);
2725        wm_adsp_buf_free(&buf_list);
2726out:
2727        kfree(file);
2728        return ret;
2729}
2730
2731static int wm_adsp_create_name(struct wm_adsp *dsp)
2732{
2733        char *p;
2734
2735        if (!dsp->name) {
2736                dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d",
2737                                           dsp->num);
2738                if (!dsp->name)
2739                        return -ENOMEM;
2740        }
2741
2742        if (!dsp->fwf_name) {
2743                p = devm_kstrdup(dsp->dev, dsp->name, GFP_KERNEL);
2744                if (!p)
2745                        return -ENOMEM;
2746
2747                dsp->fwf_name = p;
2748                for (; *p != 0; ++p)
2749                        *p = tolower(*p);
2750        }
2751
2752        return 0;
2753}
2754
2755static int wm_adsp_common_init(struct wm_adsp *dsp)
2756{
2757        int ret;
2758
2759        ret = wm_adsp_create_name(dsp);
2760        if (ret)
2761                return ret;
2762
2763        INIT_LIST_HEAD(&dsp->alg_regions);
2764        INIT_LIST_HEAD(&dsp->ctl_list);
2765        INIT_LIST_HEAD(&dsp->compr_list);
2766        INIT_LIST_HEAD(&dsp->buffer_list);
2767
2768        mutex_init(&dsp->pwr_lock);
2769
2770        return 0;
2771}
2772
2773int wm_adsp1_init(struct wm_adsp *dsp)
2774{
2775        dsp->ops = &wm_adsp1_ops;
2776
2777        return wm_adsp_common_init(dsp);
2778}
2779EXPORT_SYMBOL_GPL(wm_adsp1_init);
2780
2781int wm_adsp1_event(struct snd_soc_dapm_widget *w,
2782                   struct snd_kcontrol *kcontrol,
2783                   int event)
2784{
2785        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
2786        struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
2787        struct wm_adsp *dsp = &dsps[w->shift];
2788        struct wm_coeff_ctl *ctl;
2789        int ret;
2790        unsigned int val;
2791
2792        dsp->component = component;
2793
2794        mutex_lock(&dsp->pwr_lock);
2795
2796        switch (event) {
2797        case SND_SOC_DAPM_POST_PMU:
2798                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2799                                   ADSP1_SYS_ENA, ADSP1_SYS_ENA);
2800
2801                /*
2802                 * For simplicity set the DSP clock rate to be the
2803                 * SYSCLK rate rather than making it configurable.
2804                 */
2805                if (dsp->sysclk_reg) {
2806                        ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
2807                        if (ret != 0) {
2808                                adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
2809                                ret);
2810                                goto err_mutex;
2811                        }
2812
2813                        val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift;
2814
2815                        ret = regmap_update_bits(dsp->regmap,
2816                                                 dsp->base + ADSP1_CONTROL_31,
2817                                                 ADSP1_CLK_SEL_MASK, val);
2818                        if (ret != 0) {
2819                                adsp_err(dsp, "Failed to set clock rate: %d\n",
2820                                         ret);
2821                                goto err_mutex;
2822                        }
2823                }
2824
2825                ret = wm_adsp_load(dsp);
2826                if (ret != 0)
2827                        goto err_ena;
2828
2829                ret = wm_adsp1_setup_algs(dsp);
2830                if (ret != 0)
2831                        goto err_ena;
2832
2833                ret = wm_adsp_load_coeff(dsp);
2834                if (ret != 0)
2835                        goto err_ena;
2836
2837                /* Initialize caches for enabled and unset controls */
2838                ret = wm_coeff_init_control_caches(dsp);
2839                if (ret != 0)
2840                        goto err_ena;
2841
2842                /* Sync set controls */
2843                ret = wm_coeff_sync_controls(dsp);
2844                if (ret != 0)
2845                        goto err_ena;
2846
2847                dsp->booted = true;
2848
2849                /* Start the core running */
2850                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2851                                   ADSP1_CORE_ENA | ADSP1_START,
2852                                   ADSP1_CORE_ENA | ADSP1_START);
2853
2854                dsp->running = true;
2855                break;
2856
2857        case SND_SOC_DAPM_PRE_PMD:
2858                dsp->running = false;
2859                dsp->booted = false;
2860
2861                /* Halt the core */
2862                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2863                                   ADSP1_CORE_ENA | ADSP1_START, 0);
2864
2865                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
2866                                   ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
2867
2868                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2869                                   ADSP1_SYS_ENA, 0);
2870
2871                list_for_each_entry(ctl, &dsp->ctl_list, list)
2872                        ctl->enabled = 0;
2873
2874
2875                wm_adsp_free_alg_regions(dsp);
2876                break;
2877
2878        default:
2879                break;
2880        }
2881
2882        mutex_unlock(&dsp->pwr_lock);
2883
2884        return 0;
2885
2886err_ena:
2887        regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2888                           ADSP1_SYS_ENA, 0);
2889err_mutex:
2890        mutex_unlock(&dsp->pwr_lock);
2891
2892        return ret;
2893}
2894EXPORT_SYMBOL_GPL(wm_adsp1_event);
2895
2896static int wm_adsp2v2_enable_core(struct wm_adsp *dsp)
2897{
2898        unsigned int val;
2899        int ret, count;
2900
2901        /* Wait for the RAM to start, should be near instantaneous */
2902        for (count = 0; count < 10; ++count) {
2903                ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
2904                if (ret != 0)
2905                        return ret;
2906
2907                if (val & ADSP2_RAM_RDY)
2908                        break;
2909
2910                usleep_range(250, 500);
2911        }
2912
2913        if (!(val & ADSP2_RAM_RDY)) {
2914                adsp_err(dsp, "Failed to start DSP RAM\n");
2915                return -EBUSY;
2916        }
2917
2918        adsp_dbg(dsp, "RAM ready after %d polls\n", count);
2919
2920        return 0;
2921}
2922
2923static int wm_adsp2_enable_core(struct wm_adsp *dsp)
2924{
2925        int ret;
2926
2927        ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
2928                                       ADSP2_SYS_ENA, ADSP2_SYS_ENA);
2929        if (ret != 0)
2930                return ret;
2931
2932        return wm_adsp2v2_enable_core(dsp);
2933}
2934
2935static int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
2936{
2937        struct regmap *regmap = dsp->regmap;
2938        unsigned int code0, code1, lock_reg;
2939
2940        if (!(lock_regions & WM_ADSP2_REGION_ALL))
2941                return 0;
2942
2943        lock_regions &= WM_ADSP2_REGION_ALL;
2944        lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0;
2945
2946        while (lock_regions) {
2947                code0 = code1 = 0;
2948                if (lock_regions & BIT(0)) {
2949                        code0 = ADSP2_LOCK_CODE_0;
2950                        code1 = ADSP2_LOCK_CODE_1;
2951                }
2952                if (lock_regions & BIT(1)) {
2953                        code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT;
2954                        code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT;
2955                }
2956                regmap_write(regmap, lock_reg, code0);
2957                regmap_write(regmap, lock_reg, code1);
2958                lock_regions >>= 2;
2959                lock_reg += 2;
2960        }
2961
2962        return 0;
2963}
2964
2965static int wm_adsp2_enable_memory(struct wm_adsp *dsp)
2966{
2967        return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2968                                  ADSP2_MEM_ENA, ADSP2_MEM_ENA);
2969}
2970
2971static void wm_adsp2_disable_memory(struct wm_adsp *dsp)
2972{
2973        regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2974                           ADSP2_MEM_ENA, 0);
2975}
2976
2977static void wm_adsp2_disable_core(struct wm_adsp *dsp)
2978{
2979        regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
2980        regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
2981        regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
2982
2983        regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2984                           ADSP2_SYS_ENA, 0);
2985}
2986
2987static void wm_adsp2v2_disable_core(struct wm_adsp *dsp)
2988{
2989        regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
2990        regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
2991        regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
2992}
2993
2994static void wm_adsp_boot_work(struct work_struct *work)
2995{
2996        struct wm_adsp *dsp = container_of(work,
2997                                           struct wm_adsp,
2998                                           boot_work);
2999        int ret;
3000
3001        mutex_lock(&dsp->pwr_lock);
3002
3003        if (dsp->ops->enable_memory) {
3004                ret = dsp->ops->enable_memory(dsp);
3005                if (ret != 0)
3006                        goto err_mutex;
3007        }
3008
3009        if (dsp->ops->enable_core) {
3010                ret = dsp->ops->enable_core(dsp);
3011                if (ret != 0)
3012                        goto err_mem;
3013        }
3014
3015        ret = wm_adsp_load(dsp);
3016        if (ret != 0)
3017                goto err_ena;
3018
3019        ret = dsp->ops->setup_algs(dsp);
3020        if (ret != 0)
3021                goto err_ena;
3022
3023        ret = wm_adsp_load_coeff(dsp);
3024        if (ret != 0)
3025                goto err_ena;
3026
3027        /* Initialize caches for enabled and unset controls */
3028        ret = wm_coeff_init_control_caches(dsp);
3029        if (ret != 0)
3030                goto err_ena;
3031
3032        if (dsp->ops->disable_core)
3033                dsp->ops->disable_core(dsp);
3034
3035        dsp->booted = true;
3036
3037        mutex_unlock(&dsp->pwr_lock);
3038
3039        return;
3040
3041err_ena:
3042        if (dsp->ops->disable_core)
3043                dsp->ops->disable_core(dsp);
3044err_mem:
3045        if (dsp->ops->disable_memory)
3046                dsp->ops->disable_memory(dsp);
3047err_mutex:
3048        mutex_unlock(&dsp->pwr_lock);
3049}
3050
3051static int wm_halo_configure_mpu(struct wm_adsp *dsp, unsigned int lock_regions)
3052{
3053        struct reg_sequence config[] = {
3054                { dsp->base + HALO_MPU_LOCK_CONFIG,     0x5555 },
3055                { dsp->base + HALO_MPU_LOCK_CONFIG,     0xAAAA },
3056                { dsp->base + HALO_MPU_XMEM_ACCESS_0,   0xFFFFFFFF },
3057                { dsp->base + HALO_MPU_YMEM_ACCESS_0,   0xFFFFFFFF },
3058                { dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions },
3059                { dsp->base + HALO_MPU_XREG_ACCESS_0,   lock_regions },
3060                { dsp->base + HALO_MPU_YREG_ACCESS_0,   lock_regions },
3061                { dsp->base + HALO_MPU_XMEM_ACCESS_1,   0xFFFFFFFF },
3062                { dsp->base + HALO_MPU_YMEM_ACCESS_1,   0xFFFFFFFF },
3063                { dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions },
3064                { dsp->base + HALO_MPU_XREG_ACCESS_1,   lock_regions },
3065                { dsp->base + HALO_MPU_YREG_ACCESS_1,   lock_regions },
3066                { dsp->base + HALO_MPU_XMEM_ACCESS_2,   0xFFFFFFFF },
3067                { dsp->base + HALO_MPU_YMEM_ACCESS_2,   0xFFFFFFFF },
3068                { dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions },
3069                { dsp->base + HALO_MPU_XREG_ACCESS_2,   lock_regions },
3070                { dsp->base + HALO_MPU_YREG_ACCESS_2,   lock_regions },
3071                { dsp->base + HALO_MPU_XMEM_ACCESS_3,   0xFFFFFFFF },
3072                { dsp->base + HALO_MPU_YMEM_ACCESS_3,   0xFFFFFFFF },
3073                { dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions },
3074                { dsp->base + HALO_MPU_XREG_ACCESS_3,   lock_regions },
3075                { dsp->base + HALO_MPU_YREG_ACCESS_3,   lock_regions },
3076                { dsp->base + HALO_MPU_LOCK_CONFIG,     0 },
3077        };
3078
3079        return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config));
3080}
3081
3082int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq)
3083{
3084        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3085        struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3086        struct wm_adsp *dsp = &dsps[w->shift];
3087        int ret;
3088
3089        ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING,
3090                                 ADSP2_CLK_SEL_MASK,
3091                                 freq << ADSP2_CLK_SEL_SHIFT);
3092        if (ret)
3093                adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
3094
3095        return ret;
3096}
3097EXPORT_SYMBOL_GPL(wm_adsp2_set_dspclk);
3098
3099int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
3100                           struct snd_ctl_elem_value *ucontrol)
3101{
3102        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
3103        struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3104        struct soc_mixer_control *mc =
3105                (struct soc_mixer_control *)kcontrol->private_value;
3106        struct wm_adsp *dsp = &dsps[mc->shift - 1];
3107
3108        ucontrol->value.integer.value[0] = dsp->preloaded;
3109
3110        return 0;
3111}
3112EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get);
3113
3114int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
3115                           struct snd_ctl_elem_value *ucontrol)
3116{
3117        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
3118        struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3119        struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
3120        struct soc_mixer_control *mc =
3121                (struct soc_mixer_control *)kcontrol->private_value;
3122        struct wm_adsp *dsp = &dsps[mc->shift - 1];
3123        char preload[32];
3124
3125        snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
3126
3127        dsp->preloaded = ucontrol->value.integer.value[0];
3128
3129        if (ucontrol->value.integer.value[0])
3130                snd_soc_component_force_enable_pin(component, preload);
3131        else
3132                snd_soc_component_disable_pin(component, preload);
3133
3134        snd_soc_dapm_sync(dapm);
3135
3136        flush_work(&dsp->boot_work);
3137
3138        return 0;
3139}
3140EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
3141
3142static void wm_adsp_stop_watchdog(struct wm_adsp *dsp)
3143{
3144        regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
3145                           ADSP2_WDT_ENA_MASK, 0);
3146}
3147
3148static void wm_halo_stop_watchdog(struct wm_adsp *dsp)
3149{
3150        regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL,
3151                           HALO_WDT_EN_MASK, 0);
3152}
3153
3154int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
3155                        struct snd_kcontrol *kcontrol, int event)
3156{
3157        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3158        struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3159        struct wm_adsp *dsp = &dsps[w->shift];
3160        struct wm_coeff_ctl *ctl;
3161
3162        switch (event) {
3163        case SND_SOC_DAPM_PRE_PMU:
3164                queue_work(system_unbound_wq, &dsp->boot_work);
3165                break;
3166        case SND_SOC_DAPM_PRE_PMD:
3167                mutex_lock(&dsp->pwr_lock);
3168
3169                wm_adsp_debugfs_clear(dsp);
3170
3171                dsp->fw_id = 0;
3172                dsp->fw_id_version = 0;
3173
3174                dsp->booted = false;
3175
3176                if (dsp->ops->disable_memory)
3177                        dsp->ops->disable_memory(dsp);
3178
3179                list_for_each_entry(ctl, &dsp->ctl_list, list)
3180                        ctl->enabled = 0;
3181
3182                wm_adsp_free_alg_regions(dsp);
3183
3184                mutex_unlock(&dsp->pwr_lock);
3185
3186                adsp_dbg(dsp, "Shutdown complete\n");
3187                break;
3188        default:
3189                break;
3190        }
3191
3192        return 0;
3193}
3194EXPORT_SYMBOL_GPL(wm_adsp_early_event);
3195
3196static int wm_adsp2_start_core(struct wm_adsp *dsp)
3197{
3198        return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3199                                 ADSP2_CORE_ENA | ADSP2_START,
3200                                 ADSP2_CORE_ENA | ADSP2_START);
3201}
3202
3203static void wm_adsp2_stop_core(struct wm_adsp *dsp)
3204{
3205        regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3206                           ADSP2_CORE_ENA | ADSP2_START, 0);
3207}
3208
3209int wm_adsp_event(struct snd_soc_dapm_widget *w,
3210                  struct snd_kcontrol *kcontrol, int event)
3211{
3212        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3213        struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3214        struct wm_adsp *dsp = &dsps[w->shift];
3215        int ret;
3216
3217        switch (event) {
3218        case SND_SOC_DAPM_POST_PMU:
3219                flush_work(&dsp->boot_work);
3220
3221                mutex_lock(&dsp->pwr_lock);
3222
3223                if (!dsp->booted) {
3224                        ret = -EIO;
3225                        goto err;
3226                }
3227
3228                if (dsp->ops->enable_core) {
3229                        ret = dsp->ops->enable_core(dsp);
3230                        if (ret != 0)
3231                                goto err;
3232                }
3233
3234                /* Sync set controls */
3235                ret = wm_coeff_sync_controls(dsp);
3236                if (ret != 0)
3237                        goto err;
3238
3239                if (dsp->ops->lock_memory) {
3240                        ret = dsp->ops->lock_memory(dsp, dsp->lock_regions);
3241                        if (ret != 0) {
3242                                adsp_err(dsp, "Error configuring MPU: %d\n",
3243                                         ret);
3244                                goto err;
3245                        }
3246                }
3247
3248                if (dsp->ops->start_core) {
3249                        ret = dsp->ops->start_core(dsp);
3250                        if (ret != 0)
3251                                goto err;
3252                }
3253
3254                if (wm_adsp_fw[dsp->fw].num_caps != 0) {
3255                        ret = wm_adsp_buffer_init(dsp);
3256                        if (ret < 0)
3257                                goto err;
3258                }
3259
3260                dsp->running = true;
3261
3262                mutex_unlock(&dsp->pwr_lock);
3263                break;
3264
3265        case SND_SOC_DAPM_PRE_PMD:
3266                /* Tell the firmware to cleanup */
3267                wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN);
3268
3269                if (dsp->ops->stop_watchdog)
3270                        dsp->ops->stop_watchdog(dsp);
3271
3272                /* Log firmware state, it can be useful for analysis */
3273                if (dsp->ops->show_fw_status)
3274                        dsp->ops->show_fw_status(dsp);
3275
3276                mutex_lock(&dsp->pwr_lock);
3277
3278                dsp->running = false;
3279
3280                if (dsp->ops->stop_core)
3281                        dsp->ops->stop_core(dsp);
3282                if (dsp->ops->disable_core)
3283                        dsp->ops->disable_core(dsp);
3284
3285                if (wm_adsp_fw[dsp->fw].num_caps != 0)
3286                        wm_adsp_buffer_free(dsp);
3287
3288                dsp->fatal_error = false;
3289
3290                mutex_unlock(&dsp->pwr_lock);
3291
3292                adsp_dbg(dsp, "Execution stopped\n");
3293                break;
3294
3295        default:
3296                break;
3297        }
3298
3299        return 0;
3300err:
3301        if (dsp->ops->stop_core)
3302                dsp->ops->stop_core(dsp);
3303        if (dsp->ops->disable_core)
3304                dsp->ops->disable_core(dsp);
3305        mutex_unlock(&dsp->pwr_lock);
3306        return ret;
3307}
3308EXPORT_SYMBOL_GPL(wm_adsp_event);
3309
3310static int wm_halo_start_core(struct wm_adsp *dsp)
3311{
3312        return regmap_update_bits(dsp->regmap,
3313                                  dsp->base + HALO_CCM_CORE_CONTROL,
3314                                  HALO_CORE_EN, HALO_CORE_EN);
3315}
3316
3317static void wm_halo_stop_core(struct wm_adsp *dsp)
3318{
3319        regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
3320                           HALO_CORE_EN, 0);
3321
3322        /* reset halo core with CORE_SOFT_RESET */
3323        regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET,
3324                           HALO_CORE_SOFT_RESET_MASK, 1);
3325}
3326
3327int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
3328{
3329        char preload[32];
3330
3331        snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
3332        snd_soc_component_disable_pin(component, preload);
3333
3334        wm_adsp2_init_debugfs(dsp, component);
3335
3336        dsp->component = component;
3337
3338        return 0;
3339}
3340EXPORT_SYMBOL_GPL(wm_adsp2_component_probe);
3341
3342int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component)
3343{
3344        wm_adsp2_cleanup_debugfs(dsp);
3345
3346        return 0;
3347}
3348EXPORT_SYMBOL_GPL(wm_adsp2_component_remove);
3349
3350int wm_adsp2_init(struct wm_adsp *dsp)
3351{
3352        int ret;
3353
3354        ret = wm_adsp_common_init(dsp);
3355        if (ret)
3356                return ret;
3357
3358        switch (dsp->rev) {
3359        case 0:
3360                /*
3361                 * Disable the DSP memory by default when in reset for a small
3362                 * power saving.
3363                 */
3364                ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3365                                         ADSP2_MEM_ENA, 0);
3366                if (ret) {
3367                        adsp_err(dsp,
3368                                 "Failed to clear memory retention: %d\n", ret);
3369                        return ret;
3370                }
3371
3372                dsp->ops = &wm_adsp2_ops[0];
3373                break;
3374        case 1:
3375                dsp->ops = &wm_adsp2_ops[1];
3376                break;
3377        default:
3378                dsp->ops = &wm_adsp2_ops[2];
3379                break;
3380        }
3381
3382        INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
3383
3384        return 0;
3385}
3386EXPORT_SYMBOL_GPL(wm_adsp2_init);
3387
3388int wm_halo_init(struct wm_adsp *dsp)
3389{
3390        int ret;
3391
3392        ret = wm_adsp_common_init(dsp);
3393        if (ret)
3394                return ret;
3395
3396        dsp->ops = &wm_halo_ops;
3397
3398        INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
3399
3400        return 0;
3401}
3402EXPORT_SYMBOL_GPL(wm_halo_init);
3403
3404void wm_adsp2_remove(struct wm_adsp *dsp)
3405{
3406        struct wm_coeff_ctl *ctl;
3407
3408        while (!list_empty(&dsp->ctl_list)) {
3409                ctl = list_first_entry(&dsp->ctl_list, struct wm_coeff_ctl,
3410                                        list);
3411                list_del(&ctl->list);
3412                wm_adsp_free_ctl_blk(ctl);
3413        }
3414}
3415EXPORT_SYMBOL_GPL(wm_adsp2_remove);
3416
3417static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
3418{
3419        return compr->buf != NULL;
3420}
3421
3422static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
3423{
3424        struct wm_adsp_compr_buf *buf = NULL, *tmp;
3425
3426        if (compr->dsp->fatal_error)
3427                return -EINVAL;
3428
3429        list_for_each_entry(tmp, &compr->dsp->buffer_list, list) {
3430                if (!tmp->name || !strcmp(compr->name, tmp->name)) {
3431                        buf = tmp;
3432                        break;
3433                }
3434        }
3435
3436        if (!buf)
3437                return -EINVAL;
3438
3439        compr->buf = buf;
3440        buf->compr = compr;
3441
3442        return 0;
3443}
3444
3445static void wm_adsp_compr_detach(struct wm_adsp_compr *compr)
3446{
3447        if (!compr)
3448                return;
3449
3450        /* Wake the poll so it can see buffer is no longer attached */
3451        if (compr->stream)
3452                snd_compr_fragment_elapsed(compr->stream);
3453
3454        if (wm_adsp_compr_attached(compr)) {
3455                compr->buf->compr = NULL;
3456                compr->buf = NULL;
3457        }
3458}
3459
3460int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
3461{
3462        struct wm_adsp_compr *compr, *tmp;
3463        struct snd_soc_pcm_runtime *rtd = stream->private_data;
3464        int ret = 0;
3465
3466        mutex_lock(&dsp->pwr_lock);
3467
3468        if (wm_adsp_fw[dsp->fw].num_caps == 0) {
3469                adsp_err(dsp, "%s: Firmware does not support compressed API\n",
3470                         asoc_rtd_to_codec(rtd, 0)->name);
3471                ret = -ENXIO;
3472                goto out;
3473        }
3474
3475        if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
3476                adsp_err(dsp, "%s: Firmware does not support stream direction\n",
3477                         asoc_rtd_to_codec(rtd, 0)->name);
3478                ret = -EINVAL;
3479                goto out;
3480        }
3481
3482        list_for_each_entry(tmp, &dsp->compr_list, list) {
3483                if (!strcmp(tmp->name, asoc_rtd_to_codec(rtd, 0)->name)) {
3484                        adsp_err(dsp, "%s: Only a single stream supported per dai\n",
3485                                 asoc_rtd_to_codec(rtd, 0)->name);
3486                        ret = -EBUSY;
3487                        goto out;
3488                }
3489        }
3490
3491        compr = kzalloc(sizeof(*compr), GFP_KERNEL);
3492        if (!compr) {
3493                ret = -ENOMEM;
3494                goto out;
3495        }
3496
3497        compr->dsp = dsp;
3498        compr->stream = stream;
3499        compr->name = asoc_rtd_to_codec(rtd, 0)->name;
3500
3501        list_add_tail(&compr->list, &dsp->compr_list);
3502
3503        stream->runtime->private_data = compr;
3504
3505out:
3506        mutex_unlock(&dsp->pwr_lock);
3507
3508        return ret;
3509}
3510EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
3511
3512int wm_adsp_compr_free(struct snd_soc_component *component,
3513                       struct snd_compr_stream *stream)
3514{
3515        struct wm_adsp_compr *compr = stream->runtime->private_data;
3516        struct wm_adsp *dsp = compr->dsp;
3517
3518        mutex_lock(&dsp->pwr_lock);
3519
3520        wm_adsp_compr_detach(compr);
3521        list_del(&compr->list);
3522
3523        kfree(compr->raw_buf);
3524        kfree(compr);
3525
3526        mutex_unlock(&dsp->pwr_lock);
3527
3528        return 0;
3529}
3530EXPORT_SYMBOL_GPL(wm_adsp_compr_free);
3531
3532static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
3533                                      struct snd_compr_params *params)
3534{
3535        struct wm_adsp_compr *compr = stream->runtime->private_data;
3536        struct wm_adsp *dsp = compr->dsp;
3537        const struct wm_adsp_fw_caps *caps;
3538        const struct snd_codec_desc *desc;
3539        int i, j;
3540
3541        if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE ||
3542            params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE ||
3543            params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS ||
3544            params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS ||
3545            params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) {
3546                compr_err(compr, "Invalid buffer fragsize=%d fragments=%d\n",
3547                          params->buffer.fragment_size,
3548                          params->buffer.fragments);
3549
3550                return -EINVAL;
3551        }
3552
3553        for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) {
3554                caps = &wm_adsp_fw[dsp->fw].caps[i];
3555                desc = &caps->desc;
3556
3557                if (caps->id != params->codec.id)
3558                        continue;
3559
3560                if (stream->direction == SND_COMPRESS_PLAYBACK) {
3561                        if (desc->max_ch < params->codec.ch_out)
3562                                continue;
3563                } else {
3564                        if (desc->max_ch < params->codec.ch_in)
3565                                continue;
3566                }
3567
3568                if (!(desc->formats & (1 << params->codec.format)))
3569                        continue;
3570
3571                for (j = 0; j < desc->num_sample_rates; ++j)
3572                        if (desc->sample_rates[j] == params->codec.sample_rate)
3573                                return 0;
3574        }
3575
3576        compr_err(compr, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
3577                  params->codec.id, params->codec.ch_in, params->codec.ch_out,
3578                  params->codec.sample_rate, params->codec.format);
3579        return -EINVAL;
3580}
3581
3582static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr)
3583{
3584        return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE;
3585}
3586
3587int wm_adsp_compr_set_params(struct snd_soc_component *component,
3588                             struct snd_compr_stream *stream,
3589                             struct snd_compr_params *params)
3590{
3591        struct wm_adsp_compr *compr = stream->runtime->private_data;
3592        unsigned int size;
3593        int ret;
3594
3595        ret = wm_adsp_compr_check_params(stream, params);
3596        if (ret)
3597                return ret;
3598
3599        compr->size = params->buffer;
3600
3601        compr_dbg(compr, "fragment_size=%d fragments=%d\n",
3602                  compr->size.fragment_size, compr->size.fragments);
3603
3604        size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
3605        compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
3606        if (!compr->raw_buf)
3607                return -ENOMEM;
3608
3609        compr->sample_rate = params->codec.sample_rate;
3610
3611        return 0;
3612}
3613EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
3614
3615int wm_adsp_compr_get_caps(struct snd_soc_component *component,
3616                           struct snd_compr_stream *stream,
3617                           struct snd_compr_caps *caps)
3618{
3619        struct wm_adsp_compr *compr = stream->runtime->private_data;
3620        int fw = compr->dsp->fw;
3621        int i;
3622
3623        if (wm_adsp_fw[fw].caps) {
3624                for (i = 0; i < wm_adsp_fw[fw].num_caps; i++)
3625                        caps->codecs[i] = wm_adsp_fw[fw].caps[i].id;
3626
3627                caps->num_codecs = i;
3628                caps->direction = wm_adsp_fw[fw].compr_direction;
3629
3630                caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE;
3631                caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE;
3632                caps->min_fragments = WM_ADSP_MIN_FRAGMENTS;
3633                caps->max_fragments = WM_ADSP_MAX_FRAGMENTS;
3634        }
3635
3636        return 0;
3637}
3638EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
3639
3640static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type,
3641                                   unsigned int mem_addr,
3642                                   unsigned int num_words, u32 *data)
3643{
3644        struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
3645        unsigned int i, reg;
3646        int ret;
3647
3648        if (!mem)
3649                return -EINVAL;
3650
3651        reg = dsp->ops->region_to_reg(mem, mem_addr);
3652
3653        ret = regmap_raw_read(dsp->regmap, reg, data,
3654                              sizeof(*data) * num_words);
3655        if (ret < 0)
3656                return ret;
3657
3658        for (i = 0; i < num_words; ++i)
3659                data[i] = be32_to_cpu(data[i]) & 0x00ffffffu;
3660
3661        return 0;
3662}
3663
3664static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type,
3665                                         unsigned int mem_addr, u32 *data)
3666{
3667        return wm_adsp_read_data_block(dsp, mem_type, mem_addr, 1, data);
3668}
3669
3670static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type,
3671                                   unsigned int mem_addr, u32 data)
3672{
3673        struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
3674        unsigned int reg;
3675
3676        if (!mem)
3677                return -EINVAL;
3678
3679        reg = dsp->ops->region_to_reg(mem, mem_addr);
3680
3681        data = cpu_to_be32(data & 0x00ffffffu);
3682
3683        return regmap_raw_write(dsp->regmap, reg, &data, sizeof(data));
3684}
3685
3686static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
3687                                      unsigned int field_offset, u32 *data)
3688{
3689        return wm_adsp_read_data_word(buf->dsp, buf->host_buf_mem_type,
3690                                      buf->host_buf_ptr + field_offset, data);
3691}
3692
3693static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
3694                                       unsigned int field_offset, u32 data)
3695{
3696        return wm_adsp_write_data_word(buf->dsp, buf->host_buf_mem_type,
3697                                       buf->host_buf_ptr + field_offset, data);
3698}
3699
3700static void wm_adsp_remove_padding(u32 *buf, int nwords, int data_word_size)
3701{
3702        u8 *pack_in = (u8 *)buf;
3703        u8 *pack_out = (u8 *)buf;
3704        int i, j;
3705
3706        /* Remove the padding bytes from the data read from the DSP */
3707        for (i = 0; i < nwords; i++) {
3708                for (j = 0; j < data_word_size; j++)
3709                        *pack_out++ = *pack_in++;
3710
3711                pack_in += sizeof(*buf) - data_word_size;
3712        }
3713}
3714
3715static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
3716{
3717        const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
3718        struct wm_adsp_buffer_region *region;
3719        u32 offset = 0;
3720        int i, ret;
3721
3722        buf->regions = kcalloc(caps->num_regions, sizeof(*buf->regions),
3723                               GFP_KERNEL);
3724        if (!buf->regions)
3725                return -ENOMEM;
3726
3727        for (i = 0; i < caps->num_regions; ++i) {
3728                region = &buf->regions[i];
3729
3730                region->offset = offset;
3731                region->mem_type = caps->region_defs[i].mem_type;
3732
3733                ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
3734                                          &region->base_addr);
3735                if (ret < 0)
3736                        return ret;
3737
3738                ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
3739                                          &offset);
3740                if (ret < 0)
3741                        return ret;
3742
3743                region->cumulative_size = offset;
3744
3745                compr_dbg(buf,
3746                          "region=%d type=%d base=%08x off=%08x size=%08x\n",
3747                          i, region->mem_type, region->base_addr,
3748                          region->offset, region->cumulative_size);
3749        }
3750
3751        return 0;
3752}
3753
3754static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf)
3755{
3756        buf->irq_count = 0xFFFFFFFF;
3757        buf->read_index = -1;
3758        buf->avail = 0;
3759}
3760
3761static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp)
3762{
3763        struct wm_adsp_compr_buf *buf;
3764
3765        buf = kzalloc(sizeof(*buf), GFP_KERNEL);
3766        if (!buf)
3767                return NULL;
3768
3769        buf->dsp = dsp;
3770
3771        wm_adsp_buffer_clear(buf);
3772
3773        list_add_tail(&buf->list, &dsp->buffer_list);
3774
3775        return buf;
3776}
3777
3778static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
3779{
3780        struct wm_adsp_alg_region *alg_region;
3781        struct wm_adsp_compr_buf *buf;
3782        u32 xmalg, addr, magic;
3783        int i, ret;
3784
3785        alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
3786        if (!alg_region) {
3787                adsp_err(dsp, "No algorithm region found\n");
3788                return -EINVAL;
3789        }
3790
3791        buf = wm_adsp_buffer_alloc(dsp);
3792        if (!buf)
3793                return -ENOMEM;
3794
3795        xmalg = dsp->ops->sys_config_size / sizeof(__be32);
3796
3797        addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
3798        ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic);
3799        if (ret < 0)
3800                return ret;
3801
3802        if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
3803                return -ENODEV;
3804
3805        addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
3806        for (i = 0; i < 5; ++i) {
3807                ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr,
3808                                             &buf->host_buf_ptr);
3809                if (ret < 0)
3810                        return ret;
3811
3812                if (buf->host_buf_ptr)
3813                        break;
3814
3815                usleep_range(1000, 2000);
3816        }
3817
3818        if (!buf->host_buf_ptr)
3819                return -EIO;
3820
3821        buf->host_buf_mem_type = WMFW_ADSP2_XM;
3822
3823        ret = wm_adsp_buffer_populate(buf);
3824        if (ret < 0)
3825                return ret;
3826
3827        compr_dbg(buf, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr);
3828
3829        return 0;
3830}
3831
3832static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
3833{
3834        struct wm_adsp_host_buf_coeff_v1 coeff_v1;
3835        struct wm_adsp_compr_buf *buf;
3836        unsigned int val, reg;
3837        int ret, i;
3838
3839        ret = wm_coeff_base_reg(ctl, &reg);
3840        if (ret)
3841                return ret;
3842
3843        for (i = 0; i < 5; ++i) {
3844                ret = regmap_raw_read(ctl->dsp->regmap, reg, &val, sizeof(val));
3845                if (ret < 0)
3846                        return ret;
3847
3848                if (val)
3849                        break;
3850
3851                usleep_range(1000, 2000);
3852        }
3853
3854        if (!val) {
3855                adsp_err(ctl->dsp, "Failed to acquire host buffer\n");
3856                return -EIO;
3857        }
3858
3859        buf = wm_adsp_buffer_alloc(ctl->dsp);
3860        if (!buf)
3861                return -ENOMEM;
3862
3863        buf->host_buf_mem_type = ctl->alg_region.type;
3864        buf->host_buf_ptr = be32_to_cpu(val);
3865
3866        ret = wm_adsp_buffer_populate(buf);
3867        if (ret < 0)
3868                return ret;
3869
3870        /*
3871         * v0 host_buffer coefficients didn't have versioning, so if the
3872         * control is one word, assume version 0.
3873         */
3874        if (ctl->len == 4) {
3875                compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr);
3876                return 0;
3877        }
3878
3879        ret = regmap_raw_read(ctl->dsp->regmap, reg, &coeff_v1,
3880                              sizeof(coeff_v1));
3881        if (ret < 0)
3882                return ret;
3883
3884        coeff_v1.versions = be32_to_cpu(coeff_v1.versions);
3885        val = coeff_v1.versions & HOST_BUF_COEFF_COMPAT_VER_MASK;
3886        val >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
3887
3888        if (val > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) {
3889                adsp_err(ctl->dsp,
3890                         "Host buffer coeff ver %u > supported version %u\n",
3891                         val, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
3892                return -EINVAL;
3893        }
3894
3895        for (i = 0; i < ARRAY_SIZE(coeff_v1.name); i++)
3896                coeff_v1.name[i] = be32_to_cpu(coeff_v1.name[i]);
3897
3898        wm_adsp_remove_padding((u32 *)&coeff_v1.name,
3899                               ARRAY_SIZE(coeff_v1.name),
3900                               WM_ADSP_DATA_WORD_SIZE);
3901
3902        buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part,
3903                              (char *)&coeff_v1.name);
3904
3905        compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n",
3906                  buf->host_buf_ptr, val);
3907
3908        return val;
3909}
3910
3911static int wm_adsp_buffer_init(struct wm_adsp *dsp)
3912{
3913        struct wm_coeff_ctl *ctl;
3914        int ret;
3915
3916        list_for_each_entry(ctl, &dsp->ctl_list, list) {
3917                if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
3918                        continue;
3919
3920                if (!ctl->enabled)
3921                        continue;
3922
3923                ret = wm_adsp_buffer_parse_coeff(ctl);
3924                if (ret < 0) {
3925                        adsp_err(dsp, "Failed to parse coeff: %d\n", ret);
3926                        goto error;
3927                } else if (ret == 0) {
3928                        /* Only one buffer supported for version 0 */
3929                        return 0;
3930                }
3931        }
3932
3933        if (list_empty(&dsp->buffer_list)) {
3934                /* Fall back to legacy support */
3935                ret = wm_adsp_buffer_parse_legacy(dsp);
3936                if (ret) {
3937                        adsp_err(dsp, "Failed to parse legacy: %d\n", ret);
3938                        goto error;
3939                }
3940        }
3941
3942        return 0;
3943
3944error:
3945        wm_adsp_buffer_free(dsp);
3946        return ret;
3947}
3948
3949static int wm_adsp_buffer_free(struct wm_adsp *dsp)
3950{
3951        struct wm_adsp_compr_buf *buf, *tmp;
3952
3953        list_for_each_entry_safe(buf, tmp, &dsp->buffer_list, list) {
3954                wm_adsp_compr_detach(buf->compr);
3955
3956                kfree(buf->name);
3957                kfree(buf->regions);
3958                list_del(&buf->list);
3959                kfree(buf);
3960        }
3961
3962        return 0;
3963}
3964
3965static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf)
3966{
3967        int ret;
3968
3969        ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
3970        if (ret < 0) {
3971                compr_err(buf, "Failed to check buffer error: %d\n", ret);
3972                return ret;
3973        }
3974        if (buf->error != 0) {
3975                compr_err(buf, "Buffer error occurred: %d\n", buf->error);
3976                return -EIO;
3977        }
3978
3979        return 0;
3980}
3981
3982int wm_adsp_compr_trigger(struct snd_soc_component *component,
3983                          struct snd_compr_stream *stream, int cmd)
3984{
3985        struct wm_adsp_compr *compr = stream->runtime->private_data;
3986        struct wm_adsp *dsp = compr->dsp;
3987        int ret = 0;
3988
3989        compr_dbg(compr, "Trigger: %d\n", cmd);
3990
3991        mutex_lock(&dsp->pwr_lock);
3992
3993        switch (cmd) {
3994        case SNDRV_PCM_TRIGGER_START:
3995                if (!wm_adsp_compr_attached(compr)) {
3996                        ret = wm_adsp_compr_attach(compr);
3997                        if (ret < 0) {
3998                                compr_err(compr, "Failed to link buffer and stream: %d\n",
3999                                          ret);
4000                                break;
4001                        }
4002                }
4003
4004                ret = wm_adsp_buffer_get_error(compr->buf);
4005                if (ret < 0)
4006                        break;
4007
4008                /* Trigger the IRQ at one fragment of data */
4009                ret = wm_adsp_buffer_write(compr->buf,
4010                                           HOST_BUFFER_FIELD(high_water_mark),
4011                                           wm_adsp_compr_frag_words(compr));
4012                if (ret < 0) {
4013                        compr_err(compr, "Failed to set high water mark: %d\n",
4014                                  ret);
4015                        break;
4016                }
4017                break;
4018        case SNDRV_PCM_TRIGGER_STOP:
4019                if (wm_adsp_compr_attached(compr))
4020                        wm_adsp_buffer_clear(compr->buf);
4021                break;
4022        default:
4023                ret = -EINVAL;
4024                break;
4025        }
4026
4027        mutex_unlock(&dsp->pwr_lock);
4028
4029        return ret;
4030}
4031EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
4032
4033static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf)
4034{
4035        int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1;
4036
4037        return buf->regions[last_region].cumulative_size;
4038}
4039
4040static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
4041{
4042        u32 next_read_index, next_write_index;
4043        int write_index, read_index, avail;
4044        int ret;
4045
4046        /* Only sync read index if we haven't already read a valid index */
4047        if (buf->read_index < 0) {
4048                ret = wm_adsp_buffer_read(buf,
4049                                HOST_BUFFER_FIELD(next_read_index),
4050                                &next_read_index);
4051                if (ret < 0)
4052                        return ret;
4053
4054                read_index = sign_extend32(next_read_index, 23);
4055
4056                if (read_index < 0) {
4057                        compr_dbg(buf, "Avail check on unstarted stream\n");
4058                        return 0;
4059                }
4060
4061                buf->read_index = read_index;
4062        }
4063
4064        ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index),
4065                        &next_write_index);
4066        if (ret < 0)
4067                return ret;
4068
4069        write_index = sign_extend32(next_write_index, 23);
4070
4071        avail = write_index - buf->read_index;
4072        if (avail < 0)
4073                avail += wm_adsp_buffer_size(buf);
4074
4075        compr_dbg(buf, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
4076                  buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE);
4077
4078        buf->avail = avail;
4079
4080        return 0;
4081}
4082
4083int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
4084{
4085        struct wm_adsp_compr_buf *buf;
4086        struct wm_adsp_compr *compr;
4087        int ret = 0;
4088
4089        mutex_lock(&dsp->pwr_lock);
4090
4091        if (list_empty(&dsp->buffer_list)) {
4092                ret = -ENODEV;
4093                goto out;
4094        }
4095
4096        adsp_dbg(dsp, "Handling buffer IRQ\n");
4097
4098        list_for_each_entry(buf, &dsp->buffer_list, list) {
4099                compr = buf->compr;
4100
4101                ret = wm_adsp_buffer_get_error(buf);
4102                if (ret < 0)
4103                        goto out_notify; /* Wake poll to report error */
4104
4105                ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
4106                                          &buf->irq_count);
4107                if (ret < 0) {
4108                        compr_err(buf, "Failed to get irq_count: %d\n", ret);
4109                        goto out;
4110                }
4111
4112                ret = wm_adsp_buffer_update_avail(buf);
4113                if (ret < 0) {
4114                        compr_err(buf, "Error reading avail: %d\n", ret);
4115                        goto out;
4116                }
4117
4118                if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2)
4119                        ret = WM_ADSP_COMPR_VOICE_TRIGGER;
4120
4121out_notify:
4122                if (compr && compr->stream)
4123                        snd_compr_fragment_elapsed(compr->stream);
4124        }
4125
4126out:
4127        mutex_unlock(&dsp->pwr_lock);
4128
4129        return ret;
4130}
4131EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq);
4132
4133static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
4134{
4135        if (buf->irq_count & 0x01)
4136                return 0;
4137
4138        compr_dbg(buf, "Enable IRQ(0x%x) for next fragment\n", buf->irq_count);
4139
4140        buf->irq_count |= 0x01;
4141
4142        return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack),
4143                                    buf->irq_count);
4144}
4145
4146int wm_adsp_compr_pointer(struct snd_soc_component *component,
4147                          struct snd_compr_stream *stream,
4148                          struct snd_compr_tstamp *tstamp)
4149{
4150        struct wm_adsp_compr *compr = stream->runtime->private_data;
4151        struct wm_adsp *dsp = compr->dsp;
4152        struct wm_adsp_compr_buf *buf;
4153        int ret = 0;
4154
4155        compr_dbg(compr, "Pointer request\n");
4156
4157        mutex_lock(&dsp->pwr_lock);
4158
4159        buf = compr->buf;
4160
4161        if (dsp->fatal_error || !buf || buf->error) {
4162                snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
4163                ret = -EIO;
4164                goto out;
4165        }
4166
4167        if (buf->avail < wm_adsp_compr_frag_words(compr)) {
4168                ret = wm_adsp_buffer_update_avail(buf);
4169                if (ret < 0) {
4170                        compr_err(compr, "Error reading avail: %d\n", ret);
4171                        goto out;
4172                }
4173
4174                /*
4175                 * If we really have less than 1 fragment available tell the
4176                 * DSP to inform us once a whole fragment is available.
4177                 */
4178                if (buf->avail < wm_adsp_compr_frag_words(compr)) {
4179                        ret = wm_adsp_buffer_get_error(buf);
4180                        if (ret < 0) {
4181                                if (buf->error)
4182                                        snd_compr_stop_error(stream,
4183                                                        SNDRV_PCM_STATE_XRUN);
4184                                goto out;
4185                        }
4186
4187                        ret = wm_adsp_buffer_reenable_irq(buf);
4188                        if (ret < 0) {
4189                                compr_err(compr, "Failed to re-enable buffer IRQ: %d\n",
4190                                          ret);
4191                                goto out;
4192                        }
4193                }
4194        }
4195
4196        tstamp->copied_total = compr->copied_total;
4197        tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE;
4198        tstamp->sampling_rate = compr->sample_rate;
4199
4200out:
4201        mutex_unlock(&dsp->pwr_lock);
4202
4203        return ret;
4204}
4205EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
4206
4207static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
4208{
4209        struct wm_adsp_compr_buf *buf = compr->buf;
4210        unsigned int adsp_addr;
4211        int mem_type, nwords, max_read;
4212        int i, ret;
4213
4214        /* Calculate read parameters */
4215        for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
4216                if (buf->read_index < buf->regions[i].cumulative_size)
4217                        break;
4218
4219        if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions)
4220                return -EINVAL;
4221
4222        mem_type = buf->regions[i].mem_type;
4223        adsp_addr = buf->regions[i].base_addr +
4224                    (buf->read_index - buf->regions[i].offset);
4225
4226        max_read = wm_adsp_compr_frag_words(compr);
4227        nwords = buf->regions[i].cumulative_size - buf->read_index;
4228
4229        if (nwords > target)
4230                nwords = target;
4231        if (nwords > buf->avail)
4232                nwords = buf->avail;
4233        if (nwords > max_read)
4234                nwords = max_read;
4235        if (!nwords)
4236                return 0;
4237
4238        /* Read data from DSP */
4239        ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr,
4240                                      nwords, compr->raw_buf);
4241        if (ret < 0)
4242                return ret;
4243
4244        wm_adsp_remove_padding(compr->raw_buf, nwords, WM_ADSP_DATA_WORD_SIZE);
4245
4246        /* update read index to account for words read */
4247        buf->read_index += nwords;
4248        if (buf->read_index == wm_adsp_buffer_size(buf))
4249                buf->read_index = 0;
4250
4251        ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index),
4252                                   buf->read_index);
4253        if (ret < 0)
4254                return ret;
4255
4256        /* update avail to account for words read */
4257        buf->avail -= nwords;
4258
4259        return nwords;
4260}
4261
4262static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
4263                              char __user *buf, size_t count)
4264{
4265        struct wm_adsp *dsp = compr->dsp;
4266        int ntotal = 0;
4267        int nwords, nbytes;
4268
4269        compr_dbg(compr, "Requested read of %zu bytes\n", count);
4270
4271        if (dsp->fatal_error || !compr->buf || compr->buf->error) {
4272                snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
4273                return -EIO;
4274        }
4275
4276        count /= WM_ADSP_DATA_WORD_SIZE;
4277
4278        do {
4279                nwords = wm_adsp_buffer_capture_block(compr, count);
4280                if (nwords < 0) {
4281                        compr_err(compr, "Failed to capture block: %d\n",
4282                                  nwords);
4283                        return nwords;
4284                }
4285
4286                nbytes = nwords * WM_ADSP_DATA_WORD_SIZE;
4287
4288                compr_dbg(compr, "Read %d bytes\n", nbytes);
4289
4290                if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
4291                        compr_err(compr, "Failed to copy data to user: %d, %d\n",
4292                                  ntotal, nbytes);
4293                        return -EFAULT;
4294                }
4295
4296                count -= nwords;
4297                ntotal += nbytes;
4298        } while (nwords > 0 && count > 0);
4299
4300        compr->copied_total += ntotal;
4301
4302        return ntotal;
4303}
4304
4305int wm_adsp_compr_copy(struct snd_soc_component *component,
4306                       struct snd_compr_stream *stream, char __user *buf,
4307                       size_t count)
4308{
4309        struct wm_adsp_compr *compr = stream->runtime->private_data;
4310        struct wm_adsp *dsp = compr->dsp;
4311        int ret;
4312
4313        mutex_lock(&dsp->pwr_lock);
4314
4315        if (stream->direction == SND_COMPRESS_CAPTURE)
4316                ret = wm_adsp_compr_read(compr, buf, count);
4317        else
4318                ret = -ENOTSUPP;
4319
4320        mutex_unlock(&dsp->pwr_lock);
4321
4322        return ret;
4323}
4324EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
4325
4326static void wm_adsp_fatal_error(struct wm_adsp *dsp)
4327{
4328        struct wm_adsp_compr *compr;
4329
4330        dsp->fatal_error = true;
4331
4332        list_for_each_entry(compr, &dsp->compr_list, list) {
4333                if (compr->stream)
4334                        snd_compr_fragment_elapsed(compr->stream);
4335        }
4336}
4337
4338irqreturn_t wm_adsp2_bus_error(int irq, void *data)
4339{
4340        struct wm_adsp *dsp = (struct wm_adsp *)data;
4341        unsigned int val;
4342        struct regmap *regmap = dsp->regmap;
4343        int ret = 0;
4344
4345        mutex_lock(&dsp->pwr_lock);
4346
4347        ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val);
4348        if (ret) {
4349                adsp_err(dsp,
4350                        "Failed to read Region Lock Ctrl register: %d\n", ret);
4351                goto error;
4352        }
4353
4354        if (val & ADSP2_WDT_TIMEOUT_STS_MASK) {
4355                adsp_err(dsp, "watchdog timeout error\n");
4356                dsp->ops->stop_watchdog(dsp);
4357                wm_adsp_fatal_error(dsp);
4358        }
4359
4360        if (val & (ADSP2_SLAVE_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) {
4361                if (val & ADSP2_SLAVE_ERR_MASK)
4362                        adsp_err(dsp, "bus error: slave error\n");
4363                else
4364                        adsp_err(dsp, "bus error: region lock error\n");
4365
4366                ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val);
4367                if (ret) {
4368                        adsp_err(dsp,
4369                                 "Failed to read Bus Err Addr register: %d\n",
4370                                 ret);
4371                        goto error;
4372                }
4373
4374                adsp_err(dsp, "bus error address = 0x%x\n",
4375                         val & ADSP2_BUS_ERR_ADDR_MASK);
4376
4377                ret = regmap_read(regmap,
4378                                  dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR,
4379                                  &val);
4380                if (ret) {
4381                        adsp_err(dsp,
4382                                 "Failed to read Pmem Xmem Err Addr register: %d\n",
4383                                 ret);
4384                        goto error;
4385                }
4386
4387                adsp_err(dsp, "xmem error address = 0x%x\n",
4388                         val & ADSP2_XMEM_ERR_ADDR_MASK);
4389                adsp_err(dsp, "pmem error address = 0x%x\n",
4390                         (val & ADSP2_PMEM_ERR_ADDR_MASK) >>
4391                         ADSP2_PMEM_ERR_ADDR_SHIFT);
4392        }
4393
4394        regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL,
4395                           ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT);
4396
4397error:
4398        mutex_unlock(&dsp->pwr_lock);
4399
4400        return IRQ_HANDLED;
4401}
4402EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
4403
4404irqreturn_t wm_halo_bus_error(int irq, void *data)
4405{
4406        struct wm_adsp *dsp = (struct wm_adsp *)data;
4407        struct regmap *regmap = dsp->regmap;
4408        unsigned int fault[6];
4409        struct reg_sequence clear[] = {
4410                { dsp->base + HALO_MPU_XM_VIO_STATUS,     0x0 },
4411                { dsp->base + HALO_MPU_YM_VIO_STATUS,     0x0 },
4412                { dsp->base + HALO_MPU_PM_VIO_STATUS,     0x0 },
4413        };
4414        int ret;
4415
4416        mutex_lock(&dsp->pwr_lock);
4417
4418        ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1,
4419                          fault);
4420        if (ret) {
4421                adsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret);
4422                goto exit_unlock;
4423        }
4424
4425        adsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n",
4426                  *fault & HALO_AHBM_FLAGS_ERR_MASK,
4427                  (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >>
4428                  HALO_AHBM_CORE_ERR_ADDR_SHIFT);
4429
4430        ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0,
4431                          fault);
4432        if (ret) {
4433                adsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret);
4434                goto exit_unlock;
4435        }
4436
4437        adsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault);
4438
4439        ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR,
4440                               fault, ARRAY_SIZE(fault));
4441        if (ret) {
4442                adsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret);
4443                goto exit_unlock;
4444        }
4445
4446        adsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]);
4447        adsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]);
4448        adsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]);
4449
4450        ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear));
4451        if (ret)
4452                adsp_warn(dsp, "Failed to clear MPU status: %d\n", ret);
4453
4454exit_unlock:
4455        mutex_unlock(&dsp->pwr_lock);
4456
4457        return IRQ_HANDLED;
4458}
4459EXPORT_SYMBOL_GPL(wm_halo_bus_error);
4460
4461irqreturn_t wm_halo_wdt_expire(int irq, void *data)
4462{
4463        struct wm_adsp *dsp = data;
4464
4465        mutex_lock(&dsp->pwr_lock);
4466
4467        adsp_warn(dsp, "WDT Expiry Fault\n");
4468        dsp->ops->stop_watchdog(dsp);
4469        wm_adsp_fatal_error(dsp);
4470
4471        mutex_unlock(&dsp->pwr_lock);
4472
4473        return IRQ_HANDLED;
4474}
4475EXPORT_SYMBOL_GPL(wm_halo_wdt_expire);
4476
4477static struct wm_adsp_ops wm_adsp1_ops = {
4478        .validate_version = wm_adsp_validate_version,
4479        .parse_sizes = wm_adsp1_parse_sizes,
4480        .region_to_reg = wm_adsp_region_to_reg,
4481};
4482
4483static struct wm_adsp_ops wm_adsp2_ops[] = {
4484        {
4485                .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
4486                .parse_sizes = wm_adsp2_parse_sizes,
4487                .validate_version = wm_adsp_validate_version,
4488                .setup_algs = wm_adsp2_setup_algs,
4489                .region_to_reg = wm_adsp_region_to_reg,
4490
4491                .show_fw_status = wm_adsp2_show_fw_status,
4492
4493                .enable_memory = wm_adsp2_enable_memory,
4494                .disable_memory = wm_adsp2_disable_memory,
4495
4496                .enable_core = wm_adsp2_enable_core,
4497                .disable_core = wm_adsp2_disable_core,
4498
4499                .start_core = wm_adsp2_start_core,
4500                .stop_core = wm_adsp2_stop_core,
4501
4502        },
4503        {
4504                .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
4505                .parse_sizes = wm_adsp2_parse_sizes,
4506                .validate_version = wm_adsp_validate_version,
4507                .setup_algs = wm_adsp2_setup_algs,
4508                .region_to_reg = wm_adsp_region_to_reg,
4509
4510                .show_fw_status = wm_adsp2v2_show_fw_status,
4511
4512                .enable_memory = wm_adsp2_enable_memory,
4513                .disable_memory = wm_adsp2_disable_memory,
4514                .lock_memory = wm_adsp2_lock,
4515
4516                .enable_core = wm_adsp2v2_enable_core,
4517                .disable_core = wm_adsp2v2_disable_core,
4518
4519                .start_core = wm_adsp2_start_core,
4520                .stop_core = wm_adsp2_stop_core,
4521        },
4522        {
4523                .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
4524                .parse_sizes = wm_adsp2_parse_sizes,
4525                .validate_version = wm_adsp_validate_version,
4526                .setup_algs = wm_adsp2_setup_algs,
4527                .region_to_reg = wm_adsp_region_to_reg,
4528
4529                .show_fw_status = wm_adsp2v2_show_fw_status,
4530                .stop_watchdog = wm_adsp_stop_watchdog,
4531
4532                .enable_memory = wm_adsp2_enable_memory,
4533                .disable_memory = wm_adsp2_disable_memory,
4534                .lock_memory = wm_adsp2_lock,
4535
4536                .enable_core = wm_adsp2v2_enable_core,
4537                .disable_core = wm_adsp2v2_disable_core,
4538
4539                .start_core = wm_adsp2_start_core,
4540                .stop_core = wm_adsp2_stop_core,
4541        },
4542};
4543
4544static struct wm_adsp_ops wm_halo_ops = {
4545        .sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr),
4546        .parse_sizes = wm_adsp2_parse_sizes,
4547        .validate_version = wm_halo_validate_version,
4548        .setup_algs = wm_halo_setup_algs,
4549        .region_to_reg = wm_halo_region_to_reg,
4550
4551        .show_fw_status = wm_halo_show_fw_status,
4552        .stop_watchdog = wm_halo_stop_watchdog,
4553
4554        .lock_memory = wm_halo_configure_mpu,
4555
4556        .start_core = wm_halo_start_core,
4557        .stop_core = wm_halo_stop_core,
4558};
4559
4560MODULE_LICENSE("GPL v2");
4561