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