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 out_fw: 1635 cs_dsp_buf_free(&buf_list); 1636 1637 if (ret == -EOVERFLOW) 1638 cs_dsp_err(dsp, "%s: file content overflows file data\n", file); 1639 1640 return ret; 1641 } 1642 1643 /** 1644 * cs_dsp_get_ctl() - Finds a matching coefficient control 1645 * @dsp: pointer to DSP structure 1646 * @name: pointer to string to match with a control's subname 1647 * @type: the algorithm type to match 1648 * @alg: the algorithm id to match 1649 * 1650 * Find cs_dsp_coeff_ctl with input name as its subname 1651 * 1652 * Return: pointer to the control on success, NULL if not found 1653 */ 1654 struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, int type, 1655 unsigned int alg) 1656 { 1657 struct cs_dsp_coeff_ctl *pos, *rslt = NULL; 1658 1659 lockdep_assert_held(&dsp->pwr_lock); 1660 1661 list_for_each_entry(pos, &dsp->ctl_list, list) { 1662 if (!pos->subname) 1663 continue; 1664 if (strncmp(pos->subname, name, pos->subname_len) == 0 && 1665 pos->fw_name == dsp->fw_name && 1666 pos->alg_region.alg == alg && 1667 pos->alg_region.type == type) { 1668 rslt = pos; 1669 break; 1670 } 1671 } 1672 1673 return rslt; 1674 } 1675 EXPORT_SYMBOL_NS_GPL(cs_dsp_get_ctl, "FW_CS_DSP"); 1676 1677 static void cs_dsp_ctl_fixup_base(struct cs_dsp *dsp, 1678 const struct cs_dsp_alg_region *alg_region) 1679 { 1680 struct cs_dsp_coeff_ctl *ctl; 1681 1682 list_for_each_entry(ctl, &dsp->ctl_list, list) { 1683 if (ctl->fw_name == dsp->fw_name && 1684 alg_region->alg == ctl->alg_region.alg && 1685 alg_region->type == ctl->alg_region.type) { 1686 ctl->alg_region.base = alg_region->base; 1687 } 1688 } 1689 } 1690 1691 static void *cs_dsp_read_algs(struct cs_dsp *dsp, size_t n_algs, 1692 const struct cs_dsp_region *mem, 1693 unsigned int pos, unsigned int len) 1694 { 1695 void *alg; 1696 unsigned int reg; 1697 int ret; 1698 __be32 val; 1699 1700 if (n_algs == 0) { 1701 cs_dsp_err(dsp, "No algorithms\n"); 1702 return ERR_PTR(-EINVAL); 1703 } 1704 1705 if (n_algs > 1024) { 1706 cs_dsp_err(dsp, "Algorithm count %zx excessive\n", n_algs); 1707 return ERR_PTR(-EINVAL); 1708 } 1709 1710 /* Read the terminator first to validate the length */ 1711 reg = dsp->ops->region_to_reg(mem, pos + len); 1712 1713 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); 1714 if (ret != 0) { 1715 cs_dsp_err(dsp, "Failed to read algorithm list end: %d\n", 1716 ret); 1717 return ERR_PTR(ret); 1718 } 1719 1720 if (be32_to_cpu(val) != 0xbedead) 1721 cs_dsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n", 1722 reg, be32_to_cpu(val)); 1723 1724 /* Convert length from DSP words to bytes */ 1725 len *= sizeof(u32); 1726 1727 alg = kzalloc(len, GFP_KERNEL | GFP_DMA); 1728 if (!alg) 1729 return ERR_PTR(-ENOMEM); 1730 1731 reg = dsp->ops->region_to_reg(mem, pos); 1732 1733 ret = regmap_raw_read(dsp->regmap, reg, alg, len); 1734 if (ret != 0) { 1735 cs_dsp_err(dsp, "Failed to read algorithm list: %d\n", ret); 1736 kfree(alg); 1737 return ERR_PTR(ret); 1738 } 1739 1740 return alg; 1741 } 1742 1743 /** 1744 * cs_dsp_find_alg_region() - Finds a matching algorithm region 1745 * @dsp: pointer to DSP structure 1746 * @type: the algorithm type to match 1747 * @id: the algorithm id to match 1748 * 1749 * Return: Pointer to matching algorithm region, or NULL if not found. 1750 */ 1751 struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp, 1752 int type, unsigned int id) 1753 { 1754 struct cs_dsp_alg_region *alg_region; 1755 1756 lockdep_assert_held(&dsp->pwr_lock); 1757 1758 list_for_each_entry(alg_region, &dsp->alg_regions, list) { 1759 if (id == alg_region->alg && type == alg_region->type) 1760 return alg_region; 1761 } 1762 1763 return NULL; 1764 } 1765 EXPORT_SYMBOL_NS_GPL(cs_dsp_find_alg_region, "FW_CS_DSP"); 1766 1767 static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, 1768 int type, __be32 id, 1769 __be32 ver, __be32 base) 1770 { 1771 struct cs_dsp_alg_region *alg_region; 1772 1773 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL); 1774 if (!alg_region) 1775 return ERR_PTR(-ENOMEM); 1776 1777 alg_region->type = type; 1778 alg_region->alg = be32_to_cpu(id); 1779 alg_region->ver = be32_to_cpu(ver); 1780 alg_region->base = be32_to_cpu(base); 1781 1782 list_add_tail(&alg_region->list, &dsp->alg_regions); 1783 1784 if (dsp->wmfw_ver > 0) 1785 cs_dsp_ctl_fixup_base(dsp, alg_region); 1786 1787 return alg_region; 1788 } 1789 1790 static void cs_dsp_free_alg_regions(struct cs_dsp *dsp) 1791 { 1792 struct cs_dsp_alg_region *alg_region; 1793 1794 while (!list_empty(&dsp->alg_regions)) { 1795 alg_region = list_first_entry(&dsp->alg_regions, 1796 struct cs_dsp_alg_region, 1797 list); 1798 list_del(&alg_region->list); 1799 kfree(alg_region); 1800 } 1801 } 1802 1803 static void cs_dsp_parse_wmfw_id_header(struct cs_dsp *dsp, 1804 struct wmfw_id_hdr *fw, int nalgs) 1805 { 1806 dsp->fw_id = be32_to_cpu(fw->id); 1807 dsp->fw_id_version = be32_to_cpu(fw->ver); 1808 1809 cs_dsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n", 1810 dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16, 1811 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, 1812 nalgs); 1813 } 1814 1815 static void cs_dsp_parse_wmfw_v3_id_header(struct cs_dsp *dsp, 1816 struct wmfw_v3_id_hdr *fw, int nalgs) 1817 { 1818 dsp->fw_id = be32_to_cpu(fw->id); 1819 dsp->fw_id_version = be32_to_cpu(fw->ver); 1820 dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id); 1821 1822 cs_dsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n", 1823 dsp->fw_id, dsp->fw_vendor_id, 1824 (dsp->fw_id_version & 0xff0000) >> 16, 1825 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, 1826 nalgs); 1827 } 1828 1829 static int cs_dsp_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver, 1830 int nregions, const int *type, __be32 *base) 1831 { 1832 struct cs_dsp_alg_region *alg_region; 1833 int i; 1834 1835 for (i = 0; i < nregions; i++) { 1836 alg_region = cs_dsp_create_region(dsp, type[i], id, ver, base[i]); 1837 if (IS_ERR(alg_region)) 1838 return PTR_ERR(alg_region); 1839 } 1840 1841 return 0; 1842 } 1843 1844 static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) 1845 { 1846 struct wmfw_adsp1_id_hdr adsp1_id; 1847 struct wmfw_adsp1_alg_hdr *adsp1_alg; 1848 struct cs_dsp_alg_region *alg_region; 1849 const struct cs_dsp_region *mem; 1850 unsigned int pos, len; 1851 size_t n_algs; 1852 int i, ret; 1853 1854 mem = cs_dsp_find_region(dsp, WMFW_ADSP1_DM); 1855 if (WARN_ON(!mem)) 1856 return -EINVAL; 1857 1858 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id, 1859 sizeof(adsp1_id)); 1860 if (ret != 0) { 1861 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", 1862 ret); 1863 return ret; 1864 } 1865 1866 n_algs = be32_to_cpu(adsp1_id.n_algs); 1867 1868 cs_dsp_parse_wmfw_id_header(dsp, &adsp1_id.fw, n_algs); 1869 1870 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, 1871 adsp1_id.fw.id, adsp1_id.fw.ver, 1872 adsp1_id.zm); 1873 if (IS_ERR(alg_region)) 1874 return PTR_ERR(alg_region); 1875 1876 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, 1877 adsp1_id.fw.id, adsp1_id.fw.ver, 1878 adsp1_id.dm); 1879 if (IS_ERR(alg_region)) 1880 return PTR_ERR(alg_region); 1881 1882 /* Calculate offset and length in DSP words */ 1883 pos = sizeof(adsp1_id) / sizeof(u32); 1884 len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32); 1885 1886 adsp1_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); 1887 if (IS_ERR(adsp1_alg)) 1888 return PTR_ERR(adsp1_alg); 1889 1890 for (i = 0; i < n_algs; i++) { 1891 cs_dsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", 1892 i, be32_to_cpu(adsp1_alg[i].alg.id), 1893 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, 1894 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, 1895 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, 1896 be32_to_cpu(adsp1_alg[i].dm), 1897 be32_to_cpu(adsp1_alg[i].zm)); 1898 1899 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, 1900 adsp1_alg[i].alg.id, 1901 adsp1_alg[i].alg.ver, 1902 adsp1_alg[i].dm); 1903 if (IS_ERR(alg_region)) { 1904 ret = PTR_ERR(alg_region); 1905 goto out; 1906 } 1907 if (dsp->wmfw_ver == 0) { 1908 if (i + 1 < n_algs) { 1909 len = be32_to_cpu(adsp1_alg[i + 1].dm); 1910 len -= be32_to_cpu(adsp1_alg[i].dm); 1911 len *= 4; 1912 cs_dsp_create_control(dsp, alg_region, 0, 1913 len, NULL, 0, 0, 1914 WMFW_CTL_TYPE_BYTES); 1915 } else { 1916 cs_dsp_warn(dsp, "Missing length info for region DM with ID %x\n", 1917 be32_to_cpu(adsp1_alg[i].alg.id)); 1918 } 1919 } 1920 1921 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, 1922 adsp1_alg[i].alg.id, 1923 adsp1_alg[i].alg.ver, 1924 adsp1_alg[i].zm); 1925 if (IS_ERR(alg_region)) { 1926 ret = PTR_ERR(alg_region); 1927 goto out; 1928 } 1929 if (dsp->wmfw_ver == 0) { 1930 if (i + 1 < n_algs) { 1931 len = be32_to_cpu(adsp1_alg[i + 1].zm); 1932 len -= be32_to_cpu(adsp1_alg[i].zm); 1933 len *= 4; 1934 cs_dsp_create_control(dsp, alg_region, 0, 1935 len, NULL, 0, 0, 1936 WMFW_CTL_TYPE_BYTES); 1937 } else { 1938 cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 1939 be32_to_cpu(adsp1_alg[i].alg.id)); 1940 } 1941 } 1942 } 1943 1944 out: 1945 kfree(adsp1_alg); 1946 return ret; 1947 } 1948 1949 static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) 1950 { 1951 struct wmfw_adsp2_id_hdr adsp2_id; 1952 struct wmfw_adsp2_alg_hdr *adsp2_alg; 1953 struct cs_dsp_alg_region *alg_region; 1954 const struct cs_dsp_region *mem; 1955 unsigned int pos, len; 1956 size_t n_algs; 1957 int i, ret; 1958 1959 mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM); 1960 if (WARN_ON(!mem)) 1961 return -EINVAL; 1962 1963 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id, 1964 sizeof(adsp2_id)); 1965 if (ret != 0) { 1966 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", 1967 ret); 1968 return ret; 1969 } 1970 1971 n_algs = be32_to_cpu(adsp2_id.n_algs); 1972 1973 cs_dsp_parse_wmfw_id_header(dsp, &adsp2_id.fw, n_algs); 1974 1975 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, 1976 adsp2_id.fw.id, adsp2_id.fw.ver, 1977 adsp2_id.xm); 1978 if (IS_ERR(alg_region)) 1979 return PTR_ERR(alg_region); 1980 1981 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, 1982 adsp2_id.fw.id, adsp2_id.fw.ver, 1983 adsp2_id.ym); 1984 if (IS_ERR(alg_region)) 1985 return PTR_ERR(alg_region); 1986 1987 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, 1988 adsp2_id.fw.id, adsp2_id.fw.ver, 1989 adsp2_id.zm); 1990 if (IS_ERR(alg_region)) 1991 return PTR_ERR(alg_region); 1992 1993 /* Calculate offset and length in DSP words */ 1994 pos = sizeof(adsp2_id) / sizeof(u32); 1995 len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32); 1996 1997 adsp2_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); 1998 if (IS_ERR(adsp2_alg)) 1999 return PTR_ERR(adsp2_alg); 2000 2001 for (i = 0; i < n_algs; i++) { 2002 cs_dsp_dbg(dsp, 2003 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", 2004 i, be32_to_cpu(adsp2_alg[i].alg.id), 2005 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, 2006 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, 2007 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, 2008 be32_to_cpu(adsp2_alg[i].xm), 2009 be32_to_cpu(adsp2_alg[i].ym), 2010 be32_to_cpu(adsp2_alg[i].zm)); 2011 2012 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, 2013 adsp2_alg[i].alg.id, 2014 adsp2_alg[i].alg.ver, 2015 adsp2_alg[i].xm); 2016 if (IS_ERR(alg_region)) { 2017 ret = PTR_ERR(alg_region); 2018 goto out; 2019 } 2020 if (dsp->wmfw_ver == 0) { 2021 if (i + 1 < n_algs) { 2022 len = be32_to_cpu(adsp2_alg[i + 1].xm); 2023 len -= be32_to_cpu(adsp2_alg[i].xm); 2024 len *= 4; 2025 cs_dsp_create_control(dsp, alg_region, 0, 2026 len, NULL, 0, 0, 2027 WMFW_CTL_TYPE_BYTES); 2028 } else { 2029 cs_dsp_warn(dsp, "Missing length info for region XM with ID %x\n", 2030 be32_to_cpu(adsp2_alg[i].alg.id)); 2031 } 2032 } 2033 2034 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, 2035 adsp2_alg[i].alg.id, 2036 adsp2_alg[i].alg.ver, 2037 adsp2_alg[i].ym); 2038 if (IS_ERR(alg_region)) { 2039 ret = PTR_ERR(alg_region); 2040 goto out; 2041 } 2042 if (dsp->wmfw_ver == 0) { 2043 if (i + 1 < n_algs) { 2044 len = be32_to_cpu(adsp2_alg[i + 1].ym); 2045 len -= be32_to_cpu(adsp2_alg[i].ym); 2046 len *= 4; 2047 cs_dsp_create_control(dsp, alg_region, 0, 2048 len, NULL, 0, 0, 2049 WMFW_CTL_TYPE_BYTES); 2050 } else { 2051 cs_dsp_warn(dsp, "Missing length info for region YM with ID %x\n", 2052 be32_to_cpu(adsp2_alg[i].alg.id)); 2053 } 2054 } 2055 2056 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, 2057 adsp2_alg[i].alg.id, 2058 adsp2_alg[i].alg.ver, 2059 adsp2_alg[i].zm); 2060 if (IS_ERR(alg_region)) { 2061 ret = PTR_ERR(alg_region); 2062 goto out; 2063 } 2064 if (dsp->wmfw_ver == 0) { 2065 if (i + 1 < n_algs) { 2066 len = be32_to_cpu(adsp2_alg[i + 1].zm); 2067 len -= be32_to_cpu(adsp2_alg[i].zm); 2068 len *= 4; 2069 cs_dsp_create_control(dsp, alg_region, 0, 2070 len, NULL, 0, 0, 2071 WMFW_CTL_TYPE_BYTES); 2072 } else { 2073 cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 2074 be32_to_cpu(adsp2_alg[i].alg.id)); 2075 } 2076 } 2077 } 2078 2079 out: 2080 kfree(adsp2_alg); 2081 return ret; 2082 } 2083 2084 static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver, 2085 __be32 xm_base, __be32 ym_base) 2086 { 2087 static const int types[] = { 2088 WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED, 2089 WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED 2090 }; 2091 __be32 bases[] = { xm_base, xm_base, ym_base, ym_base }; 2092 2093 return cs_dsp_create_regions(dsp, id, ver, ARRAY_SIZE(types), types, bases); 2094 } 2095 2096 static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp) 2097 { 2098 struct wmfw_halo_id_hdr halo_id; 2099 struct wmfw_halo_alg_hdr *halo_alg; 2100 const struct cs_dsp_region *mem; 2101 unsigned int pos, len; 2102 size_t n_algs; 2103 int i, ret; 2104 2105 mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM); 2106 if (WARN_ON(!mem)) 2107 return -EINVAL; 2108 2109 ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id, 2110 sizeof(halo_id)); 2111 if (ret != 0) { 2112 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", 2113 ret); 2114 return ret; 2115 } 2116 2117 n_algs = be32_to_cpu(halo_id.n_algs); 2118 2119 cs_dsp_parse_wmfw_v3_id_header(dsp, &halo_id.fw, n_algs); 2120 2121 ret = cs_dsp_halo_create_regions(dsp, halo_id.fw.id, halo_id.fw.ver, 2122 halo_id.xm_base, halo_id.ym_base); 2123 if (ret) 2124 return ret; 2125 2126 /* Calculate offset and length in DSP words */ 2127 pos = sizeof(halo_id) / sizeof(u32); 2128 len = (sizeof(*halo_alg) * n_algs) / sizeof(u32); 2129 2130 halo_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); 2131 if (IS_ERR(halo_alg)) 2132 return PTR_ERR(halo_alg); 2133 2134 for (i = 0; i < n_algs; i++) { 2135 cs_dsp_dbg(dsp, 2136 "%d: ID %x v%d.%d.%d XM@%x YM@%x\n", 2137 i, be32_to_cpu(halo_alg[i].alg.id), 2138 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16, 2139 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8, 2140 be32_to_cpu(halo_alg[i].alg.ver) & 0xff, 2141 be32_to_cpu(halo_alg[i].xm_base), 2142 be32_to_cpu(halo_alg[i].ym_base)); 2143 2144 ret = cs_dsp_halo_create_regions(dsp, halo_alg[i].alg.id, 2145 halo_alg[i].alg.ver, 2146 halo_alg[i].xm_base, 2147 halo_alg[i].ym_base); 2148 if (ret) 2149 goto out; 2150 } 2151 2152 out: 2153 kfree(halo_alg); 2154 return ret; 2155 } 2156 2157 static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware, 2158 const char *file) 2159 { 2160 LIST_HEAD(buf_list); 2161 struct regmap *regmap = dsp->regmap; 2162 struct wmfw_coeff_hdr *hdr; 2163 struct wmfw_coeff_item *blk; 2164 const struct cs_dsp_region *mem; 2165 struct cs_dsp_alg_region *alg_region; 2166 const char *region_name; 2167 int ret, pos, blocks, type, offset, reg, version; 2168 struct cs_dsp_buf *buf; 2169 2170 if (!firmware) 2171 return 0; 2172 2173 ret = -EINVAL; 2174 2175 if (sizeof(*hdr) >= firmware->size) { 2176 cs_dsp_err(dsp, "%s: coefficient file too short, %zu bytes\n", 2177 file, firmware->size); 2178 goto out_fw; 2179 } 2180 2181 hdr = (void *)&firmware->data[0]; 2182 if (memcmp(hdr->magic, "WMDR", 4) != 0) { 2183 cs_dsp_err(dsp, "%s: invalid coefficient magic\n", file); 2184 goto out_fw; 2185 } 2186 2187 switch (be32_to_cpu(hdr->rev) & 0xff) { 2188 case 1: 2189 case 2: 2190 break; 2191 default: 2192 cs_dsp_err(dsp, "%s: Unsupported coefficient file format %d\n", 2193 file, be32_to_cpu(hdr->rev) & 0xff); 2194 ret = -EINVAL; 2195 goto out_fw; 2196 } 2197 2198 cs_dsp_info(dsp, "%s: v%d.%d.%d\n", file, 2199 (le32_to_cpu(hdr->ver) >> 16) & 0xff, 2200 (le32_to_cpu(hdr->ver) >> 8) & 0xff, 2201 le32_to_cpu(hdr->ver) & 0xff); 2202 2203 pos = le32_to_cpu(hdr->len); 2204 2205 blocks = 0; 2206 while (pos < firmware->size) { 2207 /* Is there enough data for a complete block header? */ 2208 if (sizeof(*blk) > firmware->size - pos) { 2209 ret = -EOVERFLOW; 2210 goto out_fw; 2211 } 2212 2213 blk = (void *)(&firmware->data[pos]); 2214 2215 if (le32_to_cpu(blk->len) > firmware->size - pos - sizeof(*blk)) { 2216 ret = -EOVERFLOW; 2217 goto out_fw; 2218 } 2219 2220 type = le16_to_cpu(blk->type); 2221 offset = le16_to_cpu(blk->offset); 2222 version = le32_to_cpu(blk->ver) >> 8; 2223 2224 cs_dsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", 2225 file, blocks, le32_to_cpu(blk->id), 2226 (le32_to_cpu(blk->ver) >> 16) & 0xff, 2227 (le32_to_cpu(blk->ver) >> 8) & 0xff, 2228 le32_to_cpu(blk->ver) & 0xff); 2229 cs_dsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n", 2230 file, blocks, le32_to_cpu(blk->len), offset, type); 2231 2232 reg = 0; 2233 region_name = "Unknown"; 2234 switch (type) { 2235 case (WMFW_NAME_TEXT << 8): 2236 cs_dsp_info(dsp, "%s: %.*s\n", dsp->fw_name, 2237 min(le32_to_cpu(blk->len), 100), blk->data); 2238 break; 2239 case (WMFW_INFO_TEXT << 8): 2240 case (WMFW_METADATA << 8): 2241 break; 2242 case (WMFW_ABSOLUTE << 8): 2243 /* 2244 * Old files may use this for global 2245 * coefficients. 2246 */ 2247 if (le32_to_cpu(blk->id) == dsp->fw_id && 2248 offset == 0) { 2249 region_name = "global coefficients"; 2250 mem = cs_dsp_find_region(dsp, type); 2251 if (!mem) { 2252 cs_dsp_err(dsp, "No ZM\n"); 2253 break; 2254 } 2255 reg = dsp->ops->region_to_reg(mem, 0); 2256 2257 } else { 2258 region_name = "register"; 2259 reg = offset; 2260 } 2261 break; 2262 2263 case WMFW_ADSP1_DM: 2264 case WMFW_ADSP1_ZM: 2265 case WMFW_ADSP2_XM: 2266 case WMFW_ADSP2_YM: 2267 case WMFW_HALO_XM_PACKED: 2268 case WMFW_HALO_YM_PACKED: 2269 case WMFW_HALO_PM_PACKED: 2270 cs_dsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", 2271 file, blocks, le32_to_cpu(blk->len), 2272 type, le32_to_cpu(blk->id)); 2273 2274 region_name = cs_dsp_mem_region_name(type); 2275 mem = cs_dsp_find_region(dsp, type); 2276 if (!mem) { 2277 cs_dsp_err(dsp, "No base for region %x\n", type); 2278 break; 2279 } 2280 2281 alg_region = cs_dsp_find_alg_region(dsp, type, 2282 le32_to_cpu(blk->id)); 2283 if (alg_region) { 2284 if (version != alg_region->ver) 2285 cs_dsp_warn(dsp, 2286 "Algorithm coefficient version %d.%d.%d but expected %d.%d.%d\n", 2287 (version >> 16) & 0xFF, 2288 (version >> 8) & 0xFF, 2289 version & 0xFF, 2290 (alg_region->ver >> 16) & 0xFF, 2291 (alg_region->ver >> 8) & 0xFF, 2292 alg_region->ver & 0xFF); 2293 2294 reg = alg_region->base; 2295 reg = dsp->ops->region_to_reg(mem, reg); 2296 reg += offset; 2297 } else { 2298 cs_dsp_err(dsp, "No %s for algorithm %x\n", 2299 region_name, le32_to_cpu(blk->id)); 2300 } 2301 break; 2302 2303 default: 2304 cs_dsp_err(dsp, "%s.%d: Unknown region type %x at %d\n", 2305 file, blocks, type, pos); 2306 break; 2307 } 2308 2309 if (reg) { 2310 buf = cs_dsp_buf_alloc(blk->data, 2311 le32_to_cpu(blk->len), 2312 &buf_list); 2313 if (!buf) { 2314 cs_dsp_err(dsp, "Out of memory\n"); 2315 ret = -ENOMEM; 2316 goto out_fw; 2317 } 2318 2319 cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", 2320 file, blocks, le32_to_cpu(blk->len), 2321 reg); 2322 ret = regmap_raw_write(regmap, reg, buf->buf, 2323 le32_to_cpu(blk->len)); 2324 if (ret != 0) { 2325 cs_dsp_err(dsp, 2326 "%s.%d: Failed to write to %x in %s: %d\n", 2327 file, blocks, reg, region_name, ret); 2328 } 2329 } 2330 2331 pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03; 2332 blocks++; 2333 } 2334 2335 if (pos > firmware->size) 2336 cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 2337 file, blocks, pos - firmware->size); 2338 2339 cs_dsp_debugfs_save_binname(dsp, file); 2340 2341 out_fw: 2342 cs_dsp_buf_free(&buf_list); 2343 2344 if (ret == -EOVERFLOW) 2345 cs_dsp_err(dsp, "%s: file content overflows file data\n", file); 2346 2347 return ret; 2348 } 2349 2350 static int cs_dsp_create_name(struct cs_dsp *dsp) 2351 { 2352 if (!dsp->name) { 2353 dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d", 2354 dsp->num); 2355 if (!dsp->name) 2356 return -ENOMEM; 2357 } 2358 2359 return 0; 2360 } 2361 2362 static int cs_dsp_common_init(struct cs_dsp *dsp) 2363 { 2364 int ret; 2365 2366 ret = cs_dsp_create_name(dsp); 2367 if (ret) 2368 return ret; 2369 2370 INIT_LIST_HEAD(&dsp->alg_regions); 2371 INIT_LIST_HEAD(&dsp->ctl_list); 2372 2373 mutex_init(&dsp->pwr_lock); 2374 2375 #ifdef CONFIG_DEBUG_FS 2376 /* Ensure this is invalid if client never provides a debugfs root */ 2377 dsp->debugfs_root = ERR_PTR(-ENODEV); 2378 #endif 2379 2380 return 0; 2381 } 2382 2383 /** 2384 * cs_dsp_adsp1_init() - Initialise a cs_dsp structure representing a ADSP1 device 2385 * @dsp: pointer to DSP structure 2386 * 2387 * Return: Zero for success, a negative number on error. 2388 */ 2389 int cs_dsp_adsp1_init(struct cs_dsp *dsp) 2390 { 2391 dsp->ops = &cs_dsp_adsp1_ops; 2392 2393 return cs_dsp_common_init(dsp); 2394 } 2395 EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_init, "FW_CS_DSP"); 2396 2397 /** 2398 * cs_dsp_adsp1_power_up() - Load and start the named firmware 2399 * @dsp: pointer to DSP structure 2400 * @wmfw_firmware: the firmware to be sent 2401 * @wmfw_filename: file name of firmware to be sent 2402 * @coeff_firmware: the coefficient data to be sent 2403 * @coeff_filename: file name of coefficient to data be sent 2404 * @fw_name: the user-friendly firmware name 2405 * 2406 * Return: Zero for success, a negative number on error. 2407 */ 2408 int cs_dsp_adsp1_power_up(struct cs_dsp *dsp, 2409 const struct firmware *wmfw_firmware, const char *wmfw_filename, 2410 const struct firmware *coeff_firmware, const char *coeff_filename, 2411 const char *fw_name) 2412 { 2413 unsigned int val; 2414 int ret; 2415 2416 mutex_lock(&dsp->pwr_lock); 2417 2418 dsp->fw_name = fw_name; 2419 2420 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2421 ADSP1_SYS_ENA, ADSP1_SYS_ENA); 2422 2423 /* 2424 * For simplicity set the DSP clock rate to be the 2425 * SYSCLK rate rather than making it configurable. 2426 */ 2427 if (dsp->sysclk_reg) { 2428 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); 2429 if (ret != 0) { 2430 cs_dsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); 2431 goto err_mutex; 2432 } 2433 2434 val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift; 2435 2436 ret = regmap_update_bits(dsp->regmap, 2437 dsp->base + ADSP1_CONTROL_31, 2438 ADSP1_CLK_SEL_MASK, val); 2439 if (ret != 0) { 2440 cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret); 2441 goto err_mutex; 2442 } 2443 } 2444 2445 ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename); 2446 if (ret != 0) 2447 goto err_ena; 2448 2449 ret = cs_dsp_adsp1_setup_algs(dsp); 2450 if (ret != 0) 2451 goto err_ena; 2452 2453 ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename); 2454 if (ret != 0) 2455 goto err_ena; 2456 2457 /* Initialize caches for enabled and unset controls */ 2458 ret = cs_dsp_coeff_init_control_caches(dsp); 2459 if (ret != 0) 2460 goto err_ena; 2461 2462 /* Sync set controls */ 2463 ret = cs_dsp_coeff_sync_controls(dsp); 2464 if (ret != 0) 2465 goto err_ena; 2466 2467 dsp->booted = true; 2468 2469 /* Start the core running */ 2470 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2471 ADSP1_CORE_ENA | ADSP1_START, 2472 ADSP1_CORE_ENA | ADSP1_START); 2473 2474 dsp->running = true; 2475 2476 mutex_unlock(&dsp->pwr_lock); 2477 2478 return 0; 2479 2480 err_ena: 2481 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2482 ADSP1_SYS_ENA, 0); 2483 err_mutex: 2484 mutex_unlock(&dsp->pwr_lock); 2485 return ret; 2486 } 2487 EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_up, "FW_CS_DSP"); 2488 2489 /** 2490 * cs_dsp_adsp1_power_down() - Halts the DSP 2491 * @dsp: pointer to DSP structure 2492 */ 2493 void cs_dsp_adsp1_power_down(struct cs_dsp *dsp) 2494 { 2495 struct cs_dsp_coeff_ctl *ctl; 2496 2497 mutex_lock(&dsp->pwr_lock); 2498 2499 dsp->running = false; 2500 dsp->booted = false; 2501 2502 /* Halt the core */ 2503 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2504 ADSP1_CORE_ENA | ADSP1_START, 0); 2505 2506 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, 2507 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0); 2508 2509 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2510 ADSP1_SYS_ENA, 0); 2511 2512 list_for_each_entry(ctl, &dsp->ctl_list, list) 2513 ctl->enabled = 0; 2514 2515 cs_dsp_free_alg_regions(dsp); 2516 2517 mutex_unlock(&dsp->pwr_lock); 2518 } 2519 EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_down, "FW_CS_DSP"); 2520 2521 static int cs_dsp_adsp2v2_enable_core(struct cs_dsp *dsp) 2522 { 2523 unsigned int val; 2524 int ret, count; 2525 2526 /* Wait for the RAM to start, should be near instantaneous */ 2527 for (count = 0; count < 10; ++count) { 2528 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val); 2529 if (ret != 0) 2530 return ret; 2531 2532 if (val & ADSP2_RAM_RDY) 2533 break; 2534 2535 usleep_range(250, 500); 2536 } 2537 2538 if (!(val & ADSP2_RAM_RDY)) { 2539 cs_dsp_err(dsp, "Failed to start DSP RAM\n"); 2540 return -EBUSY; 2541 } 2542 2543 cs_dsp_dbg(dsp, "RAM ready after %d polls\n", count); 2544 2545 return 0; 2546 } 2547 2548 static int cs_dsp_adsp2_enable_core(struct cs_dsp *dsp) 2549 { 2550 int ret; 2551 2552 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2553 ADSP2_SYS_ENA, ADSP2_SYS_ENA); 2554 if (ret != 0) 2555 return ret; 2556 2557 return cs_dsp_adsp2v2_enable_core(dsp); 2558 } 2559 2560 static int cs_dsp_adsp2_lock(struct cs_dsp *dsp, unsigned int lock_regions) 2561 { 2562 struct regmap *regmap = dsp->regmap; 2563 unsigned int code0, code1, lock_reg; 2564 2565 if (!(lock_regions & CS_ADSP2_REGION_ALL)) 2566 return 0; 2567 2568 lock_regions &= CS_ADSP2_REGION_ALL; 2569 lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0; 2570 2571 while (lock_regions) { 2572 code0 = code1 = 0; 2573 if (lock_regions & BIT(0)) { 2574 code0 = ADSP2_LOCK_CODE_0; 2575 code1 = ADSP2_LOCK_CODE_1; 2576 } 2577 if (lock_regions & BIT(1)) { 2578 code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT; 2579 code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT; 2580 } 2581 regmap_write(regmap, lock_reg, code0); 2582 regmap_write(regmap, lock_reg, code1); 2583 lock_regions >>= 2; 2584 lock_reg += 2; 2585 } 2586 2587 return 0; 2588 } 2589 2590 static int cs_dsp_adsp2_enable_memory(struct cs_dsp *dsp) 2591 { 2592 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2593 ADSP2_MEM_ENA, ADSP2_MEM_ENA); 2594 } 2595 2596 static void cs_dsp_adsp2_disable_memory(struct cs_dsp *dsp) 2597 { 2598 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2599 ADSP2_MEM_ENA, 0); 2600 } 2601 2602 static void cs_dsp_adsp2_disable_core(struct cs_dsp *dsp) 2603 { 2604 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); 2605 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); 2606 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); 2607 2608 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2609 ADSP2_SYS_ENA, 0); 2610 } 2611 2612 static void cs_dsp_adsp2v2_disable_core(struct cs_dsp *dsp) 2613 { 2614 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); 2615 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); 2616 regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0); 2617 } 2618 2619 static int cs_dsp_halo_configure_mpu(struct cs_dsp *dsp, unsigned int lock_regions) 2620 { 2621 struct reg_sequence config[] = { 2622 { dsp->base + HALO_MPU_LOCK_CONFIG, 0x5555 }, 2623 { dsp->base + HALO_MPU_LOCK_CONFIG, 0xAAAA }, 2624 { dsp->base + HALO_MPU_XMEM_ACCESS_0, 0xFFFFFFFF }, 2625 { dsp->base + HALO_MPU_YMEM_ACCESS_0, 0xFFFFFFFF }, 2626 { dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions }, 2627 { dsp->base + HALO_MPU_XREG_ACCESS_0, lock_regions }, 2628 { dsp->base + HALO_MPU_YREG_ACCESS_0, lock_regions }, 2629 { dsp->base + HALO_MPU_XMEM_ACCESS_1, 0xFFFFFFFF }, 2630 { dsp->base + HALO_MPU_YMEM_ACCESS_1, 0xFFFFFFFF }, 2631 { dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions }, 2632 { dsp->base + HALO_MPU_XREG_ACCESS_1, lock_regions }, 2633 { dsp->base + HALO_MPU_YREG_ACCESS_1, lock_regions }, 2634 { dsp->base + HALO_MPU_XMEM_ACCESS_2, 0xFFFFFFFF }, 2635 { dsp->base + HALO_MPU_YMEM_ACCESS_2, 0xFFFFFFFF }, 2636 { dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions }, 2637 { dsp->base + HALO_MPU_XREG_ACCESS_2, lock_regions }, 2638 { dsp->base + HALO_MPU_YREG_ACCESS_2, lock_regions }, 2639 { dsp->base + HALO_MPU_XMEM_ACCESS_3, 0xFFFFFFFF }, 2640 { dsp->base + HALO_MPU_YMEM_ACCESS_3, 0xFFFFFFFF }, 2641 { dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions }, 2642 { dsp->base + HALO_MPU_XREG_ACCESS_3, lock_regions }, 2643 { dsp->base + HALO_MPU_YREG_ACCESS_3, lock_regions }, 2644 { dsp->base + HALO_MPU_LOCK_CONFIG, 0 }, 2645 }; 2646 2647 return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config)); 2648 } 2649 2650 /** 2651 * cs_dsp_set_dspclk() - Applies the given frequency to the given cs_dsp 2652 * @dsp: pointer to DSP structure 2653 * @freq: clock rate to set 2654 * 2655 * This is only for use on ADSP2 cores. 2656 * 2657 * Return: Zero for success, a negative number on error. 2658 */ 2659 int cs_dsp_set_dspclk(struct cs_dsp *dsp, unsigned int freq) 2660 { 2661 int ret; 2662 2663 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING, 2664 ADSP2_CLK_SEL_MASK, 2665 freq << ADSP2_CLK_SEL_SHIFT); 2666 if (ret) 2667 cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret); 2668 2669 return ret; 2670 } 2671 EXPORT_SYMBOL_NS_GPL(cs_dsp_set_dspclk, "FW_CS_DSP"); 2672 2673 static void cs_dsp_stop_watchdog(struct cs_dsp *dsp) 2674 { 2675 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG, 2676 ADSP2_WDT_ENA_MASK, 0); 2677 } 2678 2679 static void cs_dsp_halo_stop_watchdog(struct cs_dsp *dsp) 2680 { 2681 regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL, 2682 HALO_WDT_EN_MASK, 0); 2683 } 2684 2685 /** 2686 * cs_dsp_power_up() - Downloads firmware to the DSP 2687 * @dsp: pointer to DSP structure 2688 * @wmfw_firmware: the firmware to be sent 2689 * @wmfw_filename: file name of firmware to be sent 2690 * @coeff_firmware: the coefficient data to be sent 2691 * @coeff_filename: file name of coefficient to data be sent 2692 * @fw_name: the user-friendly firmware name 2693 * 2694 * This function is used on ADSP2 and Halo DSP cores, it powers-up the DSP core 2695 * and downloads the firmware but does not start the firmware running. The 2696 * cs_dsp booted flag will be set once completed and if the core has a low-power 2697 * memory retention mode it will be put into this state after the firmware is 2698 * downloaded. 2699 * 2700 * Return: Zero for success, a negative number on error. 2701 */ 2702 int cs_dsp_power_up(struct cs_dsp *dsp, 2703 const struct firmware *wmfw_firmware, const char *wmfw_filename, 2704 const struct firmware *coeff_firmware, const char *coeff_filename, 2705 const char *fw_name) 2706 { 2707 int ret; 2708 2709 mutex_lock(&dsp->pwr_lock); 2710 2711 dsp->fw_name = fw_name; 2712 2713 if (dsp->ops->enable_memory) { 2714 ret = dsp->ops->enable_memory(dsp); 2715 if (ret != 0) 2716 goto err_mutex; 2717 } 2718 2719 if (dsp->ops->enable_core) { 2720 ret = dsp->ops->enable_core(dsp); 2721 if (ret != 0) 2722 goto err_mem; 2723 } 2724 2725 ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename); 2726 if (ret != 0) 2727 goto err_ena; 2728 2729 ret = dsp->ops->setup_algs(dsp); 2730 if (ret != 0) 2731 goto err_ena; 2732 2733 ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename); 2734 if (ret != 0) 2735 goto err_ena; 2736 2737 /* Initialize caches for enabled and unset controls */ 2738 ret = cs_dsp_coeff_init_control_caches(dsp); 2739 if (ret != 0) 2740 goto err_ena; 2741 2742 if (dsp->ops->disable_core) 2743 dsp->ops->disable_core(dsp); 2744 2745 dsp->booted = true; 2746 2747 mutex_unlock(&dsp->pwr_lock); 2748 2749 return 0; 2750 err_ena: 2751 if (dsp->ops->disable_core) 2752 dsp->ops->disable_core(dsp); 2753 err_mem: 2754 if (dsp->ops->disable_memory) 2755 dsp->ops->disable_memory(dsp); 2756 err_mutex: 2757 mutex_unlock(&dsp->pwr_lock); 2758 2759 return ret; 2760 } 2761 EXPORT_SYMBOL_NS_GPL(cs_dsp_power_up, "FW_CS_DSP"); 2762 2763 /** 2764 * cs_dsp_power_down() - Powers-down the DSP 2765 * @dsp: pointer to DSP structure 2766 * 2767 * cs_dsp_stop() must have been called before this function. The core will be 2768 * fully powered down and so the memory will not be retained. 2769 */ 2770 void cs_dsp_power_down(struct cs_dsp *dsp) 2771 { 2772 struct cs_dsp_coeff_ctl *ctl; 2773 2774 mutex_lock(&dsp->pwr_lock); 2775 2776 cs_dsp_debugfs_clear(dsp); 2777 2778 dsp->fw_id = 0; 2779 dsp->fw_id_version = 0; 2780 2781 dsp->booted = false; 2782 2783 if (dsp->ops->disable_memory) 2784 dsp->ops->disable_memory(dsp); 2785 2786 list_for_each_entry(ctl, &dsp->ctl_list, list) 2787 ctl->enabled = 0; 2788 2789 cs_dsp_free_alg_regions(dsp); 2790 2791 mutex_unlock(&dsp->pwr_lock); 2792 2793 cs_dsp_dbg(dsp, "Shutdown complete\n"); 2794 } 2795 EXPORT_SYMBOL_NS_GPL(cs_dsp_power_down, "FW_CS_DSP"); 2796 2797 static int cs_dsp_adsp2_start_core(struct cs_dsp *dsp) 2798 { 2799 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2800 ADSP2_CORE_ENA | ADSP2_START, 2801 ADSP2_CORE_ENA | ADSP2_START); 2802 } 2803 2804 static void cs_dsp_adsp2_stop_core(struct cs_dsp *dsp) 2805 { 2806 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2807 ADSP2_CORE_ENA | ADSP2_START, 0); 2808 } 2809 2810 /** 2811 * cs_dsp_run() - Starts the firmware running 2812 * @dsp: pointer to DSP structure 2813 * 2814 * cs_dsp_power_up() must have previously been called successfully. 2815 * 2816 * Return: Zero for success, a negative number on error. 2817 */ 2818 int cs_dsp_run(struct cs_dsp *dsp) 2819 { 2820 int ret; 2821 2822 mutex_lock(&dsp->pwr_lock); 2823 2824 if (!dsp->booted) { 2825 ret = -EIO; 2826 goto err; 2827 } 2828 2829 if (dsp->ops->enable_core) { 2830 ret = dsp->ops->enable_core(dsp); 2831 if (ret != 0) 2832 goto err; 2833 } 2834 2835 if (dsp->client_ops->pre_run) { 2836 ret = dsp->client_ops->pre_run(dsp); 2837 if (ret) 2838 goto err; 2839 } 2840 2841 /* Sync set controls */ 2842 ret = cs_dsp_coeff_sync_controls(dsp); 2843 if (ret != 0) 2844 goto err; 2845 2846 if (dsp->ops->lock_memory) { 2847 ret = dsp->ops->lock_memory(dsp, dsp->lock_regions); 2848 if (ret != 0) { 2849 cs_dsp_err(dsp, "Error configuring MPU: %d\n", ret); 2850 goto err; 2851 } 2852 } 2853 2854 if (dsp->ops->start_core) { 2855 ret = dsp->ops->start_core(dsp); 2856 if (ret != 0) 2857 goto err; 2858 } 2859 2860 dsp->running = true; 2861 2862 if (dsp->client_ops->post_run) { 2863 ret = dsp->client_ops->post_run(dsp); 2864 if (ret) 2865 goto err; 2866 } 2867 2868 mutex_unlock(&dsp->pwr_lock); 2869 2870 return 0; 2871 2872 err: 2873 if (dsp->ops->stop_core) 2874 dsp->ops->stop_core(dsp); 2875 if (dsp->ops->disable_core) 2876 dsp->ops->disable_core(dsp); 2877 mutex_unlock(&dsp->pwr_lock); 2878 2879 return ret; 2880 } 2881 EXPORT_SYMBOL_NS_GPL(cs_dsp_run, "FW_CS_DSP"); 2882 2883 /** 2884 * cs_dsp_stop() - Stops the firmware 2885 * @dsp: pointer to DSP structure 2886 * 2887 * Memory will not be disabled so firmware will remain loaded. 2888 */ 2889 void cs_dsp_stop(struct cs_dsp *dsp) 2890 { 2891 /* Tell the firmware to cleanup */ 2892 cs_dsp_signal_event_controls(dsp, CS_DSP_FW_EVENT_SHUTDOWN); 2893 2894 if (dsp->ops->stop_watchdog) 2895 dsp->ops->stop_watchdog(dsp); 2896 2897 /* Log firmware state, it can be useful for analysis */ 2898 if (dsp->ops->show_fw_status) 2899 dsp->ops->show_fw_status(dsp); 2900 2901 mutex_lock(&dsp->pwr_lock); 2902 2903 if (dsp->client_ops->pre_stop) 2904 dsp->client_ops->pre_stop(dsp); 2905 2906 dsp->running = false; 2907 2908 if (dsp->ops->stop_core) 2909 dsp->ops->stop_core(dsp); 2910 if (dsp->ops->disable_core) 2911 dsp->ops->disable_core(dsp); 2912 2913 if (dsp->client_ops->post_stop) 2914 dsp->client_ops->post_stop(dsp); 2915 2916 mutex_unlock(&dsp->pwr_lock); 2917 2918 cs_dsp_dbg(dsp, "Execution stopped\n"); 2919 } 2920 EXPORT_SYMBOL_NS_GPL(cs_dsp_stop, "FW_CS_DSP"); 2921 2922 static int cs_dsp_halo_start_core(struct cs_dsp *dsp) 2923 { 2924 int ret; 2925 2926 ret = regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, 2927 HALO_CORE_RESET | HALO_CORE_EN, 2928 HALO_CORE_RESET | HALO_CORE_EN); 2929 if (ret) 2930 return ret; 2931 2932 return regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, 2933 HALO_CORE_RESET, 0); 2934 } 2935 2936 static void cs_dsp_halo_stop_core(struct cs_dsp *dsp) 2937 { 2938 regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, 2939 HALO_CORE_EN, 0); 2940 2941 /* reset halo core with CORE_SOFT_RESET */ 2942 regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET, 2943 HALO_CORE_SOFT_RESET_MASK, 1); 2944 } 2945 2946 /** 2947 * cs_dsp_adsp2_init() - Initialise a cs_dsp structure representing a ADSP2 core 2948 * @dsp: pointer to DSP structure 2949 * 2950 * Return: Zero for success, a negative number on error. 2951 */ 2952 int cs_dsp_adsp2_init(struct cs_dsp *dsp) 2953 { 2954 int ret; 2955 2956 switch (dsp->rev) { 2957 case 0: 2958 /* 2959 * Disable the DSP memory by default when in reset for a small 2960 * power saving. 2961 */ 2962 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2963 ADSP2_MEM_ENA, 0); 2964 if (ret) { 2965 cs_dsp_err(dsp, 2966 "Failed to clear memory retention: %d\n", ret); 2967 return ret; 2968 } 2969 2970 dsp->ops = &cs_dsp_adsp2_ops[0]; 2971 break; 2972 case 1: 2973 dsp->ops = &cs_dsp_adsp2_ops[1]; 2974 break; 2975 default: 2976 dsp->ops = &cs_dsp_adsp2_ops[2]; 2977 break; 2978 } 2979 2980 return cs_dsp_common_init(dsp); 2981 } 2982 EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_init, "FW_CS_DSP"); 2983 2984 /** 2985 * cs_dsp_halo_init() - Initialise a cs_dsp structure representing a HALO Core DSP 2986 * @dsp: pointer to DSP structure 2987 * 2988 * Return: Zero for success, a negative number on error. 2989 */ 2990 int cs_dsp_halo_init(struct cs_dsp *dsp) 2991 { 2992 if (dsp->no_core_startstop) 2993 dsp->ops = &cs_dsp_halo_ao_ops; 2994 else 2995 dsp->ops = &cs_dsp_halo_ops; 2996 2997 return cs_dsp_common_init(dsp); 2998 } 2999 EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_init, "FW_CS_DSP"); 3000 3001 /** 3002 * cs_dsp_remove() - Clean a cs_dsp before deletion 3003 * @dsp: pointer to DSP structure 3004 */ 3005 void cs_dsp_remove(struct cs_dsp *dsp) 3006 { 3007 struct cs_dsp_coeff_ctl *ctl; 3008 3009 while (!list_empty(&dsp->ctl_list)) { 3010 ctl = list_first_entry(&dsp->ctl_list, struct cs_dsp_coeff_ctl, list); 3011 3012 if (dsp->client_ops->control_remove) 3013 dsp->client_ops->control_remove(ctl); 3014 3015 list_del(&ctl->list); 3016 cs_dsp_free_ctl_blk(ctl); 3017 } 3018 } 3019 EXPORT_SYMBOL_NS_GPL(cs_dsp_remove, "FW_CS_DSP"); 3020 3021 /** 3022 * cs_dsp_read_raw_data_block() - Reads a block of data from DSP memory 3023 * @dsp: pointer to DSP structure 3024 * @mem_type: the type of DSP memory containing the data to be read 3025 * @mem_addr: the address of the data within the memory region 3026 * @num_words: the length of the data to read 3027 * @data: a buffer to store the fetched data 3028 * 3029 * If this is used to read unpacked 24-bit memory, each 24-bit DSP word will 3030 * occupy 32-bits in data (MSbyte will be 0). This padding can be removed using 3031 * cs_dsp_remove_padding() 3032 * 3033 * Return: Zero for success, a negative number on error. 3034 */ 3035 int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, 3036 unsigned int num_words, __be32 *data) 3037 { 3038 struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type); 3039 unsigned int reg; 3040 int ret; 3041 3042 lockdep_assert_held(&dsp->pwr_lock); 3043 3044 if (!mem) 3045 return -EINVAL; 3046 3047 reg = dsp->ops->region_to_reg(mem, mem_addr); 3048 3049 ret = regmap_raw_read(dsp->regmap, reg, data, 3050 sizeof(*data) * num_words); 3051 if (ret < 0) 3052 return ret; 3053 3054 return 0; 3055 } 3056 EXPORT_SYMBOL_NS_GPL(cs_dsp_read_raw_data_block, "FW_CS_DSP"); 3057 3058 /** 3059 * cs_dsp_read_data_word() - Reads a word from DSP memory 3060 * @dsp: pointer to DSP structure 3061 * @mem_type: the type of DSP memory containing the data to be read 3062 * @mem_addr: the address of the data within the memory region 3063 * @data: a buffer to store the fetched data 3064 * 3065 * Return: Zero for success, a negative number on error. 3066 */ 3067 int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 *data) 3068 { 3069 __be32 raw; 3070 int ret; 3071 3072 ret = cs_dsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw); 3073 if (ret < 0) 3074 return ret; 3075 3076 *data = be32_to_cpu(raw) & 0x00ffffffu; 3077 3078 return 0; 3079 } 3080 EXPORT_SYMBOL_NS_GPL(cs_dsp_read_data_word, "FW_CS_DSP"); 3081 3082 /** 3083 * cs_dsp_write_data_word() - Writes a word to DSP memory 3084 * @dsp: pointer to DSP structure 3085 * @mem_type: the type of DSP memory containing the data to be written 3086 * @mem_addr: the address of the data within the memory region 3087 * @data: the data to be written 3088 * 3089 * Return: Zero for success, a negative number on error. 3090 */ 3091 int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 data) 3092 { 3093 struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type); 3094 __be32 val = cpu_to_be32(data & 0x00ffffffu); 3095 unsigned int reg; 3096 3097 lockdep_assert_held(&dsp->pwr_lock); 3098 3099 if (!mem) 3100 return -EINVAL; 3101 3102 reg = dsp->ops->region_to_reg(mem, mem_addr); 3103 3104 return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val)); 3105 } 3106 EXPORT_SYMBOL_NS_GPL(cs_dsp_write_data_word, "FW_CS_DSP"); 3107 3108 /** 3109 * cs_dsp_remove_padding() - Convert unpacked words to packed bytes 3110 * @buf: buffer containing DSP words read from DSP memory 3111 * @nwords: number of words to convert 3112 * 3113 * DSP words from the register map have pad bytes and the data bytes 3114 * are in swapped order. This swaps to the native endian order and 3115 * strips the pad bytes. 3116 */ 3117 void cs_dsp_remove_padding(u32 *buf, int nwords) 3118 { 3119 const __be32 *pack_in = (__be32 *)buf; 3120 u8 *pack_out = (u8 *)buf; 3121 int i; 3122 3123 for (i = 0; i < nwords; i++) { 3124 u32 word = be32_to_cpu(*pack_in++); 3125 *pack_out++ = (u8)word; 3126 *pack_out++ = (u8)(word >> 8); 3127 *pack_out++ = (u8)(word >> 16); 3128 } 3129 } 3130 EXPORT_SYMBOL_NS_GPL(cs_dsp_remove_padding, "FW_CS_DSP"); 3131 3132 /** 3133 * cs_dsp_adsp2_bus_error() - Handle a DSP bus error interrupt 3134 * @dsp: pointer to DSP structure 3135 * 3136 * The firmware and DSP state will be logged for future analysis. 3137 */ 3138 void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp) 3139 { 3140 unsigned int val; 3141 struct regmap *regmap = dsp->regmap; 3142 int ret = 0; 3143 3144 mutex_lock(&dsp->pwr_lock); 3145 3146 ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val); 3147 if (ret) { 3148 cs_dsp_err(dsp, 3149 "Failed to read Region Lock Ctrl register: %d\n", ret); 3150 goto error; 3151 } 3152 3153 if (val & ADSP2_WDT_TIMEOUT_STS_MASK) { 3154 cs_dsp_err(dsp, "watchdog timeout error\n"); 3155 dsp->ops->stop_watchdog(dsp); 3156 if (dsp->client_ops->watchdog_expired) 3157 dsp->client_ops->watchdog_expired(dsp); 3158 } 3159 3160 if (val & (ADSP2_ADDR_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) { 3161 if (val & ADSP2_ADDR_ERR_MASK) 3162 cs_dsp_err(dsp, "bus error: address error\n"); 3163 else 3164 cs_dsp_err(dsp, "bus error: region lock error\n"); 3165 3166 ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val); 3167 if (ret) { 3168 cs_dsp_err(dsp, 3169 "Failed to read Bus Err Addr register: %d\n", 3170 ret); 3171 goto error; 3172 } 3173 3174 cs_dsp_err(dsp, "bus error address = 0x%x\n", 3175 val & ADSP2_BUS_ERR_ADDR_MASK); 3176 3177 ret = regmap_read(regmap, 3178 dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR, 3179 &val); 3180 if (ret) { 3181 cs_dsp_err(dsp, 3182 "Failed to read Pmem Xmem Err Addr register: %d\n", 3183 ret); 3184 goto error; 3185 } 3186 3187 cs_dsp_err(dsp, "xmem error address = 0x%x\n", 3188 val & ADSP2_XMEM_ERR_ADDR_MASK); 3189 cs_dsp_err(dsp, "pmem error address = 0x%x\n", 3190 (val & ADSP2_PMEM_ERR_ADDR_MASK) >> 3191 ADSP2_PMEM_ERR_ADDR_SHIFT); 3192 } 3193 3194 regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, 3195 ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT); 3196 3197 error: 3198 mutex_unlock(&dsp->pwr_lock); 3199 } 3200 EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_bus_error, "FW_CS_DSP"); 3201 3202 /** 3203 * cs_dsp_halo_bus_error() - Handle a DSP bus error interrupt 3204 * @dsp: pointer to DSP structure 3205 * 3206 * The firmware and DSP state will be logged for future analysis. 3207 */ 3208 void cs_dsp_halo_bus_error(struct cs_dsp *dsp) 3209 { 3210 struct regmap *regmap = dsp->regmap; 3211 unsigned int fault[6]; 3212 struct reg_sequence clear[] = { 3213 { dsp->base + HALO_MPU_XM_VIO_STATUS, 0x0 }, 3214 { dsp->base + HALO_MPU_YM_VIO_STATUS, 0x0 }, 3215 { dsp->base + HALO_MPU_PM_VIO_STATUS, 0x0 }, 3216 }; 3217 int ret; 3218 3219 mutex_lock(&dsp->pwr_lock); 3220 3221 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1, 3222 fault); 3223 if (ret) { 3224 cs_dsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret); 3225 goto exit_unlock; 3226 } 3227 3228 cs_dsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n", 3229 *fault & HALO_AHBM_FLAGS_ERR_MASK, 3230 (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >> 3231 HALO_AHBM_CORE_ERR_ADDR_SHIFT); 3232 3233 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0, 3234 fault); 3235 if (ret) { 3236 cs_dsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret); 3237 goto exit_unlock; 3238 } 3239 3240 cs_dsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault); 3241 3242 ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR, 3243 fault, ARRAY_SIZE(fault)); 3244 if (ret) { 3245 cs_dsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret); 3246 goto exit_unlock; 3247 } 3248 3249 cs_dsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]); 3250 cs_dsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]); 3251 cs_dsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]); 3252 3253 ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear)); 3254 if (ret) 3255 cs_dsp_warn(dsp, "Failed to clear MPU status: %d\n", ret); 3256 3257 exit_unlock: 3258 mutex_unlock(&dsp->pwr_lock); 3259 } 3260 EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_bus_error, "FW_CS_DSP"); 3261 3262 /** 3263 * cs_dsp_halo_wdt_expire() - Handle DSP watchdog expiry 3264 * @dsp: pointer to DSP structure 3265 * 3266 * This is logged for future analysis. 3267 */ 3268 void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp) 3269 { 3270 mutex_lock(&dsp->pwr_lock); 3271 3272 cs_dsp_warn(dsp, "WDT Expiry Fault\n"); 3273 3274 dsp->ops->stop_watchdog(dsp); 3275 if (dsp->client_ops->watchdog_expired) 3276 dsp->client_ops->watchdog_expired(dsp); 3277 3278 mutex_unlock(&dsp->pwr_lock); 3279 } 3280 EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_wdt_expire, "FW_CS_DSP"); 3281 3282 static const struct cs_dsp_ops cs_dsp_adsp1_ops = { 3283 .validate_version = cs_dsp_validate_version, 3284 .parse_sizes = cs_dsp_adsp1_parse_sizes, 3285 .region_to_reg = cs_dsp_region_to_reg, 3286 }; 3287 3288 static const struct cs_dsp_ops cs_dsp_adsp2_ops[] = { 3289 { 3290 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3291 .validate_version = cs_dsp_validate_version, 3292 .setup_algs = cs_dsp_adsp2_setup_algs, 3293 .region_to_reg = cs_dsp_region_to_reg, 3294 3295 .show_fw_status = cs_dsp_adsp2_show_fw_status, 3296 3297 .enable_memory = cs_dsp_adsp2_enable_memory, 3298 .disable_memory = cs_dsp_adsp2_disable_memory, 3299 3300 .enable_core = cs_dsp_adsp2_enable_core, 3301 .disable_core = cs_dsp_adsp2_disable_core, 3302 3303 .start_core = cs_dsp_adsp2_start_core, 3304 .stop_core = cs_dsp_adsp2_stop_core, 3305 3306 }, 3307 { 3308 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3309 .validate_version = cs_dsp_validate_version, 3310 .setup_algs = cs_dsp_adsp2_setup_algs, 3311 .region_to_reg = cs_dsp_region_to_reg, 3312 3313 .show_fw_status = cs_dsp_adsp2v2_show_fw_status, 3314 3315 .enable_memory = cs_dsp_adsp2_enable_memory, 3316 .disable_memory = cs_dsp_adsp2_disable_memory, 3317 .lock_memory = cs_dsp_adsp2_lock, 3318 3319 .enable_core = cs_dsp_adsp2v2_enable_core, 3320 .disable_core = cs_dsp_adsp2v2_disable_core, 3321 3322 .start_core = cs_dsp_adsp2_start_core, 3323 .stop_core = cs_dsp_adsp2_stop_core, 3324 }, 3325 { 3326 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3327 .validate_version = cs_dsp_validate_version, 3328 .setup_algs = cs_dsp_adsp2_setup_algs, 3329 .region_to_reg = cs_dsp_region_to_reg, 3330 3331 .show_fw_status = cs_dsp_adsp2v2_show_fw_status, 3332 .stop_watchdog = cs_dsp_stop_watchdog, 3333 3334 .enable_memory = cs_dsp_adsp2_enable_memory, 3335 .disable_memory = cs_dsp_adsp2_disable_memory, 3336 .lock_memory = cs_dsp_adsp2_lock, 3337 3338 .enable_core = cs_dsp_adsp2v2_enable_core, 3339 .disable_core = cs_dsp_adsp2v2_disable_core, 3340 3341 .start_core = cs_dsp_adsp2_start_core, 3342 .stop_core = cs_dsp_adsp2_stop_core, 3343 }, 3344 }; 3345 3346 static const struct cs_dsp_ops cs_dsp_halo_ops = { 3347 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3348 .validate_version = cs_dsp_halo_validate_version, 3349 .setup_algs = cs_dsp_halo_setup_algs, 3350 .region_to_reg = cs_dsp_halo_region_to_reg, 3351 3352 .show_fw_status = cs_dsp_halo_show_fw_status, 3353 .stop_watchdog = cs_dsp_halo_stop_watchdog, 3354 3355 .lock_memory = cs_dsp_halo_configure_mpu, 3356 3357 .start_core = cs_dsp_halo_start_core, 3358 .stop_core = cs_dsp_halo_stop_core, 3359 }; 3360 3361 static const struct cs_dsp_ops cs_dsp_halo_ao_ops = { 3362 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3363 .validate_version = cs_dsp_halo_validate_version, 3364 .setup_algs = cs_dsp_halo_setup_algs, 3365 .region_to_reg = cs_dsp_halo_region_to_reg, 3366 .show_fw_status = cs_dsp_halo_show_fw_status, 3367 }; 3368 3369 /** 3370 * cs_dsp_chunk_write() - Format data to a DSP memory chunk 3371 * @ch: Pointer to the chunk structure 3372 * @nbits: Number of bits to write 3373 * @val: Value to write 3374 * 3375 * This function sequentially writes values into the format required for DSP 3376 * memory, it handles both inserting of the padding bytes and converting to 3377 * big endian. Note that data is only committed to the chunk when a whole DSP 3378 * words worth of data is available. 3379 * 3380 * Return: Zero for success, a negative number on error. 3381 */ 3382 int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val) 3383 { 3384 int nwrite, i; 3385 3386 nwrite = min(CS_DSP_DATA_WORD_BITS - ch->cachebits, nbits); 3387 3388 ch->cache <<= nwrite; 3389 ch->cache |= val >> (nbits - nwrite); 3390 ch->cachebits += nwrite; 3391 nbits -= nwrite; 3392 3393 if (ch->cachebits == CS_DSP_DATA_WORD_BITS) { 3394 if (cs_dsp_chunk_end(ch)) 3395 return -ENOSPC; 3396 3397 ch->cache &= 0xFFFFFF; 3398 for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE) 3399 *ch->data++ = (ch->cache & 0xFF000000) >> CS_DSP_DATA_WORD_BITS; 3400 3401 ch->bytes += sizeof(ch->cache); 3402 ch->cachebits = 0; 3403 } 3404 3405 if (nbits) 3406 return cs_dsp_chunk_write(ch, nbits, val); 3407 3408 return 0; 3409 } 3410 EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_write, "FW_CS_DSP"); 3411 3412 /** 3413 * cs_dsp_chunk_flush() - Pad remaining data with zero and commit to chunk 3414 * @ch: Pointer to the chunk structure 3415 * 3416 * As cs_dsp_chunk_write only writes data when a whole DSP word is ready to 3417 * be written out it is possible that some data will remain in the cache, this 3418 * function will pad that data with zeros upto a whole DSP word and write out. 3419 * 3420 * Return: Zero for success, a negative number on error. 3421 */ 3422 int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch) 3423 { 3424 if (!ch->cachebits) 3425 return 0; 3426 3427 return cs_dsp_chunk_write(ch, CS_DSP_DATA_WORD_BITS - ch->cachebits, 0); 3428 } 3429 EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_flush, "FW_CS_DSP"); 3430 3431 /** 3432 * cs_dsp_chunk_read() - Parse data from a DSP memory chunk 3433 * @ch: Pointer to the chunk structure 3434 * @nbits: Number of bits to read 3435 * 3436 * This function sequentially reads values from a DSP memory formatted buffer, 3437 * it handles both removing of the padding bytes and converting from big endian. 3438 * 3439 * Return: A negative number is returned on error, otherwise the read value. 3440 */ 3441 int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits) 3442 { 3443 int nread, i; 3444 u32 result; 3445 3446 if (!ch->cachebits) { 3447 if (cs_dsp_chunk_end(ch)) 3448 return -ENOSPC; 3449 3450 ch->cache = 0; 3451 ch->cachebits = CS_DSP_DATA_WORD_BITS; 3452 3453 for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE) 3454 ch->cache |= *ch->data++; 3455 3456 ch->bytes += sizeof(ch->cache); 3457 } 3458 3459 nread = min(ch->cachebits, nbits); 3460 nbits -= nread; 3461 3462 result = ch->cache >> ((sizeof(ch->cache) * BITS_PER_BYTE) - nread); 3463 ch->cache <<= nread; 3464 ch->cachebits -= nread; 3465 3466 if (nbits) 3467 result = (result << nbits) | cs_dsp_chunk_read(ch, nbits); 3468 3469 return result; 3470 } 3471 EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_read, "FW_CS_DSP"); 3472 3473 3474 struct cs_dsp_wseq_op { 3475 struct list_head list; 3476 u32 address; 3477 u32 data; 3478 u16 offset; 3479 u8 operation; 3480 }; 3481 3482 static void cs_dsp_wseq_clear(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq) 3483 { 3484 struct cs_dsp_wseq_op *op, *op_tmp; 3485 3486 list_for_each_entry_safe(op, op_tmp, &wseq->ops, list) { 3487 list_del(&op->list); 3488 devm_kfree(dsp->dev, op); 3489 } 3490 } 3491 3492 static int cs_dsp_populate_wseq(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq) 3493 { 3494 struct cs_dsp_wseq_op *op = NULL; 3495 struct cs_dsp_chunk chunk; 3496 u8 *words; 3497 int ret; 3498 3499 if (!wseq->ctl) { 3500 cs_dsp_err(dsp, "No control for write sequence\n"); 3501 return -EINVAL; 3502 } 3503 3504 words = kzalloc(wseq->ctl->len, GFP_KERNEL); 3505 if (!words) 3506 return -ENOMEM; 3507 3508 ret = cs_dsp_coeff_read_ctrl(wseq->ctl, 0, words, wseq->ctl->len); 3509 if (ret) { 3510 cs_dsp_err(dsp, "Failed to read %s: %d\n", wseq->ctl->subname, ret); 3511 goto err_free; 3512 } 3513 3514 INIT_LIST_HEAD(&wseq->ops); 3515 3516 chunk = cs_dsp_chunk(words, wseq->ctl->len); 3517 3518 while (!cs_dsp_chunk_end(&chunk)) { 3519 op = devm_kzalloc(dsp->dev, sizeof(*op), GFP_KERNEL); 3520 if (!op) { 3521 ret = -ENOMEM; 3522 goto err_free; 3523 } 3524 3525 op->offset = cs_dsp_chunk_bytes(&chunk); 3526 op->operation = cs_dsp_chunk_read(&chunk, 8); 3527 3528 switch (op->operation) { 3529 case CS_DSP_WSEQ_END: 3530 op->data = WSEQ_END_OF_SCRIPT; 3531 break; 3532 case CS_DSP_WSEQ_UNLOCK: 3533 op->data = cs_dsp_chunk_read(&chunk, 16); 3534 break; 3535 case CS_DSP_WSEQ_ADDR8: 3536 op->address = cs_dsp_chunk_read(&chunk, 8); 3537 op->data = cs_dsp_chunk_read(&chunk, 32); 3538 break; 3539 case CS_DSP_WSEQ_H16: 3540 case CS_DSP_WSEQ_L16: 3541 op->address = cs_dsp_chunk_read(&chunk, 24); 3542 op->data = cs_dsp_chunk_read(&chunk, 16); 3543 break; 3544 case CS_DSP_WSEQ_FULL: 3545 op->address = cs_dsp_chunk_read(&chunk, 32); 3546 op->data = cs_dsp_chunk_read(&chunk, 32); 3547 break; 3548 default: 3549 ret = -EINVAL; 3550 cs_dsp_err(dsp, "Unsupported op: %X\n", op->operation); 3551 devm_kfree(dsp->dev, op); 3552 goto err_free; 3553 } 3554 3555 list_add_tail(&op->list, &wseq->ops); 3556 3557 if (op->operation == CS_DSP_WSEQ_END) 3558 break; 3559 } 3560 3561 if (op && op->operation != CS_DSP_WSEQ_END) { 3562 cs_dsp_err(dsp, "%s missing end terminator\n", wseq->ctl->subname); 3563 ret = -ENOENT; 3564 } 3565 3566 err_free: 3567 kfree(words); 3568 3569 return ret; 3570 } 3571 3572 /** 3573 * cs_dsp_wseq_init() - Initialize write sequences contained within the loaded DSP firmware 3574 * @dsp: Pointer to DSP structure 3575 * @wseqs: List of write sequences to initialize 3576 * @num_wseqs: Number of write sequences to initialize 3577 * 3578 * Return: Zero for success, a negative number on error. 3579 */ 3580 int cs_dsp_wseq_init(struct cs_dsp *dsp, struct cs_dsp_wseq *wseqs, unsigned int num_wseqs) 3581 { 3582 int i, ret; 3583 3584 lockdep_assert_held(&dsp->pwr_lock); 3585 3586 for (i = 0; i < num_wseqs; i++) { 3587 ret = cs_dsp_populate_wseq(dsp, &wseqs[i]); 3588 if (ret) { 3589 cs_dsp_wseq_clear(dsp, &wseqs[i]); 3590 return ret; 3591 } 3592 } 3593 3594 return 0; 3595 } 3596 EXPORT_SYMBOL_NS_GPL(cs_dsp_wseq_init, "FW_CS_DSP"); 3597 3598 static struct cs_dsp_wseq_op *cs_dsp_wseq_find_op(u32 addr, u8 op_code, 3599 struct list_head *wseq_ops) 3600 { 3601 struct cs_dsp_wseq_op *op; 3602 3603 list_for_each_entry(op, wseq_ops, list) { 3604 if (op->operation == op_code && op->address == addr) 3605 return op; 3606 } 3607 3608 return NULL; 3609 } 3610 3611 /** 3612 * cs_dsp_wseq_write() - Add or update an entry in a write sequence 3613 * @dsp: Pointer to a DSP structure 3614 * @wseq: Write sequence to write to 3615 * @addr: Address of the register to be written to 3616 * @data: Data to be written 3617 * @op_code: The type of operation of the new entry 3618 * @update: If true, searches for the first entry in the write sequence with 3619 * the same address and op_code, and replaces it. If false, creates a new entry 3620 * at the tail 3621 * 3622 * This function formats register address and value pairs into the format 3623 * required for write sequence entries, and either updates or adds the 3624 * new entry into the write sequence. 3625 * 3626 * If update is set to true and no matching entry is found, it will add a new entry. 3627 * 3628 * Return: Zero for success, a negative number on error. 3629 */ 3630 int cs_dsp_wseq_write(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq, 3631 u32 addr, u32 data, u8 op_code, bool update) 3632 { 3633 struct cs_dsp_wseq_op *op_end, *op_new = NULL; 3634 u32 words[WSEQ_OP_MAX_WORDS]; 3635 struct cs_dsp_chunk chunk; 3636 int new_op_size, ret; 3637 3638 if (update) 3639 op_new = cs_dsp_wseq_find_op(addr, op_code, &wseq->ops); 3640 3641 /* If entry to update is not found, treat it as a new operation */ 3642 if (!op_new) { 3643 op_end = cs_dsp_wseq_find_op(0, CS_DSP_WSEQ_END, &wseq->ops); 3644 if (!op_end) { 3645 cs_dsp_err(dsp, "Missing terminator for %s\n", wseq->ctl->subname); 3646 return -EINVAL; 3647 } 3648 3649 op_new = devm_kzalloc(dsp->dev, sizeof(*op_new), GFP_KERNEL); 3650 if (!op_new) 3651 return -ENOMEM; 3652 3653 op_new->operation = op_code; 3654 op_new->address = addr; 3655 op_new->offset = op_end->offset; 3656 update = false; 3657 } 3658 3659 op_new->data = data; 3660 3661 chunk = cs_dsp_chunk(words, sizeof(words)); 3662 cs_dsp_chunk_write(&chunk, 8, op_new->operation); 3663 3664 switch (op_code) { 3665 case CS_DSP_WSEQ_FULL: 3666 cs_dsp_chunk_write(&chunk, 32, op_new->address); 3667 cs_dsp_chunk_write(&chunk, 32, op_new->data); 3668 break; 3669 case CS_DSP_WSEQ_L16: 3670 case CS_DSP_WSEQ_H16: 3671 cs_dsp_chunk_write(&chunk, 24, op_new->address); 3672 cs_dsp_chunk_write(&chunk, 16, op_new->data); 3673 break; 3674 default: 3675 ret = -EINVAL; 3676 cs_dsp_err(dsp, "Operation %X not supported\n", op_code); 3677 goto op_new_free; 3678 } 3679 3680 new_op_size = cs_dsp_chunk_bytes(&chunk); 3681 3682 if (!update) { 3683 if (wseq->ctl->len - op_end->offset < new_op_size) { 3684 cs_dsp_err(dsp, "Not enough memory in %s for entry\n", wseq->ctl->subname); 3685 ret = -E2BIG; 3686 goto op_new_free; 3687 } 3688 3689 op_end->offset += new_op_size; 3690 3691 ret = cs_dsp_coeff_write_ctrl(wseq->ctl, op_end->offset / sizeof(u32), 3692 &op_end->data, sizeof(u32)); 3693 if (ret) 3694 goto op_new_free; 3695 3696 list_add_tail(&op_new->list, &op_end->list); 3697 } 3698 3699 ret = cs_dsp_coeff_write_ctrl(wseq->ctl, op_new->offset / sizeof(u32), 3700 words, new_op_size); 3701 if (ret) 3702 goto op_new_free; 3703 3704 return 0; 3705 3706 op_new_free: 3707 devm_kfree(dsp->dev, op_new); 3708 3709 return ret; 3710 } 3711 EXPORT_SYMBOL_NS_GPL(cs_dsp_wseq_write, "FW_CS_DSP"); 3712 3713 /** 3714 * cs_dsp_wseq_multi_write() - Add or update multiple entries in a write sequence 3715 * @dsp: Pointer to a DSP structure 3716 * @wseq: Write sequence to write to 3717 * @reg_seq: List of address-data pairs 3718 * @num_regs: Number of address-data pairs 3719 * @op_code: The types of operations of the new entries 3720 * @update: If true, searches for the first entry in the write sequence with 3721 * the same address and op_code, and replaces it. If false, creates a new entry 3722 * at the tail 3723 * 3724 * This function calls cs_dsp_wseq_write() for multiple address-data pairs. 3725 * 3726 * Return: Zero for success, a negative number on error. 3727 */ 3728 int cs_dsp_wseq_multi_write(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq, 3729 const struct reg_sequence *reg_seq, int num_regs, 3730 u8 op_code, bool update) 3731 { 3732 int i, ret; 3733 3734 for (i = 0; i < num_regs; i++) { 3735 ret = cs_dsp_wseq_write(dsp, wseq, reg_seq[i].reg, 3736 reg_seq[i].def, op_code, update); 3737 if (ret) 3738 return ret; 3739 } 3740 3741 return 0; 3742 } 3743 EXPORT_SYMBOL_NS_GPL(cs_dsp_wseq_multi_write, "FW_CS_DSP"); 3744 3745 MODULE_DESCRIPTION("Cirrus Logic DSP Support"); 3746 MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>"); 3747 MODULE_LICENSE("GPL v2"); 3748