cs_dsp.c (84252B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * cs_dsp.c -- Cirrus Logic DSP firmware support 4 * 5 * Based on sound/soc/codecs/wm_adsp.c 6 * 7 * Copyright 2012 Wolfson Microelectronics plc 8 * Copyright (C) 2015-2021 Cirrus Logic, Inc. and 9 * Cirrus Logic International Semiconductor Ltd. 10 */ 11 12#include <linux/ctype.h> 13#include <linux/debugfs.h> 14#include <linux/delay.h> 15#include <linux/module.h> 16#include <linux/moduleparam.h> 17#include <linux/slab.h> 18#include <linux/vmalloc.h> 19 20#include <linux/firmware/cirrus/cs_dsp.h> 21#include <linux/firmware/cirrus/wmfw.h> 22 23#define cs_dsp_err(_dsp, fmt, ...) \ 24 dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) 25#define cs_dsp_warn(_dsp, fmt, ...) \ 26 dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) 27#define cs_dsp_info(_dsp, fmt, ...) \ 28 dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) 29#define cs_dsp_dbg(_dsp, fmt, ...) \ 30 dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) 31 32#define ADSP1_CONTROL_1 0x00 33#define ADSP1_CONTROL_2 0x02 34#define ADSP1_CONTROL_3 0x03 35#define ADSP1_CONTROL_4 0x04 36#define ADSP1_CONTROL_5 0x06 37#define ADSP1_CONTROL_6 0x07 38#define ADSP1_CONTROL_7 0x08 39#define ADSP1_CONTROL_8 0x09 40#define ADSP1_CONTROL_9 0x0A 41#define ADSP1_CONTROL_10 0x0B 42#define ADSP1_CONTROL_11 0x0C 43#define ADSP1_CONTROL_12 0x0D 44#define ADSP1_CONTROL_13 0x0F 45#define ADSP1_CONTROL_14 0x10 46#define ADSP1_CONTROL_15 0x11 47#define ADSP1_CONTROL_16 0x12 48#define ADSP1_CONTROL_17 0x13 49#define ADSP1_CONTROL_18 0x14 50#define ADSP1_CONTROL_19 0x16 51#define ADSP1_CONTROL_20 0x17 52#define ADSP1_CONTROL_21 0x18 53#define ADSP1_CONTROL_22 0x1A 54#define ADSP1_CONTROL_23 0x1B 55#define ADSP1_CONTROL_24 0x1C 56#define ADSP1_CONTROL_25 0x1E 57#define ADSP1_CONTROL_26 0x20 58#define ADSP1_CONTROL_27 0x21 59#define ADSP1_CONTROL_28 0x22 60#define ADSP1_CONTROL_29 0x23 61#define ADSP1_CONTROL_30 0x24 62#define ADSP1_CONTROL_31 0x26 63 64/* 65 * ADSP1 Control 19 66 */ 67#define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ 68#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ 69#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ 70 71/* 72 * ADSP1 Control 30 73 */ 74#define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */ 75#define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */ 76#define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */ 77#define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */ 78#define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ 79#define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ 80#define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ 81#define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ 82#define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ 83#define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ 84#define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ 85#define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ 86#define ADSP1_START 0x0001 /* DSP1_START */ 87#define ADSP1_START_MASK 0x0001 /* DSP1_START */ 88#define ADSP1_START_SHIFT 0 /* DSP1_START */ 89#define ADSP1_START_WIDTH 1 /* DSP1_START */ 90 91/* 92 * ADSP1 Control 31 93 */ 94#define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */ 95#define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ 96#define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ 97 98#define ADSP2_CONTROL 0x0 99#define ADSP2_CLOCKING 0x1 100#define ADSP2V2_CLOCKING 0x2 101#define ADSP2_STATUS1 0x4 102#define ADSP2_WDMA_CONFIG_1 0x30 103#define ADSP2_WDMA_CONFIG_2 0x31 104#define ADSP2V2_WDMA_CONFIG_2 0x32 105#define ADSP2_RDMA_CONFIG_1 0x34 106 107#define ADSP2_SCRATCH0 0x40 108#define ADSP2_SCRATCH1 0x41 109#define ADSP2_SCRATCH2 0x42 110#define ADSP2_SCRATCH3 0x43 111 112#define ADSP2V2_SCRATCH0_1 0x40 113#define ADSP2V2_SCRATCH2_3 0x42 114 115/* 116 * ADSP2 Control 117 */ 118#define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */ 119#define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */ 120#define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */ 121#define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */ 122#define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ 123#define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ 124#define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ 125#define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ 126#define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ 127#define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ 128#define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ 129#define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ 130#define ADSP2_START 0x0001 /* DSP1_START */ 131#define ADSP2_START_MASK 0x0001 /* DSP1_START */ 132#define ADSP2_START_SHIFT 0 /* DSP1_START */ 133#define ADSP2_START_WIDTH 1 /* DSP1_START */ 134 135/* 136 * ADSP2 clocking 137 */ 138#define ADSP2_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */ 139#define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ 140#define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ 141 142/* 143 * ADSP2V2 clocking 144 */ 145#define ADSP2V2_CLK_SEL_MASK 0x70000 /* CLK_SEL_ENA */ 146#define ADSP2V2_CLK_SEL_SHIFT 16 /* CLK_SEL_ENA */ 147#define ADSP2V2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ 148 149#define ADSP2V2_RATE_MASK 0x7800 /* DSP_RATE */ 150#define ADSP2V2_RATE_SHIFT 11 /* DSP_RATE */ 151#define ADSP2V2_RATE_WIDTH 4 /* DSP_RATE */ 152 153/* 154 * ADSP2 Status 1 155 */ 156#define ADSP2_RAM_RDY 0x0001 157#define ADSP2_RAM_RDY_MASK 0x0001 158#define ADSP2_RAM_RDY_SHIFT 0 159#define ADSP2_RAM_RDY_WIDTH 1 160 161/* 162 * ADSP2 Lock support 163 */ 164#define ADSP2_LOCK_CODE_0 0x5555 165#define ADSP2_LOCK_CODE_1 0xAAAA 166 167#define ADSP2_WATCHDOG 0x0A 168#define ADSP2_BUS_ERR_ADDR 0x52 169#define ADSP2_REGION_LOCK_STATUS 0x64 170#define ADSP2_LOCK_REGION_1_LOCK_REGION_0 0x66 171#define ADSP2_LOCK_REGION_3_LOCK_REGION_2 0x68 172#define ADSP2_LOCK_REGION_5_LOCK_REGION_4 0x6A 173#define ADSP2_LOCK_REGION_7_LOCK_REGION_6 0x6C 174#define ADSP2_LOCK_REGION_9_LOCK_REGION_8 0x6E 175#define ADSP2_LOCK_REGION_CTRL 0x7A 176#define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR 0x7C 177 178#define ADSP2_REGION_LOCK_ERR_MASK 0x8000 179#define ADSP2_ADDR_ERR_MASK 0x4000 180#define ADSP2_WDT_TIMEOUT_STS_MASK 0x2000 181#define ADSP2_CTRL_ERR_PAUSE_ENA 0x0002 182#define ADSP2_CTRL_ERR_EINT 0x0001 183 184#define ADSP2_BUS_ERR_ADDR_MASK 0x00FFFFFF 185#define ADSP2_XMEM_ERR_ADDR_MASK 0x0000FFFF 186#define ADSP2_PMEM_ERR_ADDR_MASK 0x7FFF0000 187#define ADSP2_PMEM_ERR_ADDR_SHIFT 16 188#define ADSP2_WDT_ENA_MASK 0xFFFFFFFD 189 190#define ADSP2_LOCK_REGION_SHIFT 16 191 192/* 193 * Event control messages 194 */ 195#define CS_DSP_FW_EVENT_SHUTDOWN 0x000001 196 197/* 198 * HALO system info 199 */ 200#define HALO_AHBM_WINDOW_DEBUG_0 0x02040 201#define HALO_AHBM_WINDOW_DEBUG_1 0x02044 202 203/* 204 * HALO core 205 */ 206#define HALO_SCRATCH1 0x005c0 207#define HALO_SCRATCH2 0x005c8 208#define HALO_SCRATCH3 0x005d0 209#define HALO_SCRATCH4 0x005d8 210#define HALO_CCM_CORE_CONTROL 0x41000 211#define HALO_CORE_SOFT_RESET 0x00010 212#define HALO_WDT_CONTROL 0x47000 213 214/* 215 * HALO MPU banks 216 */ 217#define HALO_MPU_XMEM_ACCESS_0 0x43000 218#define HALO_MPU_YMEM_ACCESS_0 0x43004 219#define HALO_MPU_WINDOW_ACCESS_0 0x43008 220#define HALO_MPU_XREG_ACCESS_0 0x4300C 221#define HALO_MPU_YREG_ACCESS_0 0x43014 222#define HALO_MPU_XMEM_ACCESS_1 0x43018 223#define HALO_MPU_YMEM_ACCESS_1 0x4301C 224#define HALO_MPU_WINDOW_ACCESS_1 0x43020 225#define HALO_MPU_XREG_ACCESS_1 0x43024 226#define HALO_MPU_YREG_ACCESS_1 0x4302C 227#define HALO_MPU_XMEM_ACCESS_2 0x43030 228#define HALO_MPU_YMEM_ACCESS_2 0x43034 229#define HALO_MPU_WINDOW_ACCESS_2 0x43038 230#define HALO_MPU_XREG_ACCESS_2 0x4303C 231#define HALO_MPU_YREG_ACCESS_2 0x43044 232#define HALO_MPU_XMEM_ACCESS_3 0x43048 233#define HALO_MPU_YMEM_ACCESS_3 0x4304C 234#define HALO_MPU_WINDOW_ACCESS_3 0x43050 235#define HALO_MPU_XREG_ACCESS_3 0x43054 236#define HALO_MPU_YREG_ACCESS_3 0x4305C 237#define HALO_MPU_XM_VIO_ADDR 0x43100 238#define HALO_MPU_XM_VIO_STATUS 0x43104 239#define HALO_MPU_YM_VIO_ADDR 0x43108 240#define HALO_MPU_YM_VIO_STATUS 0x4310C 241#define HALO_MPU_PM_VIO_ADDR 0x43110 242#define HALO_MPU_PM_VIO_STATUS 0x43114 243#define HALO_MPU_LOCK_CONFIG 0x43140 244 245/* 246 * HALO_AHBM_WINDOW_DEBUG_1 247 */ 248#define HALO_AHBM_CORE_ERR_ADDR_MASK 0x0fffff00 249#define HALO_AHBM_CORE_ERR_ADDR_SHIFT 8 250#define HALO_AHBM_FLAGS_ERR_MASK 0x000000ff 251 252/* 253 * HALO_CCM_CORE_CONTROL 254 */ 255#define HALO_CORE_RESET 0x00000200 256#define HALO_CORE_EN 0x00000001 257 258/* 259 * HALO_CORE_SOFT_RESET 260 */ 261#define HALO_CORE_SOFT_RESET_MASK 0x00000001 262 263/* 264 * HALO_WDT_CONTROL 265 */ 266#define HALO_WDT_EN_MASK 0x00000001 267 268/* 269 * HALO_MPU_?M_VIO_STATUS 270 */ 271#define HALO_MPU_VIO_STS_MASK 0x007e0000 272#define HALO_MPU_VIO_STS_SHIFT 17 273#define HALO_MPU_VIO_ERR_WR_MASK 0x00008000 274#define HALO_MPU_VIO_ERR_SRC_MASK 0x00007fff 275#define HALO_MPU_VIO_ERR_SRC_SHIFT 0 276 277struct cs_dsp_ops { 278 bool (*validate_version)(struct cs_dsp *dsp, unsigned int version); 279 unsigned int (*parse_sizes)(struct cs_dsp *dsp, 280 const char * const file, 281 unsigned int pos, 282 const struct firmware *firmware); 283 int (*setup_algs)(struct cs_dsp *dsp); 284 unsigned int (*region_to_reg)(struct cs_dsp_region const *mem, 285 unsigned int offset); 286 287 void (*show_fw_status)(struct cs_dsp *dsp); 288 void (*stop_watchdog)(struct cs_dsp *dsp); 289 290 int (*enable_memory)(struct cs_dsp *dsp); 291 void (*disable_memory)(struct cs_dsp *dsp); 292 int (*lock_memory)(struct cs_dsp *dsp, unsigned int lock_regions); 293 294 int (*enable_core)(struct cs_dsp *dsp); 295 void (*disable_core)(struct cs_dsp *dsp); 296 297 int (*start_core)(struct cs_dsp *dsp); 298 void (*stop_core)(struct cs_dsp *dsp); 299}; 300 301static const struct cs_dsp_ops cs_dsp_adsp1_ops; 302static const struct cs_dsp_ops cs_dsp_adsp2_ops[]; 303static const struct cs_dsp_ops cs_dsp_halo_ops; 304 305struct cs_dsp_buf { 306 struct list_head list; 307 void *buf; 308}; 309 310static struct cs_dsp_buf *cs_dsp_buf_alloc(const void *src, size_t len, 311 struct list_head *list) 312{ 313 struct cs_dsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL); 314 315 if (buf == NULL) 316 return NULL; 317 318 buf->buf = vmalloc(len); 319 if (!buf->buf) { 320 kfree(buf); 321 return NULL; 322 } 323 memcpy(buf->buf, src, len); 324 325 if (list) 326 list_add_tail(&buf->list, list); 327 328 return buf; 329} 330 331static void cs_dsp_buf_free(struct list_head *list) 332{ 333 while (!list_empty(list)) { 334 struct cs_dsp_buf *buf = list_first_entry(list, 335 struct cs_dsp_buf, 336 list); 337 list_del(&buf->list); 338 vfree(buf->buf); 339 kfree(buf); 340 } 341} 342 343/** 344 * cs_dsp_mem_region_name() - Return a name string for a memory type 345 * @type: the memory type to match 346 * 347 * Return: A const string identifying the memory region. 348 */ 349const char *cs_dsp_mem_region_name(unsigned int type) 350{ 351 switch (type) { 352 case WMFW_ADSP1_PM: 353 return "PM"; 354 case WMFW_HALO_PM_PACKED: 355 return "PM_PACKED"; 356 case WMFW_ADSP1_DM: 357 return "DM"; 358 case WMFW_ADSP2_XM: 359 return "XM"; 360 case WMFW_HALO_XM_PACKED: 361 return "XM_PACKED"; 362 case WMFW_ADSP2_YM: 363 return "YM"; 364 case WMFW_HALO_YM_PACKED: 365 return "YM_PACKED"; 366 case WMFW_ADSP1_ZM: 367 return "ZM"; 368 default: 369 return NULL; 370 } 371} 372EXPORT_SYMBOL_GPL(cs_dsp_mem_region_name); 373 374#ifdef CONFIG_DEBUG_FS 375static void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, const char *s) 376{ 377 char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); 378 379 kfree(dsp->wmfw_file_name); 380 dsp->wmfw_file_name = tmp; 381} 382 383static void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp, const char *s) 384{ 385 char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); 386 387 kfree(dsp->bin_file_name); 388 dsp->bin_file_name = tmp; 389} 390 391static void cs_dsp_debugfs_clear(struct cs_dsp *dsp) 392{ 393 kfree(dsp->wmfw_file_name); 394 kfree(dsp->bin_file_name); 395 dsp->wmfw_file_name = NULL; 396 dsp->bin_file_name = NULL; 397} 398 399static ssize_t cs_dsp_debugfs_wmfw_read(struct file *file, 400 char __user *user_buf, 401 size_t count, loff_t *ppos) 402{ 403 struct cs_dsp *dsp = file->private_data; 404 ssize_t ret; 405 406 mutex_lock(&dsp->pwr_lock); 407 408 if (!dsp->wmfw_file_name || !dsp->booted) 409 ret = 0; 410 else 411 ret = simple_read_from_buffer(user_buf, count, ppos, 412 dsp->wmfw_file_name, 413 strlen(dsp->wmfw_file_name)); 414 415 mutex_unlock(&dsp->pwr_lock); 416 return ret; 417} 418 419static ssize_t cs_dsp_debugfs_bin_read(struct file *file, 420 char __user *user_buf, 421 size_t count, loff_t *ppos) 422{ 423 struct cs_dsp *dsp = file->private_data; 424 ssize_t ret; 425 426 mutex_lock(&dsp->pwr_lock); 427 428 if (!dsp->bin_file_name || !dsp->booted) 429 ret = 0; 430 else 431 ret = simple_read_from_buffer(user_buf, count, ppos, 432 dsp->bin_file_name, 433 strlen(dsp->bin_file_name)); 434 435 mutex_unlock(&dsp->pwr_lock); 436 return ret; 437} 438 439static const struct { 440 const char *name; 441 const struct file_operations fops; 442} cs_dsp_debugfs_fops[] = { 443 { 444 .name = "wmfw_file_name", 445 .fops = { 446 .open = simple_open, 447 .read = cs_dsp_debugfs_wmfw_read, 448 }, 449 }, 450 { 451 .name = "bin_file_name", 452 .fops = { 453 .open = simple_open, 454 .read = cs_dsp_debugfs_bin_read, 455 }, 456 }, 457}; 458 459/** 460 * cs_dsp_init_debugfs() - Create and populate DSP representation in debugfs 461 * @dsp: pointer to DSP structure 462 * @debugfs_root: pointer to debugfs directory in which to create this DSP 463 * representation 464 */ 465void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root) 466{ 467 struct dentry *root = NULL; 468 int i; 469 470 root = debugfs_create_dir(dsp->name, debugfs_root); 471 472 debugfs_create_bool("booted", 0444, root, &dsp->booted); 473 debugfs_create_bool("running", 0444, root, &dsp->running); 474 debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id); 475 debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version); 476 477 for (i = 0; i < ARRAY_SIZE(cs_dsp_debugfs_fops); ++i) 478 debugfs_create_file(cs_dsp_debugfs_fops[i].name, 0444, root, 479 dsp, &cs_dsp_debugfs_fops[i].fops); 480 481 dsp->debugfs_root = root; 482} 483EXPORT_SYMBOL_GPL(cs_dsp_init_debugfs); 484 485/** 486 * cs_dsp_cleanup_debugfs() - Removes DSP representation from debugfs 487 * @dsp: pointer to DSP structure 488 */ 489void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp) 490{ 491 cs_dsp_debugfs_clear(dsp); 492 debugfs_remove_recursive(dsp->debugfs_root); 493 dsp->debugfs_root = NULL; 494} 495EXPORT_SYMBOL_GPL(cs_dsp_cleanup_debugfs); 496#else 497void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root) 498{ 499} 500EXPORT_SYMBOL_GPL(cs_dsp_init_debugfs); 501 502void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp) 503{ 504} 505EXPORT_SYMBOL_GPL(cs_dsp_cleanup_debugfs); 506 507static inline void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, 508 const char *s) 509{ 510} 511 512static inline void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp, 513 const char *s) 514{ 515} 516 517static inline void cs_dsp_debugfs_clear(struct cs_dsp *dsp) 518{ 519} 520#endif 521 522static const struct cs_dsp_region *cs_dsp_find_region(struct cs_dsp *dsp, 523 int type) 524{ 525 int i; 526 527 for (i = 0; i < dsp->num_mems; i++) 528 if (dsp->mem[i].type == type) 529 return &dsp->mem[i]; 530 531 return NULL; 532} 533 534static unsigned int cs_dsp_region_to_reg(struct cs_dsp_region const *mem, 535 unsigned int offset) 536{ 537 switch (mem->type) { 538 case WMFW_ADSP1_PM: 539 return mem->base + (offset * 3); 540 case WMFW_ADSP1_DM: 541 case WMFW_ADSP2_XM: 542 case WMFW_ADSP2_YM: 543 case WMFW_ADSP1_ZM: 544 return mem->base + (offset * 2); 545 default: 546 WARN(1, "Unknown memory region type"); 547 return offset; 548 } 549} 550 551static unsigned int cs_dsp_halo_region_to_reg(struct cs_dsp_region const *mem, 552 unsigned int offset) 553{ 554 switch (mem->type) { 555 case WMFW_ADSP2_XM: 556 case WMFW_ADSP2_YM: 557 return mem->base + (offset * 4); 558 case WMFW_HALO_XM_PACKED: 559 case WMFW_HALO_YM_PACKED: 560 return (mem->base + (offset * 3)) & ~0x3; 561 case WMFW_HALO_PM_PACKED: 562 return mem->base + (offset * 5); 563 default: 564 WARN(1, "Unknown memory region type"); 565 return offset; 566 } 567} 568 569static void cs_dsp_read_fw_status(struct cs_dsp *dsp, 570 int noffs, unsigned int *offs) 571{ 572 unsigned int i; 573 int ret; 574 575 for (i = 0; i < noffs; ++i) { 576 ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]); 577 if (ret) { 578 cs_dsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret); 579 return; 580 } 581 } 582} 583 584static void cs_dsp_adsp2_show_fw_status(struct cs_dsp *dsp) 585{ 586 unsigned int offs[] = { 587 ADSP2_SCRATCH0, ADSP2_SCRATCH1, ADSP2_SCRATCH2, ADSP2_SCRATCH3, 588 }; 589 590 cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs); 591 592 cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", 593 offs[0], offs[1], offs[2], offs[3]); 594} 595 596static void cs_dsp_adsp2v2_show_fw_status(struct cs_dsp *dsp) 597{ 598 unsigned int offs[] = { ADSP2V2_SCRATCH0_1, ADSP2V2_SCRATCH2_3 }; 599 600 cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs); 601 602 cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", 603 offs[0] & 0xFFFF, offs[0] >> 16, 604 offs[1] & 0xFFFF, offs[1] >> 16); 605} 606 607static void cs_dsp_halo_show_fw_status(struct cs_dsp *dsp) 608{ 609 unsigned int offs[] = { 610 HALO_SCRATCH1, HALO_SCRATCH2, HALO_SCRATCH3, HALO_SCRATCH4, 611 }; 612 613 cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs); 614 615 cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", 616 offs[0], offs[1], offs[2], offs[3]); 617} 618 619static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg, 620 unsigned int off) 621{ 622 const struct cs_dsp_alg_region *alg_region = &ctl->alg_region; 623 struct cs_dsp *dsp = ctl->dsp; 624 const struct cs_dsp_region *mem; 625 626 mem = cs_dsp_find_region(dsp, alg_region->type); 627 if (!mem) { 628 cs_dsp_err(dsp, "No base for region %x\n", 629 alg_region->type); 630 return -EINVAL; 631 } 632 633 *reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset + off); 634 635 return 0; 636} 637 638/** 639 * cs_dsp_coeff_write_acked_control() - Sends event_id to the acked control 640 * @ctl: pointer to acked coefficient control 641 * @event_id: the value to write to the given acked control 642 * 643 * Once the value has been written to the control the function shall block 644 * until the running firmware acknowledges the write or timeout is exceeded. 645 * 646 * Must be called with pwr_lock held. 647 * 648 * Return: Zero for success, a negative number on error. 649 */ 650int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int event_id) 651{ 652 struct cs_dsp *dsp = ctl->dsp; 653 __be32 val = cpu_to_be32(event_id); 654 unsigned int reg; 655 int i, ret; 656 657 lockdep_assert_held(&dsp->pwr_lock); 658 659 if (!dsp->running) 660 return -EPERM; 661 662 ret = cs_dsp_coeff_base_reg(ctl, ®, 0); 663 if (ret) 664 return ret; 665 666 cs_dsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n", 667 event_id, ctl->alg_region.alg, 668 cs_dsp_mem_region_name(ctl->alg_region.type), ctl->offset); 669 670 ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val)); 671 if (ret) { 672 cs_dsp_err(dsp, "Failed to write %x: %d\n", reg, ret); 673 return ret; 674 } 675 676 /* 677 * Poll for ack, we initially poll at ~1ms intervals for firmwares 678 * that respond quickly, then go to ~10ms polls. A firmware is unlikely 679 * to ack instantly so we do the first 1ms delay before reading the 680 * control to avoid a pointless bus transaction 681 */ 682 for (i = 0; i < CS_DSP_ACKED_CTL_TIMEOUT_MS;) { 683 switch (i) { 684 case 0 ... CS_DSP_ACKED_CTL_N_QUICKPOLLS - 1: 685 usleep_range(1000, 2000); 686 i++; 687 break; 688 default: 689 usleep_range(10000, 20000); 690 i += 10; 691 break; 692 } 693 694 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); 695 if (ret) { 696 cs_dsp_err(dsp, "Failed to read %x: %d\n", reg, ret); 697 return ret; 698 } 699 700 if (val == 0) { 701 cs_dsp_dbg(dsp, "Acked control ACKED at poll %u\n", i); 702 return 0; 703 } 704 } 705 706 cs_dsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n", 707 reg, ctl->alg_region.alg, 708 cs_dsp_mem_region_name(ctl->alg_region.type), 709 ctl->offset); 710 711 return -ETIMEDOUT; 712} 713EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_acked_control); 714 715static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, 716 unsigned int off, const void *buf, size_t len) 717{ 718 struct cs_dsp *dsp = ctl->dsp; 719 void *scratch; 720 int ret; 721 unsigned int reg; 722 723 ret = cs_dsp_coeff_base_reg(ctl, ®, off); 724 if (ret) 725 return ret; 726 727 scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA); 728 if (!scratch) 729 return -ENOMEM; 730 731 ret = regmap_raw_write(dsp->regmap, reg, scratch, 732 len); 733 if (ret) { 734 cs_dsp_err(dsp, "Failed to write %zu bytes to %x: %d\n", 735 len, reg, ret); 736 kfree(scratch); 737 return ret; 738 } 739 cs_dsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg); 740 741 kfree(scratch); 742 743 return 0; 744} 745 746/** 747 * cs_dsp_coeff_write_ctrl() - Writes the given buffer to the given coefficient control 748 * @ctl: pointer to coefficient control 749 * @off: word offset at which data should be written 750 * @buf: the buffer to write to the given control 751 * @len: the length of the buffer in bytes 752 * 753 * Must be called with pwr_lock held. 754 * 755 * Return: Zero for success, a negative number on error. 756 */ 757int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, 758 unsigned int off, const void *buf, size_t len) 759{ 760 int ret = 0; 761 762 if (!ctl) 763 return -ENOENT; 764 765 lockdep_assert_held(&ctl->dsp->pwr_lock); 766 767 if (len + off * sizeof(u32) > ctl->len) 768 return -EINVAL; 769 770 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) 771 ret = -EPERM; 772 else if (buf != ctl->cache) 773 memcpy(ctl->cache + off * sizeof(u32), buf, len); 774 775 ctl->set = 1; 776 if (ctl->enabled && ctl->dsp->running) 777 ret = cs_dsp_coeff_write_ctrl_raw(ctl, off, buf, len); 778 779 return ret; 780} 781EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_ctrl); 782 783static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, 784 unsigned int off, void *buf, size_t len) 785{ 786 struct cs_dsp *dsp = ctl->dsp; 787 void *scratch; 788 int ret; 789 unsigned int reg; 790 791 ret = cs_dsp_coeff_base_reg(ctl, ®, off); 792 if (ret) 793 return ret; 794 795 scratch = kmalloc(len, GFP_KERNEL | GFP_DMA); 796 if (!scratch) 797 return -ENOMEM; 798 799 ret = regmap_raw_read(dsp->regmap, reg, scratch, len); 800 if (ret) { 801 cs_dsp_err(dsp, "Failed to read %zu bytes from %x: %d\n", 802 len, reg, ret); 803 kfree(scratch); 804 return ret; 805 } 806 cs_dsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg); 807 808 memcpy(buf, scratch, len); 809 kfree(scratch); 810 811 return 0; 812} 813 814/** 815 * cs_dsp_coeff_read_ctrl() - Reads the given coefficient control into the given buffer 816 * @ctl: pointer to coefficient control 817 * @off: word offset at which data should be read 818 * @buf: the buffer to store to the given control 819 * @len: the length of the buffer in bytes 820 * 821 * Must be called with pwr_lock held. 822 * 823 * Return: Zero for success, a negative number on error. 824 */ 825int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, 826 unsigned int off, void *buf, size_t len) 827{ 828 int ret = 0; 829 830 if (!ctl) 831 return -ENOENT; 832 833 lockdep_assert_held(&ctl->dsp->pwr_lock); 834 835 if (len + off * sizeof(u32) > ctl->len) 836 return -EINVAL; 837 838 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { 839 if (ctl->enabled && ctl->dsp->running) 840 return cs_dsp_coeff_read_ctrl_raw(ctl, off, buf, len); 841 else 842 return -EPERM; 843 } else { 844 if (!ctl->flags && ctl->enabled && ctl->dsp->running) 845 ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len); 846 847 if (buf != ctl->cache) 848 memcpy(buf, ctl->cache + off * sizeof(u32), len); 849 } 850 851 return ret; 852} 853EXPORT_SYMBOL_GPL(cs_dsp_coeff_read_ctrl); 854 855static int cs_dsp_coeff_init_control_caches(struct cs_dsp *dsp) 856{ 857 struct cs_dsp_coeff_ctl *ctl; 858 int ret; 859 860 list_for_each_entry(ctl, &dsp->ctl_list, list) { 861 if (!ctl->enabled || ctl->set) 862 continue; 863 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) 864 continue; 865 866 /* 867 * For readable controls populate the cache from the DSP memory. 868 * For non-readable controls the cache was zero-filled when 869 * created so we don't need to do anything. 870 */ 871 if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) { 872 ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len); 873 if (ret < 0) 874 return ret; 875 } 876 } 877 878 return 0; 879} 880 881static int cs_dsp_coeff_sync_controls(struct cs_dsp *dsp) 882{ 883 struct cs_dsp_coeff_ctl *ctl; 884 int ret; 885 886 list_for_each_entry(ctl, &dsp->ctl_list, list) { 887 if (!ctl->enabled) 888 continue; 889 if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) { 890 ret = cs_dsp_coeff_write_ctrl_raw(ctl, 0, ctl->cache, 891 ctl->len); 892 if (ret < 0) 893 return ret; 894 } 895 } 896 897 return 0; 898} 899 900static void cs_dsp_signal_event_controls(struct cs_dsp *dsp, 901 unsigned int event) 902{ 903 struct cs_dsp_coeff_ctl *ctl; 904 int ret; 905 906 list_for_each_entry(ctl, &dsp->ctl_list, list) { 907 if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT) 908 continue; 909 910 if (!ctl->enabled) 911 continue; 912 913 ret = cs_dsp_coeff_write_acked_control(ctl, event); 914 if (ret) 915 cs_dsp_warn(dsp, 916 "Failed to send 0x%x event to alg 0x%x (%d)\n", 917 event, ctl->alg_region.alg, ret); 918 } 919} 920 921static void cs_dsp_free_ctl_blk(struct cs_dsp_coeff_ctl *ctl) 922{ 923 kfree(ctl->cache); 924 kfree(ctl->subname); 925 kfree(ctl); 926} 927 928static int cs_dsp_create_control(struct cs_dsp *dsp, 929 const struct cs_dsp_alg_region *alg_region, 930 unsigned int offset, unsigned int len, 931 const char *subname, unsigned int subname_len, 932 unsigned int flags, unsigned int type) 933{ 934 struct cs_dsp_coeff_ctl *ctl; 935 int ret; 936 937 list_for_each_entry(ctl, &dsp->ctl_list, list) { 938 if (ctl->fw_name == dsp->fw_name && 939 ctl->alg_region.alg == alg_region->alg && 940 ctl->alg_region.type == alg_region->type) { 941 if ((!subname && !ctl->subname) || 942 (subname && !strncmp(ctl->subname, subname, ctl->subname_len))) { 943 if (!ctl->enabled) 944 ctl->enabled = 1; 945 return 0; 946 } 947 } 948 } 949 950 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); 951 if (!ctl) 952 return -ENOMEM; 953 954 ctl->fw_name = dsp->fw_name; 955 ctl->alg_region = *alg_region; 956 if (subname && dsp->fw_ver >= 2) { 957 ctl->subname_len = subname_len; 958 ctl->subname = kasprintf(GFP_KERNEL, "%.*s", subname_len, subname); 959 if (!ctl->subname) { 960 ret = -ENOMEM; 961 goto err_ctl; 962 } 963 } 964 ctl->enabled = 1; 965 ctl->set = 0; 966 ctl->dsp = dsp; 967 968 ctl->flags = flags; 969 ctl->type = type; 970 ctl->offset = offset; 971 ctl->len = len; 972 ctl->cache = kzalloc(ctl->len, GFP_KERNEL); 973 if (!ctl->cache) { 974 ret = -ENOMEM; 975 goto err_ctl_subname; 976 } 977 978 list_add(&ctl->list, &dsp->ctl_list); 979 980 if (dsp->client_ops->control_add) { 981 ret = dsp->client_ops->control_add(ctl); 982 if (ret) 983 goto err_list_del; 984 } 985 986 return 0; 987 988err_list_del: 989 list_del(&ctl->list); 990 kfree(ctl->cache); 991err_ctl_subname: 992 kfree(ctl->subname); 993err_ctl: 994 kfree(ctl); 995 996 return ret; 997} 998 999struct cs_dsp_coeff_parsed_alg { 1000 int id; 1001 const u8 *name; 1002 int name_len; 1003 int ncoeff; 1004}; 1005 1006struct cs_dsp_coeff_parsed_coeff { 1007 int offset; 1008 int mem_type; 1009 const u8 *name; 1010 int name_len; 1011 unsigned int ctl_type; 1012 int flags; 1013 int len; 1014}; 1015 1016static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) 1017{ 1018 int length; 1019 1020 switch (bytes) { 1021 case 1: 1022 length = **pos; 1023 break; 1024 case 2: 1025 length = le16_to_cpu(*((__le16 *)*pos)); 1026 break; 1027 default: 1028 return 0; 1029 } 1030 1031 if (str) 1032 *str = *pos + bytes; 1033 1034 *pos += ((length + bytes) + 3) & ~0x03; 1035 1036 return length; 1037} 1038 1039static int cs_dsp_coeff_parse_int(int bytes, const u8 **pos) 1040{ 1041 int val = 0; 1042 1043 switch (bytes) { 1044 case 2: 1045 val = le16_to_cpu(*((__le16 *)*pos)); 1046 break; 1047 case 4: 1048 val = le32_to_cpu(*((__le32 *)*pos)); 1049 break; 1050 default: 1051 break; 1052 } 1053 1054 *pos += bytes; 1055 1056 return val; 1057} 1058 1059static inline void cs_dsp_coeff_parse_alg(struct cs_dsp *dsp, const u8 **data, 1060 struct cs_dsp_coeff_parsed_alg *blk) 1061{ 1062 const struct wmfw_adsp_alg_data *raw; 1063 1064 switch (dsp->fw_ver) { 1065 case 0: 1066 case 1: 1067 raw = (const struct wmfw_adsp_alg_data *)*data; 1068 *data = raw->data; 1069 1070 blk->id = le32_to_cpu(raw->id); 1071 blk->name = raw->name; 1072 blk->name_len = strlen(raw->name); 1073 blk->ncoeff = le32_to_cpu(raw->ncoeff); 1074 break; 1075 default: 1076 blk->id = cs_dsp_coeff_parse_int(sizeof(raw->id), data); 1077 blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), data, 1078 &blk->name); 1079 cs_dsp_coeff_parse_string(sizeof(u16), data, NULL); 1080 blk->ncoeff = cs_dsp_coeff_parse_int(sizeof(raw->ncoeff), data); 1081 break; 1082 } 1083 1084 cs_dsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); 1085 cs_dsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); 1086 cs_dsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff); 1087} 1088 1089static inline void cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, const u8 **data, 1090 struct cs_dsp_coeff_parsed_coeff *blk) 1091{ 1092 const struct wmfw_adsp_coeff_data *raw; 1093 const u8 *tmp; 1094 int length; 1095 1096 switch (dsp->fw_ver) { 1097 case 0: 1098 case 1: 1099 raw = (const struct wmfw_adsp_coeff_data *)*data; 1100 *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size); 1101 1102 blk->offset = le16_to_cpu(raw->hdr.offset); 1103 blk->mem_type = le16_to_cpu(raw->hdr.type); 1104 blk->name = raw->name; 1105 blk->name_len = strlen(raw->name); 1106 blk->ctl_type = le16_to_cpu(raw->ctl_type); 1107 blk->flags = le16_to_cpu(raw->flags); 1108 blk->len = le32_to_cpu(raw->len); 1109 break; 1110 default: 1111 tmp = *data; 1112 blk->offset = cs_dsp_coeff_parse_int(sizeof(raw->hdr.offset), &tmp); 1113 blk->mem_type = cs_dsp_coeff_parse_int(sizeof(raw->hdr.type), &tmp); 1114 length = cs_dsp_coeff_parse_int(sizeof(raw->hdr.size), &tmp); 1115 blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp, 1116 &blk->name); 1117 cs_dsp_coeff_parse_string(sizeof(u8), &tmp, NULL); 1118 cs_dsp_coeff_parse_string(sizeof(u16), &tmp, NULL); 1119 blk->ctl_type = cs_dsp_coeff_parse_int(sizeof(raw->ctl_type), &tmp); 1120 blk->flags = cs_dsp_coeff_parse_int(sizeof(raw->flags), &tmp); 1121 blk->len = cs_dsp_coeff_parse_int(sizeof(raw->len), &tmp); 1122 1123 *data = *data + sizeof(raw->hdr) + length; 1124 break; 1125 } 1126 1127 cs_dsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type); 1128 cs_dsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset); 1129 cs_dsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name); 1130 cs_dsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags); 1131 cs_dsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type); 1132 cs_dsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); 1133} 1134 1135static int cs_dsp_check_coeff_flags(struct cs_dsp *dsp, 1136 const struct cs_dsp_coeff_parsed_coeff *coeff_blk, 1137 unsigned int f_required, 1138 unsigned int f_illegal) 1139{ 1140 if ((coeff_blk->flags & f_illegal) || 1141 ((coeff_blk->flags & f_required) != f_required)) { 1142 cs_dsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n", 1143 coeff_blk->flags, coeff_blk->ctl_type); 1144 return -EINVAL; 1145 } 1146 1147 return 0; 1148} 1149 1150static int cs_dsp_parse_coeff(struct cs_dsp *dsp, 1151 const struct wmfw_region *region) 1152{ 1153 struct cs_dsp_alg_region alg_region = {}; 1154 struct cs_dsp_coeff_parsed_alg alg_blk; 1155 struct cs_dsp_coeff_parsed_coeff coeff_blk; 1156 const u8 *data = region->data; 1157 int i, ret; 1158 1159 cs_dsp_coeff_parse_alg(dsp, &data, &alg_blk); 1160 for (i = 0; i < alg_blk.ncoeff; i++) { 1161 cs_dsp_coeff_parse_coeff(dsp, &data, &coeff_blk); 1162 1163 switch (coeff_blk.ctl_type) { 1164 case WMFW_CTL_TYPE_BYTES: 1165 break; 1166 case WMFW_CTL_TYPE_ACKED: 1167 if (coeff_blk.flags & WMFW_CTL_FLAG_SYS) 1168 continue; /* ignore */ 1169 1170 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, 1171 WMFW_CTL_FLAG_VOLATILE | 1172 WMFW_CTL_FLAG_WRITEABLE | 1173 WMFW_CTL_FLAG_READABLE, 1174 0); 1175 if (ret) 1176 return -EINVAL; 1177 break; 1178 case WMFW_CTL_TYPE_HOSTEVENT: 1179 case WMFW_CTL_TYPE_FWEVENT: 1180 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, 1181 WMFW_CTL_FLAG_SYS | 1182 WMFW_CTL_FLAG_VOLATILE | 1183 WMFW_CTL_FLAG_WRITEABLE | 1184 WMFW_CTL_FLAG_READABLE, 1185 0); 1186 if (ret) 1187 return -EINVAL; 1188 break; 1189 case WMFW_CTL_TYPE_HOST_BUFFER: 1190 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, 1191 WMFW_CTL_FLAG_SYS | 1192 WMFW_CTL_FLAG_VOLATILE | 1193 WMFW_CTL_FLAG_READABLE, 1194 0); 1195 if (ret) 1196 return -EINVAL; 1197 break; 1198 default: 1199 cs_dsp_err(dsp, "Unknown control type: %d\n", 1200 coeff_blk.ctl_type); 1201 return -EINVAL; 1202 } 1203 1204 alg_region.type = coeff_blk.mem_type; 1205 alg_region.alg = alg_blk.id; 1206 1207 ret = cs_dsp_create_control(dsp, &alg_region, 1208 coeff_blk.offset, 1209 coeff_blk.len, 1210 coeff_blk.name, 1211 coeff_blk.name_len, 1212 coeff_blk.flags, 1213 coeff_blk.ctl_type); 1214 if (ret < 0) 1215 cs_dsp_err(dsp, "Failed to create control: %.*s, %d\n", 1216 coeff_blk.name_len, coeff_blk.name, ret); 1217 } 1218 1219 return 0; 1220} 1221 1222static unsigned int cs_dsp_adsp1_parse_sizes(struct cs_dsp *dsp, 1223 const char * const file, 1224 unsigned int pos, 1225 const struct firmware *firmware) 1226{ 1227 const struct wmfw_adsp1_sizes *adsp1_sizes; 1228 1229 adsp1_sizes = (void *)&firmware->data[pos]; 1230 1231 cs_dsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file, 1232 le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm), 1233 le32_to_cpu(adsp1_sizes->zm)); 1234 1235 return pos + sizeof(*adsp1_sizes); 1236} 1237 1238static unsigned int cs_dsp_adsp2_parse_sizes(struct cs_dsp *dsp, 1239 const char * const file, 1240 unsigned int pos, 1241 const struct firmware *firmware) 1242{ 1243 const struct wmfw_adsp2_sizes *adsp2_sizes; 1244 1245 adsp2_sizes = (void *)&firmware->data[pos]; 1246 1247 cs_dsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file, 1248 le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym), 1249 le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm)); 1250 1251 return pos + sizeof(*adsp2_sizes); 1252} 1253 1254static bool cs_dsp_validate_version(struct cs_dsp *dsp, unsigned int version) 1255{ 1256 switch (version) { 1257 case 0: 1258 cs_dsp_warn(dsp, "Deprecated file format %d\n", version); 1259 return true; 1260 case 1: 1261 case 2: 1262 return true; 1263 default: 1264 return false; 1265 } 1266} 1267 1268static bool cs_dsp_halo_validate_version(struct cs_dsp *dsp, unsigned int version) 1269{ 1270 switch (version) { 1271 case 3: 1272 return true; 1273 default: 1274 return false; 1275 } 1276} 1277 1278static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, 1279 const char *file) 1280{ 1281 LIST_HEAD(buf_list); 1282 struct regmap *regmap = dsp->regmap; 1283 unsigned int pos = 0; 1284 const struct wmfw_header *header; 1285 const struct wmfw_adsp1_sizes *adsp1_sizes; 1286 const struct wmfw_footer *footer; 1287 const struct wmfw_region *region; 1288 const struct cs_dsp_region *mem; 1289 const char *region_name; 1290 char *text = NULL; 1291 struct cs_dsp_buf *buf; 1292 unsigned int reg; 1293 int regions = 0; 1294 int ret, offset, type; 1295 1296 ret = -EINVAL; 1297 1298 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); 1299 if (pos >= firmware->size) { 1300 cs_dsp_err(dsp, "%s: file too short, %zu bytes\n", 1301 file, firmware->size); 1302 goto out_fw; 1303 } 1304 1305 header = (void *)&firmware->data[0]; 1306 1307 if (memcmp(&header->magic[0], "WMFW", 4) != 0) { 1308 cs_dsp_err(dsp, "%s: invalid magic\n", file); 1309 goto out_fw; 1310 } 1311 1312 if (!dsp->ops->validate_version(dsp, header->ver)) { 1313 cs_dsp_err(dsp, "%s: unknown file format %d\n", 1314 file, header->ver); 1315 goto out_fw; 1316 } 1317 1318 cs_dsp_info(dsp, "Firmware version: %d\n", header->ver); 1319 dsp->fw_ver = header->ver; 1320 1321 if (header->core != dsp->type) { 1322 cs_dsp_err(dsp, "%s: invalid core %d != %d\n", 1323 file, header->core, dsp->type); 1324 goto out_fw; 1325 } 1326 1327 pos = sizeof(*header); 1328 pos = dsp->ops->parse_sizes(dsp, file, pos, firmware); 1329 1330 footer = (void *)&firmware->data[pos]; 1331 pos += sizeof(*footer); 1332 1333 if (le32_to_cpu(header->len) != pos) { 1334 cs_dsp_err(dsp, "%s: unexpected header length %d\n", 1335 file, le32_to_cpu(header->len)); 1336 goto out_fw; 1337 } 1338 1339 cs_dsp_dbg(dsp, "%s: timestamp %llu\n", file, 1340 le64_to_cpu(footer->timestamp)); 1341 1342 while (pos < firmware->size && 1343 sizeof(*region) < firmware->size - pos) { 1344 region = (void *)&(firmware->data[pos]); 1345 region_name = "Unknown"; 1346 reg = 0; 1347 text = NULL; 1348 offset = le32_to_cpu(region->offset) & 0xffffff; 1349 type = be32_to_cpu(region->type) & 0xff; 1350 1351 switch (type) { 1352 case WMFW_NAME_TEXT: 1353 region_name = "Firmware name"; 1354 text = kzalloc(le32_to_cpu(region->len) + 1, 1355 GFP_KERNEL); 1356 break; 1357 case WMFW_ALGORITHM_DATA: 1358 region_name = "Algorithm"; 1359 ret = cs_dsp_parse_coeff(dsp, region); 1360 if (ret != 0) 1361 goto out_fw; 1362 break; 1363 case WMFW_INFO_TEXT: 1364 region_name = "Information"; 1365 text = kzalloc(le32_to_cpu(region->len) + 1, 1366 GFP_KERNEL); 1367 break; 1368 case WMFW_ABSOLUTE: 1369 region_name = "Absolute"; 1370 reg = offset; 1371 break; 1372 case WMFW_ADSP1_PM: 1373 case WMFW_ADSP1_DM: 1374 case WMFW_ADSP2_XM: 1375 case WMFW_ADSP2_YM: 1376 case WMFW_ADSP1_ZM: 1377 case WMFW_HALO_PM_PACKED: 1378 case WMFW_HALO_XM_PACKED: 1379 case WMFW_HALO_YM_PACKED: 1380 mem = cs_dsp_find_region(dsp, type); 1381 if (!mem) { 1382 cs_dsp_err(dsp, "No region of type: %x\n", type); 1383 ret = -EINVAL; 1384 goto out_fw; 1385 } 1386 1387 region_name = cs_dsp_mem_region_name(type); 1388 reg = dsp->ops->region_to_reg(mem, offset); 1389 break; 1390 default: 1391 cs_dsp_warn(dsp, 1392 "%s.%d: Unknown region type %x at %d(%x)\n", 1393 file, regions, type, pos, pos); 1394 break; 1395 } 1396 1397 cs_dsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file, 1398 regions, le32_to_cpu(region->len), offset, 1399 region_name); 1400 1401 if (le32_to_cpu(region->len) > 1402 firmware->size - pos - sizeof(*region)) { 1403 cs_dsp_err(dsp, 1404 "%s.%d: %s region len %d bytes exceeds file length %zu\n", 1405 file, regions, region_name, 1406 le32_to_cpu(region->len), firmware->size); 1407 ret = -EINVAL; 1408 goto out_fw; 1409 } 1410 1411 if (text) { 1412 memcpy(text, region->data, le32_to_cpu(region->len)); 1413 cs_dsp_info(dsp, "%s: %s\n", file, text); 1414 kfree(text); 1415 text = NULL; 1416 } 1417 1418 if (reg) { 1419 buf = cs_dsp_buf_alloc(region->data, 1420 le32_to_cpu(region->len), 1421 &buf_list); 1422 if (!buf) { 1423 cs_dsp_err(dsp, "Out of memory\n"); 1424 ret = -ENOMEM; 1425 goto out_fw; 1426 } 1427 1428 ret = regmap_raw_write_async(regmap, reg, buf->buf, 1429 le32_to_cpu(region->len)); 1430 if (ret != 0) { 1431 cs_dsp_err(dsp, 1432 "%s.%d: Failed to write %d bytes at %d in %s: %d\n", 1433 file, regions, 1434 le32_to_cpu(region->len), offset, 1435 region_name, ret); 1436 goto out_fw; 1437 } 1438 } 1439 1440 pos += le32_to_cpu(region->len) + sizeof(*region); 1441 regions++; 1442 } 1443 1444 ret = regmap_async_complete(regmap); 1445 if (ret != 0) { 1446 cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret); 1447 goto out_fw; 1448 } 1449 1450 if (pos > firmware->size) 1451 cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 1452 file, regions, pos - firmware->size); 1453 1454 cs_dsp_debugfs_save_wmfwname(dsp, file); 1455 1456out_fw: 1457 regmap_async_complete(regmap); 1458 cs_dsp_buf_free(&buf_list); 1459 kfree(text); 1460 1461 return ret; 1462} 1463 1464/** 1465 * cs_dsp_get_ctl() - Finds a matching coefficient control 1466 * @dsp: pointer to DSP structure 1467 * @name: pointer to string to match with a control's subname 1468 * @type: the algorithm type to match 1469 * @alg: the algorithm id to match 1470 * 1471 * Find cs_dsp_coeff_ctl with input name as its subname 1472 * 1473 * Return: pointer to the control on success, NULL if not found 1474 */ 1475struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, int type, 1476 unsigned int alg) 1477{ 1478 struct cs_dsp_coeff_ctl *pos, *rslt = NULL; 1479 1480 lockdep_assert_held(&dsp->pwr_lock); 1481 1482 list_for_each_entry(pos, &dsp->ctl_list, list) { 1483 if (!pos->subname) 1484 continue; 1485 if (strncmp(pos->subname, name, pos->subname_len) == 0 && 1486 pos->fw_name == dsp->fw_name && 1487 pos->alg_region.alg == alg && 1488 pos->alg_region.type == type) { 1489 rslt = pos; 1490 break; 1491 } 1492 } 1493 1494 return rslt; 1495} 1496EXPORT_SYMBOL_GPL(cs_dsp_get_ctl); 1497 1498static void cs_dsp_ctl_fixup_base(struct cs_dsp *dsp, 1499 const struct cs_dsp_alg_region *alg_region) 1500{ 1501 struct cs_dsp_coeff_ctl *ctl; 1502 1503 list_for_each_entry(ctl, &dsp->ctl_list, list) { 1504 if (ctl->fw_name == dsp->fw_name && 1505 alg_region->alg == ctl->alg_region.alg && 1506 alg_region->type == ctl->alg_region.type) { 1507 ctl->alg_region.base = alg_region->base; 1508 } 1509 } 1510} 1511 1512static void *cs_dsp_read_algs(struct cs_dsp *dsp, size_t n_algs, 1513 const struct cs_dsp_region *mem, 1514 unsigned int pos, unsigned int len) 1515{ 1516 void *alg; 1517 unsigned int reg; 1518 int ret; 1519 __be32 val; 1520 1521 if (n_algs == 0) { 1522 cs_dsp_err(dsp, "No algorithms\n"); 1523 return ERR_PTR(-EINVAL); 1524 } 1525 1526 if (n_algs > 1024) { 1527 cs_dsp_err(dsp, "Algorithm count %zx excessive\n", n_algs); 1528 return ERR_PTR(-EINVAL); 1529 } 1530 1531 /* Read the terminator first to validate the length */ 1532 reg = dsp->ops->region_to_reg(mem, pos + len); 1533 1534 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); 1535 if (ret != 0) { 1536 cs_dsp_err(dsp, "Failed to read algorithm list end: %d\n", 1537 ret); 1538 return ERR_PTR(ret); 1539 } 1540 1541 if (be32_to_cpu(val) != 0xbedead) 1542 cs_dsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n", 1543 reg, be32_to_cpu(val)); 1544 1545 /* Convert length from DSP words to bytes */ 1546 len *= sizeof(u32); 1547 1548 alg = kzalloc(len, GFP_KERNEL | GFP_DMA); 1549 if (!alg) 1550 return ERR_PTR(-ENOMEM); 1551 1552 reg = dsp->ops->region_to_reg(mem, pos); 1553 1554 ret = regmap_raw_read(dsp->regmap, reg, alg, len); 1555 if (ret != 0) { 1556 cs_dsp_err(dsp, "Failed to read algorithm list: %d\n", ret); 1557 kfree(alg); 1558 return ERR_PTR(ret); 1559 } 1560 1561 return alg; 1562} 1563 1564/** 1565 * cs_dsp_find_alg_region() - Finds a matching algorithm region 1566 * @dsp: pointer to DSP structure 1567 * @type: the algorithm type to match 1568 * @id: the algorithm id to match 1569 * 1570 * Return: Pointer to matching algorithm region, or NULL if not found. 1571 */ 1572struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp, 1573 int type, unsigned int id) 1574{ 1575 struct cs_dsp_alg_region *alg_region; 1576 1577 lockdep_assert_held(&dsp->pwr_lock); 1578 1579 list_for_each_entry(alg_region, &dsp->alg_regions, list) { 1580 if (id == alg_region->alg && type == alg_region->type) 1581 return alg_region; 1582 } 1583 1584 return NULL; 1585} 1586EXPORT_SYMBOL_GPL(cs_dsp_find_alg_region); 1587 1588static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, 1589 int type, __be32 id, 1590 __be32 ver, __be32 base) 1591{ 1592 struct cs_dsp_alg_region *alg_region; 1593 1594 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL); 1595 if (!alg_region) 1596 return ERR_PTR(-ENOMEM); 1597 1598 alg_region->type = type; 1599 alg_region->alg = be32_to_cpu(id); 1600 alg_region->ver = be32_to_cpu(ver); 1601 alg_region->base = be32_to_cpu(base); 1602 1603 list_add_tail(&alg_region->list, &dsp->alg_regions); 1604 1605 if (dsp->fw_ver > 0) 1606 cs_dsp_ctl_fixup_base(dsp, alg_region); 1607 1608 return alg_region; 1609} 1610 1611static void cs_dsp_free_alg_regions(struct cs_dsp *dsp) 1612{ 1613 struct cs_dsp_alg_region *alg_region; 1614 1615 while (!list_empty(&dsp->alg_regions)) { 1616 alg_region = list_first_entry(&dsp->alg_regions, 1617 struct cs_dsp_alg_region, 1618 list); 1619 list_del(&alg_region->list); 1620 kfree(alg_region); 1621 } 1622} 1623 1624static void cs_dsp_parse_wmfw_id_header(struct cs_dsp *dsp, 1625 struct wmfw_id_hdr *fw, int nalgs) 1626{ 1627 dsp->fw_id = be32_to_cpu(fw->id); 1628 dsp->fw_id_version = be32_to_cpu(fw->ver); 1629 1630 cs_dsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n", 1631 dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16, 1632 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, 1633 nalgs); 1634} 1635 1636static void cs_dsp_parse_wmfw_v3_id_header(struct cs_dsp *dsp, 1637 struct wmfw_v3_id_hdr *fw, int nalgs) 1638{ 1639 dsp->fw_id = be32_to_cpu(fw->id); 1640 dsp->fw_id_version = be32_to_cpu(fw->ver); 1641 dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id); 1642 1643 cs_dsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n", 1644 dsp->fw_id, dsp->fw_vendor_id, 1645 (dsp->fw_id_version & 0xff0000) >> 16, 1646 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, 1647 nalgs); 1648} 1649 1650static int cs_dsp_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver, 1651 int nregions, const int *type, __be32 *base) 1652{ 1653 struct cs_dsp_alg_region *alg_region; 1654 int i; 1655 1656 for (i = 0; i < nregions; i++) { 1657 alg_region = cs_dsp_create_region(dsp, type[i], id, ver, base[i]); 1658 if (IS_ERR(alg_region)) 1659 return PTR_ERR(alg_region); 1660 } 1661 1662 return 0; 1663} 1664 1665static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) 1666{ 1667 struct wmfw_adsp1_id_hdr adsp1_id; 1668 struct wmfw_adsp1_alg_hdr *adsp1_alg; 1669 struct cs_dsp_alg_region *alg_region; 1670 const struct cs_dsp_region *mem; 1671 unsigned int pos, len; 1672 size_t n_algs; 1673 int i, ret; 1674 1675 mem = cs_dsp_find_region(dsp, WMFW_ADSP1_DM); 1676 if (WARN_ON(!mem)) 1677 return -EINVAL; 1678 1679 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id, 1680 sizeof(adsp1_id)); 1681 if (ret != 0) { 1682 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", 1683 ret); 1684 return ret; 1685 } 1686 1687 n_algs = be32_to_cpu(adsp1_id.n_algs); 1688 1689 cs_dsp_parse_wmfw_id_header(dsp, &adsp1_id.fw, n_algs); 1690 1691 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, 1692 adsp1_id.fw.id, adsp1_id.fw.ver, 1693 adsp1_id.zm); 1694 if (IS_ERR(alg_region)) 1695 return PTR_ERR(alg_region); 1696 1697 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, 1698 adsp1_id.fw.id, adsp1_id.fw.ver, 1699 adsp1_id.dm); 1700 if (IS_ERR(alg_region)) 1701 return PTR_ERR(alg_region); 1702 1703 /* Calculate offset and length in DSP words */ 1704 pos = sizeof(adsp1_id) / sizeof(u32); 1705 len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32); 1706 1707 adsp1_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); 1708 if (IS_ERR(adsp1_alg)) 1709 return PTR_ERR(adsp1_alg); 1710 1711 for (i = 0; i < n_algs; i++) { 1712 cs_dsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", 1713 i, be32_to_cpu(adsp1_alg[i].alg.id), 1714 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, 1715 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, 1716 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, 1717 be32_to_cpu(adsp1_alg[i].dm), 1718 be32_to_cpu(adsp1_alg[i].zm)); 1719 1720 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, 1721 adsp1_alg[i].alg.id, 1722 adsp1_alg[i].alg.ver, 1723 adsp1_alg[i].dm); 1724 if (IS_ERR(alg_region)) { 1725 ret = PTR_ERR(alg_region); 1726 goto out; 1727 } 1728 if (dsp->fw_ver == 0) { 1729 if (i + 1 < n_algs) { 1730 len = be32_to_cpu(adsp1_alg[i + 1].dm); 1731 len -= be32_to_cpu(adsp1_alg[i].dm); 1732 len *= 4; 1733 cs_dsp_create_control(dsp, alg_region, 0, 1734 len, NULL, 0, 0, 1735 WMFW_CTL_TYPE_BYTES); 1736 } else { 1737 cs_dsp_warn(dsp, "Missing length info for region DM with ID %x\n", 1738 be32_to_cpu(adsp1_alg[i].alg.id)); 1739 } 1740 } 1741 1742 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, 1743 adsp1_alg[i].alg.id, 1744 adsp1_alg[i].alg.ver, 1745 adsp1_alg[i].zm); 1746 if (IS_ERR(alg_region)) { 1747 ret = PTR_ERR(alg_region); 1748 goto out; 1749 } 1750 if (dsp->fw_ver == 0) { 1751 if (i + 1 < n_algs) { 1752 len = be32_to_cpu(adsp1_alg[i + 1].zm); 1753 len -= be32_to_cpu(adsp1_alg[i].zm); 1754 len *= 4; 1755 cs_dsp_create_control(dsp, alg_region, 0, 1756 len, NULL, 0, 0, 1757 WMFW_CTL_TYPE_BYTES); 1758 } else { 1759 cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 1760 be32_to_cpu(adsp1_alg[i].alg.id)); 1761 } 1762 } 1763 } 1764 1765out: 1766 kfree(adsp1_alg); 1767 return ret; 1768} 1769 1770static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) 1771{ 1772 struct wmfw_adsp2_id_hdr adsp2_id; 1773 struct wmfw_adsp2_alg_hdr *adsp2_alg; 1774 struct cs_dsp_alg_region *alg_region; 1775 const struct cs_dsp_region *mem; 1776 unsigned int pos, len; 1777 size_t n_algs; 1778 int i, ret; 1779 1780 mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM); 1781 if (WARN_ON(!mem)) 1782 return -EINVAL; 1783 1784 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id, 1785 sizeof(adsp2_id)); 1786 if (ret != 0) { 1787 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", 1788 ret); 1789 return ret; 1790 } 1791 1792 n_algs = be32_to_cpu(adsp2_id.n_algs); 1793 1794 cs_dsp_parse_wmfw_id_header(dsp, &adsp2_id.fw, n_algs); 1795 1796 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, 1797 adsp2_id.fw.id, adsp2_id.fw.ver, 1798 adsp2_id.xm); 1799 if (IS_ERR(alg_region)) 1800 return PTR_ERR(alg_region); 1801 1802 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, 1803 adsp2_id.fw.id, adsp2_id.fw.ver, 1804 adsp2_id.ym); 1805 if (IS_ERR(alg_region)) 1806 return PTR_ERR(alg_region); 1807 1808 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, 1809 adsp2_id.fw.id, adsp2_id.fw.ver, 1810 adsp2_id.zm); 1811 if (IS_ERR(alg_region)) 1812 return PTR_ERR(alg_region); 1813 1814 /* Calculate offset and length in DSP words */ 1815 pos = sizeof(adsp2_id) / sizeof(u32); 1816 len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32); 1817 1818 adsp2_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); 1819 if (IS_ERR(adsp2_alg)) 1820 return PTR_ERR(adsp2_alg); 1821 1822 for (i = 0; i < n_algs; i++) { 1823 cs_dsp_info(dsp, 1824 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", 1825 i, be32_to_cpu(adsp2_alg[i].alg.id), 1826 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, 1827 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, 1828 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, 1829 be32_to_cpu(adsp2_alg[i].xm), 1830 be32_to_cpu(adsp2_alg[i].ym), 1831 be32_to_cpu(adsp2_alg[i].zm)); 1832 1833 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, 1834 adsp2_alg[i].alg.id, 1835 adsp2_alg[i].alg.ver, 1836 adsp2_alg[i].xm); 1837 if (IS_ERR(alg_region)) { 1838 ret = PTR_ERR(alg_region); 1839 goto out; 1840 } 1841 if (dsp->fw_ver == 0) { 1842 if (i + 1 < n_algs) { 1843 len = be32_to_cpu(adsp2_alg[i + 1].xm); 1844 len -= be32_to_cpu(adsp2_alg[i].xm); 1845 len *= 4; 1846 cs_dsp_create_control(dsp, alg_region, 0, 1847 len, NULL, 0, 0, 1848 WMFW_CTL_TYPE_BYTES); 1849 } else { 1850 cs_dsp_warn(dsp, "Missing length info for region XM with ID %x\n", 1851 be32_to_cpu(adsp2_alg[i].alg.id)); 1852 } 1853 } 1854 1855 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, 1856 adsp2_alg[i].alg.id, 1857 adsp2_alg[i].alg.ver, 1858 adsp2_alg[i].ym); 1859 if (IS_ERR(alg_region)) { 1860 ret = PTR_ERR(alg_region); 1861 goto out; 1862 } 1863 if (dsp->fw_ver == 0) { 1864 if (i + 1 < n_algs) { 1865 len = be32_to_cpu(adsp2_alg[i + 1].ym); 1866 len -= be32_to_cpu(adsp2_alg[i].ym); 1867 len *= 4; 1868 cs_dsp_create_control(dsp, alg_region, 0, 1869 len, NULL, 0, 0, 1870 WMFW_CTL_TYPE_BYTES); 1871 } else { 1872 cs_dsp_warn(dsp, "Missing length info for region YM with ID %x\n", 1873 be32_to_cpu(adsp2_alg[i].alg.id)); 1874 } 1875 } 1876 1877 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, 1878 adsp2_alg[i].alg.id, 1879 adsp2_alg[i].alg.ver, 1880 adsp2_alg[i].zm); 1881 if (IS_ERR(alg_region)) { 1882 ret = PTR_ERR(alg_region); 1883 goto out; 1884 } 1885 if (dsp->fw_ver == 0) { 1886 if (i + 1 < n_algs) { 1887 len = be32_to_cpu(adsp2_alg[i + 1].zm); 1888 len -= be32_to_cpu(adsp2_alg[i].zm); 1889 len *= 4; 1890 cs_dsp_create_control(dsp, alg_region, 0, 1891 len, NULL, 0, 0, 1892 WMFW_CTL_TYPE_BYTES); 1893 } else { 1894 cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 1895 be32_to_cpu(adsp2_alg[i].alg.id)); 1896 } 1897 } 1898 } 1899 1900out: 1901 kfree(adsp2_alg); 1902 return ret; 1903} 1904 1905static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver, 1906 __be32 xm_base, __be32 ym_base) 1907{ 1908 static const int types[] = { 1909 WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED, 1910 WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED 1911 }; 1912 __be32 bases[] = { xm_base, xm_base, ym_base, ym_base }; 1913 1914 return cs_dsp_create_regions(dsp, id, ver, ARRAY_SIZE(types), types, bases); 1915} 1916 1917static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp) 1918{ 1919 struct wmfw_halo_id_hdr halo_id; 1920 struct wmfw_halo_alg_hdr *halo_alg; 1921 const struct cs_dsp_region *mem; 1922 unsigned int pos, len; 1923 size_t n_algs; 1924 int i, ret; 1925 1926 mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM); 1927 if (WARN_ON(!mem)) 1928 return -EINVAL; 1929 1930 ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id, 1931 sizeof(halo_id)); 1932 if (ret != 0) { 1933 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", 1934 ret); 1935 return ret; 1936 } 1937 1938 n_algs = be32_to_cpu(halo_id.n_algs); 1939 1940 cs_dsp_parse_wmfw_v3_id_header(dsp, &halo_id.fw, n_algs); 1941 1942 ret = cs_dsp_halo_create_regions(dsp, halo_id.fw.id, halo_id.fw.ver, 1943 halo_id.xm_base, halo_id.ym_base); 1944 if (ret) 1945 return ret; 1946 1947 /* Calculate offset and length in DSP words */ 1948 pos = sizeof(halo_id) / sizeof(u32); 1949 len = (sizeof(*halo_alg) * n_algs) / sizeof(u32); 1950 1951 halo_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); 1952 if (IS_ERR(halo_alg)) 1953 return PTR_ERR(halo_alg); 1954 1955 for (i = 0; i < n_algs; i++) { 1956 cs_dsp_info(dsp, 1957 "%d: ID %x v%d.%d.%d XM@%x YM@%x\n", 1958 i, be32_to_cpu(halo_alg[i].alg.id), 1959 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16, 1960 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8, 1961 be32_to_cpu(halo_alg[i].alg.ver) & 0xff, 1962 be32_to_cpu(halo_alg[i].xm_base), 1963 be32_to_cpu(halo_alg[i].ym_base)); 1964 1965 ret = cs_dsp_halo_create_regions(dsp, halo_alg[i].alg.id, 1966 halo_alg[i].alg.ver, 1967 halo_alg[i].xm_base, 1968 halo_alg[i].ym_base); 1969 if (ret) 1970 goto out; 1971 } 1972 1973out: 1974 kfree(halo_alg); 1975 return ret; 1976} 1977 1978static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware, 1979 const char *file) 1980{ 1981 LIST_HEAD(buf_list); 1982 struct regmap *regmap = dsp->regmap; 1983 struct wmfw_coeff_hdr *hdr; 1984 struct wmfw_coeff_item *blk; 1985 const struct cs_dsp_region *mem; 1986 struct cs_dsp_alg_region *alg_region; 1987 const char *region_name; 1988 int ret, pos, blocks, type, offset, reg, version; 1989 char *text = NULL; 1990 struct cs_dsp_buf *buf; 1991 1992 if (!firmware) 1993 return 0; 1994 1995 ret = -EINVAL; 1996 1997 if (sizeof(*hdr) >= firmware->size) { 1998 cs_dsp_err(dsp, "%s: coefficient file too short, %zu bytes\n", 1999 file, firmware->size); 2000 goto out_fw; 2001 } 2002 2003 hdr = (void *)&firmware->data[0]; 2004 if (memcmp(hdr->magic, "WMDR", 4) != 0) { 2005 cs_dsp_err(dsp, "%s: invalid coefficient magic\n", file); 2006 goto out_fw; 2007 } 2008 2009 switch (be32_to_cpu(hdr->rev) & 0xff) { 2010 case 1: 2011 case 2: 2012 break; 2013 default: 2014 cs_dsp_err(dsp, "%s: Unsupported coefficient file format %d\n", 2015 file, be32_to_cpu(hdr->rev) & 0xff); 2016 ret = -EINVAL; 2017 goto out_fw; 2018 } 2019 2020 cs_dsp_dbg(dsp, "%s: v%d.%d.%d\n", file, 2021 (le32_to_cpu(hdr->ver) >> 16) & 0xff, 2022 (le32_to_cpu(hdr->ver) >> 8) & 0xff, 2023 le32_to_cpu(hdr->ver) & 0xff); 2024 2025 pos = le32_to_cpu(hdr->len); 2026 2027 blocks = 0; 2028 while (pos < firmware->size && 2029 sizeof(*blk) < firmware->size - pos) { 2030 blk = (void *)(&firmware->data[pos]); 2031 2032 type = le16_to_cpu(blk->type); 2033 offset = le16_to_cpu(blk->offset); 2034 version = le32_to_cpu(blk->ver) >> 8; 2035 2036 cs_dsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", 2037 file, blocks, le32_to_cpu(blk->id), 2038 (le32_to_cpu(blk->ver) >> 16) & 0xff, 2039 (le32_to_cpu(blk->ver) >> 8) & 0xff, 2040 le32_to_cpu(blk->ver) & 0xff); 2041 cs_dsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n", 2042 file, blocks, le32_to_cpu(blk->len), offset, type); 2043 2044 reg = 0; 2045 region_name = "Unknown"; 2046 switch (type) { 2047 case (WMFW_NAME_TEXT << 8): 2048 text = kzalloc(le32_to_cpu(blk->len) + 1, GFP_KERNEL); 2049 break; 2050 case (WMFW_INFO_TEXT << 8): 2051 case (WMFW_METADATA << 8): 2052 break; 2053 case (WMFW_ABSOLUTE << 8): 2054 /* 2055 * Old files may use this for global 2056 * coefficients. 2057 */ 2058 if (le32_to_cpu(blk->id) == dsp->fw_id && 2059 offset == 0) { 2060 region_name = "global coefficients"; 2061 mem = cs_dsp_find_region(dsp, type); 2062 if (!mem) { 2063 cs_dsp_err(dsp, "No ZM\n"); 2064 break; 2065 } 2066 reg = dsp->ops->region_to_reg(mem, 0); 2067 2068 } else { 2069 region_name = "register"; 2070 reg = offset; 2071 } 2072 break; 2073 2074 case WMFW_ADSP1_DM: 2075 case WMFW_ADSP1_ZM: 2076 case WMFW_ADSP2_XM: 2077 case WMFW_ADSP2_YM: 2078 case WMFW_HALO_XM_PACKED: 2079 case WMFW_HALO_YM_PACKED: 2080 case WMFW_HALO_PM_PACKED: 2081 cs_dsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", 2082 file, blocks, le32_to_cpu(blk->len), 2083 type, le32_to_cpu(blk->id)); 2084 2085 mem = cs_dsp_find_region(dsp, type); 2086 if (!mem) { 2087 cs_dsp_err(dsp, "No base for region %x\n", type); 2088 break; 2089 } 2090 2091 alg_region = cs_dsp_find_alg_region(dsp, type, 2092 le32_to_cpu(blk->id)); 2093 if (alg_region) { 2094 if (version != alg_region->ver) 2095 cs_dsp_warn(dsp, 2096 "Algorithm coefficient version %d.%d.%d but expected %d.%d.%d\n", 2097 (version >> 16) & 0xFF, 2098 (version >> 8) & 0xFF, 2099 version & 0xFF, 2100 (alg_region->ver >> 16) & 0xFF, 2101 (alg_region->ver >> 8) & 0xFF, 2102 alg_region->ver & 0xFF); 2103 2104 reg = alg_region->base; 2105 reg = dsp->ops->region_to_reg(mem, reg); 2106 reg += offset; 2107 } else { 2108 cs_dsp_err(dsp, "No %x for algorithm %x\n", 2109 type, le32_to_cpu(blk->id)); 2110 } 2111 break; 2112 2113 default: 2114 cs_dsp_err(dsp, "%s.%d: Unknown region type %x at %d\n", 2115 file, blocks, type, pos); 2116 break; 2117 } 2118 2119 if (text) { 2120 memcpy(text, blk->data, le32_to_cpu(blk->len)); 2121 cs_dsp_info(dsp, "%s: %s\n", dsp->fw_name, text); 2122 kfree(text); 2123 text = NULL; 2124 } 2125 2126 if (reg) { 2127 if (le32_to_cpu(blk->len) > 2128 firmware->size - pos - sizeof(*blk)) { 2129 cs_dsp_err(dsp, 2130 "%s.%d: %s region len %d bytes exceeds file length %zu\n", 2131 file, blocks, region_name, 2132 le32_to_cpu(blk->len), 2133 firmware->size); 2134 ret = -EINVAL; 2135 goto out_fw; 2136 } 2137 2138 buf = cs_dsp_buf_alloc(blk->data, 2139 le32_to_cpu(blk->len), 2140 &buf_list); 2141 if (!buf) { 2142 cs_dsp_err(dsp, "Out of memory\n"); 2143 ret = -ENOMEM; 2144 goto out_fw; 2145 } 2146 2147 cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", 2148 file, blocks, le32_to_cpu(blk->len), 2149 reg); 2150 ret = regmap_raw_write_async(regmap, reg, buf->buf, 2151 le32_to_cpu(blk->len)); 2152 if (ret != 0) { 2153 cs_dsp_err(dsp, 2154 "%s.%d: Failed to write to %x in %s: %d\n", 2155 file, blocks, reg, region_name, ret); 2156 } 2157 } 2158 2159 pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03; 2160 blocks++; 2161 } 2162 2163 ret = regmap_async_complete(regmap); 2164 if (ret != 0) 2165 cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret); 2166 2167 if (pos > firmware->size) 2168 cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 2169 file, blocks, pos - firmware->size); 2170 2171 cs_dsp_debugfs_save_binname(dsp, file); 2172 2173out_fw: 2174 regmap_async_complete(regmap); 2175 cs_dsp_buf_free(&buf_list); 2176 kfree(text); 2177 return ret; 2178} 2179 2180static int cs_dsp_create_name(struct cs_dsp *dsp) 2181{ 2182 if (!dsp->name) { 2183 dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d", 2184 dsp->num); 2185 if (!dsp->name) 2186 return -ENOMEM; 2187 } 2188 2189 return 0; 2190} 2191 2192static int cs_dsp_common_init(struct cs_dsp *dsp) 2193{ 2194 int ret; 2195 2196 ret = cs_dsp_create_name(dsp); 2197 if (ret) 2198 return ret; 2199 2200 INIT_LIST_HEAD(&dsp->alg_regions); 2201 INIT_LIST_HEAD(&dsp->ctl_list); 2202 2203 mutex_init(&dsp->pwr_lock); 2204 2205 return 0; 2206} 2207 2208/** 2209 * cs_dsp_adsp1_init() - Initialise a cs_dsp structure representing a ADSP1 device 2210 * @dsp: pointer to DSP structure 2211 * 2212 * Return: Zero for success, a negative number on error. 2213 */ 2214int cs_dsp_adsp1_init(struct cs_dsp *dsp) 2215{ 2216 dsp->ops = &cs_dsp_adsp1_ops; 2217 2218 return cs_dsp_common_init(dsp); 2219} 2220EXPORT_SYMBOL_GPL(cs_dsp_adsp1_init); 2221 2222/** 2223 * cs_dsp_adsp1_power_up() - Load and start the named firmware 2224 * @dsp: pointer to DSP structure 2225 * @wmfw_firmware: the firmware to be sent 2226 * @wmfw_filename: file name of firmware to be sent 2227 * @coeff_firmware: the coefficient data to be sent 2228 * @coeff_filename: file name of coefficient to data be sent 2229 * @fw_name: the user-friendly firmware name 2230 * 2231 * Return: Zero for success, a negative number on error. 2232 */ 2233int cs_dsp_adsp1_power_up(struct cs_dsp *dsp, 2234 const struct firmware *wmfw_firmware, char *wmfw_filename, 2235 const struct firmware *coeff_firmware, char *coeff_filename, 2236 const char *fw_name) 2237{ 2238 unsigned int val; 2239 int ret; 2240 2241 mutex_lock(&dsp->pwr_lock); 2242 2243 dsp->fw_name = fw_name; 2244 2245 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2246 ADSP1_SYS_ENA, ADSP1_SYS_ENA); 2247 2248 /* 2249 * For simplicity set the DSP clock rate to be the 2250 * SYSCLK rate rather than making it configurable. 2251 */ 2252 if (dsp->sysclk_reg) { 2253 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); 2254 if (ret != 0) { 2255 cs_dsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); 2256 goto err_mutex; 2257 } 2258 2259 val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift; 2260 2261 ret = regmap_update_bits(dsp->regmap, 2262 dsp->base + ADSP1_CONTROL_31, 2263 ADSP1_CLK_SEL_MASK, val); 2264 if (ret != 0) { 2265 cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret); 2266 goto err_mutex; 2267 } 2268 } 2269 2270 ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename); 2271 if (ret != 0) 2272 goto err_ena; 2273 2274 ret = cs_dsp_adsp1_setup_algs(dsp); 2275 if (ret != 0) 2276 goto err_ena; 2277 2278 ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename); 2279 if (ret != 0) 2280 goto err_ena; 2281 2282 /* Initialize caches for enabled and unset controls */ 2283 ret = cs_dsp_coeff_init_control_caches(dsp); 2284 if (ret != 0) 2285 goto err_ena; 2286 2287 /* Sync set controls */ 2288 ret = cs_dsp_coeff_sync_controls(dsp); 2289 if (ret != 0) 2290 goto err_ena; 2291 2292 dsp->booted = true; 2293 2294 /* Start the core running */ 2295 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2296 ADSP1_CORE_ENA | ADSP1_START, 2297 ADSP1_CORE_ENA | ADSP1_START); 2298 2299 dsp->running = true; 2300 2301 mutex_unlock(&dsp->pwr_lock); 2302 2303 return 0; 2304 2305err_ena: 2306 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2307 ADSP1_SYS_ENA, 0); 2308err_mutex: 2309 mutex_unlock(&dsp->pwr_lock); 2310 return ret; 2311} 2312EXPORT_SYMBOL_GPL(cs_dsp_adsp1_power_up); 2313 2314/** 2315 * cs_dsp_adsp1_power_down() - Halts the DSP 2316 * @dsp: pointer to DSP structure 2317 */ 2318void cs_dsp_adsp1_power_down(struct cs_dsp *dsp) 2319{ 2320 struct cs_dsp_coeff_ctl *ctl; 2321 2322 mutex_lock(&dsp->pwr_lock); 2323 2324 dsp->running = false; 2325 dsp->booted = false; 2326 2327 /* Halt the core */ 2328 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2329 ADSP1_CORE_ENA | ADSP1_START, 0); 2330 2331 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, 2332 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0); 2333 2334 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2335 ADSP1_SYS_ENA, 0); 2336 2337 list_for_each_entry(ctl, &dsp->ctl_list, list) 2338 ctl->enabled = 0; 2339 2340 cs_dsp_free_alg_regions(dsp); 2341 2342 mutex_unlock(&dsp->pwr_lock); 2343} 2344EXPORT_SYMBOL_GPL(cs_dsp_adsp1_power_down); 2345 2346static int cs_dsp_adsp2v2_enable_core(struct cs_dsp *dsp) 2347{ 2348 unsigned int val; 2349 int ret, count; 2350 2351 /* Wait for the RAM to start, should be near instantaneous */ 2352 for (count = 0; count < 10; ++count) { 2353 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val); 2354 if (ret != 0) 2355 return ret; 2356 2357 if (val & ADSP2_RAM_RDY) 2358 break; 2359 2360 usleep_range(250, 500); 2361 } 2362 2363 if (!(val & ADSP2_RAM_RDY)) { 2364 cs_dsp_err(dsp, "Failed to start DSP RAM\n"); 2365 return -EBUSY; 2366 } 2367 2368 cs_dsp_dbg(dsp, "RAM ready after %d polls\n", count); 2369 2370 return 0; 2371} 2372 2373static int cs_dsp_adsp2_enable_core(struct cs_dsp *dsp) 2374{ 2375 int ret; 2376 2377 ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL, 2378 ADSP2_SYS_ENA, ADSP2_SYS_ENA); 2379 if (ret != 0) 2380 return ret; 2381 2382 return cs_dsp_adsp2v2_enable_core(dsp); 2383} 2384 2385static int cs_dsp_adsp2_lock(struct cs_dsp *dsp, unsigned int lock_regions) 2386{ 2387 struct regmap *regmap = dsp->regmap; 2388 unsigned int code0, code1, lock_reg; 2389 2390 if (!(lock_regions & CS_ADSP2_REGION_ALL)) 2391 return 0; 2392 2393 lock_regions &= CS_ADSP2_REGION_ALL; 2394 lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0; 2395 2396 while (lock_regions) { 2397 code0 = code1 = 0; 2398 if (lock_regions & BIT(0)) { 2399 code0 = ADSP2_LOCK_CODE_0; 2400 code1 = ADSP2_LOCK_CODE_1; 2401 } 2402 if (lock_regions & BIT(1)) { 2403 code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT; 2404 code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT; 2405 } 2406 regmap_write(regmap, lock_reg, code0); 2407 regmap_write(regmap, lock_reg, code1); 2408 lock_regions >>= 2; 2409 lock_reg += 2; 2410 } 2411 2412 return 0; 2413} 2414 2415static int cs_dsp_adsp2_enable_memory(struct cs_dsp *dsp) 2416{ 2417 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2418 ADSP2_MEM_ENA, ADSP2_MEM_ENA); 2419} 2420 2421static void cs_dsp_adsp2_disable_memory(struct cs_dsp *dsp) 2422{ 2423 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2424 ADSP2_MEM_ENA, 0); 2425} 2426 2427static void cs_dsp_adsp2_disable_core(struct cs_dsp *dsp) 2428{ 2429 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); 2430 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); 2431 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); 2432 2433 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2434 ADSP2_SYS_ENA, 0); 2435} 2436 2437static void cs_dsp_adsp2v2_disable_core(struct cs_dsp *dsp) 2438{ 2439 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); 2440 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); 2441 regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0); 2442} 2443 2444static int cs_dsp_halo_configure_mpu(struct cs_dsp *dsp, unsigned int lock_regions) 2445{ 2446 struct reg_sequence config[] = { 2447 { dsp->base + HALO_MPU_LOCK_CONFIG, 0x5555 }, 2448 { dsp->base + HALO_MPU_LOCK_CONFIG, 0xAAAA }, 2449 { dsp->base + HALO_MPU_XMEM_ACCESS_0, 0xFFFFFFFF }, 2450 { dsp->base + HALO_MPU_YMEM_ACCESS_0, 0xFFFFFFFF }, 2451 { dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions }, 2452 { dsp->base + HALO_MPU_XREG_ACCESS_0, lock_regions }, 2453 { dsp->base + HALO_MPU_YREG_ACCESS_0, lock_regions }, 2454 { dsp->base + HALO_MPU_XMEM_ACCESS_1, 0xFFFFFFFF }, 2455 { dsp->base + HALO_MPU_YMEM_ACCESS_1, 0xFFFFFFFF }, 2456 { dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions }, 2457 { dsp->base + HALO_MPU_XREG_ACCESS_1, lock_regions }, 2458 { dsp->base + HALO_MPU_YREG_ACCESS_1, lock_regions }, 2459 { dsp->base + HALO_MPU_XMEM_ACCESS_2, 0xFFFFFFFF }, 2460 { dsp->base + HALO_MPU_YMEM_ACCESS_2, 0xFFFFFFFF }, 2461 { dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions }, 2462 { dsp->base + HALO_MPU_XREG_ACCESS_2, lock_regions }, 2463 { dsp->base + HALO_MPU_YREG_ACCESS_2, lock_regions }, 2464 { dsp->base + HALO_MPU_XMEM_ACCESS_3, 0xFFFFFFFF }, 2465 { dsp->base + HALO_MPU_YMEM_ACCESS_3, 0xFFFFFFFF }, 2466 { dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions }, 2467 { dsp->base + HALO_MPU_XREG_ACCESS_3, lock_regions }, 2468 { dsp->base + HALO_MPU_YREG_ACCESS_3, lock_regions }, 2469 { dsp->base + HALO_MPU_LOCK_CONFIG, 0 }, 2470 }; 2471 2472 return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config)); 2473} 2474 2475/** 2476 * cs_dsp_set_dspclk() - Applies the given frequency to the given cs_dsp 2477 * @dsp: pointer to DSP structure 2478 * @freq: clock rate to set 2479 * 2480 * This is only for use on ADSP2 cores. 2481 * 2482 * Return: Zero for success, a negative number on error. 2483 */ 2484int cs_dsp_set_dspclk(struct cs_dsp *dsp, unsigned int freq) 2485{ 2486 int ret; 2487 2488 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING, 2489 ADSP2_CLK_SEL_MASK, 2490 freq << ADSP2_CLK_SEL_SHIFT); 2491 if (ret) 2492 cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret); 2493 2494 return ret; 2495} 2496EXPORT_SYMBOL_GPL(cs_dsp_set_dspclk); 2497 2498static void cs_dsp_stop_watchdog(struct cs_dsp *dsp) 2499{ 2500 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG, 2501 ADSP2_WDT_ENA_MASK, 0); 2502} 2503 2504static void cs_dsp_halo_stop_watchdog(struct cs_dsp *dsp) 2505{ 2506 regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL, 2507 HALO_WDT_EN_MASK, 0); 2508} 2509 2510/** 2511 * cs_dsp_power_up() - Downloads firmware to the DSP 2512 * @dsp: pointer to DSP structure 2513 * @wmfw_firmware: the firmware to be sent 2514 * @wmfw_filename: file name of firmware to be sent 2515 * @coeff_firmware: the coefficient data to be sent 2516 * @coeff_filename: file name of coefficient to data be sent 2517 * @fw_name: the user-friendly firmware name 2518 * 2519 * This function is used on ADSP2 and Halo DSP cores, it powers-up the DSP core 2520 * and downloads the firmware but does not start the firmware running. The 2521 * cs_dsp booted flag will be set once completed and if the core has a low-power 2522 * memory retention mode it will be put into this state after the firmware is 2523 * downloaded. 2524 * 2525 * Return: Zero for success, a negative number on error. 2526 */ 2527int cs_dsp_power_up(struct cs_dsp *dsp, 2528 const struct firmware *wmfw_firmware, char *wmfw_filename, 2529 const struct firmware *coeff_firmware, char *coeff_filename, 2530 const char *fw_name) 2531{ 2532 int ret; 2533 2534 mutex_lock(&dsp->pwr_lock); 2535 2536 dsp->fw_name = fw_name; 2537 2538 if (dsp->ops->enable_memory) { 2539 ret = dsp->ops->enable_memory(dsp); 2540 if (ret != 0) 2541 goto err_mutex; 2542 } 2543 2544 if (dsp->ops->enable_core) { 2545 ret = dsp->ops->enable_core(dsp); 2546 if (ret != 0) 2547 goto err_mem; 2548 } 2549 2550 ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename); 2551 if (ret != 0) 2552 goto err_ena; 2553 2554 ret = dsp->ops->setup_algs(dsp); 2555 if (ret != 0) 2556 goto err_ena; 2557 2558 ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename); 2559 if (ret != 0) 2560 goto err_ena; 2561 2562 /* Initialize caches for enabled and unset controls */ 2563 ret = cs_dsp_coeff_init_control_caches(dsp); 2564 if (ret != 0) 2565 goto err_ena; 2566 2567 if (dsp->ops->disable_core) 2568 dsp->ops->disable_core(dsp); 2569 2570 dsp->booted = true; 2571 2572 mutex_unlock(&dsp->pwr_lock); 2573 2574 return 0; 2575err_ena: 2576 if (dsp->ops->disable_core) 2577 dsp->ops->disable_core(dsp); 2578err_mem: 2579 if (dsp->ops->disable_memory) 2580 dsp->ops->disable_memory(dsp); 2581err_mutex: 2582 mutex_unlock(&dsp->pwr_lock); 2583 2584 return ret; 2585} 2586EXPORT_SYMBOL_GPL(cs_dsp_power_up); 2587 2588/** 2589 * cs_dsp_power_down() - Powers-down the DSP 2590 * @dsp: pointer to DSP structure 2591 * 2592 * cs_dsp_stop() must have been called before this function. The core will be 2593 * fully powered down and so the memory will not be retained. 2594 */ 2595void cs_dsp_power_down(struct cs_dsp *dsp) 2596{ 2597 struct cs_dsp_coeff_ctl *ctl; 2598 2599 mutex_lock(&dsp->pwr_lock); 2600 2601 cs_dsp_debugfs_clear(dsp); 2602 2603 dsp->fw_id = 0; 2604 dsp->fw_id_version = 0; 2605 2606 dsp->booted = false; 2607 2608 if (dsp->ops->disable_memory) 2609 dsp->ops->disable_memory(dsp); 2610 2611 list_for_each_entry(ctl, &dsp->ctl_list, list) 2612 ctl->enabled = 0; 2613 2614 cs_dsp_free_alg_regions(dsp); 2615 2616 mutex_unlock(&dsp->pwr_lock); 2617 2618 cs_dsp_dbg(dsp, "Shutdown complete\n"); 2619} 2620EXPORT_SYMBOL_GPL(cs_dsp_power_down); 2621 2622static int cs_dsp_adsp2_start_core(struct cs_dsp *dsp) 2623{ 2624 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2625 ADSP2_CORE_ENA | ADSP2_START, 2626 ADSP2_CORE_ENA | ADSP2_START); 2627} 2628 2629static void cs_dsp_adsp2_stop_core(struct cs_dsp *dsp) 2630{ 2631 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2632 ADSP2_CORE_ENA | ADSP2_START, 0); 2633} 2634 2635/** 2636 * cs_dsp_run() - Starts the firmware running 2637 * @dsp: pointer to DSP structure 2638 * 2639 * cs_dsp_power_up() must have previously been called successfully. 2640 * 2641 * Return: Zero for success, a negative number on error. 2642 */ 2643int cs_dsp_run(struct cs_dsp *dsp) 2644{ 2645 int ret; 2646 2647 mutex_lock(&dsp->pwr_lock); 2648 2649 if (!dsp->booted) { 2650 ret = -EIO; 2651 goto err; 2652 } 2653 2654 if (dsp->ops->enable_core) { 2655 ret = dsp->ops->enable_core(dsp); 2656 if (ret != 0) 2657 goto err; 2658 } 2659 2660 if (dsp->client_ops->pre_run) { 2661 ret = dsp->client_ops->pre_run(dsp); 2662 if (ret) 2663 goto err; 2664 } 2665 2666 /* Sync set controls */ 2667 ret = cs_dsp_coeff_sync_controls(dsp); 2668 if (ret != 0) 2669 goto err; 2670 2671 if (dsp->ops->lock_memory) { 2672 ret = dsp->ops->lock_memory(dsp, dsp->lock_regions); 2673 if (ret != 0) { 2674 cs_dsp_err(dsp, "Error configuring MPU: %d\n", ret); 2675 goto err; 2676 } 2677 } 2678 2679 if (dsp->ops->start_core) { 2680 ret = dsp->ops->start_core(dsp); 2681 if (ret != 0) 2682 goto err; 2683 } 2684 2685 dsp->running = true; 2686 2687 if (dsp->client_ops->post_run) { 2688 ret = dsp->client_ops->post_run(dsp); 2689 if (ret) 2690 goto err; 2691 } 2692 2693 mutex_unlock(&dsp->pwr_lock); 2694 2695 return 0; 2696 2697err: 2698 if (dsp->ops->stop_core) 2699 dsp->ops->stop_core(dsp); 2700 if (dsp->ops->disable_core) 2701 dsp->ops->disable_core(dsp); 2702 mutex_unlock(&dsp->pwr_lock); 2703 2704 return ret; 2705} 2706EXPORT_SYMBOL_GPL(cs_dsp_run); 2707 2708/** 2709 * cs_dsp_stop() - Stops the firmware 2710 * @dsp: pointer to DSP structure 2711 * 2712 * Memory will not be disabled so firmware will remain loaded. 2713 */ 2714void cs_dsp_stop(struct cs_dsp *dsp) 2715{ 2716 /* Tell the firmware to cleanup */ 2717 cs_dsp_signal_event_controls(dsp, CS_DSP_FW_EVENT_SHUTDOWN); 2718 2719 if (dsp->ops->stop_watchdog) 2720 dsp->ops->stop_watchdog(dsp); 2721 2722 /* Log firmware state, it can be useful for analysis */ 2723 if (dsp->ops->show_fw_status) 2724 dsp->ops->show_fw_status(dsp); 2725 2726 mutex_lock(&dsp->pwr_lock); 2727 2728 dsp->running = false; 2729 2730 if (dsp->ops->stop_core) 2731 dsp->ops->stop_core(dsp); 2732 if (dsp->ops->disable_core) 2733 dsp->ops->disable_core(dsp); 2734 2735 if (dsp->client_ops->post_stop) 2736 dsp->client_ops->post_stop(dsp); 2737 2738 mutex_unlock(&dsp->pwr_lock); 2739 2740 cs_dsp_dbg(dsp, "Execution stopped\n"); 2741} 2742EXPORT_SYMBOL_GPL(cs_dsp_stop); 2743 2744static int cs_dsp_halo_start_core(struct cs_dsp *dsp) 2745{ 2746 int ret; 2747 2748 ret = regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, 2749 HALO_CORE_RESET | HALO_CORE_EN, 2750 HALO_CORE_RESET | HALO_CORE_EN); 2751 if (ret) 2752 return ret; 2753 2754 return regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, 2755 HALO_CORE_RESET, 0); 2756} 2757 2758static void cs_dsp_halo_stop_core(struct cs_dsp *dsp) 2759{ 2760 regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, 2761 HALO_CORE_EN, 0); 2762 2763 /* reset halo core with CORE_SOFT_RESET */ 2764 regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET, 2765 HALO_CORE_SOFT_RESET_MASK, 1); 2766} 2767 2768/** 2769 * cs_dsp_adsp2_init() - Initialise a cs_dsp structure representing a ADSP2 core 2770 * @dsp: pointer to DSP structure 2771 * 2772 * Return: Zero for success, a negative number on error. 2773 */ 2774int cs_dsp_adsp2_init(struct cs_dsp *dsp) 2775{ 2776 int ret; 2777 2778 switch (dsp->rev) { 2779 case 0: 2780 /* 2781 * Disable the DSP memory by default when in reset for a small 2782 * power saving. 2783 */ 2784 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2785 ADSP2_MEM_ENA, 0); 2786 if (ret) { 2787 cs_dsp_err(dsp, 2788 "Failed to clear memory retention: %d\n", ret); 2789 return ret; 2790 } 2791 2792 dsp->ops = &cs_dsp_adsp2_ops[0]; 2793 break; 2794 case 1: 2795 dsp->ops = &cs_dsp_adsp2_ops[1]; 2796 break; 2797 default: 2798 dsp->ops = &cs_dsp_adsp2_ops[2]; 2799 break; 2800 } 2801 2802 return cs_dsp_common_init(dsp); 2803} 2804EXPORT_SYMBOL_GPL(cs_dsp_adsp2_init); 2805 2806/** 2807 * cs_dsp_halo_init() - Initialise a cs_dsp structure representing a HALO Core DSP 2808 * @dsp: pointer to DSP structure 2809 * 2810 * Return: Zero for success, a negative number on error. 2811 */ 2812int cs_dsp_halo_init(struct cs_dsp *dsp) 2813{ 2814 dsp->ops = &cs_dsp_halo_ops; 2815 2816 return cs_dsp_common_init(dsp); 2817} 2818EXPORT_SYMBOL_GPL(cs_dsp_halo_init); 2819 2820/** 2821 * cs_dsp_remove() - Clean a cs_dsp before deletion 2822 * @dsp: pointer to DSP structure 2823 */ 2824void cs_dsp_remove(struct cs_dsp *dsp) 2825{ 2826 struct cs_dsp_coeff_ctl *ctl; 2827 2828 while (!list_empty(&dsp->ctl_list)) { 2829 ctl = list_first_entry(&dsp->ctl_list, struct cs_dsp_coeff_ctl, list); 2830 2831 if (dsp->client_ops->control_remove) 2832 dsp->client_ops->control_remove(ctl); 2833 2834 list_del(&ctl->list); 2835 cs_dsp_free_ctl_blk(ctl); 2836 } 2837} 2838EXPORT_SYMBOL_GPL(cs_dsp_remove); 2839 2840/** 2841 * cs_dsp_read_raw_data_block() - Reads a block of data from DSP memory 2842 * @dsp: pointer to DSP structure 2843 * @mem_type: the type of DSP memory containing the data to be read 2844 * @mem_addr: the address of the data within the memory region 2845 * @num_words: the length of the data to read 2846 * @data: a buffer to store the fetched data 2847 * 2848 * If this is used to read unpacked 24-bit memory, each 24-bit DSP word will 2849 * occupy 32-bits in data (MSbyte will be 0). This padding can be removed using 2850 * cs_dsp_remove_padding() 2851 * 2852 * Return: Zero for success, a negative number on error. 2853 */ 2854int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, 2855 unsigned int num_words, __be32 *data) 2856{ 2857 struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type); 2858 unsigned int reg; 2859 int ret; 2860 2861 lockdep_assert_held(&dsp->pwr_lock); 2862 2863 if (!mem) 2864 return -EINVAL; 2865 2866 reg = dsp->ops->region_to_reg(mem, mem_addr); 2867 2868 ret = regmap_raw_read(dsp->regmap, reg, data, 2869 sizeof(*data) * num_words); 2870 if (ret < 0) 2871 return ret; 2872 2873 return 0; 2874} 2875EXPORT_SYMBOL_GPL(cs_dsp_read_raw_data_block); 2876 2877/** 2878 * cs_dsp_read_data_word() - Reads a word from DSP memory 2879 * @dsp: pointer to DSP structure 2880 * @mem_type: the type of DSP memory containing the data to be read 2881 * @mem_addr: the address of the data within the memory region 2882 * @data: a buffer to store the fetched data 2883 * 2884 * Return: Zero for success, a negative number on error. 2885 */ 2886int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 *data) 2887{ 2888 __be32 raw; 2889 int ret; 2890 2891 ret = cs_dsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw); 2892 if (ret < 0) 2893 return ret; 2894 2895 *data = be32_to_cpu(raw) & 0x00ffffffu; 2896 2897 return 0; 2898} 2899EXPORT_SYMBOL_GPL(cs_dsp_read_data_word); 2900 2901/** 2902 * cs_dsp_write_data_word() - Writes a word to DSP memory 2903 * @dsp: pointer to DSP structure 2904 * @mem_type: the type of DSP memory containing the data to be written 2905 * @mem_addr: the address of the data within the memory region 2906 * @data: the data to be written 2907 * 2908 * Return: Zero for success, a negative number on error. 2909 */ 2910int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 data) 2911{ 2912 struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type); 2913 __be32 val = cpu_to_be32(data & 0x00ffffffu); 2914 unsigned int reg; 2915 2916 lockdep_assert_held(&dsp->pwr_lock); 2917 2918 if (!mem) 2919 return -EINVAL; 2920 2921 reg = dsp->ops->region_to_reg(mem, mem_addr); 2922 2923 return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val)); 2924} 2925EXPORT_SYMBOL_GPL(cs_dsp_write_data_word); 2926 2927/** 2928 * cs_dsp_remove_padding() - Convert unpacked words to packed bytes 2929 * @buf: buffer containing DSP words read from DSP memory 2930 * @nwords: number of words to convert 2931 * 2932 * DSP words from the register map have pad bytes and the data bytes 2933 * are in swapped order. This swaps to the native endian order and 2934 * strips the pad bytes. 2935 */ 2936void cs_dsp_remove_padding(u32 *buf, int nwords) 2937{ 2938 const __be32 *pack_in = (__be32 *)buf; 2939 u8 *pack_out = (u8 *)buf; 2940 int i; 2941 2942 for (i = 0; i < nwords; i++) { 2943 u32 word = be32_to_cpu(*pack_in++); 2944 *pack_out++ = (u8)word; 2945 *pack_out++ = (u8)(word >> 8); 2946 *pack_out++ = (u8)(word >> 16); 2947 } 2948} 2949EXPORT_SYMBOL_GPL(cs_dsp_remove_padding); 2950 2951/** 2952 * cs_dsp_adsp2_bus_error() - Handle a DSP bus error interrupt 2953 * @dsp: pointer to DSP structure 2954 * 2955 * The firmware and DSP state will be logged for future analysis. 2956 */ 2957void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp) 2958{ 2959 unsigned int val; 2960 struct regmap *regmap = dsp->regmap; 2961 int ret = 0; 2962 2963 mutex_lock(&dsp->pwr_lock); 2964 2965 ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val); 2966 if (ret) { 2967 cs_dsp_err(dsp, 2968 "Failed to read Region Lock Ctrl register: %d\n", ret); 2969 goto error; 2970 } 2971 2972 if (val & ADSP2_WDT_TIMEOUT_STS_MASK) { 2973 cs_dsp_err(dsp, "watchdog timeout error\n"); 2974 dsp->ops->stop_watchdog(dsp); 2975 if (dsp->client_ops->watchdog_expired) 2976 dsp->client_ops->watchdog_expired(dsp); 2977 } 2978 2979 if (val & (ADSP2_ADDR_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) { 2980 if (val & ADSP2_ADDR_ERR_MASK) 2981 cs_dsp_err(dsp, "bus error: address error\n"); 2982 else 2983 cs_dsp_err(dsp, "bus error: region lock error\n"); 2984 2985 ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val); 2986 if (ret) { 2987 cs_dsp_err(dsp, 2988 "Failed to read Bus Err Addr register: %d\n", 2989 ret); 2990 goto error; 2991 } 2992 2993 cs_dsp_err(dsp, "bus error address = 0x%x\n", 2994 val & ADSP2_BUS_ERR_ADDR_MASK); 2995 2996 ret = regmap_read(regmap, 2997 dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR, 2998 &val); 2999 if (ret) { 3000 cs_dsp_err(dsp, 3001 "Failed to read Pmem Xmem Err Addr register: %d\n", 3002 ret); 3003 goto error; 3004 } 3005 3006 cs_dsp_err(dsp, "xmem error address = 0x%x\n", 3007 val & ADSP2_XMEM_ERR_ADDR_MASK); 3008 cs_dsp_err(dsp, "pmem error address = 0x%x\n", 3009 (val & ADSP2_PMEM_ERR_ADDR_MASK) >> 3010 ADSP2_PMEM_ERR_ADDR_SHIFT); 3011 } 3012 3013 regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, 3014 ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT); 3015 3016error: 3017 mutex_unlock(&dsp->pwr_lock); 3018} 3019EXPORT_SYMBOL_GPL(cs_dsp_adsp2_bus_error); 3020 3021/** 3022 * cs_dsp_halo_bus_error() - Handle a DSP bus error interrupt 3023 * @dsp: pointer to DSP structure 3024 * 3025 * The firmware and DSP state will be logged for future analysis. 3026 */ 3027void cs_dsp_halo_bus_error(struct cs_dsp *dsp) 3028{ 3029 struct regmap *regmap = dsp->regmap; 3030 unsigned int fault[6]; 3031 struct reg_sequence clear[] = { 3032 { dsp->base + HALO_MPU_XM_VIO_STATUS, 0x0 }, 3033 { dsp->base + HALO_MPU_YM_VIO_STATUS, 0x0 }, 3034 { dsp->base + HALO_MPU_PM_VIO_STATUS, 0x0 }, 3035 }; 3036 int ret; 3037 3038 mutex_lock(&dsp->pwr_lock); 3039 3040 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1, 3041 fault); 3042 if (ret) { 3043 cs_dsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret); 3044 goto exit_unlock; 3045 } 3046 3047 cs_dsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n", 3048 *fault & HALO_AHBM_FLAGS_ERR_MASK, 3049 (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >> 3050 HALO_AHBM_CORE_ERR_ADDR_SHIFT); 3051 3052 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0, 3053 fault); 3054 if (ret) { 3055 cs_dsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret); 3056 goto exit_unlock; 3057 } 3058 3059 cs_dsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault); 3060 3061 ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR, 3062 fault, ARRAY_SIZE(fault)); 3063 if (ret) { 3064 cs_dsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret); 3065 goto exit_unlock; 3066 } 3067 3068 cs_dsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]); 3069 cs_dsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]); 3070 cs_dsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]); 3071 3072 ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear)); 3073 if (ret) 3074 cs_dsp_warn(dsp, "Failed to clear MPU status: %d\n", ret); 3075 3076exit_unlock: 3077 mutex_unlock(&dsp->pwr_lock); 3078} 3079EXPORT_SYMBOL_GPL(cs_dsp_halo_bus_error); 3080 3081/** 3082 * cs_dsp_halo_wdt_expire() - Handle DSP watchdog expiry 3083 * @dsp: pointer to DSP structure 3084 * 3085 * This is logged for future analysis. 3086 */ 3087void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp) 3088{ 3089 mutex_lock(&dsp->pwr_lock); 3090 3091 cs_dsp_warn(dsp, "WDT Expiry Fault\n"); 3092 3093 dsp->ops->stop_watchdog(dsp); 3094 if (dsp->client_ops->watchdog_expired) 3095 dsp->client_ops->watchdog_expired(dsp); 3096 3097 mutex_unlock(&dsp->pwr_lock); 3098} 3099EXPORT_SYMBOL_GPL(cs_dsp_halo_wdt_expire); 3100 3101static const struct cs_dsp_ops cs_dsp_adsp1_ops = { 3102 .validate_version = cs_dsp_validate_version, 3103 .parse_sizes = cs_dsp_adsp1_parse_sizes, 3104 .region_to_reg = cs_dsp_region_to_reg, 3105}; 3106 3107static const struct cs_dsp_ops cs_dsp_adsp2_ops[] = { 3108 { 3109 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3110 .validate_version = cs_dsp_validate_version, 3111 .setup_algs = cs_dsp_adsp2_setup_algs, 3112 .region_to_reg = cs_dsp_region_to_reg, 3113 3114 .show_fw_status = cs_dsp_adsp2_show_fw_status, 3115 3116 .enable_memory = cs_dsp_adsp2_enable_memory, 3117 .disable_memory = cs_dsp_adsp2_disable_memory, 3118 3119 .enable_core = cs_dsp_adsp2_enable_core, 3120 .disable_core = cs_dsp_adsp2_disable_core, 3121 3122 .start_core = cs_dsp_adsp2_start_core, 3123 .stop_core = cs_dsp_adsp2_stop_core, 3124 3125 }, 3126 { 3127 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3128 .validate_version = cs_dsp_validate_version, 3129 .setup_algs = cs_dsp_adsp2_setup_algs, 3130 .region_to_reg = cs_dsp_region_to_reg, 3131 3132 .show_fw_status = cs_dsp_adsp2v2_show_fw_status, 3133 3134 .enable_memory = cs_dsp_adsp2_enable_memory, 3135 .disable_memory = cs_dsp_adsp2_disable_memory, 3136 .lock_memory = cs_dsp_adsp2_lock, 3137 3138 .enable_core = cs_dsp_adsp2v2_enable_core, 3139 .disable_core = cs_dsp_adsp2v2_disable_core, 3140 3141 .start_core = cs_dsp_adsp2_start_core, 3142 .stop_core = cs_dsp_adsp2_stop_core, 3143 }, 3144 { 3145 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3146 .validate_version = cs_dsp_validate_version, 3147 .setup_algs = cs_dsp_adsp2_setup_algs, 3148 .region_to_reg = cs_dsp_region_to_reg, 3149 3150 .show_fw_status = cs_dsp_adsp2v2_show_fw_status, 3151 .stop_watchdog = cs_dsp_stop_watchdog, 3152 3153 .enable_memory = cs_dsp_adsp2_enable_memory, 3154 .disable_memory = cs_dsp_adsp2_disable_memory, 3155 .lock_memory = cs_dsp_adsp2_lock, 3156 3157 .enable_core = cs_dsp_adsp2v2_enable_core, 3158 .disable_core = cs_dsp_adsp2v2_disable_core, 3159 3160 .start_core = cs_dsp_adsp2_start_core, 3161 .stop_core = cs_dsp_adsp2_stop_core, 3162 }, 3163}; 3164 3165static const struct cs_dsp_ops cs_dsp_halo_ops = { 3166 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3167 .validate_version = cs_dsp_halo_validate_version, 3168 .setup_algs = cs_dsp_halo_setup_algs, 3169 .region_to_reg = cs_dsp_halo_region_to_reg, 3170 3171 .show_fw_status = cs_dsp_halo_show_fw_status, 3172 .stop_watchdog = cs_dsp_halo_stop_watchdog, 3173 3174 .lock_memory = cs_dsp_halo_configure_mpu, 3175 3176 .start_core = cs_dsp_halo_start_core, 3177 .stop_core = cs_dsp_halo_stop_core, 3178}; 3179 3180MODULE_DESCRIPTION("Cirrus Logic DSP Support"); 3181MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>"); 3182MODULE_LICENSE("GPL v2");