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