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