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