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