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 if (in & WMFW_CTL_FLAG_READABLE) 1263 out |= rd; 1264 if (in & WMFW_CTL_FLAG_WRITEABLE) 1265 out |= wr; 1266 if (in & WMFW_CTL_FLAG_VOLATILE) 1267 out |= vol; 1268 } else { 1269 out |= rd | wr | vol; 1270 } 1271 1272 return out; 1273 } 1274 1275 static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) 1276 { 1277 struct snd_kcontrol_new *kcontrol; 1278 int ret; 1279 1280 if (!ctl || !ctl->name) 1281 return -EINVAL; 1282 1283 kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL); 1284 if (!kcontrol) 1285 return -ENOMEM; 1286 1287 kcontrol->name = ctl->name; 1288 kcontrol->info = wm_coeff_info; 1289 kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER; 1290 kcontrol->tlv.c = snd_soc_bytes_tlv_callback; 1291 kcontrol->private_value = (unsigned long)&ctl->bytes_ext; 1292 kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len); 1293 1294 switch (ctl->type) { 1295 case WMFW_CTL_TYPE_ACKED: 1296 kcontrol->get = wm_coeff_get_acked; 1297 kcontrol->put = wm_coeff_put_acked; 1298 break; 1299 default: 1300 if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 1301 ctl->bytes_ext.max = ctl->len; 1302 ctl->bytes_ext.get = wm_coeff_tlv_get; 1303 ctl->bytes_ext.put = wm_coeff_tlv_put; 1304 } else { 1305 kcontrol->get = wm_coeff_get; 1306 kcontrol->put = wm_coeff_put; 1307 } 1308 break; 1309 } 1310 1311 ret = snd_soc_add_component_controls(dsp->component, kcontrol, 1); 1312 if (ret < 0) 1313 goto err_kcontrol; 1314 1315 kfree(kcontrol); 1316 1317 return 0; 1318 1319 err_kcontrol: 1320 kfree(kcontrol); 1321 return ret; 1322 } 1323 1324 static int wm_coeff_init_control_caches(struct wm_adsp *dsp) 1325 { 1326 struct wm_coeff_ctl *ctl; 1327 int ret; 1328 1329 list_for_each_entry(ctl, &dsp->ctl_list, list) { 1330 if (!ctl->enabled || ctl->set) 1331 continue; 1332 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) 1333 continue; 1334 1335 /* 1336 * For readable controls populate the cache from the DSP memory. 1337 * For non-readable controls the cache was zero-filled when 1338 * created so we don't need to do anything. 1339 */ 1340 if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) { 1341 ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len); 1342 if (ret < 0) 1343 return ret; 1344 } 1345 } 1346 1347 return 0; 1348 } 1349 1350 static int wm_coeff_sync_controls(struct wm_adsp *dsp) 1351 { 1352 struct wm_coeff_ctl *ctl; 1353 int ret; 1354 1355 list_for_each_entry(ctl, &dsp->ctl_list, list) { 1356 if (!ctl->enabled) 1357 continue; 1358 if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) { 1359 ret = wm_coeff_write_control(ctl, ctl->cache, ctl->len); 1360 if (ret < 0) 1361 return ret; 1362 } 1363 } 1364 1365 return 0; 1366 } 1367 1368 static void wm_adsp_signal_event_controls(struct wm_adsp *dsp, 1369 unsigned int event) 1370 { 1371 struct wm_coeff_ctl *ctl; 1372 int ret; 1373 1374 list_for_each_entry(ctl, &dsp->ctl_list, list) { 1375 if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT) 1376 continue; 1377 1378 if (!ctl->enabled) 1379 continue; 1380 1381 ret = wm_coeff_write_acked_control(ctl, event); 1382 if (ret) 1383 adsp_warn(dsp, 1384 "Failed to send 0x%x event to alg 0x%x (%d)\n", 1385 event, ctl->alg_region.alg, ret); 1386 } 1387 } 1388 1389 static void wm_adsp_ctl_work(struct work_struct *work) 1390 { 1391 struct wmfw_ctl_work *ctl_work = container_of(work, 1392 struct wmfw_ctl_work, 1393 work); 1394 1395 wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl); 1396 kfree(ctl_work); 1397 } 1398 1399 static void wm_adsp_free_ctl_blk(struct wm_coeff_ctl *ctl) 1400 { 1401 kfree(ctl->cache); 1402 kfree(ctl->name); 1403 kfree(ctl); 1404 } 1405 1406 static int wm_adsp_create_control(struct wm_adsp *dsp, 1407 const struct wm_adsp_alg_region *alg_region, 1408 unsigned int offset, unsigned int len, 1409 const char *subname, unsigned int subname_len, 1410 unsigned int flags, unsigned int type) 1411 { 1412 struct wm_coeff_ctl *ctl; 1413 struct wmfw_ctl_work *ctl_work; 1414 char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 1415 const char *region_name; 1416 int ret; 1417 1418 region_name = wm_adsp_mem_region_name(alg_region->type); 1419 if (!region_name) { 1420 adsp_err(dsp, "Unknown region type: %d\n", alg_region->type); 1421 return -EINVAL; 1422 } 1423 1424 switch (dsp->fw_ver) { 1425 case 0: 1426 case 1: 1427 snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x", 1428 dsp->name, region_name, alg_region->alg); 1429 subname = NULL; /* don't append subname */ 1430 break; 1431 case 2: 1432 ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, 1433 "%s%c %.12s %x", dsp->name, *region_name, 1434 wm_adsp_fw_text[dsp->fw], alg_region->alg); 1435 break; 1436 default: 1437 ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, 1438 "%s %.12s %x", dsp->name, 1439 wm_adsp_fw_text[dsp->fw], alg_region->alg); 1440 break; 1441 } 1442 1443 if (subname) { 1444 int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2; 1445 int skip = 0; 1446 1447 if (dsp->component->name_prefix) 1448 avail -= strlen(dsp->component->name_prefix) + 1; 1449 1450 /* Truncate the subname from the start if it is too long */ 1451 if (subname_len > avail) 1452 skip = subname_len - avail; 1453 1454 snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, 1455 " %.*s", subname_len - skip, subname + skip); 1456 } 1457 1458 list_for_each_entry(ctl, &dsp->ctl_list, list) { 1459 if (!strcmp(ctl->name, name)) { 1460 if (!ctl->enabled) 1461 ctl->enabled = 1; 1462 return 0; 1463 } 1464 } 1465 1466 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); 1467 if (!ctl) 1468 return -ENOMEM; 1469 ctl->fw_name = wm_adsp_fw_text[dsp->fw]; 1470 ctl->alg_region = *alg_region; 1471 ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL); 1472 if (!ctl->name) { 1473 ret = -ENOMEM; 1474 goto err_ctl; 1475 } 1476 ctl->enabled = 1; 1477 ctl->set = 0; 1478 ctl->ops.xget = wm_coeff_get; 1479 ctl->ops.xput = wm_coeff_put; 1480 ctl->dsp = dsp; 1481 1482 ctl->flags = flags; 1483 ctl->type = type; 1484 ctl->offset = offset; 1485 ctl->len = len; 1486 ctl->cache = kzalloc(ctl->len, GFP_KERNEL); 1487 if (!ctl->cache) { 1488 ret = -ENOMEM; 1489 goto err_ctl_name; 1490 } 1491 1492 list_add(&ctl->list, &dsp->ctl_list); 1493 1494 if (flags & WMFW_CTL_FLAG_SYS) 1495 return 0; 1496 1497 ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL); 1498 if (!ctl_work) { 1499 ret = -ENOMEM; 1500 goto err_ctl_cache; 1501 } 1502 1503 ctl_work->dsp = dsp; 1504 ctl_work->ctl = ctl; 1505 INIT_WORK(&ctl_work->work, wm_adsp_ctl_work); 1506 schedule_work(&ctl_work->work); 1507 1508 return 0; 1509 1510 err_ctl_cache: 1511 kfree(ctl->cache); 1512 err_ctl_name: 1513 kfree(ctl->name); 1514 err_ctl: 1515 kfree(ctl); 1516 1517 return ret; 1518 } 1519 1520 struct wm_coeff_parsed_alg { 1521 int id; 1522 const u8 *name; 1523 int name_len; 1524 int ncoeff; 1525 }; 1526 1527 struct wm_coeff_parsed_coeff { 1528 int offset; 1529 int mem_type; 1530 const u8 *name; 1531 int name_len; 1532 int ctl_type; 1533 int flags; 1534 int len; 1535 }; 1536 1537 static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) 1538 { 1539 int length; 1540 1541 switch (bytes) { 1542 case 1: 1543 length = **pos; 1544 break; 1545 case 2: 1546 length = le16_to_cpu(*((__le16 *)*pos)); 1547 break; 1548 default: 1549 return 0; 1550 } 1551 1552 if (str) 1553 *str = *pos + bytes; 1554 1555 *pos += ((length + bytes) + 3) & ~0x03; 1556 1557 return length; 1558 } 1559 1560 static int wm_coeff_parse_int(int bytes, const u8 **pos) 1561 { 1562 int val = 0; 1563 1564 switch (bytes) { 1565 case 2: 1566 val = le16_to_cpu(*((__le16 *)*pos)); 1567 break; 1568 case 4: 1569 val = le32_to_cpu(*((__le32 *)*pos)); 1570 break; 1571 default: 1572 break; 1573 } 1574 1575 *pos += bytes; 1576 1577 return val; 1578 } 1579 1580 static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data, 1581 struct wm_coeff_parsed_alg *blk) 1582 { 1583 const struct wmfw_adsp_alg_data *raw; 1584 1585 switch (dsp->fw_ver) { 1586 case 0: 1587 case 1: 1588 raw = (const struct wmfw_adsp_alg_data *)*data; 1589 *data = raw->data; 1590 1591 blk->id = le32_to_cpu(raw->id); 1592 blk->name = raw->name; 1593 blk->name_len = strlen(raw->name); 1594 blk->ncoeff = le32_to_cpu(raw->ncoeff); 1595 break; 1596 default: 1597 blk->id = wm_coeff_parse_int(sizeof(raw->id), data); 1598 blk->name_len = wm_coeff_parse_string(sizeof(u8), data, 1599 &blk->name); 1600 wm_coeff_parse_string(sizeof(u16), data, NULL); 1601 blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data); 1602 break; 1603 } 1604 1605 adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); 1606 adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); 1607 adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff); 1608 } 1609 1610 static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data, 1611 struct wm_coeff_parsed_coeff *blk) 1612 { 1613 const struct wmfw_adsp_coeff_data *raw; 1614 const u8 *tmp; 1615 int length; 1616 1617 switch (dsp->fw_ver) { 1618 case 0: 1619 case 1: 1620 raw = (const struct wmfw_adsp_coeff_data *)*data; 1621 *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size); 1622 1623 blk->offset = le16_to_cpu(raw->hdr.offset); 1624 blk->mem_type = le16_to_cpu(raw->hdr.type); 1625 blk->name = raw->name; 1626 blk->name_len = strlen(raw->name); 1627 blk->ctl_type = le16_to_cpu(raw->ctl_type); 1628 blk->flags = le16_to_cpu(raw->flags); 1629 blk->len = le32_to_cpu(raw->len); 1630 break; 1631 default: 1632 tmp = *data; 1633 blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp); 1634 blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp); 1635 length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp); 1636 blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp, 1637 &blk->name); 1638 wm_coeff_parse_string(sizeof(u8), &tmp, NULL); 1639 wm_coeff_parse_string(sizeof(u16), &tmp, NULL); 1640 blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp); 1641 blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp); 1642 blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp); 1643 1644 *data = *data + sizeof(raw->hdr) + length; 1645 break; 1646 } 1647 1648 adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type); 1649 adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset); 1650 adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name); 1651 adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags); 1652 adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type); 1653 adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); 1654 } 1655 1656 static int wm_adsp_check_coeff_flags(struct wm_adsp *dsp, 1657 const struct wm_coeff_parsed_coeff *coeff_blk, 1658 unsigned int f_required, 1659 unsigned int f_illegal) 1660 { 1661 if ((coeff_blk->flags & f_illegal) || 1662 ((coeff_blk->flags & f_required) != f_required)) { 1663 adsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n", 1664 coeff_blk->flags, coeff_blk->ctl_type); 1665 return -EINVAL; 1666 } 1667 1668 return 0; 1669 } 1670 1671 static int wm_adsp_parse_coeff(struct wm_adsp *dsp, 1672 const struct wmfw_region *region) 1673 { 1674 struct wm_adsp_alg_region alg_region = {}; 1675 struct wm_coeff_parsed_alg alg_blk; 1676 struct wm_coeff_parsed_coeff coeff_blk; 1677 const u8 *data = region->data; 1678 int i, ret; 1679 1680 wm_coeff_parse_alg(dsp, &data, &alg_blk); 1681 for (i = 0; i < alg_blk.ncoeff; i++) { 1682 wm_coeff_parse_coeff(dsp, &data, &coeff_blk); 1683 1684 switch (coeff_blk.ctl_type) { 1685 case SNDRV_CTL_ELEM_TYPE_BYTES: 1686 break; 1687 case WMFW_CTL_TYPE_ACKED: 1688 if (coeff_blk.flags & WMFW_CTL_FLAG_SYS) 1689 continue; /* ignore */ 1690 1691 ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, 1692 WMFW_CTL_FLAG_VOLATILE | 1693 WMFW_CTL_FLAG_WRITEABLE | 1694 WMFW_CTL_FLAG_READABLE, 1695 0); 1696 if (ret) 1697 return -EINVAL; 1698 break; 1699 case WMFW_CTL_TYPE_HOSTEVENT: 1700 ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, 1701 WMFW_CTL_FLAG_SYS | 1702 WMFW_CTL_FLAG_VOLATILE | 1703 WMFW_CTL_FLAG_WRITEABLE | 1704 WMFW_CTL_FLAG_READABLE, 1705 0); 1706 if (ret) 1707 return -EINVAL; 1708 break; 1709 case WMFW_CTL_TYPE_HOST_BUFFER: 1710 ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, 1711 WMFW_CTL_FLAG_SYS | 1712 WMFW_CTL_FLAG_VOLATILE | 1713 WMFW_CTL_FLAG_READABLE, 1714 0); 1715 if (ret) 1716 return -EINVAL; 1717 break; 1718 default: 1719 adsp_err(dsp, "Unknown control type: %d\n", 1720 coeff_blk.ctl_type); 1721 return -EINVAL; 1722 } 1723 1724 alg_region.type = coeff_blk.mem_type; 1725 alg_region.alg = alg_blk.id; 1726 1727 ret = wm_adsp_create_control(dsp, &alg_region, 1728 coeff_blk.offset, 1729 coeff_blk.len, 1730 coeff_blk.name, 1731 coeff_blk.name_len, 1732 coeff_blk.flags, 1733 coeff_blk.ctl_type); 1734 if (ret < 0) 1735 adsp_err(dsp, "Failed to create control: %.*s, %d\n", 1736 coeff_blk.name_len, coeff_blk.name, ret); 1737 } 1738 1739 return 0; 1740 } 1741 1742 static unsigned int wm_adsp1_parse_sizes(struct wm_adsp *dsp, 1743 const char * const file, 1744 unsigned int pos, 1745 const struct firmware *firmware) 1746 { 1747 const struct wmfw_adsp1_sizes *adsp1_sizes; 1748 1749 adsp1_sizes = (void *)&firmware->data[pos]; 1750 1751 adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file, 1752 le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm), 1753 le32_to_cpu(adsp1_sizes->zm)); 1754 1755 return pos + sizeof(*adsp1_sizes); 1756 } 1757 1758 static unsigned int wm_adsp2_parse_sizes(struct wm_adsp *dsp, 1759 const char * const file, 1760 unsigned int pos, 1761 const struct firmware *firmware) 1762 { 1763 const struct wmfw_adsp2_sizes *adsp2_sizes; 1764 1765 adsp2_sizes = (void *)&firmware->data[pos]; 1766 1767 adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file, 1768 le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym), 1769 le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm)); 1770 1771 return pos + sizeof(*adsp2_sizes); 1772 } 1773 1774 static bool wm_adsp_validate_version(struct wm_adsp *dsp, unsigned int version) 1775 { 1776 switch (version) { 1777 case 0: 1778 adsp_warn(dsp, "Deprecated file format %d\n", version); 1779 return true; 1780 case 1: 1781 case 2: 1782 return true; 1783 default: 1784 return false; 1785 } 1786 } 1787 1788 static bool wm_halo_validate_version(struct wm_adsp *dsp, unsigned int version) 1789 { 1790 switch (version) { 1791 case 3: 1792 return true; 1793 default: 1794 return false; 1795 } 1796 } 1797 1798 static int wm_adsp_load(struct wm_adsp *dsp) 1799 { 1800 LIST_HEAD(buf_list); 1801 const struct firmware *firmware; 1802 struct regmap *regmap = dsp->regmap; 1803 unsigned int pos = 0; 1804 const struct wmfw_header *header; 1805 const struct wmfw_adsp1_sizes *adsp1_sizes; 1806 const struct wmfw_footer *footer; 1807 const struct wmfw_region *region; 1808 const struct wm_adsp_region *mem; 1809 const char *region_name; 1810 char *file, *text = NULL; 1811 struct wm_adsp_buf *buf; 1812 unsigned int reg; 1813 int regions = 0; 1814 int ret, offset, type; 1815 1816 file = kzalloc(PAGE_SIZE, GFP_KERNEL); 1817 if (file == NULL) 1818 return -ENOMEM; 1819 1820 snprintf(file, PAGE_SIZE, "%s-%s-%s.wmfw", dsp->part, dsp->fwf_name, 1821 wm_adsp_fw[dsp->fw].file); 1822 file[PAGE_SIZE - 1] = '\0'; 1823 1824 ret = request_firmware(&firmware, file, dsp->dev); 1825 if (ret != 0) { 1826 adsp_err(dsp, "Failed to request '%s'\n", file); 1827 goto out; 1828 } 1829 ret = -EINVAL; 1830 1831 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); 1832 if (pos >= firmware->size) { 1833 adsp_err(dsp, "%s: file too short, %zu bytes\n", 1834 file, firmware->size); 1835 goto out_fw; 1836 } 1837 1838 header = (void *)&firmware->data[0]; 1839 1840 if (memcmp(&header->magic[0], "WMFW", 4) != 0) { 1841 adsp_err(dsp, "%s: invalid magic\n", file); 1842 goto out_fw; 1843 } 1844 1845 if (!dsp->ops->validate_version(dsp, header->ver)) { 1846 adsp_err(dsp, "%s: unknown file format %d\n", 1847 file, header->ver); 1848 goto out_fw; 1849 } 1850 1851 adsp_info(dsp, "Firmware version: %d\n", header->ver); 1852 dsp->fw_ver = header->ver; 1853 1854 if (header->core != dsp->type) { 1855 adsp_err(dsp, "%s: invalid core %d != %d\n", 1856 file, header->core, dsp->type); 1857 goto out_fw; 1858 } 1859 1860 pos = sizeof(*header); 1861 pos = dsp->ops->parse_sizes(dsp, file, pos, firmware); 1862 1863 footer = (void *)&firmware->data[pos]; 1864 pos += sizeof(*footer); 1865 1866 if (le32_to_cpu(header->len) != pos) { 1867 adsp_err(dsp, "%s: unexpected header length %d\n", 1868 file, le32_to_cpu(header->len)); 1869 goto out_fw; 1870 } 1871 1872 adsp_dbg(dsp, "%s: timestamp %llu\n", file, 1873 le64_to_cpu(footer->timestamp)); 1874 1875 while (pos < firmware->size && 1876 sizeof(*region) < firmware->size - pos) { 1877 region = (void *)&(firmware->data[pos]); 1878 region_name = "Unknown"; 1879 reg = 0; 1880 text = NULL; 1881 offset = le32_to_cpu(region->offset) & 0xffffff; 1882 type = be32_to_cpu(region->type) & 0xff; 1883 1884 switch (type) { 1885 case WMFW_NAME_TEXT: 1886 region_name = "Firmware name"; 1887 text = kzalloc(le32_to_cpu(region->len) + 1, 1888 GFP_KERNEL); 1889 break; 1890 case WMFW_ALGORITHM_DATA: 1891 region_name = "Algorithm"; 1892 ret = wm_adsp_parse_coeff(dsp, region); 1893 if (ret != 0) 1894 goto out_fw; 1895 break; 1896 case WMFW_INFO_TEXT: 1897 region_name = "Information"; 1898 text = kzalloc(le32_to_cpu(region->len) + 1, 1899 GFP_KERNEL); 1900 break; 1901 case WMFW_ABSOLUTE: 1902 region_name = "Absolute"; 1903 reg = offset; 1904 break; 1905 case WMFW_ADSP1_PM: 1906 case WMFW_ADSP1_DM: 1907 case WMFW_ADSP2_XM: 1908 case WMFW_ADSP2_YM: 1909 case WMFW_ADSP1_ZM: 1910 case WMFW_HALO_PM_PACKED: 1911 case WMFW_HALO_XM_PACKED: 1912 case WMFW_HALO_YM_PACKED: 1913 mem = wm_adsp_find_region(dsp, type); 1914 if (!mem) { 1915 adsp_err(dsp, "No region of type: %x\n", type); 1916 goto out_fw; 1917 } 1918 1919 region_name = wm_adsp_mem_region_name(type); 1920 reg = dsp->ops->region_to_reg(mem, offset); 1921 break; 1922 default: 1923 adsp_warn(dsp, 1924 "%s.%d: Unknown region type %x at %d(%x)\n", 1925 file, regions, type, pos, pos); 1926 break; 1927 } 1928 1929 adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file, 1930 regions, le32_to_cpu(region->len), offset, 1931 region_name); 1932 1933 if (le32_to_cpu(region->len) > 1934 firmware->size - pos - sizeof(*region)) { 1935 adsp_err(dsp, 1936 "%s.%d: %s region len %d bytes exceeds file length %zu\n", 1937 file, regions, region_name, 1938 le32_to_cpu(region->len), firmware->size); 1939 ret = -EINVAL; 1940 goto out_fw; 1941 } 1942 1943 if (text) { 1944 memcpy(text, region->data, le32_to_cpu(region->len)); 1945 adsp_info(dsp, "%s: %s\n", file, text); 1946 kfree(text); 1947 text = NULL; 1948 } 1949 1950 if (reg) { 1951 buf = wm_adsp_buf_alloc(region->data, 1952 le32_to_cpu(region->len), 1953 &buf_list); 1954 if (!buf) { 1955 adsp_err(dsp, "Out of memory\n"); 1956 ret = -ENOMEM; 1957 goto out_fw; 1958 } 1959 1960 ret = regmap_raw_write_async(regmap, reg, buf->buf, 1961 le32_to_cpu(region->len)); 1962 if (ret != 0) { 1963 adsp_err(dsp, 1964 "%s.%d: Failed to write %d bytes at %d in %s: %d\n", 1965 file, regions, 1966 le32_to_cpu(region->len), offset, 1967 region_name, ret); 1968 goto out_fw; 1969 } 1970 } 1971 1972 pos += le32_to_cpu(region->len) + sizeof(*region); 1973 regions++; 1974 } 1975 1976 ret = regmap_async_complete(regmap); 1977 if (ret != 0) { 1978 adsp_err(dsp, "Failed to complete async write: %d\n", ret); 1979 goto out_fw; 1980 } 1981 1982 if (pos > firmware->size) 1983 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 1984 file, regions, pos - firmware->size); 1985 1986 wm_adsp_debugfs_save_wmfwname(dsp, file); 1987 1988 out_fw: 1989 regmap_async_complete(regmap); 1990 wm_adsp_buf_free(&buf_list); 1991 release_firmware(firmware); 1992 kfree(text); 1993 out: 1994 kfree(file); 1995 1996 return ret; 1997 } 1998 1999 static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp, 2000 const struct wm_adsp_alg_region *alg_region) 2001 { 2002 struct wm_coeff_ctl *ctl; 2003 2004 list_for_each_entry(ctl, &dsp->ctl_list, list) { 2005 if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] && 2006 alg_region->alg == ctl->alg_region.alg && 2007 alg_region->type == ctl->alg_region.type) { 2008 ctl->alg_region.base = alg_region->base; 2009 } 2010 } 2011 } 2012 2013 static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, 2014 const struct wm_adsp_region *mem, 2015 unsigned int pos, unsigned int len) 2016 { 2017 void *alg; 2018 unsigned int reg; 2019 int ret; 2020 __be32 val; 2021 2022 if (n_algs == 0) { 2023 adsp_err(dsp, "No algorithms\n"); 2024 return ERR_PTR(-EINVAL); 2025 } 2026 2027 if (n_algs > 1024) { 2028 adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs); 2029 return ERR_PTR(-EINVAL); 2030 } 2031 2032 /* Read the terminator first to validate the length */ 2033 reg = dsp->ops->region_to_reg(mem, pos + len); 2034 2035 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); 2036 if (ret != 0) { 2037 adsp_err(dsp, "Failed to read algorithm list end: %d\n", 2038 ret); 2039 return ERR_PTR(ret); 2040 } 2041 2042 if (be32_to_cpu(val) != 0xbedead) 2043 adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n", 2044 reg, be32_to_cpu(val)); 2045 2046 /* Convert length from DSP words to bytes */ 2047 len *= sizeof(u32); 2048 2049 alg = kzalloc(len, GFP_KERNEL | GFP_DMA); 2050 if (!alg) 2051 return ERR_PTR(-ENOMEM); 2052 2053 reg = dsp->ops->region_to_reg(mem, pos); 2054 2055 ret = regmap_raw_read(dsp->regmap, reg, alg, len); 2056 if (ret != 0) { 2057 adsp_err(dsp, "Failed to read algorithm list: %d\n", ret); 2058 kfree(alg); 2059 return ERR_PTR(ret); 2060 } 2061 2062 return alg; 2063 } 2064 2065 static struct wm_adsp_alg_region * 2066 wm_adsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id) 2067 { 2068 struct wm_adsp_alg_region *alg_region; 2069 2070 list_for_each_entry(alg_region, &dsp->alg_regions, list) { 2071 if (id == alg_region->alg && type == alg_region->type) 2072 return alg_region; 2073 } 2074 2075 return NULL; 2076 } 2077 2078 static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp, 2079 int type, __be32 id, 2080 __be32 base) 2081 { 2082 struct wm_adsp_alg_region *alg_region; 2083 2084 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL); 2085 if (!alg_region) 2086 return ERR_PTR(-ENOMEM); 2087 2088 alg_region->type = type; 2089 alg_region->alg = be32_to_cpu(id); 2090 alg_region->base = be32_to_cpu(base); 2091 2092 list_add_tail(&alg_region->list, &dsp->alg_regions); 2093 2094 if (dsp->fw_ver > 0) 2095 wm_adsp_ctl_fixup_base(dsp, alg_region); 2096 2097 return alg_region; 2098 } 2099 2100 static void wm_adsp_free_alg_regions(struct wm_adsp *dsp) 2101 { 2102 struct wm_adsp_alg_region *alg_region; 2103 2104 while (!list_empty(&dsp->alg_regions)) { 2105 alg_region = list_first_entry(&dsp->alg_regions, 2106 struct wm_adsp_alg_region, 2107 list); 2108 list_del(&alg_region->list); 2109 kfree(alg_region); 2110 } 2111 } 2112 2113 static void wmfw_parse_id_header(struct wm_adsp *dsp, 2114 struct wmfw_id_hdr *fw, int nalgs) 2115 { 2116 dsp->fw_id = be32_to_cpu(fw->id); 2117 dsp->fw_id_version = be32_to_cpu(fw->ver); 2118 2119 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n", 2120 dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16, 2121 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, 2122 nalgs); 2123 } 2124 2125 static void wmfw_v3_parse_id_header(struct wm_adsp *dsp, 2126 struct wmfw_v3_id_hdr *fw, int nalgs) 2127 { 2128 dsp->fw_id = be32_to_cpu(fw->id); 2129 dsp->fw_id_version = be32_to_cpu(fw->ver); 2130 dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id); 2131 2132 adsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n", 2133 dsp->fw_id, dsp->fw_vendor_id, 2134 (dsp->fw_id_version & 0xff0000) >> 16, 2135 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, 2136 nalgs); 2137 } 2138 2139 static int wm_adsp_create_regions(struct wm_adsp *dsp, __be32 id, int nregions, 2140 int *type, __be32 *base) 2141 { 2142 struct wm_adsp_alg_region *alg_region; 2143 int i; 2144 2145 for (i = 0; i < nregions; i++) { 2146 alg_region = wm_adsp_create_region(dsp, type[i], id, base[i]); 2147 if (IS_ERR(alg_region)) 2148 return PTR_ERR(alg_region); 2149 } 2150 2151 return 0; 2152 } 2153 2154 static int wm_adsp1_setup_algs(struct wm_adsp *dsp) 2155 { 2156 struct wmfw_adsp1_id_hdr adsp1_id; 2157 struct wmfw_adsp1_alg_hdr *adsp1_alg; 2158 struct wm_adsp_alg_region *alg_region; 2159 const struct wm_adsp_region *mem; 2160 unsigned int pos, len; 2161 size_t n_algs; 2162 int i, ret; 2163 2164 mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM); 2165 if (WARN_ON(!mem)) 2166 return -EINVAL; 2167 2168 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id, 2169 sizeof(adsp1_id)); 2170 if (ret != 0) { 2171 adsp_err(dsp, "Failed to read algorithm info: %d\n", 2172 ret); 2173 return ret; 2174 } 2175 2176 n_algs = be32_to_cpu(adsp1_id.n_algs); 2177 2178 wmfw_parse_id_header(dsp, &adsp1_id.fw, n_algs); 2179 2180 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM, 2181 adsp1_id.fw.id, adsp1_id.zm); 2182 if (IS_ERR(alg_region)) 2183 return PTR_ERR(alg_region); 2184 2185 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM, 2186 adsp1_id.fw.id, adsp1_id.dm); 2187 if (IS_ERR(alg_region)) 2188 return PTR_ERR(alg_region); 2189 2190 /* Calculate offset and length in DSP words */ 2191 pos = sizeof(adsp1_id) / sizeof(u32); 2192 len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32); 2193 2194 adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len); 2195 if (IS_ERR(adsp1_alg)) 2196 return PTR_ERR(adsp1_alg); 2197 2198 for (i = 0; i < n_algs; i++) { 2199 adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", 2200 i, be32_to_cpu(adsp1_alg[i].alg.id), 2201 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, 2202 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, 2203 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, 2204 be32_to_cpu(adsp1_alg[i].dm), 2205 be32_to_cpu(adsp1_alg[i].zm)); 2206 2207 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM, 2208 adsp1_alg[i].alg.id, 2209 adsp1_alg[i].dm); 2210 if (IS_ERR(alg_region)) { 2211 ret = PTR_ERR(alg_region); 2212 goto out; 2213 } 2214 if (dsp->fw_ver == 0) { 2215 if (i + 1 < n_algs) { 2216 len = be32_to_cpu(adsp1_alg[i + 1].dm); 2217 len -= be32_to_cpu(adsp1_alg[i].dm); 2218 len *= 4; 2219 wm_adsp_create_control(dsp, alg_region, 0, 2220 len, NULL, 0, 0, 2221 SNDRV_CTL_ELEM_TYPE_BYTES); 2222 } else { 2223 adsp_warn(dsp, "Missing length info for region DM with ID %x\n", 2224 be32_to_cpu(adsp1_alg[i].alg.id)); 2225 } 2226 } 2227 2228 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM, 2229 adsp1_alg[i].alg.id, 2230 adsp1_alg[i].zm); 2231 if (IS_ERR(alg_region)) { 2232 ret = PTR_ERR(alg_region); 2233 goto out; 2234 } 2235 if (dsp->fw_ver == 0) { 2236 if (i + 1 < n_algs) { 2237 len = be32_to_cpu(adsp1_alg[i + 1].zm); 2238 len -= be32_to_cpu(adsp1_alg[i].zm); 2239 len *= 4; 2240 wm_adsp_create_control(dsp, alg_region, 0, 2241 len, NULL, 0, 0, 2242 SNDRV_CTL_ELEM_TYPE_BYTES); 2243 } else { 2244 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 2245 be32_to_cpu(adsp1_alg[i].alg.id)); 2246 } 2247 } 2248 } 2249 2250 out: 2251 kfree(adsp1_alg); 2252 return ret; 2253 } 2254 2255 static int wm_adsp2_setup_algs(struct wm_adsp *dsp) 2256 { 2257 struct wmfw_adsp2_id_hdr adsp2_id; 2258 struct wmfw_adsp2_alg_hdr *adsp2_alg; 2259 struct wm_adsp_alg_region *alg_region; 2260 const struct wm_adsp_region *mem; 2261 unsigned int pos, len; 2262 size_t n_algs; 2263 int i, ret; 2264 2265 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); 2266 if (WARN_ON(!mem)) 2267 return -EINVAL; 2268 2269 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id, 2270 sizeof(adsp2_id)); 2271 if (ret != 0) { 2272 adsp_err(dsp, "Failed to read algorithm info: %d\n", 2273 ret); 2274 return ret; 2275 } 2276 2277 n_algs = be32_to_cpu(adsp2_id.n_algs); 2278 2279 wmfw_parse_id_header(dsp, &adsp2_id.fw, n_algs); 2280 2281 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, 2282 adsp2_id.fw.id, adsp2_id.xm); 2283 if (IS_ERR(alg_region)) 2284 return PTR_ERR(alg_region); 2285 2286 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM, 2287 adsp2_id.fw.id, adsp2_id.ym); 2288 if (IS_ERR(alg_region)) 2289 return PTR_ERR(alg_region); 2290 2291 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM, 2292 adsp2_id.fw.id, adsp2_id.zm); 2293 if (IS_ERR(alg_region)) 2294 return PTR_ERR(alg_region); 2295 2296 /* Calculate offset and length in DSP words */ 2297 pos = sizeof(adsp2_id) / sizeof(u32); 2298 len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32); 2299 2300 adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len); 2301 if (IS_ERR(adsp2_alg)) 2302 return PTR_ERR(adsp2_alg); 2303 2304 for (i = 0; i < n_algs; i++) { 2305 adsp_info(dsp, 2306 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", 2307 i, be32_to_cpu(adsp2_alg[i].alg.id), 2308 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, 2309 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, 2310 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, 2311 be32_to_cpu(adsp2_alg[i].xm), 2312 be32_to_cpu(adsp2_alg[i].ym), 2313 be32_to_cpu(adsp2_alg[i].zm)); 2314 2315 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, 2316 adsp2_alg[i].alg.id, 2317 adsp2_alg[i].xm); 2318 if (IS_ERR(alg_region)) { 2319 ret = PTR_ERR(alg_region); 2320 goto out; 2321 } 2322 if (dsp->fw_ver == 0) { 2323 if (i + 1 < n_algs) { 2324 len = be32_to_cpu(adsp2_alg[i + 1].xm); 2325 len -= be32_to_cpu(adsp2_alg[i].xm); 2326 len *= 4; 2327 wm_adsp_create_control(dsp, alg_region, 0, 2328 len, NULL, 0, 0, 2329 SNDRV_CTL_ELEM_TYPE_BYTES); 2330 } else { 2331 adsp_warn(dsp, "Missing length info for region XM with ID %x\n", 2332 be32_to_cpu(adsp2_alg[i].alg.id)); 2333 } 2334 } 2335 2336 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM, 2337 adsp2_alg[i].alg.id, 2338 adsp2_alg[i].ym); 2339 if (IS_ERR(alg_region)) { 2340 ret = PTR_ERR(alg_region); 2341 goto out; 2342 } 2343 if (dsp->fw_ver == 0) { 2344 if (i + 1 < n_algs) { 2345 len = be32_to_cpu(adsp2_alg[i + 1].ym); 2346 len -= be32_to_cpu(adsp2_alg[i].ym); 2347 len *= 4; 2348 wm_adsp_create_control(dsp, alg_region, 0, 2349 len, NULL, 0, 0, 2350 SNDRV_CTL_ELEM_TYPE_BYTES); 2351 } else { 2352 adsp_warn(dsp, "Missing length info for region YM with ID %x\n", 2353 be32_to_cpu(adsp2_alg[i].alg.id)); 2354 } 2355 } 2356 2357 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM, 2358 adsp2_alg[i].alg.id, 2359 adsp2_alg[i].zm); 2360 if (IS_ERR(alg_region)) { 2361 ret = PTR_ERR(alg_region); 2362 goto out; 2363 } 2364 if (dsp->fw_ver == 0) { 2365 if (i + 1 < n_algs) { 2366 len = be32_to_cpu(adsp2_alg[i + 1].zm); 2367 len -= be32_to_cpu(adsp2_alg[i].zm); 2368 len *= 4; 2369 wm_adsp_create_control(dsp, alg_region, 0, 2370 len, NULL, 0, 0, 2371 SNDRV_CTL_ELEM_TYPE_BYTES); 2372 } else { 2373 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 2374 be32_to_cpu(adsp2_alg[i].alg.id)); 2375 } 2376 } 2377 } 2378 2379 out: 2380 kfree(adsp2_alg); 2381 return ret; 2382 } 2383 2384 static int wm_halo_create_regions(struct wm_adsp *dsp, __be32 id, 2385 __be32 xm_base, __be32 ym_base) 2386 { 2387 int types[] = { 2388 WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED, 2389 WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED 2390 }; 2391 __be32 bases[] = { xm_base, xm_base, ym_base, ym_base }; 2392 2393 return wm_adsp_create_regions(dsp, id, ARRAY_SIZE(types), types, bases); 2394 } 2395 2396 static int wm_halo_setup_algs(struct wm_adsp *dsp) 2397 { 2398 struct wmfw_halo_id_hdr halo_id; 2399 struct wmfw_halo_alg_hdr *halo_alg; 2400 const struct wm_adsp_region *mem; 2401 unsigned int pos, len; 2402 size_t n_algs; 2403 int i, ret; 2404 2405 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); 2406 if (WARN_ON(!mem)) 2407 return -EINVAL; 2408 2409 ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id, 2410 sizeof(halo_id)); 2411 if (ret != 0) { 2412 adsp_err(dsp, "Failed to read algorithm info: %d\n", 2413 ret); 2414 return ret; 2415 } 2416 2417 n_algs = be32_to_cpu(halo_id.n_algs); 2418 2419 wmfw_v3_parse_id_header(dsp, &halo_id.fw, n_algs); 2420 2421 ret = wm_halo_create_regions(dsp, halo_id.fw.id, 2422 halo_id.xm_base, halo_id.ym_base); 2423 if (ret) 2424 return ret; 2425 2426 /* Calculate offset and length in DSP words */ 2427 pos = sizeof(halo_id) / sizeof(u32); 2428 len = (sizeof(*halo_alg) * n_algs) / sizeof(u32); 2429 2430 halo_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len); 2431 if (IS_ERR(halo_alg)) 2432 return PTR_ERR(halo_alg); 2433 2434 for (i = 0; i < n_algs; i++) { 2435 adsp_info(dsp, 2436 "%d: ID %x v%d.%d.%d XM@%x YM@%x\n", 2437 i, be32_to_cpu(halo_alg[i].alg.id), 2438 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16, 2439 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8, 2440 be32_to_cpu(halo_alg[i].alg.ver) & 0xff, 2441 be32_to_cpu(halo_alg[i].xm_base), 2442 be32_to_cpu(halo_alg[i].ym_base)); 2443 2444 ret = wm_halo_create_regions(dsp, halo_alg[i].alg.id, 2445 halo_alg[i].xm_base, 2446 halo_alg[i].ym_base); 2447 if (ret) 2448 goto out; 2449 } 2450 2451 out: 2452 kfree(halo_alg); 2453 return ret; 2454 } 2455 2456 static int wm_adsp_load_coeff(struct wm_adsp *dsp) 2457 { 2458 LIST_HEAD(buf_list); 2459 struct regmap *regmap = dsp->regmap; 2460 struct wmfw_coeff_hdr *hdr; 2461 struct wmfw_coeff_item *blk; 2462 const struct firmware *firmware; 2463 const struct wm_adsp_region *mem; 2464 struct wm_adsp_alg_region *alg_region; 2465 const char *region_name; 2466 int ret, pos, blocks, type, offset, reg; 2467 char *file; 2468 struct wm_adsp_buf *buf; 2469 2470 file = kzalloc(PAGE_SIZE, GFP_KERNEL); 2471 if (file == NULL) 2472 return -ENOMEM; 2473 2474 snprintf(file, PAGE_SIZE, "%s-%s-%s.bin", dsp->part, dsp->fwf_name, 2475 wm_adsp_fw[dsp->fw].file); 2476 file[PAGE_SIZE - 1] = '\0'; 2477 2478 ret = request_firmware(&firmware, file, dsp->dev); 2479 if (ret != 0) { 2480 adsp_warn(dsp, "Failed to request '%s'\n", file); 2481 ret = 0; 2482 goto out; 2483 } 2484 ret = -EINVAL; 2485 2486 if (sizeof(*hdr) >= firmware->size) { 2487 adsp_err(dsp, "%s: file too short, %zu bytes\n", 2488 file, firmware->size); 2489 goto out_fw; 2490 } 2491 2492 hdr = (void *)&firmware->data[0]; 2493 if (memcmp(hdr->magic, "WMDR", 4) != 0) { 2494 adsp_err(dsp, "%s: invalid magic\n", file); 2495 goto out_fw; 2496 } 2497 2498 switch (be32_to_cpu(hdr->rev) & 0xff) { 2499 case 1: 2500 break; 2501 default: 2502 adsp_err(dsp, "%s: Unsupported coefficient file format %d\n", 2503 file, be32_to_cpu(hdr->rev) & 0xff); 2504 ret = -EINVAL; 2505 goto out_fw; 2506 } 2507 2508 adsp_dbg(dsp, "%s: v%d.%d.%d\n", file, 2509 (le32_to_cpu(hdr->ver) >> 16) & 0xff, 2510 (le32_to_cpu(hdr->ver) >> 8) & 0xff, 2511 le32_to_cpu(hdr->ver) & 0xff); 2512 2513 pos = le32_to_cpu(hdr->len); 2514 2515 blocks = 0; 2516 while (pos < firmware->size && 2517 sizeof(*blk) < firmware->size - pos) { 2518 blk = (void *)(&firmware->data[pos]); 2519 2520 type = le16_to_cpu(blk->type); 2521 offset = le16_to_cpu(blk->offset); 2522 2523 adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", 2524 file, blocks, le32_to_cpu(blk->id), 2525 (le32_to_cpu(blk->ver) >> 16) & 0xff, 2526 (le32_to_cpu(blk->ver) >> 8) & 0xff, 2527 le32_to_cpu(blk->ver) & 0xff); 2528 adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n", 2529 file, blocks, le32_to_cpu(blk->len), offset, type); 2530 2531 reg = 0; 2532 region_name = "Unknown"; 2533 switch (type) { 2534 case (WMFW_NAME_TEXT << 8): 2535 case (WMFW_INFO_TEXT << 8): 2536 break; 2537 case (WMFW_ABSOLUTE << 8): 2538 /* 2539 * Old files may use this for global 2540 * coefficients. 2541 */ 2542 if (le32_to_cpu(blk->id) == dsp->fw_id && 2543 offset == 0) { 2544 region_name = "global coefficients"; 2545 mem = wm_adsp_find_region(dsp, type); 2546 if (!mem) { 2547 adsp_err(dsp, "No ZM\n"); 2548 break; 2549 } 2550 reg = dsp->ops->region_to_reg(mem, 0); 2551 2552 } else { 2553 region_name = "register"; 2554 reg = offset; 2555 } 2556 break; 2557 2558 case WMFW_ADSP1_DM: 2559 case WMFW_ADSP1_ZM: 2560 case WMFW_ADSP2_XM: 2561 case WMFW_ADSP2_YM: 2562 case WMFW_HALO_XM_PACKED: 2563 case WMFW_HALO_YM_PACKED: 2564 case WMFW_HALO_PM_PACKED: 2565 adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", 2566 file, blocks, le32_to_cpu(blk->len), 2567 type, le32_to_cpu(blk->id)); 2568 2569 mem = wm_adsp_find_region(dsp, type); 2570 if (!mem) { 2571 adsp_err(dsp, "No base for region %x\n", type); 2572 break; 2573 } 2574 2575 alg_region = wm_adsp_find_alg_region(dsp, type, 2576 le32_to_cpu(blk->id)); 2577 if (alg_region) { 2578 reg = alg_region->base; 2579 reg = dsp->ops->region_to_reg(mem, reg); 2580 reg += offset; 2581 } else { 2582 adsp_err(dsp, "No %x for algorithm %x\n", 2583 type, le32_to_cpu(blk->id)); 2584 } 2585 break; 2586 2587 default: 2588 adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n", 2589 file, blocks, type, pos); 2590 break; 2591 } 2592 2593 if (reg) { 2594 if (le32_to_cpu(blk->len) > 2595 firmware->size - pos - sizeof(*blk)) { 2596 adsp_err(dsp, 2597 "%s.%d: %s region len %d bytes exceeds file length %zu\n", 2598 file, blocks, region_name, 2599 le32_to_cpu(blk->len), 2600 firmware->size); 2601 ret = -EINVAL; 2602 goto out_fw; 2603 } 2604 2605 buf = wm_adsp_buf_alloc(blk->data, 2606 le32_to_cpu(blk->len), 2607 &buf_list); 2608 if (!buf) { 2609 adsp_err(dsp, "Out of memory\n"); 2610 ret = -ENOMEM; 2611 goto out_fw; 2612 } 2613 2614 adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", 2615 file, blocks, le32_to_cpu(blk->len), 2616 reg); 2617 ret = regmap_raw_write_async(regmap, reg, buf->buf, 2618 le32_to_cpu(blk->len)); 2619 if (ret != 0) { 2620 adsp_err(dsp, 2621 "%s.%d: Failed to write to %x in %s: %d\n", 2622 file, blocks, reg, region_name, ret); 2623 } 2624 } 2625 2626 pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03; 2627 blocks++; 2628 } 2629 2630 ret = regmap_async_complete(regmap); 2631 if (ret != 0) 2632 adsp_err(dsp, "Failed to complete async write: %d\n", ret); 2633 2634 if (pos > firmware->size) 2635 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 2636 file, blocks, pos - firmware->size); 2637 2638 wm_adsp_debugfs_save_binname(dsp, file); 2639 2640 out_fw: 2641 regmap_async_complete(regmap); 2642 release_firmware(firmware); 2643 wm_adsp_buf_free(&buf_list); 2644 out: 2645 kfree(file); 2646 return ret; 2647 } 2648 2649 static int wm_adsp_create_name(struct wm_adsp *dsp) 2650 { 2651 char *p; 2652 2653 if (!dsp->name) { 2654 dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d", 2655 dsp->num); 2656 if (!dsp->name) 2657 return -ENOMEM; 2658 } 2659 2660 if (!dsp->fwf_name) { 2661 p = devm_kstrdup(dsp->dev, dsp->name, GFP_KERNEL); 2662 if (!p) 2663 return -ENOMEM; 2664 2665 dsp->fwf_name = p; 2666 for (; *p != 0; ++p) 2667 *p = tolower(*p); 2668 } 2669 2670 return 0; 2671 } 2672 2673 static int wm_adsp_common_init(struct wm_adsp *dsp) 2674 { 2675 int ret; 2676 2677 ret = wm_adsp_create_name(dsp); 2678 if (ret) 2679 return ret; 2680 2681 INIT_LIST_HEAD(&dsp->alg_regions); 2682 INIT_LIST_HEAD(&dsp->ctl_list); 2683 INIT_LIST_HEAD(&dsp->compr_list); 2684 INIT_LIST_HEAD(&dsp->buffer_list); 2685 2686 mutex_init(&dsp->pwr_lock); 2687 2688 return 0; 2689 } 2690 2691 int wm_adsp1_init(struct wm_adsp *dsp) 2692 { 2693 dsp->ops = &wm_adsp1_ops; 2694 2695 return wm_adsp_common_init(dsp); 2696 } 2697 EXPORT_SYMBOL_GPL(wm_adsp1_init); 2698 2699 int wm_adsp1_event(struct snd_soc_dapm_widget *w, 2700 struct snd_kcontrol *kcontrol, 2701 int event) 2702 { 2703 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 2704 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); 2705 struct wm_adsp *dsp = &dsps[w->shift]; 2706 struct wm_coeff_ctl *ctl; 2707 int ret; 2708 unsigned int val; 2709 2710 dsp->component = component; 2711 2712 mutex_lock(&dsp->pwr_lock); 2713 2714 switch (event) { 2715 case SND_SOC_DAPM_POST_PMU: 2716 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2717 ADSP1_SYS_ENA, ADSP1_SYS_ENA); 2718 2719 /* 2720 * For simplicity set the DSP clock rate to be the 2721 * SYSCLK rate rather than making it configurable. 2722 */ 2723 if (dsp->sysclk_reg) { 2724 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); 2725 if (ret != 0) { 2726 adsp_err(dsp, "Failed to read SYSCLK state: %d\n", 2727 ret); 2728 goto err_mutex; 2729 } 2730 2731 val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift; 2732 2733 ret = regmap_update_bits(dsp->regmap, 2734 dsp->base + ADSP1_CONTROL_31, 2735 ADSP1_CLK_SEL_MASK, val); 2736 if (ret != 0) { 2737 adsp_err(dsp, "Failed to set clock rate: %d\n", 2738 ret); 2739 goto err_mutex; 2740 } 2741 } 2742 2743 ret = wm_adsp_load(dsp); 2744 if (ret != 0) 2745 goto err_ena; 2746 2747 ret = wm_adsp1_setup_algs(dsp); 2748 if (ret != 0) 2749 goto err_ena; 2750 2751 ret = wm_adsp_load_coeff(dsp); 2752 if (ret != 0) 2753 goto err_ena; 2754 2755 /* Initialize caches for enabled and unset controls */ 2756 ret = wm_coeff_init_control_caches(dsp); 2757 if (ret != 0) 2758 goto err_ena; 2759 2760 /* Sync set controls */ 2761 ret = wm_coeff_sync_controls(dsp); 2762 if (ret != 0) 2763 goto err_ena; 2764 2765 dsp->booted = true; 2766 2767 /* Start the core running */ 2768 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2769 ADSP1_CORE_ENA | ADSP1_START, 2770 ADSP1_CORE_ENA | ADSP1_START); 2771 2772 dsp->running = true; 2773 break; 2774 2775 case SND_SOC_DAPM_PRE_PMD: 2776 dsp->running = false; 2777 dsp->booted = false; 2778 2779 /* Halt the core */ 2780 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2781 ADSP1_CORE_ENA | ADSP1_START, 0); 2782 2783 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, 2784 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0); 2785 2786 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2787 ADSP1_SYS_ENA, 0); 2788 2789 list_for_each_entry(ctl, &dsp->ctl_list, list) 2790 ctl->enabled = 0; 2791 2792 2793 wm_adsp_free_alg_regions(dsp); 2794 break; 2795 2796 default: 2797 break; 2798 } 2799 2800 mutex_unlock(&dsp->pwr_lock); 2801 2802 return 0; 2803 2804 err_ena: 2805 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2806 ADSP1_SYS_ENA, 0); 2807 err_mutex: 2808 mutex_unlock(&dsp->pwr_lock); 2809 2810 return ret; 2811 } 2812 EXPORT_SYMBOL_GPL(wm_adsp1_event); 2813 2814 static int wm_adsp2v2_enable_core(struct wm_adsp *dsp) 2815 { 2816 unsigned int val; 2817 int ret, count; 2818 2819 /* Wait for the RAM to start, should be near instantaneous */ 2820 for (count = 0; count < 10; ++count) { 2821 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val); 2822 if (ret != 0) 2823 return ret; 2824 2825 if (val & ADSP2_RAM_RDY) 2826 break; 2827 2828 usleep_range(250, 500); 2829 } 2830 2831 if (!(val & ADSP2_RAM_RDY)) { 2832 adsp_err(dsp, "Failed to start DSP RAM\n"); 2833 return -EBUSY; 2834 } 2835 2836 adsp_dbg(dsp, "RAM ready after %d polls\n", count); 2837 2838 return 0; 2839 } 2840 2841 static int wm_adsp2_enable_core(struct wm_adsp *dsp) 2842 { 2843 int ret; 2844 2845 ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL, 2846 ADSP2_SYS_ENA, ADSP2_SYS_ENA); 2847 if (ret != 0) 2848 return ret; 2849 2850 return wm_adsp2v2_enable_core(dsp); 2851 } 2852 2853 static int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions) 2854 { 2855 struct regmap *regmap = dsp->regmap; 2856 unsigned int code0, code1, lock_reg; 2857 2858 if (!(lock_regions & WM_ADSP2_REGION_ALL)) 2859 return 0; 2860 2861 lock_regions &= WM_ADSP2_REGION_ALL; 2862 lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0; 2863 2864 while (lock_regions) { 2865 code0 = code1 = 0; 2866 if (lock_regions & BIT(0)) { 2867 code0 = ADSP2_LOCK_CODE_0; 2868 code1 = ADSP2_LOCK_CODE_1; 2869 } 2870 if (lock_regions & BIT(1)) { 2871 code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT; 2872 code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT; 2873 } 2874 regmap_write(regmap, lock_reg, code0); 2875 regmap_write(regmap, lock_reg, code1); 2876 lock_regions >>= 2; 2877 lock_reg += 2; 2878 } 2879 2880 return 0; 2881 } 2882 2883 static int wm_adsp2_enable_memory(struct wm_adsp *dsp) 2884 { 2885 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2886 ADSP2_MEM_ENA, ADSP2_MEM_ENA); 2887 } 2888 2889 static void wm_adsp2_disable_memory(struct wm_adsp *dsp) 2890 { 2891 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2892 ADSP2_MEM_ENA, 0); 2893 } 2894 2895 static void wm_adsp2_disable_core(struct wm_adsp *dsp) 2896 { 2897 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); 2898 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); 2899 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); 2900 2901 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2902 ADSP2_SYS_ENA, 0); 2903 } 2904 2905 static void wm_adsp2v2_disable_core(struct wm_adsp *dsp) 2906 { 2907 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); 2908 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); 2909 regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0); 2910 } 2911 2912 static void wm_adsp_boot_work(struct work_struct *work) 2913 { 2914 struct wm_adsp *dsp = container_of(work, 2915 struct wm_adsp, 2916 boot_work); 2917 int ret; 2918 2919 mutex_lock(&dsp->pwr_lock); 2920 2921 if (dsp->ops->enable_memory) { 2922 ret = dsp->ops->enable_memory(dsp); 2923 if (ret != 0) 2924 goto err_mutex; 2925 } 2926 2927 if (dsp->ops->enable_core) { 2928 ret = dsp->ops->enable_core(dsp); 2929 if (ret != 0) 2930 goto err_mem; 2931 } 2932 2933 ret = wm_adsp_load(dsp); 2934 if (ret != 0) 2935 goto err_ena; 2936 2937 ret = dsp->ops->setup_algs(dsp); 2938 if (ret != 0) 2939 goto err_ena; 2940 2941 ret = wm_adsp_load_coeff(dsp); 2942 if (ret != 0) 2943 goto err_ena; 2944 2945 /* Initialize caches for enabled and unset controls */ 2946 ret = wm_coeff_init_control_caches(dsp); 2947 if (ret != 0) 2948 goto err_ena; 2949 2950 if (dsp->ops->disable_core) 2951 dsp->ops->disable_core(dsp); 2952 2953 dsp->booted = true; 2954 2955 mutex_unlock(&dsp->pwr_lock); 2956 2957 return; 2958 2959 err_ena: 2960 if (dsp->ops->disable_core) 2961 dsp->ops->disable_core(dsp); 2962 err_mem: 2963 if (dsp->ops->disable_memory) 2964 dsp->ops->disable_memory(dsp); 2965 err_mutex: 2966 mutex_unlock(&dsp->pwr_lock); 2967 } 2968 2969 static int wm_halo_configure_mpu(struct wm_adsp *dsp, unsigned int lock_regions) 2970 { 2971 struct reg_sequence config[] = { 2972 { dsp->base + HALO_MPU_LOCK_CONFIG, 0x5555 }, 2973 { dsp->base + HALO_MPU_LOCK_CONFIG, 0xAAAA }, 2974 { dsp->base + HALO_MPU_XMEM_ACCESS_0, 0xFFFFFFFF }, 2975 { dsp->base + HALO_MPU_YMEM_ACCESS_0, 0xFFFFFFFF }, 2976 { dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions }, 2977 { dsp->base + HALO_MPU_XREG_ACCESS_0, lock_regions }, 2978 { dsp->base + HALO_MPU_YREG_ACCESS_0, lock_regions }, 2979 { dsp->base + HALO_MPU_XMEM_ACCESS_1, 0xFFFFFFFF }, 2980 { dsp->base + HALO_MPU_YMEM_ACCESS_1, 0xFFFFFFFF }, 2981 { dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions }, 2982 { dsp->base + HALO_MPU_XREG_ACCESS_1, lock_regions }, 2983 { dsp->base + HALO_MPU_YREG_ACCESS_1, lock_regions }, 2984 { dsp->base + HALO_MPU_XMEM_ACCESS_2, 0xFFFFFFFF }, 2985 { dsp->base + HALO_MPU_YMEM_ACCESS_2, 0xFFFFFFFF }, 2986 { dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions }, 2987 { dsp->base + HALO_MPU_XREG_ACCESS_2, lock_regions }, 2988 { dsp->base + HALO_MPU_YREG_ACCESS_2, lock_regions }, 2989 { dsp->base + HALO_MPU_XMEM_ACCESS_3, 0xFFFFFFFF }, 2990 { dsp->base + HALO_MPU_YMEM_ACCESS_3, 0xFFFFFFFF }, 2991 { dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions }, 2992 { dsp->base + HALO_MPU_XREG_ACCESS_3, lock_regions }, 2993 { dsp->base + HALO_MPU_YREG_ACCESS_3, lock_regions }, 2994 { dsp->base + HALO_MPU_LOCK_CONFIG, 0 }, 2995 }; 2996 2997 return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config)); 2998 } 2999 3000 int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq) 3001 { 3002 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 3003 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); 3004 struct wm_adsp *dsp = &dsps[w->shift]; 3005 int ret; 3006 3007 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING, 3008 ADSP2_CLK_SEL_MASK, 3009 freq << ADSP2_CLK_SEL_SHIFT); 3010 if (ret) 3011 adsp_err(dsp, "Failed to set clock rate: %d\n", ret); 3012 3013 return ret; 3014 } 3015 EXPORT_SYMBOL_GPL(wm_adsp2_set_dspclk); 3016 3017 int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol, 3018 struct snd_ctl_elem_value *ucontrol) 3019 { 3020 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 3021 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); 3022 struct soc_mixer_control *mc = 3023 (struct soc_mixer_control *)kcontrol->private_value; 3024 struct wm_adsp *dsp = &dsps[mc->shift - 1]; 3025 3026 ucontrol->value.integer.value[0] = dsp->preloaded; 3027 3028 return 0; 3029 } 3030 EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get); 3031 3032 int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, 3033 struct snd_ctl_elem_value *ucontrol) 3034 { 3035 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 3036 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); 3037 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 3038 struct soc_mixer_control *mc = 3039 (struct soc_mixer_control *)kcontrol->private_value; 3040 struct wm_adsp *dsp = &dsps[mc->shift - 1]; 3041 char preload[32]; 3042 3043 snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name); 3044 3045 dsp->preloaded = ucontrol->value.integer.value[0]; 3046 3047 if (ucontrol->value.integer.value[0]) 3048 snd_soc_component_force_enable_pin(component, preload); 3049 else 3050 snd_soc_component_disable_pin(component, preload); 3051 3052 snd_soc_dapm_sync(dapm); 3053 3054 flush_work(&dsp->boot_work); 3055 3056 return 0; 3057 } 3058 EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); 3059 3060 static void wm_adsp_stop_watchdog(struct wm_adsp *dsp) 3061 { 3062 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG, 3063 ADSP2_WDT_ENA_MASK, 0); 3064 } 3065 3066 static void wm_halo_stop_watchdog(struct wm_adsp *dsp) 3067 { 3068 regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL, 3069 HALO_WDT_EN_MASK, 0); 3070 } 3071 3072 int wm_adsp_early_event(struct snd_soc_dapm_widget *w, 3073 struct snd_kcontrol *kcontrol, int event) 3074 { 3075 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 3076 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); 3077 struct wm_adsp *dsp = &dsps[w->shift]; 3078 struct wm_coeff_ctl *ctl; 3079 3080 switch (event) { 3081 case SND_SOC_DAPM_PRE_PMU: 3082 queue_work(system_unbound_wq, &dsp->boot_work); 3083 break; 3084 case SND_SOC_DAPM_PRE_PMD: 3085 mutex_lock(&dsp->pwr_lock); 3086 3087 wm_adsp_debugfs_clear(dsp); 3088 3089 dsp->fw_id = 0; 3090 dsp->fw_id_version = 0; 3091 3092 dsp->booted = false; 3093 3094 if (dsp->ops->disable_memory) 3095 dsp->ops->disable_memory(dsp); 3096 3097 list_for_each_entry(ctl, &dsp->ctl_list, list) 3098 ctl->enabled = 0; 3099 3100 wm_adsp_free_alg_regions(dsp); 3101 3102 mutex_unlock(&dsp->pwr_lock); 3103 3104 adsp_dbg(dsp, "Shutdown complete\n"); 3105 break; 3106 default: 3107 break; 3108 } 3109 3110 return 0; 3111 } 3112 EXPORT_SYMBOL_GPL(wm_adsp_early_event); 3113 3114 static int wm_adsp2_start_core(struct wm_adsp *dsp) 3115 { 3116 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 3117 ADSP2_CORE_ENA | ADSP2_START, 3118 ADSP2_CORE_ENA | ADSP2_START); 3119 } 3120 3121 static void wm_adsp2_stop_core(struct wm_adsp *dsp) 3122 { 3123 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 3124 ADSP2_CORE_ENA | ADSP2_START, 0); 3125 } 3126 3127 int wm_adsp_event(struct snd_soc_dapm_widget *w, 3128 struct snd_kcontrol *kcontrol, int event) 3129 { 3130 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 3131 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); 3132 struct wm_adsp *dsp = &dsps[w->shift]; 3133 int ret; 3134 3135 switch (event) { 3136 case SND_SOC_DAPM_POST_PMU: 3137 flush_work(&dsp->boot_work); 3138 3139 mutex_lock(&dsp->pwr_lock); 3140 3141 if (!dsp->booted) { 3142 ret = -EIO; 3143 goto err; 3144 } 3145 3146 if (dsp->ops->enable_core) { 3147 ret = dsp->ops->enable_core(dsp); 3148 if (ret != 0) 3149 goto err; 3150 } 3151 3152 /* Sync set controls */ 3153 ret = wm_coeff_sync_controls(dsp); 3154 if (ret != 0) 3155 goto err; 3156 3157 if (dsp->ops->lock_memory) { 3158 ret = dsp->ops->lock_memory(dsp, dsp->lock_regions); 3159 if (ret != 0) { 3160 adsp_err(dsp, "Error configuring MPU: %d\n", 3161 ret); 3162 goto err; 3163 } 3164 } 3165 3166 if (dsp->ops->start_core) { 3167 ret = dsp->ops->start_core(dsp); 3168 if (ret != 0) 3169 goto err; 3170 } 3171 3172 if (wm_adsp_fw[dsp->fw].num_caps != 0) { 3173 ret = wm_adsp_buffer_init(dsp); 3174 if (ret < 0) 3175 goto err; 3176 } 3177 3178 dsp->running = true; 3179 3180 mutex_unlock(&dsp->pwr_lock); 3181 break; 3182 3183 case SND_SOC_DAPM_PRE_PMD: 3184 /* Tell the firmware to cleanup */ 3185 wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN); 3186 3187 if (dsp->ops->stop_watchdog) 3188 dsp->ops->stop_watchdog(dsp); 3189 3190 /* Log firmware state, it can be useful for analysis */ 3191 if (dsp->ops->show_fw_status) 3192 dsp->ops->show_fw_status(dsp); 3193 3194 mutex_lock(&dsp->pwr_lock); 3195 3196 dsp->running = false; 3197 3198 if (dsp->ops->stop_core) 3199 dsp->ops->stop_core(dsp); 3200 if (dsp->ops->disable_core) 3201 dsp->ops->disable_core(dsp); 3202 3203 if (wm_adsp_fw[dsp->fw].num_caps != 0) 3204 wm_adsp_buffer_free(dsp); 3205 3206 dsp->fatal_error = false; 3207 3208 mutex_unlock(&dsp->pwr_lock); 3209 3210 adsp_dbg(dsp, "Execution stopped\n"); 3211 break; 3212 3213 default: 3214 break; 3215 } 3216 3217 return 0; 3218 err: 3219 if (dsp->ops->stop_core) 3220 dsp->ops->stop_core(dsp); 3221 if (dsp->ops->disable_core) 3222 dsp->ops->disable_core(dsp); 3223 mutex_unlock(&dsp->pwr_lock); 3224 return ret; 3225 } 3226 EXPORT_SYMBOL_GPL(wm_adsp_event); 3227 3228 static int wm_halo_start_core(struct wm_adsp *dsp) 3229 { 3230 return regmap_update_bits(dsp->regmap, 3231 dsp->base + HALO_CCM_CORE_CONTROL, 3232 HALO_CORE_EN, HALO_CORE_EN); 3233 } 3234 3235 static void wm_halo_stop_core(struct wm_adsp *dsp) 3236 { 3237 regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, 3238 HALO_CORE_EN, 0); 3239 3240 /* reset halo core with CORE_SOFT_RESET */ 3241 regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET, 3242 HALO_CORE_SOFT_RESET_MASK, 1); 3243 } 3244 3245 int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component) 3246 { 3247 char preload[32]; 3248 3249 snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name); 3250 snd_soc_component_disable_pin(component, preload); 3251 3252 wm_adsp2_init_debugfs(dsp, component); 3253 3254 dsp->component = component; 3255 3256 return 0; 3257 } 3258 EXPORT_SYMBOL_GPL(wm_adsp2_component_probe); 3259 3260 int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component) 3261 { 3262 wm_adsp2_cleanup_debugfs(dsp); 3263 3264 return 0; 3265 } 3266 EXPORT_SYMBOL_GPL(wm_adsp2_component_remove); 3267 3268 int wm_adsp2_init(struct wm_adsp *dsp) 3269 { 3270 int ret; 3271 3272 ret = wm_adsp_common_init(dsp); 3273 if (ret) 3274 return ret; 3275 3276 switch (dsp->rev) { 3277 case 0: 3278 /* 3279 * Disable the DSP memory by default when in reset for a small 3280 * power saving. 3281 */ 3282 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 3283 ADSP2_MEM_ENA, 0); 3284 if (ret) { 3285 adsp_err(dsp, 3286 "Failed to clear memory retention: %d\n", ret); 3287 return ret; 3288 } 3289 3290 dsp->ops = &wm_adsp2_ops[0]; 3291 break; 3292 case 1: 3293 dsp->ops = &wm_adsp2_ops[1]; 3294 break; 3295 default: 3296 dsp->ops = &wm_adsp2_ops[2]; 3297 break; 3298 } 3299 3300 INIT_WORK(&dsp->boot_work, wm_adsp_boot_work); 3301 3302 return 0; 3303 } 3304 EXPORT_SYMBOL_GPL(wm_adsp2_init); 3305 3306 int wm_halo_init(struct wm_adsp *dsp) 3307 { 3308 int ret; 3309 3310 ret = wm_adsp_common_init(dsp); 3311 if (ret) 3312 return ret; 3313 3314 dsp->ops = &wm_halo_ops; 3315 3316 INIT_WORK(&dsp->boot_work, wm_adsp_boot_work); 3317 3318 return 0; 3319 } 3320 EXPORT_SYMBOL_GPL(wm_halo_init); 3321 3322 void wm_adsp2_remove(struct wm_adsp *dsp) 3323 { 3324 struct wm_coeff_ctl *ctl; 3325 3326 while (!list_empty(&dsp->ctl_list)) { 3327 ctl = list_first_entry(&dsp->ctl_list, struct wm_coeff_ctl, 3328 list); 3329 list_del(&ctl->list); 3330 wm_adsp_free_ctl_blk(ctl); 3331 } 3332 } 3333 EXPORT_SYMBOL_GPL(wm_adsp2_remove); 3334 3335 static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr) 3336 { 3337 return compr->buf != NULL; 3338 } 3339 3340 static int wm_adsp_compr_attach(struct wm_adsp_compr *compr) 3341 { 3342 struct wm_adsp_compr_buf *buf = NULL, *tmp; 3343 3344 if (compr->dsp->fatal_error) 3345 return -EINVAL; 3346 3347 list_for_each_entry(tmp, &compr->dsp->buffer_list, list) { 3348 if (!tmp->name || !strcmp(compr->name, tmp->name)) { 3349 buf = tmp; 3350 break; 3351 } 3352 } 3353 3354 if (!buf) 3355 return -EINVAL; 3356 3357 compr->buf = buf; 3358 buf->compr = compr; 3359 3360 return 0; 3361 } 3362 3363 static void wm_adsp_compr_detach(struct wm_adsp_compr *compr) 3364 { 3365 if (!compr) 3366 return; 3367 3368 /* Wake the poll so it can see buffer is no longer attached */ 3369 if (compr->stream) 3370 snd_compr_fragment_elapsed(compr->stream); 3371 3372 if (wm_adsp_compr_attached(compr)) { 3373 compr->buf->compr = NULL; 3374 compr->buf = NULL; 3375 } 3376 } 3377 3378 int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) 3379 { 3380 struct wm_adsp_compr *compr, *tmp; 3381 struct snd_soc_pcm_runtime *rtd = stream->private_data; 3382 int ret = 0; 3383 3384 mutex_lock(&dsp->pwr_lock); 3385 3386 if (wm_adsp_fw[dsp->fw].num_caps == 0) { 3387 adsp_err(dsp, "%s: Firmware does not support compressed API\n", 3388 rtd->codec_dai->name); 3389 ret = -ENXIO; 3390 goto out; 3391 } 3392 3393 if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) { 3394 adsp_err(dsp, "%s: Firmware does not support stream direction\n", 3395 rtd->codec_dai->name); 3396 ret = -EINVAL; 3397 goto out; 3398 } 3399 3400 list_for_each_entry(tmp, &dsp->compr_list, list) { 3401 if (!strcmp(tmp->name, rtd->codec_dai->name)) { 3402 adsp_err(dsp, "%s: Only a single stream supported per dai\n", 3403 rtd->codec_dai->name); 3404 ret = -EBUSY; 3405 goto out; 3406 } 3407 } 3408 3409 compr = kzalloc(sizeof(*compr), GFP_KERNEL); 3410 if (!compr) { 3411 ret = -ENOMEM; 3412 goto out; 3413 } 3414 3415 compr->dsp = dsp; 3416 compr->stream = stream; 3417 compr->name = rtd->codec_dai->name; 3418 3419 list_add_tail(&compr->list, &dsp->compr_list); 3420 3421 stream->runtime->private_data = compr; 3422 3423 out: 3424 mutex_unlock(&dsp->pwr_lock); 3425 3426 return ret; 3427 } 3428 EXPORT_SYMBOL_GPL(wm_adsp_compr_open); 3429 3430 int wm_adsp_compr_free(struct snd_compr_stream *stream) 3431 { 3432 struct wm_adsp_compr *compr = stream->runtime->private_data; 3433 struct wm_adsp *dsp = compr->dsp; 3434 3435 mutex_lock(&dsp->pwr_lock); 3436 3437 wm_adsp_compr_detach(compr); 3438 list_del(&compr->list); 3439 3440 kfree(compr->raw_buf); 3441 kfree(compr); 3442 3443 mutex_unlock(&dsp->pwr_lock); 3444 3445 return 0; 3446 } 3447 EXPORT_SYMBOL_GPL(wm_adsp_compr_free); 3448 3449 static int wm_adsp_compr_check_params(struct snd_compr_stream *stream, 3450 struct snd_compr_params *params) 3451 { 3452 struct wm_adsp_compr *compr = stream->runtime->private_data; 3453 struct wm_adsp *dsp = compr->dsp; 3454 const struct wm_adsp_fw_caps *caps; 3455 const struct snd_codec_desc *desc; 3456 int i, j; 3457 3458 if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE || 3459 params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE || 3460 params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS || 3461 params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS || 3462 params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) { 3463 compr_err(compr, "Invalid buffer fragsize=%d fragments=%d\n", 3464 params->buffer.fragment_size, 3465 params->buffer.fragments); 3466 3467 return -EINVAL; 3468 } 3469 3470 for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) { 3471 caps = &wm_adsp_fw[dsp->fw].caps[i]; 3472 desc = &caps->desc; 3473 3474 if (caps->id != params->codec.id) 3475 continue; 3476 3477 if (stream->direction == SND_COMPRESS_PLAYBACK) { 3478 if (desc->max_ch < params->codec.ch_out) 3479 continue; 3480 } else { 3481 if (desc->max_ch < params->codec.ch_in) 3482 continue; 3483 } 3484 3485 if (!(desc->formats & (1 << params->codec.format))) 3486 continue; 3487 3488 for (j = 0; j < desc->num_sample_rates; ++j) 3489 if (desc->sample_rates[j] == params->codec.sample_rate) 3490 return 0; 3491 } 3492 3493 compr_err(compr, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n", 3494 params->codec.id, params->codec.ch_in, params->codec.ch_out, 3495 params->codec.sample_rate, params->codec.format); 3496 return -EINVAL; 3497 } 3498 3499 static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr) 3500 { 3501 return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE; 3502 } 3503 3504 int wm_adsp_compr_set_params(struct snd_compr_stream *stream, 3505 struct snd_compr_params *params) 3506 { 3507 struct wm_adsp_compr *compr = stream->runtime->private_data; 3508 unsigned int size; 3509 int ret; 3510 3511 ret = wm_adsp_compr_check_params(stream, params); 3512 if (ret) 3513 return ret; 3514 3515 compr->size = params->buffer; 3516 3517 compr_dbg(compr, "fragment_size=%d fragments=%d\n", 3518 compr->size.fragment_size, compr->size.fragments); 3519 3520 size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf); 3521 compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL); 3522 if (!compr->raw_buf) 3523 return -ENOMEM; 3524 3525 compr->sample_rate = params->codec.sample_rate; 3526 3527 return 0; 3528 } 3529 EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params); 3530 3531 int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, 3532 struct snd_compr_caps *caps) 3533 { 3534 struct wm_adsp_compr *compr = stream->runtime->private_data; 3535 int fw = compr->dsp->fw; 3536 int i; 3537 3538 if (wm_adsp_fw[fw].caps) { 3539 for (i = 0; i < wm_adsp_fw[fw].num_caps; i++) 3540 caps->codecs[i] = wm_adsp_fw[fw].caps[i].id; 3541 3542 caps->num_codecs = i; 3543 caps->direction = wm_adsp_fw[fw].compr_direction; 3544 3545 caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE; 3546 caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE; 3547 caps->min_fragments = WM_ADSP_MIN_FRAGMENTS; 3548 caps->max_fragments = WM_ADSP_MAX_FRAGMENTS; 3549 } 3550 3551 return 0; 3552 } 3553 EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps); 3554 3555 static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type, 3556 unsigned int mem_addr, 3557 unsigned int num_words, u32 *data) 3558 { 3559 struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type); 3560 unsigned int i, reg; 3561 int ret; 3562 3563 if (!mem) 3564 return -EINVAL; 3565 3566 reg = dsp->ops->region_to_reg(mem, mem_addr); 3567 3568 ret = regmap_raw_read(dsp->regmap, reg, data, 3569 sizeof(*data) * num_words); 3570 if (ret < 0) 3571 return ret; 3572 3573 for (i = 0; i < num_words; ++i) 3574 data[i] = be32_to_cpu(data[i]) & 0x00ffffffu; 3575 3576 return 0; 3577 } 3578 3579 static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type, 3580 unsigned int mem_addr, u32 *data) 3581 { 3582 return wm_adsp_read_data_block(dsp, mem_type, mem_addr, 1, data); 3583 } 3584 3585 static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type, 3586 unsigned int mem_addr, u32 data) 3587 { 3588 struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type); 3589 unsigned int reg; 3590 3591 if (!mem) 3592 return -EINVAL; 3593 3594 reg = dsp->ops->region_to_reg(mem, mem_addr); 3595 3596 data = cpu_to_be32(data & 0x00ffffffu); 3597 3598 return regmap_raw_write(dsp->regmap, reg, &data, sizeof(data)); 3599 } 3600 3601 static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf, 3602 unsigned int field_offset, u32 *data) 3603 { 3604 return wm_adsp_read_data_word(buf->dsp, buf->host_buf_mem_type, 3605 buf->host_buf_ptr + field_offset, data); 3606 } 3607 3608 static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf, 3609 unsigned int field_offset, u32 data) 3610 { 3611 return wm_adsp_write_data_word(buf->dsp, buf->host_buf_mem_type, 3612 buf->host_buf_ptr + field_offset, data); 3613 } 3614 3615 static void wm_adsp_remove_padding(u32 *buf, int nwords, int data_word_size) 3616 { 3617 u8 *pack_in = (u8 *)buf; 3618 u8 *pack_out = (u8 *)buf; 3619 int i, j; 3620 3621 /* Remove the padding bytes from the data read from the DSP */ 3622 for (i = 0; i < nwords; i++) { 3623 for (j = 0; j < data_word_size; j++) 3624 *pack_out++ = *pack_in++; 3625 3626 pack_in += sizeof(*buf) - data_word_size; 3627 } 3628 } 3629 3630 static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf) 3631 { 3632 const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps; 3633 struct wm_adsp_buffer_region *region; 3634 u32 offset = 0; 3635 int i, ret; 3636 3637 buf->regions = kcalloc(caps->num_regions, sizeof(*buf->regions), 3638 GFP_KERNEL); 3639 if (!buf->regions) 3640 return -ENOMEM; 3641 3642 for (i = 0; i < caps->num_regions; ++i) { 3643 region = &buf->regions[i]; 3644 3645 region->offset = offset; 3646 region->mem_type = caps->region_defs[i].mem_type; 3647 3648 ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset, 3649 ®ion->base_addr); 3650 if (ret < 0) 3651 return ret; 3652 3653 ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset, 3654 &offset); 3655 if (ret < 0) 3656 return ret; 3657 3658 region->cumulative_size = offset; 3659 3660 compr_dbg(buf, 3661 "region=%d type=%d base=%08x off=%08x size=%08x\n", 3662 i, region->mem_type, region->base_addr, 3663 region->offset, region->cumulative_size); 3664 } 3665 3666 return 0; 3667 } 3668 3669 static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf) 3670 { 3671 buf->irq_count = 0xFFFFFFFF; 3672 buf->read_index = -1; 3673 buf->avail = 0; 3674 } 3675 3676 static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp) 3677 { 3678 struct wm_adsp_compr_buf *buf; 3679 3680 buf = kzalloc(sizeof(*buf), GFP_KERNEL); 3681 if (!buf) 3682 return NULL; 3683 3684 buf->dsp = dsp; 3685 3686 wm_adsp_buffer_clear(buf); 3687 3688 list_add_tail(&buf->list, &dsp->buffer_list); 3689 3690 return buf; 3691 } 3692 3693 static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) 3694 { 3695 struct wm_adsp_alg_region *alg_region; 3696 struct wm_adsp_compr_buf *buf; 3697 u32 xmalg, addr, magic; 3698 int i, ret; 3699 3700 buf = wm_adsp_buffer_alloc(dsp); 3701 if (!buf) 3702 return -ENOMEM; 3703 3704 alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id); 3705 xmalg = dsp->ops->sys_config_size / sizeof(__be32); 3706 3707 addr = alg_region->base + xmalg + ALG_XM_FIELD(magic); 3708 ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic); 3709 if (ret < 0) 3710 return ret; 3711 3712 if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC) 3713 return -ENODEV; 3714 3715 addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr); 3716 for (i = 0; i < 5; ++i) { 3717 ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, 3718 &buf->host_buf_ptr); 3719 if (ret < 0) 3720 return ret; 3721 3722 if (buf->host_buf_ptr) 3723 break; 3724 3725 usleep_range(1000, 2000); 3726 } 3727 3728 if (!buf->host_buf_ptr) 3729 return -EIO; 3730 3731 buf->host_buf_mem_type = WMFW_ADSP2_XM; 3732 3733 ret = wm_adsp_buffer_populate(buf); 3734 if (ret < 0) 3735 return ret; 3736 3737 compr_dbg(buf, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr); 3738 3739 return 0; 3740 } 3741 3742 static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) 3743 { 3744 struct wm_adsp_host_buf_coeff_v1 coeff_v1; 3745 struct wm_adsp_compr_buf *buf; 3746 unsigned int val, reg; 3747 int ret, i; 3748 3749 ret = wm_coeff_base_reg(ctl, ®); 3750 if (ret) 3751 return ret; 3752 3753 for (i = 0; i < 5; ++i) { 3754 ret = regmap_raw_read(ctl->dsp->regmap, reg, &val, sizeof(val)); 3755 if (ret < 0) 3756 return ret; 3757 3758 if (val) 3759 break; 3760 3761 usleep_range(1000, 2000); 3762 } 3763 3764 if (!val) { 3765 adsp_err(ctl->dsp, "Failed to acquire host buffer\n"); 3766 return -EIO; 3767 } 3768 3769 buf = wm_adsp_buffer_alloc(ctl->dsp); 3770 if (!buf) 3771 return -ENOMEM; 3772 3773 buf->host_buf_mem_type = ctl->alg_region.type; 3774 buf->host_buf_ptr = be32_to_cpu(val); 3775 3776 ret = wm_adsp_buffer_populate(buf); 3777 if (ret < 0) 3778 return ret; 3779 3780 /* 3781 * v0 host_buffer coefficients didn't have versioning, so if the 3782 * control is one word, assume version 0. 3783 */ 3784 if (ctl->len == 4) { 3785 compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr); 3786 return 0; 3787 } 3788 3789 ret = regmap_raw_read(ctl->dsp->regmap, reg, &coeff_v1, 3790 sizeof(coeff_v1)); 3791 if (ret < 0) 3792 return ret; 3793 3794 coeff_v1.versions = be32_to_cpu(coeff_v1.versions); 3795 val = coeff_v1.versions & HOST_BUF_COEFF_COMPAT_VER_MASK; 3796 val >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT; 3797 3798 if (val > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) { 3799 adsp_err(ctl->dsp, 3800 "Host buffer coeff ver %u > supported version %u\n", 3801 val, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER); 3802 return -EINVAL; 3803 } 3804 3805 for (i = 0; i < ARRAY_SIZE(coeff_v1.name); i++) 3806 coeff_v1.name[i] = be32_to_cpu(coeff_v1.name[i]); 3807 3808 wm_adsp_remove_padding((u32 *)&coeff_v1.name, 3809 ARRAY_SIZE(coeff_v1.name), 3810 WM_ADSP_DATA_WORD_SIZE); 3811 3812 buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part, 3813 (char *)&coeff_v1.name); 3814 3815 compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n", 3816 buf->host_buf_ptr, val); 3817 3818 return val; 3819 } 3820 3821 static int wm_adsp_buffer_init(struct wm_adsp *dsp) 3822 { 3823 struct wm_coeff_ctl *ctl; 3824 int ret; 3825 3826 list_for_each_entry(ctl, &dsp->ctl_list, list) { 3827 if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER) 3828 continue; 3829 3830 if (!ctl->enabled) 3831 continue; 3832 3833 ret = wm_adsp_buffer_parse_coeff(ctl); 3834 if (ret < 0) { 3835 adsp_err(dsp, "Failed to parse coeff: %d\n", ret); 3836 goto error; 3837 } else if (ret == 0) { 3838 /* Only one buffer supported for version 0 */ 3839 return 0; 3840 } 3841 } 3842 3843 if (list_empty(&dsp->buffer_list)) { 3844 /* Fall back to legacy support */ 3845 ret = wm_adsp_buffer_parse_legacy(dsp); 3846 if (ret) { 3847 adsp_err(dsp, "Failed to parse legacy: %d\n", ret); 3848 goto error; 3849 } 3850 } 3851 3852 return 0; 3853 3854 error: 3855 wm_adsp_buffer_free(dsp); 3856 return ret; 3857 } 3858 3859 static int wm_adsp_buffer_free(struct wm_adsp *dsp) 3860 { 3861 struct wm_adsp_compr_buf *buf, *tmp; 3862 3863 list_for_each_entry_safe(buf, tmp, &dsp->buffer_list, list) { 3864 wm_adsp_compr_detach(buf->compr); 3865 3866 kfree(buf->name); 3867 kfree(buf->regions); 3868 list_del(&buf->list); 3869 kfree(buf); 3870 } 3871 3872 return 0; 3873 } 3874 3875 static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf) 3876 { 3877 int ret; 3878 3879 ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); 3880 if (ret < 0) { 3881 compr_err(buf, "Failed to check buffer error: %d\n", ret); 3882 return ret; 3883 } 3884 if (buf->error != 0) { 3885 compr_err(buf, "Buffer error occurred: %d\n", buf->error); 3886 return -EIO; 3887 } 3888 3889 return 0; 3890 } 3891 3892 int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) 3893 { 3894 struct wm_adsp_compr *compr = stream->runtime->private_data; 3895 struct wm_adsp *dsp = compr->dsp; 3896 int ret = 0; 3897 3898 compr_dbg(compr, "Trigger: %d\n", cmd); 3899 3900 mutex_lock(&dsp->pwr_lock); 3901 3902 switch (cmd) { 3903 case SNDRV_PCM_TRIGGER_START: 3904 if (!wm_adsp_compr_attached(compr)) { 3905 ret = wm_adsp_compr_attach(compr); 3906 if (ret < 0) { 3907 compr_err(compr, "Failed to link buffer and stream: %d\n", 3908 ret); 3909 break; 3910 } 3911 } 3912 3913 ret = wm_adsp_buffer_get_error(compr->buf); 3914 if (ret < 0) 3915 break; 3916 3917 /* Trigger the IRQ at one fragment of data */ 3918 ret = wm_adsp_buffer_write(compr->buf, 3919 HOST_BUFFER_FIELD(high_water_mark), 3920 wm_adsp_compr_frag_words(compr)); 3921 if (ret < 0) { 3922 compr_err(compr, "Failed to set high water mark: %d\n", 3923 ret); 3924 break; 3925 } 3926 break; 3927 case SNDRV_PCM_TRIGGER_STOP: 3928 if (wm_adsp_compr_attached(compr)) 3929 wm_adsp_buffer_clear(compr->buf); 3930 break; 3931 default: 3932 ret = -EINVAL; 3933 break; 3934 } 3935 3936 mutex_unlock(&dsp->pwr_lock); 3937 3938 return ret; 3939 } 3940 EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger); 3941 3942 static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf) 3943 { 3944 int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1; 3945 3946 return buf->regions[last_region].cumulative_size; 3947 } 3948 3949 static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf) 3950 { 3951 u32 next_read_index, next_write_index; 3952 int write_index, read_index, avail; 3953 int ret; 3954 3955 /* Only sync read index if we haven't already read a valid index */ 3956 if (buf->read_index < 0) { 3957 ret = wm_adsp_buffer_read(buf, 3958 HOST_BUFFER_FIELD(next_read_index), 3959 &next_read_index); 3960 if (ret < 0) 3961 return ret; 3962 3963 read_index = sign_extend32(next_read_index, 23); 3964 3965 if (read_index < 0) { 3966 compr_dbg(buf, "Avail check on unstarted stream\n"); 3967 return 0; 3968 } 3969 3970 buf->read_index = read_index; 3971 } 3972 3973 ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index), 3974 &next_write_index); 3975 if (ret < 0) 3976 return ret; 3977 3978 write_index = sign_extend32(next_write_index, 23); 3979 3980 avail = write_index - buf->read_index; 3981 if (avail < 0) 3982 avail += wm_adsp_buffer_size(buf); 3983 3984 compr_dbg(buf, "readindex=0x%x, writeindex=0x%x, avail=%d\n", 3985 buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE); 3986 3987 buf->avail = avail; 3988 3989 return 0; 3990 } 3991 3992 int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) 3993 { 3994 struct wm_adsp_compr_buf *buf; 3995 struct wm_adsp_compr *compr; 3996 int ret = 0; 3997 3998 mutex_lock(&dsp->pwr_lock); 3999 4000 if (list_empty(&dsp->buffer_list)) { 4001 ret = -ENODEV; 4002 goto out; 4003 } 4004 4005 adsp_dbg(dsp, "Handling buffer IRQ\n"); 4006 4007 list_for_each_entry(buf, &dsp->buffer_list, list) { 4008 compr = buf->compr; 4009 4010 ret = wm_adsp_buffer_get_error(buf); 4011 if (ret < 0) 4012 goto out_notify; /* Wake poll to report error */ 4013 4014 ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), 4015 &buf->irq_count); 4016 if (ret < 0) { 4017 compr_err(buf, "Failed to get irq_count: %d\n", ret); 4018 goto out; 4019 } 4020 4021 ret = wm_adsp_buffer_update_avail(buf); 4022 if (ret < 0) { 4023 compr_err(buf, "Error reading avail: %d\n", ret); 4024 goto out; 4025 } 4026 4027 if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2) 4028 ret = WM_ADSP_COMPR_VOICE_TRIGGER; 4029 4030 out_notify: 4031 if (compr && compr->stream) 4032 snd_compr_fragment_elapsed(compr->stream); 4033 } 4034 4035 out: 4036 mutex_unlock(&dsp->pwr_lock); 4037 4038 return ret; 4039 } 4040 EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq); 4041 4042 static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf) 4043 { 4044 if (buf->irq_count & 0x01) 4045 return 0; 4046 4047 compr_dbg(buf, "Enable IRQ(0x%x) for next fragment\n", buf->irq_count); 4048 4049 buf->irq_count |= 0x01; 4050 4051 return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack), 4052 buf->irq_count); 4053 } 4054 4055 int wm_adsp_compr_pointer(struct snd_compr_stream *stream, 4056 struct snd_compr_tstamp *tstamp) 4057 { 4058 struct wm_adsp_compr *compr = stream->runtime->private_data; 4059 struct wm_adsp *dsp = compr->dsp; 4060 struct wm_adsp_compr_buf *buf; 4061 int ret = 0; 4062 4063 compr_dbg(compr, "Pointer request\n"); 4064 4065 mutex_lock(&dsp->pwr_lock); 4066 4067 buf = compr->buf; 4068 4069 if (dsp->fatal_error || !buf || buf->error) { 4070 snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN); 4071 ret = -EIO; 4072 goto out; 4073 } 4074 4075 if (buf->avail < wm_adsp_compr_frag_words(compr)) { 4076 ret = wm_adsp_buffer_update_avail(buf); 4077 if (ret < 0) { 4078 compr_err(compr, "Error reading avail: %d\n", ret); 4079 goto out; 4080 } 4081 4082 /* 4083 * If we really have less than 1 fragment available tell the 4084 * DSP to inform us once a whole fragment is available. 4085 */ 4086 if (buf->avail < wm_adsp_compr_frag_words(compr)) { 4087 ret = wm_adsp_buffer_get_error(buf); 4088 if (ret < 0) { 4089 if (buf->error) 4090 snd_compr_stop_error(stream, 4091 SNDRV_PCM_STATE_XRUN); 4092 goto out; 4093 } 4094 4095 ret = wm_adsp_buffer_reenable_irq(buf); 4096 if (ret < 0) { 4097 compr_err(compr, "Failed to re-enable buffer IRQ: %d\n", 4098 ret); 4099 goto out; 4100 } 4101 } 4102 } 4103 4104 tstamp->copied_total = compr->copied_total; 4105 tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE; 4106 tstamp->sampling_rate = compr->sample_rate; 4107 4108 out: 4109 mutex_unlock(&dsp->pwr_lock); 4110 4111 return ret; 4112 } 4113 EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer); 4114 4115 static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target) 4116 { 4117 struct wm_adsp_compr_buf *buf = compr->buf; 4118 unsigned int adsp_addr; 4119 int mem_type, nwords, max_read; 4120 int i, ret; 4121 4122 /* Calculate read parameters */ 4123 for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i) 4124 if (buf->read_index < buf->regions[i].cumulative_size) 4125 break; 4126 4127 if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions) 4128 return -EINVAL; 4129 4130 mem_type = buf->regions[i].mem_type; 4131 adsp_addr = buf->regions[i].base_addr + 4132 (buf->read_index - buf->regions[i].offset); 4133 4134 max_read = wm_adsp_compr_frag_words(compr); 4135 nwords = buf->regions[i].cumulative_size - buf->read_index; 4136 4137 if (nwords > target) 4138 nwords = target; 4139 if (nwords > buf->avail) 4140 nwords = buf->avail; 4141 if (nwords > max_read) 4142 nwords = max_read; 4143 if (!nwords) 4144 return 0; 4145 4146 /* Read data from DSP */ 4147 ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr, 4148 nwords, compr->raw_buf); 4149 if (ret < 0) 4150 return ret; 4151 4152 wm_adsp_remove_padding(compr->raw_buf, nwords, WM_ADSP_DATA_WORD_SIZE); 4153 4154 /* update read index to account for words read */ 4155 buf->read_index += nwords; 4156 if (buf->read_index == wm_adsp_buffer_size(buf)) 4157 buf->read_index = 0; 4158 4159 ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index), 4160 buf->read_index); 4161 if (ret < 0) 4162 return ret; 4163 4164 /* update avail to account for words read */ 4165 buf->avail -= nwords; 4166 4167 return nwords; 4168 } 4169 4170 static int wm_adsp_compr_read(struct wm_adsp_compr *compr, 4171 char __user *buf, size_t count) 4172 { 4173 struct wm_adsp *dsp = compr->dsp; 4174 int ntotal = 0; 4175 int nwords, nbytes; 4176 4177 compr_dbg(compr, "Requested read of %zu bytes\n", count); 4178 4179 if (dsp->fatal_error || !compr->buf || compr->buf->error) { 4180 snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN); 4181 return -EIO; 4182 } 4183 4184 count /= WM_ADSP_DATA_WORD_SIZE; 4185 4186 do { 4187 nwords = wm_adsp_buffer_capture_block(compr, count); 4188 if (nwords < 0) { 4189 compr_err(compr, "Failed to capture block: %d\n", 4190 nwords); 4191 return nwords; 4192 } 4193 4194 nbytes = nwords * WM_ADSP_DATA_WORD_SIZE; 4195 4196 compr_dbg(compr, "Read %d bytes\n", nbytes); 4197 4198 if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) { 4199 compr_err(compr, "Failed to copy data to user: %d, %d\n", 4200 ntotal, nbytes); 4201 return -EFAULT; 4202 } 4203 4204 count -= nwords; 4205 ntotal += nbytes; 4206 } while (nwords > 0 && count > 0); 4207 4208 compr->copied_total += ntotal; 4209 4210 return ntotal; 4211 } 4212 4213 int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf, 4214 size_t count) 4215 { 4216 struct wm_adsp_compr *compr = stream->runtime->private_data; 4217 struct wm_adsp *dsp = compr->dsp; 4218 int ret; 4219 4220 mutex_lock(&dsp->pwr_lock); 4221 4222 if (stream->direction == SND_COMPRESS_CAPTURE) 4223 ret = wm_adsp_compr_read(compr, buf, count); 4224 else 4225 ret = -ENOTSUPP; 4226 4227 mutex_unlock(&dsp->pwr_lock); 4228 4229 return ret; 4230 } 4231 EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); 4232 4233 static void wm_adsp_fatal_error(struct wm_adsp *dsp) 4234 { 4235 struct wm_adsp_compr *compr; 4236 4237 dsp->fatal_error = true; 4238 4239 list_for_each_entry(compr, &dsp->compr_list, list) { 4240 if (compr->stream) 4241 snd_compr_fragment_elapsed(compr->stream); 4242 } 4243 } 4244 4245 irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp) 4246 { 4247 unsigned int val; 4248 struct regmap *regmap = dsp->regmap; 4249 int ret = 0; 4250 4251 mutex_lock(&dsp->pwr_lock); 4252 4253 ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val); 4254 if (ret) { 4255 adsp_err(dsp, 4256 "Failed to read Region Lock Ctrl register: %d\n", ret); 4257 goto error; 4258 } 4259 4260 if (val & ADSP2_WDT_TIMEOUT_STS_MASK) { 4261 adsp_err(dsp, "watchdog timeout error\n"); 4262 dsp->ops->stop_watchdog(dsp); 4263 wm_adsp_fatal_error(dsp); 4264 } 4265 4266 if (val & (ADSP2_SLAVE_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) { 4267 if (val & ADSP2_SLAVE_ERR_MASK) 4268 adsp_err(dsp, "bus error: slave error\n"); 4269 else 4270 adsp_err(dsp, "bus error: region lock error\n"); 4271 4272 ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val); 4273 if (ret) { 4274 adsp_err(dsp, 4275 "Failed to read Bus Err Addr register: %d\n", 4276 ret); 4277 goto error; 4278 } 4279 4280 adsp_err(dsp, "bus error address = 0x%x\n", 4281 val & ADSP2_BUS_ERR_ADDR_MASK); 4282 4283 ret = regmap_read(regmap, 4284 dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR, 4285 &val); 4286 if (ret) { 4287 adsp_err(dsp, 4288 "Failed to read Pmem Xmem Err Addr register: %d\n", 4289 ret); 4290 goto error; 4291 } 4292 4293 adsp_err(dsp, "xmem error address = 0x%x\n", 4294 val & ADSP2_XMEM_ERR_ADDR_MASK); 4295 adsp_err(dsp, "pmem error address = 0x%x\n", 4296 (val & ADSP2_PMEM_ERR_ADDR_MASK) >> 4297 ADSP2_PMEM_ERR_ADDR_SHIFT); 4298 } 4299 4300 regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, 4301 ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT); 4302 4303 error: 4304 mutex_unlock(&dsp->pwr_lock); 4305 4306 return IRQ_HANDLED; 4307 } 4308 EXPORT_SYMBOL_GPL(wm_adsp2_bus_error); 4309 4310 irqreturn_t wm_halo_bus_error(struct wm_adsp *dsp) 4311 { 4312 struct regmap *regmap = dsp->regmap; 4313 unsigned int fault[6]; 4314 struct reg_sequence clear[] = { 4315 { dsp->base + HALO_MPU_XM_VIO_STATUS, 0x0 }, 4316 { dsp->base + HALO_MPU_YM_VIO_STATUS, 0x0 }, 4317 { dsp->base + HALO_MPU_PM_VIO_STATUS, 0x0 }, 4318 }; 4319 int ret; 4320 4321 mutex_lock(&dsp->pwr_lock); 4322 4323 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1, 4324 fault); 4325 if (ret) { 4326 adsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret); 4327 goto exit_unlock; 4328 } 4329 4330 adsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n", 4331 *fault & HALO_AHBM_FLAGS_ERR_MASK, 4332 (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >> 4333 HALO_AHBM_CORE_ERR_ADDR_SHIFT); 4334 4335 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0, 4336 fault); 4337 if (ret) { 4338 adsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret); 4339 goto exit_unlock; 4340 } 4341 4342 adsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault); 4343 4344 ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR, 4345 fault, ARRAY_SIZE(fault)); 4346 if (ret) { 4347 adsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret); 4348 goto exit_unlock; 4349 } 4350 4351 adsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]); 4352 adsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]); 4353 adsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]); 4354 4355 ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear)); 4356 if (ret) 4357 adsp_warn(dsp, "Failed to clear MPU status: %d\n", ret); 4358 4359 exit_unlock: 4360 mutex_unlock(&dsp->pwr_lock); 4361 4362 return IRQ_HANDLED; 4363 } 4364 EXPORT_SYMBOL_GPL(wm_halo_bus_error); 4365 4366 irqreturn_t wm_halo_wdt_expire(int irq, void *data) 4367 { 4368 struct wm_adsp *dsp = data; 4369 4370 mutex_lock(&dsp->pwr_lock); 4371 4372 adsp_warn(dsp, "WDT Expiry Fault\n"); 4373 dsp->ops->stop_watchdog(dsp); 4374 wm_adsp_fatal_error(dsp); 4375 4376 mutex_unlock(&dsp->pwr_lock); 4377 4378 return IRQ_HANDLED; 4379 } 4380 EXPORT_SYMBOL_GPL(wm_halo_wdt_expire); 4381 4382 static struct wm_adsp_ops wm_adsp1_ops = { 4383 .validate_version = wm_adsp_validate_version, 4384 .parse_sizes = wm_adsp1_parse_sizes, 4385 .region_to_reg = wm_adsp_region_to_reg, 4386 }; 4387 4388 static struct wm_adsp_ops wm_adsp2_ops[] = { 4389 { 4390 .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr), 4391 .parse_sizes = wm_adsp2_parse_sizes, 4392 .validate_version = wm_adsp_validate_version, 4393 .setup_algs = wm_adsp2_setup_algs, 4394 .region_to_reg = wm_adsp_region_to_reg, 4395 4396 .show_fw_status = wm_adsp2_show_fw_status, 4397 4398 .enable_memory = wm_adsp2_enable_memory, 4399 .disable_memory = wm_adsp2_disable_memory, 4400 4401 .enable_core = wm_adsp2_enable_core, 4402 .disable_core = wm_adsp2_disable_core, 4403 4404 .start_core = wm_adsp2_start_core, 4405 .stop_core = wm_adsp2_stop_core, 4406 4407 }, 4408 { 4409 .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr), 4410 .parse_sizes = wm_adsp2_parse_sizes, 4411 .validate_version = wm_adsp_validate_version, 4412 .setup_algs = wm_adsp2_setup_algs, 4413 .region_to_reg = wm_adsp_region_to_reg, 4414 4415 .show_fw_status = wm_adsp2v2_show_fw_status, 4416 4417 .enable_memory = wm_adsp2_enable_memory, 4418 .disable_memory = wm_adsp2_disable_memory, 4419 .lock_memory = wm_adsp2_lock, 4420 4421 .enable_core = wm_adsp2v2_enable_core, 4422 .disable_core = wm_adsp2v2_disable_core, 4423 4424 .start_core = wm_adsp2_start_core, 4425 .stop_core = wm_adsp2_stop_core, 4426 }, 4427 { 4428 .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr), 4429 .parse_sizes = wm_adsp2_parse_sizes, 4430 .validate_version = wm_adsp_validate_version, 4431 .setup_algs = wm_adsp2_setup_algs, 4432 .region_to_reg = wm_adsp_region_to_reg, 4433 4434 .show_fw_status = wm_adsp2v2_show_fw_status, 4435 .stop_watchdog = wm_adsp_stop_watchdog, 4436 4437 .enable_memory = wm_adsp2_enable_memory, 4438 .disable_memory = wm_adsp2_disable_memory, 4439 .lock_memory = wm_adsp2_lock, 4440 4441 .enable_core = wm_adsp2v2_enable_core, 4442 .disable_core = wm_adsp2v2_disable_core, 4443 4444 .start_core = wm_adsp2_start_core, 4445 .stop_core = wm_adsp2_stop_core, 4446 }, 4447 }; 4448 4449 static struct wm_adsp_ops wm_halo_ops = { 4450 .sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr), 4451 .parse_sizes = wm_adsp2_parse_sizes, 4452 .validate_version = wm_halo_validate_version, 4453 .setup_algs = wm_halo_setup_algs, 4454 .region_to_reg = wm_halo_region_to_reg, 4455 4456 .show_fw_status = wm_halo_show_fw_status, 4457 .stop_watchdog = wm_halo_stop_watchdog, 4458 4459 .lock_memory = wm_halo_configure_mpu, 4460 4461 .start_core = wm_halo_start_core, 4462 .stop_core = wm_halo_stop_core, 4463 }; 4464 4465 MODULE_LICENSE("GPL v2"); 4466