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