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 277 struct 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 301 static const struct cs_dsp_ops cs_dsp_adsp1_ops; 302 static const struct cs_dsp_ops cs_dsp_adsp2_ops[]; 303 static const struct cs_dsp_ops cs_dsp_halo_ops; 304 305 struct cs_dsp_buf { 306 struct list_head list; 307 void *buf; 308 }; 309 310 static 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 331 static 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 */ 349 const 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 } 372 EXPORT_SYMBOL_GPL(cs_dsp_mem_region_name); 373 374 #ifdef CONFIG_DEBUG_FS 375 static 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 383 static 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 391 static 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 399 static 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 419 static 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 439 static 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 */ 465 void 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 } 483 EXPORT_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 */ 489 void 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 } 495 EXPORT_SYMBOL_GPL(cs_dsp_cleanup_debugfs); 496 #else 497 void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root) 498 { 499 } 500 EXPORT_SYMBOL_GPL(cs_dsp_init_debugfs); 501 502 void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp) 503 { 504 } 505 EXPORT_SYMBOL_GPL(cs_dsp_cleanup_debugfs); 506 507 static inline void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, 508 const char *s) 509 { 510 } 511 512 static inline void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp, 513 const char *s) 514 { 515 } 516 517 static inline void cs_dsp_debugfs_clear(struct cs_dsp *dsp) 518 { 519 } 520 #endif 521 522 static 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 534 static 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 551 static 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 569 static 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 584 static 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 596 static 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 607 static 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 619 static 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 */ 650 int 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 } 713 EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_acked_control); 714 715 static 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 */ 757 int 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 } 781 EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_ctrl); 782 783 static 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 */ 825 int 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 } 853 EXPORT_SYMBOL_GPL(cs_dsp_coeff_read_ctrl); 854 855 static 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 881 static 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 900 static 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 921 static 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 928 static 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 = kmemdup(subname, 959 strlen(subname) + 1, GFP_KERNEL); 960 if (!ctl->subname) { 961 ret = -ENOMEM; 962 goto err_ctl; 963 } 964 } 965 ctl->enabled = 1; 966 ctl->set = 0; 967 ctl->dsp = dsp; 968 969 ctl->flags = flags; 970 ctl->type = type; 971 ctl->offset = offset; 972 ctl->len = len; 973 ctl->cache = kzalloc(ctl->len, GFP_KERNEL); 974 if (!ctl->cache) { 975 ret = -ENOMEM; 976 goto err_ctl_subname; 977 } 978 979 list_add(&ctl->list, &dsp->ctl_list); 980 981 if (dsp->client_ops->control_add) { 982 ret = dsp->client_ops->control_add(ctl); 983 if (ret) 984 goto err_list_del; 985 } 986 987 return 0; 988 989 err_list_del: 990 list_del(&ctl->list); 991 kfree(ctl->cache); 992 err_ctl_subname: 993 kfree(ctl->subname); 994 err_ctl: 995 kfree(ctl); 996 997 return ret; 998 } 999 1000 struct cs_dsp_coeff_parsed_alg { 1001 int id; 1002 const u8 *name; 1003 int name_len; 1004 int ncoeff; 1005 }; 1006 1007 struct cs_dsp_coeff_parsed_coeff { 1008 int offset; 1009 int mem_type; 1010 const u8 *name; 1011 int name_len; 1012 unsigned int ctl_type; 1013 int flags; 1014 int len; 1015 }; 1016 1017 static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) 1018 { 1019 int length; 1020 1021 switch (bytes) { 1022 case 1: 1023 length = **pos; 1024 break; 1025 case 2: 1026 length = le16_to_cpu(*((__le16 *)*pos)); 1027 break; 1028 default: 1029 return 0; 1030 } 1031 1032 if (str) 1033 *str = *pos + bytes; 1034 1035 *pos += ((length + bytes) + 3) & ~0x03; 1036 1037 return length; 1038 } 1039 1040 static int cs_dsp_coeff_parse_int(int bytes, const u8 **pos) 1041 { 1042 int val = 0; 1043 1044 switch (bytes) { 1045 case 2: 1046 val = le16_to_cpu(*((__le16 *)*pos)); 1047 break; 1048 case 4: 1049 val = le32_to_cpu(*((__le32 *)*pos)); 1050 break; 1051 default: 1052 break; 1053 } 1054 1055 *pos += bytes; 1056 1057 return val; 1058 } 1059 1060 static inline void cs_dsp_coeff_parse_alg(struct cs_dsp *dsp, const u8 **data, 1061 struct cs_dsp_coeff_parsed_alg *blk) 1062 { 1063 const struct wmfw_adsp_alg_data *raw; 1064 1065 switch (dsp->fw_ver) { 1066 case 0: 1067 case 1: 1068 raw = (const struct wmfw_adsp_alg_data *)*data; 1069 *data = raw->data; 1070 1071 blk->id = le32_to_cpu(raw->id); 1072 blk->name = raw->name; 1073 blk->name_len = strlen(raw->name); 1074 blk->ncoeff = le32_to_cpu(raw->ncoeff); 1075 break; 1076 default: 1077 blk->id = cs_dsp_coeff_parse_int(sizeof(raw->id), data); 1078 blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), data, 1079 &blk->name); 1080 cs_dsp_coeff_parse_string(sizeof(u16), data, NULL); 1081 blk->ncoeff = cs_dsp_coeff_parse_int(sizeof(raw->ncoeff), data); 1082 break; 1083 } 1084 1085 cs_dsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); 1086 cs_dsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); 1087 cs_dsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff); 1088 } 1089 1090 static inline void cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, const u8 **data, 1091 struct cs_dsp_coeff_parsed_coeff *blk) 1092 { 1093 const struct wmfw_adsp_coeff_data *raw; 1094 const u8 *tmp; 1095 int length; 1096 1097 switch (dsp->fw_ver) { 1098 case 0: 1099 case 1: 1100 raw = (const struct wmfw_adsp_coeff_data *)*data; 1101 *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size); 1102 1103 blk->offset = le16_to_cpu(raw->hdr.offset); 1104 blk->mem_type = le16_to_cpu(raw->hdr.type); 1105 blk->name = raw->name; 1106 blk->name_len = strlen(raw->name); 1107 blk->ctl_type = le16_to_cpu(raw->ctl_type); 1108 blk->flags = le16_to_cpu(raw->flags); 1109 blk->len = le32_to_cpu(raw->len); 1110 break; 1111 default: 1112 tmp = *data; 1113 blk->offset = cs_dsp_coeff_parse_int(sizeof(raw->hdr.offset), &tmp); 1114 blk->mem_type = cs_dsp_coeff_parse_int(sizeof(raw->hdr.type), &tmp); 1115 length = cs_dsp_coeff_parse_int(sizeof(raw->hdr.size), &tmp); 1116 blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp, 1117 &blk->name); 1118 cs_dsp_coeff_parse_string(sizeof(u8), &tmp, NULL); 1119 cs_dsp_coeff_parse_string(sizeof(u16), &tmp, NULL); 1120 blk->ctl_type = cs_dsp_coeff_parse_int(sizeof(raw->ctl_type), &tmp); 1121 blk->flags = cs_dsp_coeff_parse_int(sizeof(raw->flags), &tmp); 1122 blk->len = cs_dsp_coeff_parse_int(sizeof(raw->len), &tmp); 1123 1124 *data = *data + sizeof(raw->hdr) + length; 1125 break; 1126 } 1127 1128 cs_dsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type); 1129 cs_dsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset); 1130 cs_dsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name); 1131 cs_dsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags); 1132 cs_dsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type); 1133 cs_dsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); 1134 } 1135 1136 static int cs_dsp_check_coeff_flags(struct cs_dsp *dsp, 1137 const struct cs_dsp_coeff_parsed_coeff *coeff_blk, 1138 unsigned int f_required, 1139 unsigned int f_illegal) 1140 { 1141 if ((coeff_blk->flags & f_illegal) || 1142 ((coeff_blk->flags & f_required) != f_required)) { 1143 cs_dsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n", 1144 coeff_blk->flags, coeff_blk->ctl_type); 1145 return -EINVAL; 1146 } 1147 1148 return 0; 1149 } 1150 1151 static int cs_dsp_parse_coeff(struct cs_dsp *dsp, 1152 const struct wmfw_region *region) 1153 { 1154 struct cs_dsp_alg_region alg_region = {}; 1155 struct cs_dsp_coeff_parsed_alg alg_blk; 1156 struct cs_dsp_coeff_parsed_coeff coeff_blk; 1157 const u8 *data = region->data; 1158 int i, ret; 1159 1160 cs_dsp_coeff_parse_alg(dsp, &data, &alg_blk); 1161 for (i = 0; i < alg_blk.ncoeff; i++) { 1162 cs_dsp_coeff_parse_coeff(dsp, &data, &coeff_blk); 1163 1164 switch (coeff_blk.ctl_type) { 1165 case WMFW_CTL_TYPE_BYTES: 1166 break; 1167 case WMFW_CTL_TYPE_ACKED: 1168 if (coeff_blk.flags & WMFW_CTL_FLAG_SYS) 1169 continue; /* ignore */ 1170 1171 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, 1172 WMFW_CTL_FLAG_VOLATILE | 1173 WMFW_CTL_FLAG_WRITEABLE | 1174 WMFW_CTL_FLAG_READABLE, 1175 0); 1176 if (ret) 1177 return -EINVAL; 1178 break; 1179 case WMFW_CTL_TYPE_HOSTEVENT: 1180 case WMFW_CTL_TYPE_FWEVENT: 1181 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, 1182 WMFW_CTL_FLAG_SYS | 1183 WMFW_CTL_FLAG_VOLATILE | 1184 WMFW_CTL_FLAG_WRITEABLE | 1185 WMFW_CTL_FLAG_READABLE, 1186 0); 1187 if (ret) 1188 return -EINVAL; 1189 break; 1190 case WMFW_CTL_TYPE_HOST_BUFFER: 1191 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, 1192 WMFW_CTL_FLAG_SYS | 1193 WMFW_CTL_FLAG_VOLATILE | 1194 WMFW_CTL_FLAG_READABLE, 1195 0); 1196 if (ret) 1197 return -EINVAL; 1198 break; 1199 default: 1200 cs_dsp_err(dsp, "Unknown control type: %d\n", 1201 coeff_blk.ctl_type); 1202 return -EINVAL; 1203 } 1204 1205 alg_region.type = coeff_blk.mem_type; 1206 alg_region.alg = alg_blk.id; 1207 1208 ret = cs_dsp_create_control(dsp, &alg_region, 1209 coeff_blk.offset, 1210 coeff_blk.len, 1211 coeff_blk.name, 1212 coeff_blk.name_len, 1213 coeff_blk.flags, 1214 coeff_blk.ctl_type); 1215 if (ret < 0) 1216 cs_dsp_err(dsp, "Failed to create control: %.*s, %d\n", 1217 coeff_blk.name_len, coeff_blk.name, ret); 1218 } 1219 1220 return 0; 1221 } 1222 1223 static unsigned int cs_dsp_adsp1_parse_sizes(struct cs_dsp *dsp, 1224 const char * const file, 1225 unsigned int pos, 1226 const struct firmware *firmware) 1227 { 1228 const struct wmfw_adsp1_sizes *adsp1_sizes; 1229 1230 adsp1_sizes = (void *)&firmware->data[pos]; 1231 1232 cs_dsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file, 1233 le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm), 1234 le32_to_cpu(adsp1_sizes->zm)); 1235 1236 return pos + sizeof(*adsp1_sizes); 1237 } 1238 1239 static unsigned int cs_dsp_adsp2_parse_sizes(struct cs_dsp *dsp, 1240 const char * const file, 1241 unsigned int pos, 1242 const struct firmware *firmware) 1243 { 1244 const struct wmfw_adsp2_sizes *adsp2_sizes; 1245 1246 adsp2_sizes = (void *)&firmware->data[pos]; 1247 1248 cs_dsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file, 1249 le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym), 1250 le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm)); 1251 1252 return pos + sizeof(*adsp2_sizes); 1253 } 1254 1255 static bool cs_dsp_validate_version(struct cs_dsp *dsp, unsigned int version) 1256 { 1257 switch (version) { 1258 case 0: 1259 cs_dsp_warn(dsp, "Deprecated file format %d\n", version); 1260 return true; 1261 case 1: 1262 case 2: 1263 return true; 1264 default: 1265 return false; 1266 } 1267 } 1268 1269 static bool cs_dsp_halo_validate_version(struct cs_dsp *dsp, unsigned int version) 1270 { 1271 switch (version) { 1272 case 3: 1273 return true; 1274 default: 1275 return false; 1276 } 1277 } 1278 1279 static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, 1280 const char *file) 1281 { 1282 LIST_HEAD(buf_list); 1283 struct regmap *regmap = dsp->regmap; 1284 unsigned int pos = 0; 1285 const struct wmfw_header *header; 1286 const struct wmfw_adsp1_sizes *adsp1_sizes; 1287 const struct wmfw_footer *footer; 1288 const struct wmfw_region *region; 1289 const struct cs_dsp_region *mem; 1290 const char *region_name; 1291 char *text = NULL; 1292 struct cs_dsp_buf *buf; 1293 unsigned int reg; 1294 int regions = 0; 1295 int ret, offset, type; 1296 1297 ret = -EINVAL; 1298 1299 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); 1300 if (pos >= firmware->size) { 1301 cs_dsp_err(dsp, "%s: file too short, %zu bytes\n", 1302 file, firmware->size); 1303 goto out_fw; 1304 } 1305 1306 header = (void *)&firmware->data[0]; 1307 1308 if (memcmp(&header->magic[0], "WMFW", 4) != 0) { 1309 cs_dsp_err(dsp, "%s: invalid magic\n", file); 1310 goto out_fw; 1311 } 1312 1313 if (!dsp->ops->validate_version(dsp, header->ver)) { 1314 cs_dsp_err(dsp, "%s: unknown file format %d\n", 1315 file, header->ver); 1316 goto out_fw; 1317 } 1318 1319 cs_dsp_info(dsp, "Firmware version: %d\n", header->ver); 1320 dsp->fw_ver = header->ver; 1321 1322 if (header->core != dsp->type) { 1323 cs_dsp_err(dsp, "%s: invalid core %d != %d\n", 1324 file, header->core, dsp->type); 1325 goto out_fw; 1326 } 1327 1328 pos = sizeof(*header); 1329 pos = dsp->ops->parse_sizes(dsp, file, pos, firmware); 1330 1331 footer = (void *)&firmware->data[pos]; 1332 pos += sizeof(*footer); 1333 1334 if (le32_to_cpu(header->len) != pos) { 1335 cs_dsp_err(dsp, "%s: unexpected header length %d\n", 1336 file, le32_to_cpu(header->len)); 1337 goto out_fw; 1338 } 1339 1340 cs_dsp_dbg(dsp, "%s: timestamp %llu\n", file, 1341 le64_to_cpu(footer->timestamp)); 1342 1343 while (pos < firmware->size && 1344 sizeof(*region) < firmware->size - pos) { 1345 region = (void *)&(firmware->data[pos]); 1346 region_name = "Unknown"; 1347 reg = 0; 1348 text = NULL; 1349 offset = le32_to_cpu(region->offset) & 0xffffff; 1350 type = be32_to_cpu(region->type) & 0xff; 1351 1352 switch (type) { 1353 case WMFW_NAME_TEXT: 1354 region_name = "Firmware name"; 1355 text = kzalloc(le32_to_cpu(region->len) + 1, 1356 GFP_KERNEL); 1357 break; 1358 case WMFW_ALGORITHM_DATA: 1359 region_name = "Algorithm"; 1360 ret = cs_dsp_parse_coeff(dsp, region); 1361 if (ret != 0) 1362 goto out_fw; 1363 break; 1364 case WMFW_INFO_TEXT: 1365 region_name = "Information"; 1366 text = kzalloc(le32_to_cpu(region->len) + 1, 1367 GFP_KERNEL); 1368 break; 1369 case WMFW_ABSOLUTE: 1370 region_name = "Absolute"; 1371 reg = offset; 1372 break; 1373 case WMFW_ADSP1_PM: 1374 case WMFW_ADSP1_DM: 1375 case WMFW_ADSP2_XM: 1376 case WMFW_ADSP2_YM: 1377 case WMFW_ADSP1_ZM: 1378 case WMFW_HALO_PM_PACKED: 1379 case WMFW_HALO_XM_PACKED: 1380 case WMFW_HALO_YM_PACKED: 1381 mem = cs_dsp_find_region(dsp, type); 1382 if (!mem) { 1383 cs_dsp_err(dsp, "No region of type: %x\n", type); 1384 ret = -EINVAL; 1385 goto out_fw; 1386 } 1387 1388 region_name = cs_dsp_mem_region_name(type); 1389 reg = dsp->ops->region_to_reg(mem, offset); 1390 break; 1391 default: 1392 cs_dsp_warn(dsp, 1393 "%s.%d: Unknown region type %x at %d(%x)\n", 1394 file, regions, type, pos, pos); 1395 break; 1396 } 1397 1398 cs_dsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file, 1399 regions, le32_to_cpu(region->len), offset, 1400 region_name); 1401 1402 if (le32_to_cpu(region->len) > 1403 firmware->size - pos - sizeof(*region)) { 1404 cs_dsp_err(dsp, 1405 "%s.%d: %s region len %d bytes exceeds file length %zu\n", 1406 file, regions, region_name, 1407 le32_to_cpu(region->len), firmware->size); 1408 ret = -EINVAL; 1409 goto out_fw; 1410 } 1411 1412 if (text) { 1413 memcpy(text, region->data, le32_to_cpu(region->len)); 1414 cs_dsp_info(dsp, "%s: %s\n", file, text); 1415 kfree(text); 1416 text = NULL; 1417 } 1418 1419 if (reg) { 1420 buf = cs_dsp_buf_alloc(region->data, 1421 le32_to_cpu(region->len), 1422 &buf_list); 1423 if (!buf) { 1424 cs_dsp_err(dsp, "Out of memory\n"); 1425 ret = -ENOMEM; 1426 goto out_fw; 1427 } 1428 1429 ret = regmap_raw_write_async(regmap, reg, buf->buf, 1430 le32_to_cpu(region->len)); 1431 if (ret != 0) { 1432 cs_dsp_err(dsp, 1433 "%s.%d: Failed to write %d bytes at %d in %s: %d\n", 1434 file, regions, 1435 le32_to_cpu(region->len), offset, 1436 region_name, ret); 1437 goto out_fw; 1438 } 1439 } 1440 1441 pos += le32_to_cpu(region->len) + sizeof(*region); 1442 regions++; 1443 } 1444 1445 ret = regmap_async_complete(regmap); 1446 if (ret != 0) { 1447 cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret); 1448 goto out_fw; 1449 } 1450 1451 if (pos > firmware->size) 1452 cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 1453 file, regions, pos - firmware->size); 1454 1455 cs_dsp_debugfs_save_wmfwname(dsp, file); 1456 1457 out_fw: 1458 regmap_async_complete(regmap); 1459 cs_dsp_buf_free(&buf_list); 1460 kfree(text); 1461 1462 return ret; 1463 } 1464 1465 /** 1466 * cs_dsp_get_ctl() - Finds a matching coefficient control 1467 * @dsp: pointer to DSP structure 1468 * @name: pointer to string to match with a control's subname 1469 * @type: the algorithm type to match 1470 * @alg: the algorithm id to match 1471 * 1472 * Find cs_dsp_coeff_ctl with input name as its subname 1473 * 1474 * Return: pointer to the control on success, NULL if not found 1475 */ 1476 struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, int type, 1477 unsigned int alg) 1478 { 1479 struct cs_dsp_coeff_ctl *pos, *rslt = NULL; 1480 1481 lockdep_assert_held(&dsp->pwr_lock); 1482 1483 list_for_each_entry(pos, &dsp->ctl_list, list) { 1484 if (!pos->subname) 1485 continue; 1486 if (strncmp(pos->subname, name, pos->subname_len) == 0 && 1487 pos->fw_name == dsp->fw_name && 1488 pos->alg_region.alg == alg && 1489 pos->alg_region.type == type) { 1490 rslt = pos; 1491 break; 1492 } 1493 } 1494 1495 return rslt; 1496 } 1497 EXPORT_SYMBOL_GPL(cs_dsp_get_ctl); 1498 1499 static void cs_dsp_ctl_fixup_base(struct cs_dsp *dsp, 1500 const struct cs_dsp_alg_region *alg_region) 1501 { 1502 struct cs_dsp_coeff_ctl *ctl; 1503 1504 list_for_each_entry(ctl, &dsp->ctl_list, list) { 1505 if (ctl->fw_name == dsp->fw_name && 1506 alg_region->alg == ctl->alg_region.alg && 1507 alg_region->type == ctl->alg_region.type) { 1508 ctl->alg_region.base = alg_region->base; 1509 } 1510 } 1511 } 1512 1513 static void *cs_dsp_read_algs(struct cs_dsp *dsp, size_t n_algs, 1514 const struct cs_dsp_region *mem, 1515 unsigned int pos, unsigned int len) 1516 { 1517 void *alg; 1518 unsigned int reg; 1519 int ret; 1520 __be32 val; 1521 1522 if (n_algs == 0) { 1523 cs_dsp_err(dsp, "No algorithms\n"); 1524 return ERR_PTR(-EINVAL); 1525 } 1526 1527 if (n_algs > 1024) { 1528 cs_dsp_err(dsp, "Algorithm count %zx excessive\n", n_algs); 1529 return ERR_PTR(-EINVAL); 1530 } 1531 1532 /* Read the terminator first to validate the length */ 1533 reg = dsp->ops->region_to_reg(mem, pos + len); 1534 1535 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); 1536 if (ret != 0) { 1537 cs_dsp_err(dsp, "Failed to read algorithm list end: %d\n", 1538 ret); 1539 return ERR_PTR(ret); 1540 } 1541 1542 if (be32_to_cpu(val) != 0xbedead) 1543 cs_dsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n", 1544 reg, be32_to_cpu(val)); 1545 1546 /* Convert length from DSP words to bytes */ 1547 len *= sizeof(u32); 1548 1549 alg = kzalloc(len, GFP_KERNEL | GFP_DMA); 1550 if (!alg) 1551 return ERR_PTR(-ENOMEM); 1552 1553 reg = dsp->ops->region_to_reg(mem, pos); 1554 1555 ret = regmap_raw_read(dsp->regmap, reg, alg, len); 1556 if (ret != 0) { 1557 cs_dsp_err(dsp, "Failed to read algorithm list: %d\n", ret); 1558 kfree(alg); 1559 return ERR_PTR(ret); 1560 } 1561 1562 return alg; 1563 } 1564 1565 /** 1566 * cs_dsp_find_alg_region() - Finds a matching algorithm region 1567 * @dsp: pointer to DSP structure 1568 * @type: the algorithm type to match 1569 * @id: the algorithm id to match 1570 * 1571 * Return: Pointer to matching algorithm region, or NULL if not found. 1572 */ 1573 struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp, 1574 int type, unsigned int id) 1575 { 1576 struct cs_dsp_alg_region *alg_region; 1577 1578 lockdep_assert_held(&dsp->pwr_lock); 1579 1580 list_for_each_entry(alg_region, &dsp->alg_regions, list) { 1581 if (id == alg_region->alg && type == alg_region->type) 1582 return alg_region; 1583 } 1584 1585 return NULL; 1586 } 1587 EXPORT_SYMBOL_GPL(cs_dsp_find_alg_region); 1588 1589 static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, 1590 int type, __be32 id, 1591 __be32 ver, __be32 base) 1592 { 1593 struct cs_dsp_alg_region *alg_region; 1594 1595 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL); 1596 if (!alg_region) 1597 return ERR_PTR(-ENOMEM); 1598 1599 alg_region->type = type; 1600 alg_region->alg = be32_to_cpu(id); 1601 alg_region->ver = be32_to_cpu(ver); 1602 alg_region->base = be32_to_cpu(base); 1603 1604 list_add_tail(&alg_region->list, &dsp->alg_regions); 1605 1606 if (dsp->fw_ver > 0) 1607 cs_dsp_ctl_fixup_base(dsp, alg_region); 1608 1609 return alg_region; 1610 } 1611 1612 static void cs_dsp_free_alg_regions(struct cs_dsp *dsp) 1613 { 1614 struct cs_dsp_alg_region *alg_region; 1615 1616 while (!list_empty(&dsp->alg_regions)) { 1617 alg_region = list_first_entry(&dsp->alg_regions, 1618 struct cs_dsp_alg_region, 1619 list); 1620 list_del(&alg_region->list); 1621 kfree(alg_region); 1622 } 1623 } 1624 1625 static void cs_dsp_parse_wmfw_id_header(struct cs_dsp *dsp, 1626 struct wmfw_id_hdr *fw, int nalgs) 1627 { 1628 dsp->fw_id = be32_to_cpu(fw->id); 1629 dsp->fw_id_version = be32_to_cpu(fw->ver); 1630 1631 cs_dsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n", 1632 dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16, 1633 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, 1634 nalgs); 1635 } 1636 1637 static void cs_dsp_parse_wmfw_v3_id_header(struct cs_dsp *dsp, 1638 struct wmfw_v3_id_hdr *fw, int nalgs) 1639 { 1640 dsp->fw_id = be32_to_cpu(fw->id); 1641 dsp->fw_id_version = be32_to_cpu(fw->ver); 1642 dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id); 1643 1644 cs_dsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n", 1645 dsp->fw_id, dsp->fw_vendor_id, 1646 (dsp->fw_id_version & 0xff0000) >> 16, 1647 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, 1648 nalgs); 1649 } 1650 1651 static int cs_dsp_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver, 1652 int nregions, const int *type, __be32 *base) 1653 { 1654 struct cs_dsp_alg_region *alg_region; 1655 int i; 1656 1657 for (i = 0; i < nregions; i++) { 1658 alg_region = cs_dsp_create_region(dsp, type[i], id, ver, base[i]); 1659 if (IS_ERR(alg_region)) 1660 return PTR_ERR(alg_region); 1661 } 1662 1663 return 0; 1664 } 1665 1666 static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) 1667 { 1668 struct wmfw_adsp1_id_hdr adsp1_id; 1669 struct wmfw_adsp1_alg_hdr *adsp1_alg; 1670 struct cs_dsp_alg_region *alg_region; 1671 const struct cs_dsp_region *mem; 1672 unsigned int pos, len; 1673 size_t n_algs; 1674 int i, ret; 1675 1676 mem = cs_dsp_find_region(dsp, WMFW_ADSP1_DM); 1677 if (WARN_ON(!mem)) 1678 return -EINVAL; 1679 1680 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id, 1681 sizeof(adsp1_id)); 1682 if (ret != 0) { 1683 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", 1684 ret); 1685 return ret; 1686 } 1687 1688 n_algs = be32_to_cpu(adsp1_id.n_algs); 1689 1690 cs_dsp_parse_wmfw_id_header(dsp, &adsp1_id.fw, n_algs); 1691 1692 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, 1693 adsp1_id.fw.id, adsp1_id.fw.ver, 1694 adsp1_id.zm); 1695 if (IS_ERR(alg_region)) 1696 return PTR_ERR(alg_region); 1697 1698 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, 1699 adsp1_id.fw.id, adsp1_id.fw.ver, 1700 adsp1_id.dm); 1701 if (IS_ERR(alg_region)) 1702 return PTR_ERR(alg_region); 1703 1704 /* Calculate offset and length in DSP words */ 1705 pos = sizeof(adsp1_id) / sizeof(u32); 1706 len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32); 1707 1708 adsp1_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); 1709 if (IS_ERR(adsp1_alg)) 1710 return PTR_ERR(adsp1_alg); 1711 1712 for (i = 0; i < n_algs; i++) { 1713 cs_dsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", 1714 i, be32_to_cpu(adsp1_alg[i].alg.id), 1715 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, 1716 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, 1717 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, 1718 be32_to_cpu(adsp1_alg[i].dm), 1719 be32_to_cpu(adsp1_alg[i].zm)); 1720 1721 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, 1722 adsp1_alg[i].alg.id, 1723 adsp1_alg[i].alg.ver, 1724 adsp1_alg[i].dm); 1725 if (IS_ERR(alg_region)) { 1726 ret = PTR_ERR(alg_region); 1727 goto out; 1728 } 1729 if (dsp->fw_ver == 0) { 1730 if (i + 1 < n_algs) { 1731 len = be32_to_cpu(adsp1_alg[i + 1].dm); 1732 len -= be32_to_cpu(adsp1_alg[i].dm); 1733 len *= 4; 1734 cs_dsp_create_control(dsp, alg_region, 0, 1735 len, NULL, 0, 0, 1736 WMFW_CTL_TYPE_BYTES); 1737 } else { 1738 cs_dsp_warn(dsp, "Missing length info for region DM with ID %x\n", 1739 be32_to_cpu(adsp1_alg[i].alg.id)); 1740 } 1741 } 1742 1743 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, 1744 adsp1_alg[i].alg.id, 1745 adsp1_alg[i].alg.ver, 1746 adsp1_alg[i].zm); 1747 if (IS_ERR(alg_region)) { 1748 ret = PTR_ERR(alg_region); 1749 goto out; 1750 } 1751 if (dsp->fw_ver == 0) { 1752 if (i + 1 < n_algs) { 1753 len = be32_to_cpu(adsp1_alg[i + 1].zm); 1754 len -= be32_to_cpu(adsp1_alg[i].zm); 1755 len *= 4; 1756 cs_dsp_create_control(dsp, alg_region, 0, 1757 len, NULL, 0, 0, 1758 WMFW_CTL_TYPE_BYTES); 1759 } else { 1760 cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 1761 be32_to_cpu(adsp1_alg[i].alg.id)); 1762 } 1763 } 1764 } 1765 1766 out: 1767 kfree(adsp1_alg); 1768 return ret; 1769 } 1770 1771 static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) 1772 { 1773 struct wmfw_adsp2_id_hdr adsp2_id; 1774 struct wmfw_adsp2_alg_hdr *adsp2_alg; 1775 struct cs_dsp_alg_region *alg_region; 1776 const struct cs_dsp_region *mem; 1777 unsigned int pos, len; 1778 size_t n_algs; 1779 int i, ret; 1780 1781 mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM); 1782 if (WARN_ON(!mem)) 1783 return -EINVAL; 1784 1785 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id, 1786 sizeof(adsp2_id)); 1787 if (ret != 0) { 1788 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", 1789 ret); 1790 return ret; 1791 } 1792 1793 n_algs = be32_to_cpu(adsp2_id.n_algs); 1794 1795 cs_dsp_parse_wmfw_id_header(dsp, &adsp2_id.fw, n_algs); 1796 1797 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, 1798 adsp2_id.fw.id, adsp2_id.fw.ver, 1799 adsp2_id.xm); 1800 if (IS_ERR(alg_region)) 1801 return PTR_ERR(alg_region); 1802 1803 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, 1804 adsp2_id.fw.id, adsp2_id.fw.ver, 1805 adsp2_id.ym); 1806 if (IS_ERR(alg_region)) 1807 return PTR_ERR(alg_region); 1808 1809 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, 1810 adsp2_id.fw.id, adsp2_id.fw.ver, 1811 adsp2_id.zm); 1812 if (IS_ERR(alg_region)) 1813 return PTR_ERR(alg_region); 1814 1815 /* Calculate offset and length in DSP words */ 1816 pos = sizeof(adsp2_id) / sizeof(u32); 1817 len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32); 1818 1819 adsp2_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); 1820 if (IS_ERR(adsp2_alg)) 1821 return PTR_ERR(adsp2_alg); 1822 1823 for (i = 0; i < n_algs; i++) { 1824 cs_dsp_info(dsp, 1825 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", 1826 i, be32_to_cpu(adsp2_alg[i].alg.id), 1827 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, 1828 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, 1829 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, 1830 be32_to_cpu(adsp2_alg[i].xm), 1831 be32_to_cpu(adsp2_alg[i].ym), 1832 be32_to_cpu(adsp2_alg[i].zm)); 1833 1834 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, 1835 adsp2_alg[i].alg.id, 1836 adsp2_alg[i].alg.ver, 1837 adsp2_alg[i].xm); 1838 if (IS_ERR(alg_region)) { 1839 ret = PTR_ERR(alg_region); 1840 goto out; 1841 } 1842 if (dsp->fw_ver == 0) { 1843 if (i + 1 < n_algs) { 1844 len = be32_to_cpu(adsp2_alg[i + 1].xm); 1845 len -= be32_to_cpu(adsp2_alg[i].xm); 1846 len *= 4; 1847 cs_dsp_create_control(dsp, alg_region, 0, 1848 len, NULL, 0, 0, 1849 WMFW_CTL_TYPE_BYTES); 1850 } else { 1851 cs_dsp_warn(dsp, "Missing length info for region XM with ID %x\n", 1852 be32_to_cpu(adsp2_alg[i].alg.id)); 1853 } 1854 } 1855 1856 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, 1857 adsp2_alg[i].alg.id, 1858 adsp2_alg[i].alg.ver, 1859 adsp2_alg[i].ym); 1860 if (IS_ERR(alg_region)) { 1861 ret = PTR_ERR(alg_region); 1862 goto out; 1863 } 1864 if (dsp->fw_ver == 0) { 1865 if (i + 1 < n_algs) { 1866 len = be32_to_cpu(adsp2_alg[i + 1].ym); 1867 len -= be32_to_cpu(adsp2_alg[i].ym); 1868 len *= 4; 1869 cs_dsp_create_control(dsp, alg_region, 0, 1870 len, NULL, 0, 0, 1871 WMFW_CTL_TYPE_BYTES); 1872 } else { 1873 cs_dsp_warn(dsp, "Missing length info for region YM with ID %x\n", 1874 be32_to_cpu(adsp2_alg[i].alg.id)); 1875 } 1876 } 1877 1878 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, 1879 adsp2_alg[i].alg.id, 1880 adsp2_alg[i].alg.ver, 1881 adsp2_alg[i].zm); 1882 if (IS_ERR(alg_region)) { 1883 ret = PTR_ERR(alg_region); 1884 goto out; 1885 } 1886 if (dsp->fw_ver == 0) { 1887 if (i + 1 < n_algs) { 1888 len = be32_to_cpu(adsp2_alg[i + 1].zm); 1889 len -= be32_to_cpu(adsp2_alg[i].zm); 1890 len *= 4; 1891 cs_dsp_create_control(dsp, alg_region, 0, 1892 len, NULL, 0, 0, 1893 WMFW_CTL_TYPE_BYTES); 1894 } else { 1895 cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 1896 be32_to_cpu(adsp2_alg[i].alg.id)); 1897 } 1898 } 1899 } 1900 1901 out: 1902 kfree(adsp2_alg); 1903 return ret; 1904 } 1905 1906 static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver, 1907 __be32 xm_base, __be32 ym_base) 1908 { 1909 static const int types[] = { 1910 WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED, 1911 WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED 1912 }; 1913 __be32 bases[] = { xm_base, xm_base, ym_base, ym_base }; 1914 1915 return cs_dsp_create_regions(dsp, id, ver, ARRAY_SIZE(types), types, bases); 1916 } 1917 1918 static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp) 1919 { 1920 struct wmfw_halo_id_hdr halo_id; 1921 struct wmfw_halo_alg_hdr *halo_alg; 1922 const struct cs_dsp_region *mem; 1923 unsigned int pos, len; 1924 size_t n_algs; 1925 int i, ret; 1926 1927 mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM); 1928 if (WARN_ON(!mem)) 1929 return -EINVAL; 1930 1931 ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id, 1932 sizeof(halo_id)); 1933 if (ret != 0) { 1934 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", 1935 ret); 1936 return ret; 1937 } 1938 1939 n_algs = be32_to_cpu(halo_id.n_algs); 1940 1941 cs_dsp_parse_wmfw_v3_id_header(dsp, &halo_id.fw, n_algs); 1942 1943 ret = cs_dsp_halo_create_regions(dsp, halo_id.fw.id, halo_id.fw.ver, 1944 halo_id.xm_base, halo_id.ym_base); 1945 if (ret) 1946 return ret; 1947 1948 /* Calculate offset and length in DSP words */ 1949 pos = sizeof(halo_id) / sizeof(u32); 1950 len = (sizeof(*halo_alg) * n_algs) / sizeof(u32); 1951 1952 halo_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); 1953 if (IS_ERR(halo_alg)) 1954 return PTR_ERR(halo_alg); 1955 1956 for (i = 0; i < n_algs; i++) { 1957 cs_dsp_info(dsp, 1958 "%d: ID %x v%d.%d.%d XM@%x YM@%x\n", 1959 i, be32_to_cpu(halo_alg[i].alg.id), 1960 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16, 1961 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8, 1962 be32_to_cpu(halo_alg[i].alg.ver) & 0xff, 1963 be32_to_cpu(halo_alg[i].xm_base), 1964 be32_to_cpu(halo_alg[i].ym_base)); 1965 1966 ret = cs_dsp_halo_create_regions(dsp, halo_alg[i].alg.id, 1967 halo_alg[i].alg.ver, 1968 halo_alg[i].xm_base, 1969 halo_alg[i].ym_base); 1970 if (ret) 1971 goto out; 1972 } 1973 1974 out: 1975 kfree(halo_alg); 1976 return ret; 1977 } 1978 1979 static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware, 1980 const char *file) 1981 { 1982 LIST_HEAD(buf_list); 1983 struct regmap *regmap = dsp->regmap; 1984 struct wmfw_coeff_hdr *hdr; 1985 struct wmfw_coeff_item *blk; 1986 const struct cs_dsp_region *mem; 1987 struct cs_dsp_alg_region *alg_region; 1988 const char *region_name; 1989 int ret, pos, blocks, type, offset, reg, version; 1990 char *text = NULL; 1991 struct cs_dsp_buf *buf; 1992 1993 if (!firmware) 1994 return 0; 1995 1996 ret = -EINVAL; 1997 1998 if (sizeof(*hdr) >= firmware->size) { 1999 cs_dsp_err(dsp, "%s: coefficient file too short, %zu bytes\n", 2000 file, firmware->size); 2001 goto out_fw; 2002 } 2003 2004 hdr = (void *)&firmware->data[0]; 2005 if (memcmp(hdr->magic, "WMDR", 4) != 0) { 2006 cs_dsp_err(dsp, "%s: invalid coefficient magic\n", file); 2007 goto out_fw; 2008 } 2009 2010 switch (be32_to_cpu(hdr->rev) & 0xff) { 2011 case 1: 2012 case 2: 2013 break; 2014 default: 2015 cs_dsp_err(dsp, "%s: Unsupported coefficient file format %d\n", 2016 file, be32_to_cpu(hdr->rev) & 0xff); 2017 ret = -EINVAL; 2018 goto out_fw; 2019 } 2020 2021 cs_dsp_dbg(dsp, "%s: v%d.%d.%d\n", file, 2022 (le32_to_cpu(hdr->ver) >> 16) & 0xff, 2023 (le32_to_cpu(hdr->ver) >> 8) & 0xff, 2024 le32_to_cpu(hdr->ver) & 0xff); 2025 2026 pos = le32_to_cpu(hdr->len); 2027 2028 blocks = 0; 2029 while (pos < firmware->size && 2030 sizeof(*blk) < firmware->size - pos) { 2031 blk = (void *)(&firmware->data[pos]); 2032 2033 type = le16_to_cpu(blk->type); 2034 offset = le16_to_cpu(blk->offset); 2035 version = le32_to_cpu(blk->ver) >> 8; 2036 2037 cs_dsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", 2038 file, blocks, le32_to_cpu(blk->id), 2039 (le32_to_cpu(blk->ver) >> 16) & 0xff, 2040 (le32_to_cpu(blk->ver) >> 8) & 0xff, 2041 le32_to_cpu(blk->ver) & 0xff); 2042 cs_dsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n", 2043 file, blocks, le32_to_cpu(blk->len), offset, type); 2044 2045 reg = 0; 2046 region_name = "Unknown"; 2047 switch (type) { 2048 case (WMFW_NAME_TEXT << 8): 2049 text = kzalloc(le32_to_cpu(blk->len) + 1, GFP_KERNEL); 2050 break; 2051 case (WMFW_INFO_TEXT << 8): 2052 case (WMFW_METADATA << 8): 2053 break; 2054 case (WMFW_ABSOLUTE << 8): 2055 /* 2056 * Old files may use this for global 2057 * coefficients. 2058 */ 2059 if (le32_to_cpu(blk->id) == dsp->fw_id && 2060 offset == 0) { 2061 region_name = "global coefficients"; 2062 mem = cs_dsp_find_region(dsp, type); 2063 if (!mem) { 2064 cs_dsp_err(dsp, "No ZM\n"); 2065 break; 2066 } 2067 reg = dsp->ops->region_to_reg(mem, 0); 2068 2069 } else { 2070 region_name = "register"; 2071 reg = offset; 2072 } 2073 break; 2074 2075 case WMFW_ADSP1_DM: 2076 case WMFW_ADSP1_ZM: 2077 case WMFW_ADSP2_XM: 2078 case WMFW_ADSP2_YM: 2079 case WMFW_HALO_XM_PACKED: 2080 case WMFW_HALO_YM_PACKED: 2081 case WMFW_HALO_PM_PACKED: 2082 cs_dsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", 2083 file, blocks, le32_to_cpu(blk->len), 2084 type, le32_to_cpu(blk->id)); 2085 2086 mem = cs_dsp_find_region(dsp, type); 2087 if (!mem) { 2088 cs_dsp_err(dsp, "No base for region %x\n", type); 2089 break; 2090 } 2091 2092 alg_region = cs_dsp_find_alg_region(dsp, type, 2093 le32_to_cpu(blk->id)); 2094 if (alg_region) { 2095 if (version != alg_region->ver) 2096 cs_dsp_warn(dsp, 2097 "Algorithm coefficient version %d.%d.%d but expected %d.%d.%d\n", 2098 (version >> 16) & 0xFF, 2099 (version >> 8) & 0xFF, 2100 version & 0xFF, 2101 (alg_region->ver >> 16) & 0xFF, 2102 (alg_region->ver >> 8) & 0xFF, 2103 alg_region->ver & 0xFF); 2104 2105 reg = alg_region->base; 2106 reg = dsp->ops->region_to_reg(mem, reg); 2107 reg += offset; 2108 } else { 2109 cs_dsp_err(dsp, "No %x for algorithm %x\n", 2110 type, le32_to_cpu(blk->id)); 2111 } 2112 break; 2113 2114 default: 2115 cs_dsp_err(dsp, "%s.%d: Unknown region type %x at %d\n", 2116 file, blocks, type, pos); 2117 break; 2118 } 2119 2120 if (text) { 2121 memcpy(text, blk->data, le32_to_cpu(blk->len)); 2122 cs_dsp_info(dsp, "%s: %s\n", dsp->fw_name, text); 2123 kfree(text); 2124 text = NULL; 2125 } 2126 2127 if (reg) { 2128 if (le32_to_cpu(blk->len) > 2129 firmware->size - pos - sizeof(*blk)) { 2130 cs_dsp_err(dsp, 2131 "%s.%d: %s region len %d bytes exceeds file length %zu\n", 2132 file, blocks, region_name, 2133 le32_to_cpu(blk->len), 2134 firmware->size); 2135 ret = -EINVAL; 2136 goto out_fw; 2137 } 2138 2139 buf = cs_dsp_buf_alloc(blk->data, 2140 le32_to_cpu(blk->len), 2141 &buf_list); 2142 if (!buf) { 2143 cs_dsp_err(dsp, "Out of memory\n"); 2144 ret = -ENOMEM; 2145 goto out_fw; 2146 } 2147 2148 cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", 2149 file, blocks, le32_to_cpu(blk->len), 2150 reg); 2151 ret = regmap_raw_write_async(regmap, reg, buf->buf, 2152 le32_to_cpu(blk->len)); 2153 if (ret != 0) { 2154 cs_dsp_err(dsp, 2155 "%s.%d: Failed to write to %x in %s: %d\n", 2156 file, blocks, reg, region_name, ret); 2157 } 2158 } 2159 2160 pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03; 2161 blocks++; 2162 } 2163 2164 ret = regmap_async_complete(regmap); 2165 if (ret != 0) 2166 cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret); 2167 2168 if (pos > firmware->size) 2169 cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 2170 file, blocks, pos - firmware->size); 2171 2172 cs_dsp_debugfs_save_binname(dsp, file); 2173 2174 out_fw: 2175 regmap_async_complete(regmap); 2176 cs_dsp_buf_free(&buf_list); 2177 kfree(text); 2178 return ret; 2179 } 2180 2181 static int cs_dsp_create_name(struct cs_dsp *dsp) 2182 { 2183 if (!dsp->name) { 2184 dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d", 2185 dsp->num); 2186 if (!dsp->name) 2187 return -ENOMEM; 2188 } 2189 2190 return 0; 2191 } 2192 2193 static int cs_dsp_common_init(struct cs_dsp *dsp) 2194 { 2195 int ret; 2196 2197 ret = cs_dsp_create_name(dsp); 2198 if (ret) 2199 return ret; 2200 2201 INIT_LIST_HEAD(&dsp->alg_regions); 2202 INIT_LIST_HEAD(&dsp->ctl_list); 2203 2204 mutex_init(&dsp->pwr_lock); 2205 2206 return 0; 2207 } 2208 2209 /** 2210 * cs_dsp_adsp1_init() - Initialise a cs_dsp structure representing a ADSP1 device 2211 * @dsp: pointer to DSP structure 2212 * 2213 * Return: Zero for success, a negative number on error. 2214 */ 2215 int cs_dsp_adsp1_init(struct cs_dsp *dsp) 2216 { 2217 dsp->ops = &cs_dsp_adsp1_ops; 2218 2219 return cs_dsp_common_init(dsp); 2220 } 2221 EXPORT_SYMBOL_GPL(cs_dsp_adsp1_init); 2222 2223 /** 2224 * cs_dsp_adsp1_power_up() - Load and start the named firmware 2225 * @dsp: pointer to DSP structure 2226 * @wmfw_firmware: the firmware to be sent 2227 * @wmfw_filename: file name of firmware to be sent 2228 * @coeff_firmware: the coefficient data to be sent 2229 * @coeff_filename: file name of coefficient to data be sent 2230 * @fw_name: the user-friendly firmware name 2231 * 2232 * Return: Zero for success, a negative number on error. 2233 */ 2234 int cs_dsp_adsp1_power_up(struct cs_dsp *dsp, 2235 const struct firmware *wmfw_firmware, char *wmfw_filename, 2236 const struct firmware *coeff_firmware, char *coeff_filename, 2237 const char *fw_name) 2238 { 2239 unsigned int val; 2240 int ret; 2241 2242 mutex_lock(&dsp->pwr_lock); 2243 2244 dsp->fw_name = fw_name; 2245 2246 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2247 ADSP1_SYS_ENA, ADSP1_SYS_ENA); 2248 2249 /* 2250 * For simplicity set the DSP clock rate to be the 2251 * SYSCLK rate rather than making it configurable. 2252 */ 2253 if (dsp->sysclk_reg) { 2254 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); 2255 if (ret != 0) { 2256 cs_dsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); 2257 goto err_mutex; 2258 } 2259 2260 val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift; 2261 2262 ret = regmap_update_bits(dsp->regmap, 2263 dsp->base + ADSP1_CONTROL_31, 2264 ADSP1_CLK_SEL_MASK, val); 2265 if (ret != 0) { 2266 cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret); 2267 goto err_mutex; 2268 } 2269 } 2270 2271 ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename); 2272 if (ret != 0) 2273 goto err_ena; 2274 2275 ret = cs_dsp_adsp1_setup_algs(dsp); 2276 if (ret != 0) 2277 goto err_ena; 2278 2279 ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename); 2280 if (ret != 0) 2281 goto err_ena; 2282 2283 /* Initialize caches for enabled and unset controls */ 2284 ret = cs_dsp_coeff_init_control_caches(dsp); 2285 if (ret != 0) 2286 goto err_ena; 2287 2288 /* Sync set controls */ 2289 ret = cs_dsp_coeff_sync_controls(dsp); 2290 if (ret != 0) 2291 goto err_ena; 2292 2293 dsp->booted = true; 2294 2295 /* Start the core running */ 2296 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2297 ADSP1_CORE_ENA | ADSP1_START, 2298 ADSP1_CORE_ENA | ADSP1_START); 2299 2300 dsp->running = true; 2301 2302 mutex_unlock(&dsp->pwr_lock); 2303 2304 return 0; 2305 2306 err_ena: 2307 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2308 ADSP1_SYS_ENA, 0); 2309 err_mutex: 2310 mutex_unlock(&dsp->pwr_lock); 2311 return ret; 2312 } 2313 EXPORT_SYMBOL_GPL(cs_dsp_adsp1_power_up); 2314 2315 /** 2316 * cs_dsp_adsp1_power_down() - Halts the DSP 2317 * @dsp: pointer to DSP structure 2318 */ 2319 void cs_dsp_adsp1_power_down(struct cs_dsp *dsp) 2320 { 2321 struct cs_dsp_coeff_ctl *ctl; 2322 2323 mutex_lock(&dsp->pwr_lock); 2324 2325 dsp->running = false; 2326 dsp->booted = false; 2327 2328 /* Halt the core */ 2329 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2330 ADSP1_CORE_ENA | ADSP1_START, 0); 2331 2332 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, 2333 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0); 2334 2335 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2336 ADSP1_SYS_ENA, 0); 2337 2338 list_for_each_entry(ctl, &dsp->ctl_list, list) 2339 ctl->enabled = 0; 2340 2341 cs_dsp_free_alg_regions(dsp); 2342 2343 mutex_unlock(&dsp->pwr_lock); 2344 } 2345 EXPORT_SYMBOL_GPL(cs_dsp_adsp1_power_down); 2346 2347 static int cs_dsp_adsp2v2_enable_core(struct cs_dsp *dsp) 2348 { 2349 unsigned int val; 2350 int ret, count; 2351 2352 /* Wait for the RAM to start, should be near instantaneous */ 2353 for (count = 0; count < 10; ++count) { 2354 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val); 2355 if (ret != 0) 2356 return ret; 2357 2358 if (val & ADSP2_RAM_RDY) 2359 break; 2360 2361 usleep_range(250, 500); 2362 } 2363 2364 if (!(val & ADSP2_RAM_RDY)) { 2365 cs_dsp_err(dsp, "Failed to start DSP RAM\n"); 2366 return -EBUSY; 2367 } 2368 2369 cs_dsp_dbg(dsp, "RAM ready after %d polls\n", count); 2370 2371 return 0; 2372 } 2373 2374 static int cs_dsp_adsp2_enable_core(struct cs_dsp *dsp) 2375 { 2376 int ret; 2377 2378 ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL, 2379 ADSP2_SYS_ENA, ADSP2_SYS_ENA); 2380 if (ret != 0) 2381 return ret; 2382 2383 return cs_dsp_adsp2v2_enable_core(dsp); 2384 } 2385 2386 static int cs_dsp_adsp2_lock(struct cs_dsp *dsp, unsigned int lock_regions) 2387 { 2388 struct regmap *regmap = dsp->regmap; 2389 unsigned int code0, code1, lock_reg; 2390 2391 if (!(lock_regions & CS_ADSP2_REGION_ALL)) 2392 return 0; 2393 2394 lock_regions &= CS_ADSP2_REGION_ALL; 2395 lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0; 2396 2397 while (lock_regions) { 2398 code0 = code1 = 0; 2399 if (lock_regions & BIT(0)) { 2400 code0 = ADSP2_LOCK_CODE_0; 2401 code1 = ADSP2_LOCK_CODE_1; 2402 } 2403 if (lock_regions & BIT(1)) { 2404 code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT; 2405 code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT; 2406 } 2407 regmap_write(regmap, lock_reg, code0); 2408 regmap_write(regmap, lock_reg, code1); 2409 lock_regions >>= 2; 2410 lock_reg += 2; 2411 } 2412 2413 return 0; 2414 } 2415 2416 static int cs_dsp_adsp2_enable_memory(struct cs_dsp *dsp) 2417 { 2418 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2419 ADSP2_MEM_ENA, ADSP2_MEM_ENA); 2420 } 2421 2422 static void cs_dsp_adsp2_disable_memory(struct cs_dsp *dsp) 2423 { 2424 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2425 ADSP2_MEM_ENA, 0); 2426 } 2427 2428 static void cs_dsp_adsp2_disable_core(struct cs_dsp *dsp) 2429 { 2430 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); 2431 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); 2432 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); 2433 2434 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2435 ADSP2_SYS_ENA, 0); 2436 } 2437 2438 static void cs_dsp_adsp2v2_disable_core(struct cs_dsp *dsp) 2439 { 2440 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); 2441 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); 2442 regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0); 2443 } 2444 2445 static int cs_dsp_halo_configure_mpu(struct cs_dsp *dsp, unsigned int lock_regions) 2446 { 2447 struct reg_sequence config[] = { 2448 { dsp->base + HALO_MPU_LOCK_CONFIG, 0x5555 }, 2449 { dsp->base + HALO_MPU_LOCK_CONFIG, 0xAAAA }, 2450 { dsp->base + HALO_MPU_XMEM_ACCESS_0, 0xFFFFFFFF }, 2451 { dsp->base + HALO_MPU_YMEM_ACCESS_0, 0xFFFFFFFF }, 2452 { dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions }, 2453 { dsp->base + HALO_MPU_XREG_ACCESS_0, lock_regions }, 2454 { dsp->base + HALO_MPU_YREG_ACCESS_0, lock_regions }, 2455 { dsp->base + HALO_MPU_XMEM_ACCESS_1, 0xFFFFFFFF }, 2456 { dsp->base + HALO_MPU_YMEM_ACCESS_1, 0xFFFFFFFF }, 2457 { dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions }, 2458 { dsp->base + HALO_MPU_XREG_ACCESS_1, lock_regions }, 2459 { dsp->base + HALO_MPU_YREG_ACCESS_1, lock_regions }, 2460 { dsp->base + HALO_MPU_XMEM_ACCESS_2, 0xFFFFFFFF }, 2461 { dsp->base + HALO_MPU_YMEM_ACCESS_2, 0xFFFFFFFF }, 2462 { dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions }, 2463 { dsp->base + HALO_MPU_XREG_ACCESS_2, lock_regions }, 2464 { dsp->base + HALO_MPU_YREG_ACCESS_2, lock_regions }, 2465 { dsp->base + HALO_MPU_XMEM_ACCESS_3, 0xFFFFFFFF }, 2466 { dsp->base + HALO_MPU_YMEM_ACCESS_3, 0xFFFFFFFF }, 2467 { dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions }, 2468 { dsp->base + HALO_MPU_XREG_ACCESS_3, lock_regions }, 2469 { dsp->base + HALO_MPU_YREG_ACCESS_3, lock_regions }, 2470 { dsp->base + HALO_MPU_LOCK_CONFIG, 0 }, 2471 }; 2472 2473 return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config)); 2474 } 2475 2476 /** 2477 * cs_dsp_set_dspclk() - Applies the given frequency to the given cs_dsp 2478 * @dsp: pointer to DSP structure 2479 * @freq: clock rate to set 2480 * 2481 * This is only for use on ADSP2 cores. 2482 * 2483 * Return: Zero for success, a negative number on error. 2484 */ 2485 int cs_dsp_set_dspclk(struct cs_dsp *dsp, unsigned int freq) 2486 { 2487 int ret; 2488 2489 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING, 2490 ADSP2_CLK_SEL_MASK, 2491 freq << ADSP2_CLK_SEL_SHIFT); 2492 if (ret) 2493 cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret); 2494 2495 return ret; 2496 } 2497 EXPORT_SYMBOL_GPL(cs_dsp_set_dspclk); 2498 2499 static void cs_dsp_stop_watchdog(struct cs_dsp *dsp) 2500 { 2501 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG, 2502 ADSP2_WDT_ENA_MASK, 0); 2503 } 2504 2505 static void cs_dsp_halo_stop_watchdog(struct cs_dsp *dsp) 2506 { 2507 regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL, 2508 HALO_WDT_EN_MASK, 0); 2509 } 2510 2511 /** 2512 * cs_dsp_power_up() - Downloads firmware to the DSP 2513 * @dsp: pointer to DSP structure 2514 * @wmfw_firmware: the firmware to be sent 2515 * @wmfw_filename: file name of firmware to be sent 2516 * @coeff_firmware: the coefficient data to be sent 2517 * @coeff_filename: file name of coefficient to data be sent 2518 * @fw_name: the user-friendly firmware name 2519 * 2520 * This function is used on ADSP2 and Halo DSP cores, it powers-up the DSP core 2521 * and downloads the firmware but does not start the firmware running. The 2522 * cs_dsp booted flag will be set once completed and if the core has a low-power 2523 * memory retention mode it will be put into this state after the firmware is 2524 * downloaded. 2525 * 2526 * Return: Zero for success, a negative number on error. 2527 */ 2528 int cs_dsp_power_up(struct cs_dsp *dsp, 2529 const struct firmware *wmfw_firmware, char *wmfw_filename, 2530 const struct firmware *coeff_firmware, char *coeff_filename, 2531 const char *fw_name) 2532 { 2533 int ret; 2534 2535 mutex_lock(&dsp->pwr_lock); 2536 2537 dsp->fw_name = fw_name; 2538 2539 if (dsp->ops->enable_memory) { 2540 ret = dsp->ops->enable_memory(dsp); 2541 if (ret != 0) 2542 goto err_mutex; 2543 } 2544 2545 if (dsp->ops->enable_core) { 2546 ret = dsp->ops->enable_core(dsp); 2547 if (ret != 0) 2548 goto err_mem; 2549 } 2550 2551 ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename); 2552 if (ret != 0) 2553 goto err_ena; 2554 2555 ret = dsp->ops->setup_algs(dsp); 2556 if (ret != 0) 2557 goto err_ena; 2558 2559 ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename); 2560 if (ret != 0) 2561 goto err_ena; 2562 2563 /* Initialize caches for enabled and unset controls */ 2564 ret = cs_dsp_coeff_init_control_caches(dsp); 2565 if (ret != 0) 2566 goto err_ena; 2567 2568 if (dsp->ops->disable_core) 2569 dsp->ops->disable_core(dsp); 2570 2571 dsp->booted = true; 2572 2573 mutex_unlock(&dsp->pwr_lock); 2574 2575 return 0; 2576 err_ena: 2577 if (dsp->ops->disable_core) 2578 dsp->ops->disable_core(dsp); 2579 err_mem: 2580 if (dsp->ops->disable_memory) 2581 dsp->ops->disable_memory(dsp); 2582 err_mutex: 2583 mutex_unlock(&dsp->pwr_lock); 2584 2585 return ret; 2586 } 2587 EXPORT_SYMBOL_GPL(cs_dsp_power_up); 2588 2589 /** 2590 * cs_dsp_power_down() - Powers-down the DSP 2591 * @dsp: pointer to DSP structure 2592 * 2593 * cs_dsp_stop() must have been called before this function. The core will be 2594 * fully powered down and so the memory will not be retained. 2595 */ 2596 void cs_dsp_power_down(struct cs_dsp *dsp) 2597 { 2598 struct cs_dsp_coeff_ctl *ctl; 2599 2600 mutex_lock(&dsp->pwr_lock); 2601 2602 cs_dsp_debugfs_clear(dsp); 2603 2604 dsp->fw_id = 0; 2605 dsp->fw_id_version = 0; 2606 2607 dsp->booted = false; 2608 2609 if (dsp->ops->disable_memory) 2610 dsp->ops->disable_memory(dsp); 2611 2612 list_for_each_entry(ctl, &dsp->ctl_list, list) 2613 ctl->enabled = 0; 2614 2615 cs_dsp_free_alg_regions(dsp); 2616 2617 mutex_unlock(&dsp->pwr_lock); 2618 2619 cs_dsp_dbg(dsp, "Shutdown complete\n"); 2620 } 2621 EXPORT_SYMBOL_GPL(cs_dsp_power_down); 2622 2623 static int cs_dsp_adsp2_start_core(struct cs_dsp *dsp) 2624 { 2625 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2626 ADSP2_CORE_ENA | ADSP2_START, 2627 ADSP2_CORE_ENA | ADSP2_START); 2628 } 2629 2630 static void cs_dsp_adsp2_stop_core(struct cs_dsp *dsp) 2631 { 2632 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2633 ADSP2_CORE_ENA | ADSP2_START, 0); 2634 } 2635 2636 /** 2637 * cs_dsp_run() - Starts the firmware running 2638 * @dsp: pointer to DSP structure 2639 * 2640 * cs_dsp_power_up() must have previously been called successfully. 2641 * 2642 * Return: Zero for success, a negative number on error. 2643 */ 2644 int cs_dsp_run(struct cs_dsp *dsp) 2645 { 2646 int ret; 2647 2648 mutex_lock(&dsp->pwr_lock); 2649 2650 if (!dsp->booted) { 2651 ret = -EIO; 2652 goto err; 2653 } 2654 2655 if (dsp->ops->enable_core) { 2656 ret = dsp->ops->enable_core(dsp); 2657 if (ret != 0) 2658 goto err; 2659 } 2660 2661 if (dsp->client_ops->pre_run) { 2662 ret = dsp->client_ops->pre_run(dsp); 2663 if (ret) 2664 goto err; 2665 } 2666 2667 /* Sync set controls */ 2668 ret = cs_dsp_coeff_sync_controls(dsp); 2669 if (ret != 0) 2670 goto err; 2671 2672 if (dsp->ops->lock_memory) { 2673 ret = dsp->ops->lock_memory(dsp, dsp->lock_regions); 2674 if (ret != 0) { 2675 cs_dsp_err(dsp, "Error configuring MPU: %d\n", ret); 2676 goto err; 2677 } 2678 } 2679 2680 if (dsp->ops->start_core) { 2681 ret = dsp->ops->start_core(dsp); 2682 if (ret != 0) 2683 goto err; 2684 } 2685 2686 dsp->running = true; 2687 2688 if (dsp->client_ops->post_run) { 2689 ret = dsp->client_ops->post_run(dsp); 2690 if (ret) 2691 goto err; 2692 } 2693 2694 mutex_unlock(&dsp->pwr_lock); 2695 2696 return 0; 2697 2698 err: 2699 if (dsp->ops->stop_core) 2700 dsp->ops->stop_core(dsp); 2701 if (dsp->ops->disable_core) 2702 dsp->ops->disable_core(dsp); 2703 mutex_unlock(&dsp->pwr_lock); 2704 2705 return ret; 2706 } 2707 EXPORT_SYMBOL_GPL(cs_dsp_run); 2708 2709 /** 2710 * cs_dsp_stop() - Stops the firmware 2711 * @dsp: pointer to DSP structure 2712 * 2713 * Memory will not be disabled so firmware will remain loaded. 2714 */ 2715 void cs_dsp_stop(struct cs_dsp *dsp) 2716 { 2717 /* Tell the firmware to cleanup */ 2718 cs_dsp_signal_event_controls(dsp, CS_DSP_FW_EVENT_SHUTDOWN); 2719 2720 if (dsp->ops->stop_watchdog) 2721 dsp->ops->stop_watchdog(dsp); 2722 2723 /* Log firmware state, it can be useful for analysis */ 2724 if (dsp->ops->show_fw_status) 2725 dsp->ops->show_fw_status(dsp); 2726 2727 mutex_lock(&dsp->pwr_lock); 2728 2729 dsp->running = false; 2730 2731 if (dsp->ops->stop_core) 2732 dsp->ops->stop_core(dsp); 2733 if (dsp->ops->disable_core) 2734 dsp->ops->disable_core(dsp); 2735 2736 if (dsp->client_ops->post_stop) 2737 dsp->client_ops->post_stop(dsp); 2738 2739 mutex_unlock(&dsp->pwr_lock); 2740 2741 cs_dsp_dbg(dsp, "Execution stopped\n"); 2742 } 2743 EXPORT_SYMBOL_GPL(cs_dsp_stop); 2744 2745 static int cs_dsp_halo_start_core(struct cs_dsp *dsp) 2746 { 2747 int ret; 2748 2749 ret = regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, 2750 HALO_CORE_RESET | HALO_CORE_EN, 2751 HALO_CORE_RESET | HALO_CORE_EN); 2752 if (ret) 2753 return ret; 2754 2755 return regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, 2756 HALO_CORE_RESET, 0); 2757 } 2758 2759 static void cs_dsp_halo_stop_core(struct cs_dsp *dsp) 2760 { 2761 regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, 2762 HALO_CORE_EN, 0); 2763 2764 /* reset halo core with CORE_SOFT_RESET */ 2765 regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET, 2766 HALO_CORE_SOFT_RESET_MASK, 1); 2767 } 2768 2769 /** 2770 * cs_dsp_adsp2_init() - Initialise a cs_dsp structure representing a ADSP2 core 2771 * @dsp: pointer to DSP structure 2772 * 2773 * Return: Zero for success, a negative number on error. 2774 */ 2775 int cs_dsp_adsp2_init(struct cs_dsp *dsp) 2776 { 2777 int ret; 2778 2779 switch (dsp->rev) { 2780 case 0: 2781 /* 2782 * Disable the DSP memory by default when in reset for a small 2783 * power saving. 2784 */ 2785 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2786 ADSP2_MEM_ENA, 0); 2787 if (ret) { 2788 cs_dsp_err(dsp, 2789 "Failed to clear memory retention: %d\n", ret); 2790 return ret; 2791 } 2792 2793 dsp->ops = &cs_dsp_adsp2_ops[0]; 2794 break; 2795 case 1: 2796 dsp->ops = &cs_dsp_adsp2_ops[1]; 2797 break; 2798 default: 2799 dsp->ops = &cs_dsp_adsp2_ops[2]; 2800 break; 2801 } 2802 2803 return cs_dsp_common_init(dsp); 2804 } 2805 EXPORT_SYMBOL_GPL(cs_dsp_adsp2_init); 2806 2807 /** 2808 * cs_dsp_halo_init() - Initialise a cs_dsp structure representing a HALO Core DSP 2809 * @dsp: pointer to DSP structure 2810 * 2811 * Return: Zero for success, a negative number on error. 2812 */ 2813 int cs_dsp_halo_init(struct cs_dsp *dsp) 2814 { 2815 dsp->ops = &cs_dsp_halo_ops; 2816 2817 return cs_dsp_common_init(dsp); 2818 } 2819 EXPORT_SYMBOL_GPL(cs_dsp_halo_init); 2820 2821 /** 2822 * cs_dsp_remove() - Clean a cs_dsp before deletion 2823 * @dsp: pointer to DSP structure 2824 */ 2825 void cs_dsp_remove(struct cs_dsp *dsp) 2826 { 2827 struct cs_dsp_coeff_ctl *ctl; 2828 2829 while (!list_empty(&dsp->ctl_list)) { 2830 ctl = list_first_entry(&dsp->ctl_list, struct cs_dsp_coeff_ctl, list); 2831 2832 if (dsp->client_ops->control_remove) 2833 dsp->client_ops->control_remove(ctl); 2834 2835 list_del(&ctl->list); 2836 cs_dsp_free_ctl_blk(ctl); 2837 } 2838 } 2839 EXPORT_SYMBOL_GPL(cs_dsp_remove); 2840 2841 /** 2842 * cs_dsp_read_raw_data_block() - Reads a block of data from DSP memory 2843 * @dsp: pointer to DSP structure 2844 * @mem_type: the type of DSP memory containing the data to be read 2845 * @mem_addr: the address of the data within the memory region 2846 * @num_words: the length of the data to read 2847 * @data: a buffer to store the fetched data 2848 * 2849 * If this is used to read unpacked 24-bit memory, each 24-bit DSP word will 2850 * occupy 32-bits in data (MSbyte will be 0). This padding can be removed using 2851 * cs_dsp_remove_padding() 2852 * 2853 * Return: Zero for success, a negative number on error. 2854 */ 2855 int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, 2856 unsigned int num_words, __be32 *data) 2857 { 2858 struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type); 2859 unsigned int reg; 2860 int ret; 2861 2862 lockdep_assert_held(&dsp->pwr_lock); 2863 2864 if (!mem) 2865 return -EINVAL; 2866 2867 reg = dsp->ops->region_to_reg(mem, mem_addr); 2868 2869 ret = regmap_raw_read(dsp->regmap, reg, data, 2870 sizeof(*data) * num_words); 2871 if (ret < 0) 2872 return ret; 2873 2874 return 0; 2875 } 2876 EXPORT_SYMBOL_GPL(cs_dsp_read_raw_data_block); 2877 2878 /** 2879 * cs_dsp_read_data_word() - Reads a word from DSP memory 2880 * @dsp: pointer to DSP structure 2881 * @mem_type: the type of DSP memory containing the data to be read 2882 * @mem_addr: the address of the data within the memory region 2883 * @data: a buffer to store the fetched data 2884 * 2885 * Return: Zero for success, a negative number on error. 2886 */ 2887 int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 *data) 2888 { 2889 __be32 raw; 2890 int ret; 2891 2892 ret = cs_dsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw); 2893 if (ret < 0) 2894 return ret; 2895 2896 *data = be32_to_cpu(raw) & 0x00ffffffu; 2897 2898 return 0; 2899 } 2900 EXPORT_SYMBOL_GPL(cs_dsp_read_data_word); 2901 2902 /** 2903 * cs_dsp_write_data_word() - Writes a word to DSP memory 2904 * @dsp: pointer to DSP structure 2905 * @mem_type: the type of DSP memory containing the data to be written 2906 * @mem_addr: the address of the data within the memory region 2907 * @data: the data to be written 2908 * 2909 * Return: Zero for success, a negative number on error. 2910 */ 2911 int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 data) 2912 { 2913 struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type); 2914 __be32 val = cpu_to_be32(data & 0x00ffffffu); 2915 unsigned int reg; 2916 2917 lockdep_assert_held(&dsp->pwr_lock); 2918 2919 if (!mem) 2920 return -EINVAL; 2921 2922 reg = dsp->ops->region_to_reg(mem, mem_addr); 2923 2924 return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val)); 2925 } 2926 EXPORT_SYMBOL_GPL(cs_dsp_write_data_word); 2927 2928 /** 2929 * cs_dsp_remove_padding() - Convert unpacked words to packed bytes 2930 * @buf: buffer containing DSP words read from DSP memory 2931 * @nwords: number of words to convert 2932 * 2933 * DSP words from the register map have pad bytes and the data bytes 2934 * are in swapped order. This swaps to the native endian order and 2935 * strips the pad bytes. 2936 */ 2937 void cs_dsp_remove_padding(u32 *buf, int nwords) 2938 { 2939 const __be32 *pack_in = (__be32 *)buf; 2940 u8 *pack_out = (u8 *)buf; 2941 int i; 2942 2943 for (i = 0; i < nwords; i++) { 2944 u32 word = be32_to_cpu(*pack_in++); 2945 *pack_out++ = (u8)word; 2946 *pack_out++ = (u8)(word >> 8); 2947 *pack_out++ = (u8)(word >> 16); 2948 } 2949 } 2950 EXPORT_SYMBOL_GPL(cs_dsp_remove_padding); 2951 2952 /** 2953 * cs_dsp_adsp2_bus_error() - Handle a DSP bus error interrupt 2954 * @dsp: pointer to DSP structure 2955 * 2956 * The firmware and DSP state will be logged for future analysis. 2957 */ 2958 void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp) 2959 { 2960 unsigned int val; 2961 struct regmap *regmap = dsp->regmap; 2962 int ret = 0; 2963 2964 mutex_lock(&dsp->pwr_lock); 2965 2966 ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val); 2967 if (ret) { 2968 cs_dsp_err(dsp, 2969 "Failed to read Region Lock Ctrl register: %d\n", ret); 2970 goto error; 2971 } 2972 2973 if (val & ADSP2_WDT_TIMEOUT_STS_MASK) { 2974 cs_dsp_err(dsp, "watchdog timeout error\n"); 2975 dsp->ops->stop_watchdog(dsp); 2976 if (dsp->client_ops->watchdog_expired) 2977 dsp->client_ops->watchdog_expired(dsp); 2978 } 2979 2980 if (val & (ADSP2_ADDR_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) { 2981 if (val & ADSP2_ADDR_ERR_MASK) 2982 cs_dsp_err(dsp, "bus error: address error\n"); 2983 else 2984 cs_dsp_err(dsp, "bus error: region lock error\n"); 2985 2986 ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val); 2987 if (ret) { 2988 cs_dsp_err(dsp, 2989 "Failed to read Bus Err Addr register: %d\n", 2990 ret); 2991 goto error; 2992 } 2993 2994 cs_dsp_err(dsp, "bus error address = 0x%x\n", 2995 val & ADSP2_BUS_ERR_ADDR_MASK); 2996 2997 ret = regmap_read(regmap, 2998 dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR, 2999 &val); 3000 if (ret) { 3001 cs_dsp_err(dsp, 3002 "Failed to read Pmem Xmem Err Addr register: %d\n", 3003 ret); 3004 goto error; 3005 } 3006 3007 cs_dsp_err(dsp, "xmem error address = 0x%x\n", 3008 val & ADSP2_XMEM_ERR_ADDR_MASK); 3009 cs_dsp_err(dsp, "pmem error address = 0x%x\n", 3010 (val & ADSP2_PMEM_ERR_ADDR_MASK) >> 3011 ADSP2_PMEM_ERR_ADDR_SHIFT); 3012 } 3013 3014 regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, 3015 ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT); 3016 3017 error: 3018 mutex_unlock(&dsp->pwr_lock); 3019 } 3020 EXPORT_SYMBOL_GPL(cs_dsp_adsp2_bus_error); 3021 3022 /** 3023 * cs_dsp_halo_bus_error() - Handle a DSP bus error interrupt 3024 * @dsp: pointer to DSP structure 3025 * 3026 * The firmware and DSP state will be logged for future analysis. 3027 */ 3028 void cs_dsp_halo_bus_error(struct cs_dsp *dsp) 3029 { 3030 struct regmap *regmap = dsp->regmap; 3031 unsigned int fault[6]; 3032 struct reg_sequence clear[] = { 3033 { dsp->base + HALO_MPU_XM_VIO_STATUS, 0x0 }, 3034 { dsp->base + HALO_MPU_YM_VIO_STATUS, 0x0 }, 3035 { dsp->base + HALO_MPU_PM_VIO_STATUS, 0x0 }, 3036 }; 3037 int ret; 3038 3039 mutex_lock(&dsp->pwr_lock); 3040 3041 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1, 3042 fault); 3043 if (ret) { 3044 cs_dsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret); 3045 goto exit_unlock; 3046 } 3047 3048 cs_dsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n", 3049 *fault & HALO_AHBM_FLAGS_ERR_MASK, 3050 (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >> 3051 HALO_AHBM_CORE_ERR_ADDR_SHIFT); 3052 3053 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0, 3054 fault); 3055 if (ret) { 3056 cs_dsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret); 3057 goto exit_unlock; 3058 } 3059 3060 cs_dsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault); 3061 3062 ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR, 3063 fault, ARRAY_SIZE(fault)); 3064 if (ret) { 3065 cs_dsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret); 3066 goto exit_unlock; 3067 } 3068 3069 cs_dsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]); 3070 cs_dsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]); 3071 cs_dsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]); 3072 3073 ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear)); 3074 if (ret) 3075 cs_dsp_warn(dsp, "Failed to clear MPU status: %d\n", ret); 3076 3077 exit_unlock: 3078 mutex_unlock(&dsp->pwr_lock); 3079 } 3080 EXPORT_SYMBOL_GPL(cs_dsp_halo_bus_error); 3081 3082 /** 3083 * cs_dsp_halo_wdt_expire() - Handle DSP watchdog expiry 3084 * @dsp: pointer to DSP structure 3085 * 3086 * This is logged for future analysis. 3087 */ 3088 void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp) 3089 { 3090 mutex_lock(&dsp->pwr_lock); 3091 3092 cs_dsp_warn(dsp, "WDT Expiry Fault\n"); 3093 3094 dsp->ops->stop_watchdog(dsp); 3095 if (dsp->client_ops->watchdog_expired) 3096 dsp->client_ops->watchdog_expired(dsp); 3097 3098 mutex_unlock(&dsp->pwr_lock); 3099 } 3100 EXPORT_SYMBOL_GPL(cs_dsp_halo_wdt_expire); 3101 3102 static const struct cs_dsp_ops cs_dsp_adsp1_ops = { 3103 .validate_version = cs_dsp_validate_version, 3104 .parse_sizes = cs_dsp_adsp1_parse_sizes, 3105 .region_to_reg = cs_dsp_region_to_reg, 3106 }; 3107 3108 static const struct cs_dsp_ops cs_dsp_adsp2_ops[] = { 3109 { 3110 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3111 .validate_version = cs_dsp_validate_version, 3112 .setup_algs = cs_dsp_adsp2_setup_algs, 3113 .region_to_reg = cs_dsp_region_to_reg, 3114 3115 .show_fw_status = cs_dsp_adsp2_show_fw_status, 3116 3117 .enable_memory = cs_dsp_adsp2_enable_memory, 3118 .disable_memory = cs_dsp_adsp2_disable_memory, 3119 3120 .enable_core = cs_dsp_adsp2_enable_core, 3121 .disable_core = cs_dsp_adsp2_disable_core, 3122 3123 .start_core = cs_dsp_adsp2_start_core, 3124 .stop_core = cs_dsp_adsp2_stop_core, 3125 3126 }, 3127 { 3128 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3129 .validate_version = cs_dsp_validate_version, 3130 .setup_algs = cs_dsp_adsp2_setup_algs, 3131 .region_to_reg = cs_dsp_region_to_reg, 3132 3133 .show_fw_status = cs_dsp_adsp2v2_show_fw_status, 3134 3135 .enable_memory = cs_dsp_adsp2_enable_memory, 3136 .disable_memory = cs_dsp_adsp2_disable_memory, 3137 .lock_memory = cs_dsp_adsp2_lock, 3138 3139 .enable_core = cs_dsp_adsp2v2_enable_core, 3140 .disable_core = cs_dsp_adsp2v2_disable_core, 3141 3142 .start_core = cs_dsp_adsp2_start_core, 3143 .stop_core = cs_dsp_adsp2_stop_core, 3144 }, 3145 { 3146 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3147 .validate_version = cs_dsp_validate_version, 3148 .setup_algs = cs_dsp_adsp2_setup_algs, 3149 .region_to_reg = cs_dsp_region_to_reg, 3150 3151 .show_fw_status = cs_dsp_adsp2v2_show_fw_status, 3152 .stop_watchdog = cs_dsp_stop_watchdog, 3153 3154 .enable_memory = cs_dsp_adsp2_enable_memory, 3155 .disable_memory = cs_dsp_adsp2_disable_memory, 3156 .lock_memory = cs_dsp_adsp2_lock, 3157 3158 .enable_core = cs_dsp_adsp2v2_enable_core, 3159 .disable_core = cs_dsp_adsp2v2_disable_core, 3160 3161 .start_core = cs_dsp_adsp2_start_core, 3162 .stop_core = cs_dsp_adsp2_stop_core, 3163 }, 3164 }; 3165 3166 static const struct cs_dsp_ops cs_dsp_halo_ops = { 3167 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3168 .validate_version = cs_dsp_halo_validate_version, 3169 .setup_algs = cs_dsp_halo_setup_algs, 3170 .region_to_reg = cs_dsp_halo_region_to_reg, 3171 3172 .show_fw_status = cs_dsp_halo_show_fw_status, 3173 .stop_watchdog = cs_dsp_halo_stop_watchdog, 3174 3175 .lock_memory = cs_dsp_halo_configure_mpu, 3176 3177 .start_core = cs_dsp_halo_start_core, 3178 .stop_core = cs_dsp_halo_stop_core, 3179 }; 3180 3181 MODULE_DESCRIPTION("Cirrus Logic DSP Support"); 3182 MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>"); 3183 MODULE_LICENSE("GPL v2"); 3184