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