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