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