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