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