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