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