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