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