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