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, const u8 **str) 1111 { 1112 int length; 1113 1114 switch (bytes) { 1115 case 1: 1116 length = **pos; 1117 break; 1118 case 2: 1119 length = le16_to_cpu(*((__le16 *)*pos)); 1120 break; 1121 default: 1122 return 0; 1123 } 1124 1125 if (str) 1126 *str = *pos + bytes; 1127 1128 *pos += ((length + bytes) + 3) & ~0x03; 1129 1130 return length; 1131 } 1132 1133 static int cs_dsp_coeff_parse_int(int bytes, const u8 **pos) 1134 { 1135 int val = 0; 1136 1137 switch (bytes) { 1138 case 2: 1139 val = le16_to_cpu(*((__le16 *)*pos)); 1140 break; 1141 case 4: 1142 val = le32_to_cpu(*((__le32 *)*pos)); 1143 break; 1144 default: 1145 break; 1146 } 1147 1148 *pos += bytes; 1149 1150 return val; 1151 } 1152 1153 static inline void cs_dsp_coeff_parse_alg(struct cs_dsp *dsp, const u8 **data, 1154 struct cs_dsp_coeff_parsed_alg *blk) 1155 { 1156 const struct wmfw_adsp_alg_data *raw; 1157 1158 switch (dsp->fw_ver) { 1159 case 0: 1160 case 1: 1161 raw = (const struct wmfw_adsp_alg_data *)*data; 1162 *data = raw->data; 1163 1164 blk->id = le32_to_cpu(raw->id); 1165 blk->name = raw->name; 1166 blk->name_len = strlen(raw->name); 1167 blk->ncoeff = le32_to_cpu(raw->ncoeff); 1168 break; 1169 default: 1170 blk->id = cs_dsp_coeff_parse_int(sizeof(raw->id), data); 1171 blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), data, 1172 &blk->name); 1173 cs_dsp_coeff_parse_string(sizeof(u16), data, NULL); 1174 blk->ncoeff = cs_dsp_coeff_parse_int(sizeof(raw->ncoeff), data); 1175 break; 1176 } 1177 1178 cs_dsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); 1179 cs_dsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); 1180 cs_dsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff); 1181 } 1182 1183 static inline void cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, const u8 **data, 1184 struct cs_dsp_coeff_parsed_coeff *blk) 1185 { 1186 const struct wmfw_adsp_coeff_data *raw; 1187 const u8 *tmp; 1188 int length; 1189 1190 switch (dsp->fw_ver) { 1191 case 0: 1192 case 1: 1193 raw = (const struct wmfw_adsp_coeff_data *)*data; 1194 *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size); 1195 1196 blk->offset = le16_to_cpu(raw->hdr.offset); 1197 blk->mem_type = le16_to_cpu(raw->hdr.type); 1198 blk->name = raw->name; 1199 blk->name_len = strlen(raw->name); 1200 blk->ctl_type = le16_to_cpu(raw->ctl_type); 1201 blk->flags = le16_to_cpu(raw->flags); 1202 blk->len = le32_to_cpu(raw->len); 1203 break; 1204 default: 1205 tmp = *data; 1206 blk->offset = cs_dsp_coeff_parse_int(sizeof(raw->hdr.offset), &tmp); 1207 blk->mem_type = cs_dsp_coeff_parse_int(sizeof(raw->hdr.type), &tmp); 1208 length = cs_dsp_coeff_parse_int(sizeof(raw->hdr.size), &tmp); 1209 blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp, 1210 &blk->name); 1211 cs_dsp_coeff_parse_string(sizeof(u8), &tmp, NULL); 1212 cs_dsp_coeff_parse_string(sizeof(u16), &tmp, NULL); 1213 blk->ctl_type = cs_dsp_coeff_parse_int(sizeof(raw->ctl_type), &tmp); 1214 blk->flags = cs_dsp_coeff_parse_int(sizeof(raw->flags), &tmp); 1215 blk->len = cs_dsp_coeff_parse_int(sizeof(raw->len), &tmp); 1216 1217 *data = *data + sizeof(raw->hdr) + length; 1218 break; 1219 } 1220 1221 cs_dsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type); 1222 cs_dsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset); 1223 cs_dsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name); 1224 cs_dsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags); 1225 cs_dsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type); 1226 cs_dsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); 1227 } 1228 1229 static int cs_dsp_check_coeff_flags(struct cs_dsp *dsp, 1230 const struct cs_dsp_coeff_parsed_coeff *coeff_blk, 1231 unsigned int f_required, 1232 unsigned int f_illegal) 1233 { 1234 if ((coeff_blk->flags & f_illegal) || 1235 ((coeff_blk->flags & f_required) != f_required)) { 1236 cs_dsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n", 1237 coeff_blk->flags, coeff_blk->ctl_type); 1238 return -EINVAL; 1239 } 1240 1241 return 0; 1242 } 1243 1244 static int cs_dsp_parse_coeff(struct cs_dsp *dsp, 1245 const struct wmfw_region *region) 1246 { 1247 struct cs_dsp_alg_region alg_region = {}; 1248 struct cs_dsp_coeff_parsed_alg alg_blk; 1249 struct cs_dsp_coeff_parsed_coeff coeff_blk; 1250 const u8 *data = region->data; 1251 int i, ret; 1252 1253 cs_dsp_coeff_parse_alg(dsp, &data, &alg_blk); 1254 for (i = 0; i < alg_blk.ncoeff; i++) { 1255 cs_dsp_coeff_parse_coeff(dsp, &data, &coeff_blk); 1256 1257 switch (coeff_blk.ctl_type) { 1258 case WMFW_CTL_TYPE_BYTES: 1259 break; 1260 case WMFW_CTL_TYPE_ACKED: 1261 if (coeff_blk.flags & WMFW_CTL_FLAG_SYS) 1262 continue; /* ignore */ 1263 1264 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, 1265 WMFW_CTL_FLAG_VOLATILE | 1266 WMFW_CTL_FLAG_WRITEABLE | 1267 WMFW_CTL_FLAG_READABLE, 1268 0); 1269 if (ret) 1270 return -EINVAL; 1271 break; 1272 case WMFW_CTL_TYPE_HOSTEVENT: 1273 case WMFW_CTL_TYPE_FWEVENT: 1274 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, 1275 WMFW_CTL_FLAG_SYS | 1276 WMFW_CTL_FLAG_VOLATILE | 1277 WMFW_CTL_FLAG_WRITEABLE | 1278 WMFW_CTL_FLAG_READABLE, 1279 0); 1280 if (ret) 1281 return -EINVAL; 1282 break; 1283 case WMFW_CTL_TYPE_HOST_BUFFER: 1284 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, 1285 WMFW_CTL_FLAG_SYS | 1286 WMFW_CTL_FLAG_VOLATILE | 1287 WMFW_CTL_FLAG_READABLE, 1288 0); 1289 if (ret) 1290 return -EINVAL; 1291 break; 1292 default: 1293 cs_dsp_err(dsp, "Unknown control type: %d\n", 1294 coeff_blk.ctl_type); 1295 return -EINVAL; 1296 } 1297 1298 alg_region.type = coeff_blk.mem_type; 1299 alg_region.alg = alg_blk.id; 1300 1301 ret = cs_dsp_create_control(dsp, &alg_region, 1302 coeff_blk.offset, 1303 coeff_blk.len, 1304 coeff_blk.name, 1305 coeff_blk.name_len, 1306 coeff_blk.flags, 1307 coeff_blk.ctl_type); 1308 if (ret < 0) 1309 cs_dsp_err(dsp, "Failed to create control: %.*s, %d\n", 1310 coeff_blk.name_len, coeff_blk.name, ret); 1311 } 1312 1313 return 0; 1314 } 1315 1316 static unsigned int cs_dsp_adsp1_parse_sizes(struct cs_dsp *dsp, 1317 const char * const file, 1318 unsigned int pos, 1319 const struct firmware *firmware) 1320 { 1321 const struct wmfw_adsp1_sizes *adsp1_sizes; 1322 1323 adsp1_sizes = (void *)&firmware->data[pos]; 1324 1325 cs_dsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file, 1326 le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm), 1327 le32_to_cpu(adsp1_sizes->zm)); 1328 1329 return pos + sizeof(*adsp1_sizes); 1330 } 1331 1332 static unsigned int cs_dsp_adsp2_parse_sizes(struct cs_dsp *dsp, 1333 const char * const file, 1334 unsigned int pos, 1335 const struct firmware *firmware) 1336 { 1337 const struct wmfw_adsp2_sizes *adsp2_sizes; 1338 1339 adsp2_sizes = (void *)&firmware->data[pos]; 1340 1341 cs_dsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file, 1342 le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym), 1343 le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm)); 1344 1345 return pos + sizeof(*adsp2_sizes); 1346 } 1347 1348 static bool cs_dsp_validate_version(struct cs_dsp *dsp, unsigned int version) 1349 { 1350 switch (version) { 1351 case 0: 1352 cs_dsp_warn(dsp, "Deprecated file format %d\n", version); 1353 return true; 1354 case 1: 1355 case 2: 1356 return true; 1357 default: 1358 return false; 1359 } 1360 } 1361 1362 static bool cs_dsp_halo_validate_version(struct cs_dsp *dsp, unsigned int version) 1363 { 1364 switch (version) { 1365 case 3: 1366 return true; 1367 default: 1368 return false; 1369 } 1370 } 1371 1372 static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, 1373 const char *file) 1374 { 1375 LIST_HEAD(buf_list); 1376 struct regmap *regmap = dsp->regmap; 1377 unsigned int pos = 0; 1378 const struct wmfw_header *header; 1379 const struct wmfw_adsp1_sizes *adsp1_sizes; 1380 const struct wmfw_footer *footer; 1381 const struct wmfw_region *region; 1382 const struct cs_dsp_region *mem; 1383 const char *region_name; 1384 char *text = NULL; 1385 struct cs_dsp_buf *buf; 1386 unsigned int reg; 1387 int regions = 0; 1388 int ret, offset, type; 1389 1390 if (!firmware) 1391 return 0; 1392 1393 ret = -EINVAL; 1394 1395 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); 1396 if (pos >= firmware->size) { 1397 cs_dsp_err(dsp, "%s: file too short, %zu bytes\n", 1398 file, firmware->size); 1399 goto out_fw; 1400 } 1401 1402 header = (void *)&firmware->data[0]; 1403 1404 if (memcmp(&header->magic[0], "WMFW", 4) != 0) { 1405 cs_dsp_err(dsp, "%s: invalid magic\n", file); 1406 goto out_fw; 1407 } 1408 1409 if (!dsp->ops->validate_version(dsp, header->ver)) { 1410 cs_dsp_err(dsp, "%s: unknown file format %d\n", 1411 file, header->ver); 1412 goto out_fw; 1413 } 1414 1415 cs_dsp_info(dsp, "Firmware version: %d\n", header->ver); 1416 dsp->fw_ver = header->ver; 1417 1418 if (header->core != dsp->type) { 1419 cs_dsp_err(dsp, "%s: invalid core %d != %d\n", 1420 file, header->core, dsp->type); 1421 goto out_fw; 1422 } 1423 1424 pos = sizeof(*header); 1425 pos = dsp->ops->parse_sizes(dsp, file, pos, firmware); 1426 1427 footer = (void *)&firmware->data[pos]; 1428 pos += sizeof(*footer); 1429 1430 if (le32_to_cpu(header->len) != pos) { 1431 cs_dsp_err(dsp, "%s: unexpected header length %d\n", 1432 file, le32_to_cpu(header->len)); 1433 goto out_fw; 1434 } 1435 1436 cs_dsp_dbg(dsp, "%s: timestamp %llu\n", file, 1437 le64_to_cpu(footer->timestamp)); 1438 1439 while (pos < firmware->size && 1440 sizeof(*region) < firmware->size - pos) { 1441 region = (void *)&(firmware->data[pos]); 1442 region_name = "Unknown"; 1443 reg = 0; 1444 text = NULL; 1445 offset = le32_to_cpu(region->offset) & 0xffffff; 1446 type = be32_to_cpu(region->type) & 0xff; 1447 1448 switch (type) { 1449 case WMFW_NAME_TEXT: 1450 region_name = "Firmware name"; 1451 text = kzalloc(le32_to_cpu(region->len) + 1, 1452 GFP_KERNEL); 1453 break; 1454 case WMFW_ALGORITHM_DATA: 1455 region_name = "Algorithm"; 1456 ret = cs_dsp_parse_coeff(dsp, region); 1457 if (ret != 0) 1458 goto out_fw; 1459 break; 1460 case WMFW_INFO_TEXT: 1461 region_name = "Information"; 1462 text = kzalloc(le32_to_cpu(region->len) + 1, 1463 GFP_KERNEL); 1464 break; 1465 case WMFW_ABSOLUTE: 1466 region_name = "Absolute"; 1467 reg = offset; 1468 break; 1469 case WMFW_ADSP1_PM: 1470 case WMFW_ADSP1_DM: 1471 case WMFW_ADSP2_XM: 1472 case WMFW_ADSP2_YM: 1473 case WMFW_ADSP1_ZM: 1474 case WMFW_HALO_PM_PACKED: 1475 case WMFW_HALO_XM_PACKED: 1476 case WMFW_HALO_YM_PACKED: 1477 mem = cs_dsp_find_region(dsp, type); 1478 if (!mem) { 1479 cs_dsp_err(dsp, "No region of type: %x\n", type); 1480 ret = -EINVAL; 1481 goto out_fw; 1482 } 1483 1484 region_name = cs_dsp_mem_region_name(type); 1485 reg = dsp->ops->region_to_reg(mem, offset); 1486 break; 1487 default: 1488 cs_dsp_warn(dsp, 1489 "%s.%d: Unknown region type %x at %d(%x)\n", 1490 file, regions, type, pos, pos); 1491 break; 1492 } 1493 1494 cs_dsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file, 1495 regions, le32_to_cpu(region->len), offset, 1496 region_name); 1497 1498 if (le32_to_cpu(region->len) > 1499 firmware->size - pos - sizeof(*region)) { 1500 cs_dsp_err(dsp, 1501 "%s.%d: %s region len %d bytes exceeds file length %zu\n", 1502 file, regions, region_name, 1503 le32_to_cpu(region->len), firmware->size); 1504 ret = -EINVAL; 1505 goto out_fw; 1506 } 1507 1508 if (text) { 1509 memcpy(text, region->data, le32_to_cpu(region->len)); 1510 cs_dsp_info(dsp, "%s: %s\n", file, text); 1511 kfree(text); 1512 text = NULL; 1513 } 1514 1515 if (reg) { 1516 buf = cs_dsp_buf_alloc(region->data, 1517 le32_to_cpu(region->len), 1518 &buf_list); 1519 if (!buf) { 1520 cs_dsp_err(dsp, "Out of memory\n"); 1521 ret = -ENOMEM; 1522 goto out_fw; 1523 } 1524 1525 ret = regmap_raw_write_async(regmap, reg, buf->buf, 1526 le32_to_cpu(region->len)); 1527 if (ret != 0) { 1528 cs_dsp_err(dsp, 1529 "%s.%d: Failed to write %d bytes at %d in %s: %d\n", 1530 file, regions, 1531 le32_to_cpu(region->len), offset, 1532 region_name, ret); 1533 goto out_fw; 1534 } 1535 } 1536 1537 pos += le32_to_cpu(region->len) + sizeof(*region); 1538 regions++; 1539 } 1540 1541 ret = regmap_async_complete(regmap); 1542 if (ret != 0) { 1543 cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret); 1544 goto out_fw; 1545 } 1546 1547 if (pos > firmware->size) 1548 cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 1549 file, regions, pos - firmware->size); 1550 1551 cs_dsp_debugfs_save_wmfwname(dsp, file); 1552 1553 out_fw: 1554 regmap_async_complete(regmap); 1555 cs_dsp_buf_free(&buf_list); 1556 kfree(text); 1557 1558 return ret; 1559 } 1560 1561 /** 1562 * cs_dsp_get_ctl() - Finds a matching coefficient control 1563 * @dsp: pointer to DSP structure 1564 * @name: pointer to string to match with a control's subname 1565 * @type: the algorithm type to match 1566 * @alg: the algorithm id to match 1567 * 1568 * Find cs_dsp_coeff_ctl with input name as its subname 1569 * 1570 * Return: pointer to the control on success, NULL if not found 1571 */ 1572 struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, int type, 1573 unsigned int alg) 1574 { 1575 struct cs_dsp_coeff_ctl *pos, *rslt = NULL; 1576 1577 lockdep_assert_held(&dsp->pwr_lock); 1578 1579 list_for_each_entry(pos, &dsp->ctl_list, list) { 1580 if (!pos->subname) 1581 continue; 1582 if (strncmp(pos->subname, name, pos->subname_len) == 0 && 1583 pos->fw_name == dsp->fw_name && 1584 pos->alg_region.alg == alg && 1585 pos->alg_region.type == type) { 1586 rslt = pos; 1587 break; 1588 } 1589 } 1590 1591 return rslt; 1592 } 1593 EXPORT_SYMBOL_NS_GPL(cs_dsp_get_ctl, FW_CS_DSP); 1594 1595 static void cs_dsp_ctl_fixup_base(struct cs_dsp *dsp, 1596 const struct cs_dsp_alg_region *alg_region) 1597 { 1598 struct cs_dsp_coeff_ctl *ctl; 1599 1600 list_for_each_entry(ctl, &dsp->ctl_list, list) { 1601 if (ctl->fw_name == dsp->fw_name && 1602 alg_region->alg == ctl->alg_region.alg && 1603 alg_region->type == ctl->alg_region.type) { 1604 ctl->alg_region.base = alg_region->base; 1605 } 1606 } 1607 } 1608 1609 static void *cs_dsp_read_algs(struct cs_dsp *dsp, size_t n_algs, 1610 const struct cs_dsp_region *mem, 1611 unsigned int pos, unsigned int len) 1612 { 1613 void *alg; 1614 unsigned int reg; 1615 int ret; 1616 __be32 val; 1617 1618 if (n_algs == 0) { 1619 cs_dsp_err(dsp, "No algorithms\n"); 1620 return ERR_PTR(-EINVAL); 1621 } 1622 1623 if (n_algs > 1024) { 1624 cs_dsp_err(dsp, "Algorithm count %zx excessive\n", n_algs); 1625 return ERR_PTR(-EINVAL); 1626 } 1627 1628 /* Read the terminator first to validate the length */ 1629 reg = dsp->ops->region_to_reg(mem, pos + len); 1630 1631 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); 1632 if (ret != 0) { 1633 cs_dsp_err(dsp, "Failed to read algorithm list end: %d\n", 1634 ret); 1635 return ERR_PTR(ret); 1636 } 1637 1638 if (be32_to_cpu(val) != 0xbedead) 1639 cs_dsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n", 1640 reg, be32_to_cpu(val)); 1641 1642 /* Convert length from DSP words to bytes */ 1643 len *= sizeof(u32); 1644 1645 alg = kzalloc(len, GFP_KERNEL | GFP_DMA); 1646 if (!alg) 1647 return ERR_PTR(-ENOMEM); 1648 1649 reg = dsp->ops->region_to_reg(mem, pos); 1650 1651 ret = regmap_raw_read(dsp->regmap, reg, alg, len); 1652 if (ret != 0) { 1653 cs_dsp_err(dsp, "Failed to read algorithm list: %d\n", ret); 1654 kfree(alg); 1655 return ERR_PTR(ret); 1656 } 1657 1658 return alg; 1659 } 1660 1661 /** 1662 * cs_dsp_find_alg_region() - Finds a matching algorithm region 1663 * @dsp: pointer to DSP structure 1664 * @type: the algorithm type to match 1665 * @id: the algorithm id to match 1666 * 1667 * Return: Pointer to matching algorithm region, or NULL if not found. 1668 */ 1669 struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp, 1670 int type, unsigned int id) 1671 { 1672 struct cs_dsp_alg_region *alg_region; 1673 1674 lockdep_assert_held(&dsp->pwr_lock); 1675 1676 list_for_each_entry(alg_region, &dsp->alg_regions, list) { 1677 if (id == alg_region->alg && type == alg_region->type) 1678 return alg_region; 1679 } 1680 1681 return NULL; 1682 } 1683 EXPORT_SYMBOL_NS_GPL(cs_dsp_find_alg_region, FW_CS_DSP); 1684 1685 static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, 1686 int type, __be32 id, 1687 __be32 ver, __be32 base) 1688 { 1689 struct cs_dsp_alg_region *alg_region; 1690 1691 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL); 1692 if (!alg_region) 1693 return ERR_PTR(-ENOMEM); 1694 1695 alg_region->type = type; 1696 alg_region->alg = be32_to_cpu(id); 1697 alg_region->ver = be32_to_cpu(ver); 1698 alg_region->base = be32_to_cpu(base); 1699 1700 list_add_tail(&alg_region->list, &dsp->alg_regions); 1701 1702 if (dsp->fw_ver > 0) 1703 cs_dsp_ctl_fixup_base(dsp, alg_region); 1704 1705 return alg_region; 1706 } 1707 1708 static void cs_dsp_free_alg_regions(struct cs_dsp *dsp) 1709 { 1710 struct cs_dsp_alg_region *alg_region; 1711 1712 while (!list_empty(&dsp->alg_regions)) { 1713 alg_region = list_first_entry(&dsp->alg_regions, 1714 struct cs_dsp_alg_region, 1715 list); 1716 list_del(&alg_region->list); 1717 kfree(alg_region); 1718 } 1719 } 1720 1721 static void cs_dsp_parse_wmfw_id_header(struct cs_dsp *dsp, 1722 struct wmfw_id_hdr *fw, int nalgs) 1723 { 1724 dsp->fw_id = be32_to_cpu(fw->id); 1725 dsp->fw_id_version = be32_to_cpu(fw->ver); 1726 1727 cs_dsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n", 1728 dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16, 1729 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, 1730 nalgs); 1731 } 1732 1733 static void cs_dsp_parse_wmfw_v3_id_header(struct cs_dsp *dsp, 1734 struct wmfw_v3_id_hdr *fw, int nalgs) 1735 { 1736 dsp->fw_id = be32_to_cpu(fw->id); 1737 dsp->fw_id_version = be32_to_cpu(fw->ver); 1738 dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id); 1739 1740 cs_dsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n", 1741 dsp->fw_id, dsp->fw_vendor_id, 1742 (dsp->fw_id_version & 0xff0000) >> 16, 1743 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, 1744 nalgs); 1745 } 1746 1747 static int cs_dsp_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver, 1748 int nregions, const int *type, __be32 *base) 1749 { 1750 struct cs_dsp_alg_region *alg_region; 1751 int i; 1752 1753 for (i = 0; i < nregions; i++) { 1754 alg_region = cs_dsp_create_region(dsp, type[i], id, ver, base[i]); 1755 if (IS_ERR(alg_region)) 1756 return PTR_ERR(alg_region); 1757 } 1758 1759 return 0; 1760 } 1761 1762 static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) 1763 { 1764 struct wmfw_adsp1_id_hdr adsp1_id; 1765 struct wmfw_adsp1_alg_hdr *adsp1_alg; 1766 struct cs_dsp_alg_region *alg_region; 1767 const struct cs_dsp_region *mem; 1768 unsigned int pos, len; 1769 size_t n_algs; 1770 int i, ret; 1771 1772 mem = cs_dsp_find_region(dsp, WMFW_ADSP1_DM); 1773 if (WARN_ON(!mem)) 1774 return -EINVAL; 1775 1776 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id, 1777 sizeof(adsp1_id)); 1778 if (ret != 0) { 1779 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", 1780 ret); 1781 return ret; 1782 } 1783 1784 n_algs = be32_to_cpu(adsp1_id.n_algs); 1785 1786 cs_dsp_parse_wmfw_id_header(dsp, &adsp1_id.fw, n_algs); 1787 1788 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, 1789 adsp1_id.fw.id, adsp1_id.fw.ver, 1790 adsp1_id.zm); 1791 if (IS_ERR(alg_region)) 1792 return PTR_ERR(alg_region); 1793 1794 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, 1795 adsp1_id.fw.id, adsp1_id.fw.ver, 1796 adsp1_id.dm); 1797 if (IS_ERR(alg_region)) 1798 return PTR_ERR(alg_region); 1799 1800 /* Calculate offset and length in DSP words */ 1801 pos = sizeof(adsp1_id) / sizeof(u32); 1802 len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32); 1803 1804 adsp1_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); 1805 if (IS_ERR(adsp1_alg)) 1806 return PTR_ERR(adsp1_alg); 1807 1808 for (i = 0; i < n_algs; i++) { 1809 cs_dsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", 1810 i, be32_to_cpu(adsp1_alg[i].alg.id), 1811 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, 1812 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, 1813 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, 1814 be32_to_cpu(adsp1_alg[i].dm), 1815 be32_to_cpu(adsp1_alg[i].zm)); 1816 1817 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, 1818 adsp1_alg[i].alg.id, 1819 adsp1_alg[i].alg.ver, 1820 adsp1_alg[i].dm); 1821 if (IS_ERR(alg_region)) { 1822 ret = PTR_ERR(alg_region); 1823 goto out; 1824 } 1825 if (dsp->fw_ver == 0) { 1826 if (i + 1 < n_algs) { 1827 len = be32_to_cpu(adsp1_alg[i + 1].dm); 1828 len -= be32_to_cpu(adsp1_alg[i].dm); 1829 len *= 4; 1830 cs_dsp_create_control(dsp, alg_region, 0, 1831 len, NULL, 0, 0, 1832 WMFW_CTL_TYPE_BYTES); 1833 } else { 1834 cs_dsp_warn(dsp, "Missing length info for region DM with ID %x\n", 1835 be32_to_cpu(adsp1_alg[i].alg.id)); 1836 } 1837 } 1838 1839 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, 1840 adsp1_alg[i].alg.id, 1841 adsp1_alg[i].alg.ver, 1842 adsp1_alg[i].zm); 1843 if (IS_ERR(alg_region)) { 1844 ret = PTR_ERR(alg_region); 1845 goto out; 1846 } 1847 if (dsp->fw_ver == 0) { 1848 if (i + 1 < n_algs) { 1849 len = be32_to_cpu(adsp1_alg[i + 1].zm); 1850 len -= be32_to_cpu(adsp1_alg[i].zm); 1851 len *= 4; 1852 cs_dsp_create_control(dsp, alg_region, 0, 1853 len, NULL, 0, 0, 1854 WMFW_CTL_TYPE_BYTES); 1855 } else { 1856 cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 1857 be32_to_cpu(adsp1_alg[i].alg.id)); 1858 } 1859 } 1860 } 1861 1862 out: 1863 kfree(adsp1_alg); 1864 return ret; 1865 } 1866 1867 static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) 1868 { 1869 struct wmfw_adsp2_id_hdr adsp2_id; 1870 struct wmfw_adsp2_alg_hdr *adsp2_alg; 1871 struct cs_dsp_alg_region *alg_region; 1872 const struct cs_dsp_region *mem; 1873 unsigned int pos, len; 1874 size_t n_algs; 1875 int i, ret; 1876 1877 mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM); 1878 if (WARN_ON(!mem)) 1879 return -EINVAL; 1880 1881 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id, 1882 sizeof(adsp2_id)); 1883 if (ret != 0) { 1884 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", 1885 ret); 1886 return ret; 1887 } 1888 1889 n_algs = be32_to_cpu(adsp2_id.n_algs); 1890 1891 cs_dsp_parse_wmfw_id_header(dsp, &adsp2_id.fw, n_algs); 1892 1893 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, 1894 adsp2_id.fw.id, adsp2_id.fw.ver, 1895 adsp2_id.xm); 1896 if (IS_ERR(alg_region)) 1897 return PTR_ERR(alg_region); 1898 1899 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, 1900 adsp2_id.fw.id, adsp2_id.fw.ver, 1901 adsp2_id.ym); 1902 if (IS_ERR(alg_region)) 1903 return PTR_ERR(alg_region); 1904 1905 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, 1906 adsp2_id.fw.id, adsp2_id.fw.ver, 1907 adsp2_id.zm); 1908 if (IS_ERR(alg_region)) 1909 return PTR_ERR(alg_region); 1910 1911 /* Calculate offset and length in DSP words */ 1912 pos = sizeof(adsp2_id) / sizeof(u32); 1913 len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32); 1914 1915 adsp2_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); 1916 if (IS_ERR(adsp2_alg)) 1917 return PTR_ERR(adsp2_alg); 1918 1919 for (i = 0; i < n_algs; i++) { 1920 cs_dsp_dbg(dsp, 1921 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", 1922 i, be32_to_cpu(adsp2_alg[i].alg.id), 1923 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, 1924 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, 1925 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, 1926 be32_to_cpu(adsp2_alg[i].xm), 1927 be32_to_cpu(adsp2_alg[i].ym), 1928 be32_to_cpu(adsp2_alg[i].zm)); 1929 1930 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, 1931 adsp2_alg[i].alg.id, 1932 adsp2_alg[i].alg.ver, 1933 adsp2_alg[i].xm); 1934 if (IS_ERR(alg_region)) { 1935 ret = PTR_ERR(alg_region); 1936 goto out; 1937 } 1938 if (dsp->fw_ver == 0) { 1939 if (i + 1 < n_algs) { 1940 len = be32_to_cpu(adsp2_alg[i + 1].xm); 1941 len -= be32_to_cpu(adsp2_alg[i].xm); 1942 len *= 4; 1943 cs_dsp_create_control(dsp, alg_region, 0, 1944 len, NULL, 0, 0, 1945 WMFW_CTL_TYPE_BYTES); 1946 } else { 1947 cs_dsp_warn(dsp, "Missing length info for region XM with ID %x\n", 1948 be32_to_cpu(adsp2_alg[i].alg.id)); 1949 } 1950 } 1951 1952 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, 1953 adsp2_alg[i].alg.id, 1954 adsp2_alg[i].alg.ver, 1955 adsp2_alg[i].ym); 1956 if (IS_ERR(alg_region)) { 1957 ret = PTR_ERR(alg_region); 1958 goto out; 1959 } 1960 if (dsp->fw_ver == 0) { 1961 if (i + 1 < n_algs) { 1962 len = be32_to_cpu(adsp2_alg[i + 1].ym); 1963 len -= be32_to_cpu(adsp2_alg[i].ym); 1964 len *= 4; 1965 cs_dsp_create_control(dsp, alg_region, 0, 1966 len, NULL, 0, 0, 1967 WMFW_CTL_TYPE_BYTES); 1968 } else { 1969 cs_dsp_warn(dsp, "Missing length info for region YM with ID %x\n", 1970 be32_to_cpu(adsp2_alg[i].alg.id)); 1971 } 1972 } 1973 1974 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, 1975 adsp2_alg[i].alg.id, 1976 adsp2_alg[i].alg.ver, 1977 adsp2_alg[i].zm); 1978 if (IS_ERR(alg_region)) { 1979 ret = PTR_ERR(alg_region); 1980 goto out; 1981 } 1982 if (dsp->fw_ver == 0) { 1983 if (i + 1 < n_algs) { 1984 len = be32_to_cpu(adsp2_alg[i + 1].zm); 1985 len -= be32_to_cpu(adsp2_alg[i].zm); 1986 len *= 4; 1987 cs_dsp_create_control(dsp, alg_region, 0, 1988 len, NULL, 0, 0, 1989 WMFW_CTL_TYPE_BYTES); 1990 } else { 1991 cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 1992 be32_to_cpu(adsp2_alg[i].alg.id)); 1993 } 1994 } 1995 } 1996 1997 out: 1998 kfree(adsp2_alg); 1999 return ret; 2000 } 2001 2002 static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver, 2003 __be32 xm_base, __be32 ym_base) 2004 { 2005 static const int types[] = { 2006 WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED, 2007 WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED 2008 }; 2009 __be32 bases[] = { xm_base, xm_base, ym_base, ym_base }; 2010 2011 return cs_dsp_create_regions(dsp, id, ver, ARRAY_SIZE(types), types, bases); 2012 } 2013 2014 static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp) 2015 { 2016 struct wmfw_halo_id_hdr halo_id; 2017 struct wmfw_halo_alg_hdr *halo_alg; 2018 const struct cs_dsp_region *mem; 2019 unsigned int pos, len; 2020 size_t n_algs; 2021 int i, ret; 2022 2023 mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM); 2024 if (WARN_ON(!mem)) 2025 return -EINVAL; 2026 2027 ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id, 2028 sizeof(halo_id)); 2029 if (ret != 0) { 2030 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", 2031 ret); 2032 return ret; 2033 } 2034 2035 n_algs = be32_to_cpu(halo_id.n_algs); 2036 2037 cs_dsp_parse_wmfw_v3_id_header(dsp, &halo_id.fw, n_algs); 2038 2039 ret = cs_dsp_halo_create_regions(dsp, halo_id.fw.id, halo_id.fw.ver, 2040 halo_id.xm_base, halo_id.ym_base); 2041 if (ret) 2042 return ret; 2043 2044 /* Calculate offset and length in DSP words */ 2045 pos = sizeof(halo_id) / sizeof(u32); 2046 len = (sizeof(*halo_alg) * n_algs) / sizeof(u32); 2047 2048 halo_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); 2049 if (IS_ERR(halo_alg)) 2050 return PTR_ERR(halo_alg); 2051 2052 for (i = 0; i < n_algs; i++) { 2053 cs_dsp_dbg(dsp, 2054 "%d: ID %x v%d.%d.%d XM@%x YM@%x\n", 2055 i, be32_to_cpu(halo_alg[i].alg.id), 2056 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16, 2057 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8, 2058 be32_to_cpu(halo_alg[i].alg.ver) & 0xff, 2059 be32_to_cpu(halo_alg[i].xm_base), 2060 be32_to_cpu(halo_alg[i].ym_base)); 2061 2062 ret = cs_dsp_halo_create_regions(dsp, halo_alg[i].alg.id, 2063 halo_alg[i].alg.ver, 2064 halo_alg[i].xm_base, 2065 halo_alg[i].ym_base); 2066 if (ret) 2067 goto out; 2068 } 2069 2070 out: 2071 kfree(halo_alg); 2072 return ret; 2073 } 2074 2075 static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware, 2076 const char *file) 2077 { 2078 LIST_HEAD(buf_list); 2079 struct regmap *regmap = dsp->regmap; 2080 struct wmfw_coeff_hdr *hdr; 2081 struct wmfw_coeff_item *blk; 2082 const struct cs_dsp_region *mem; 2083 struct cs_dsp_alg_region *alg_region; 2084 const char *region_name; 2085 int ret, pos, blocks, type, offset, reg, version; 2086 char *text = NULL; 2087 struct cs_dsp_buf *buf; 2088 2089 if (!firmware) 2090 return 0; 2091 2092 ret = -EINVAL; 2093 2094 if (sizeof(*hdr) >= firmware->size) { 2095 cs_dsp_err(dsp, "%s: coefficient file too short, %zu bytes\n", 2096 file, firmware->size); 2097 goto out_fw; 2098 } 2099 2100 hdr = (void *)&firmware->data[0]; 2101 if (memcmp(hdr->magic, "WMDR", 4) != 0) { 2102 cs_dsp_err(dsp, "%s: invalid coefficient magic\n", file); 2103 goto out_fw; 2104 } 2105 2106 switch (be32_to_cpu(hdr->rev) & 0xff) { 2107 case 1: 2108 case 2: 2109 break; 2110 default: 2111 cs_dsp_err(dsp, "%s: Unsupported coefficient file format %d\n", 2112 file, be32_to_cpu(hdr->rev) & 0xff); 2113 ret = -EINVAL; 2114 goto out_fw; 2115 } 2116 2117 cs_dsp_info(dsp, "%s: v%d.%d.%d\n", file, 2118 (le32_to_cpu(hdr->ver) >> 16) & 0xff, 2119 (le32_to_cpu(hdr->ver) >> 8) & 0xff, 2120 le32_to_cpu(hdr->ver) & 0xff); 2121 2122 pos = le32_to_cpu(hdr->len); 2123 2124 blocks = 0; 2125 while (pos < firmware->size && 2126 sizeof(*blk) < firmware->size - pos) { 2127 blk = (void *)(&firmware->data[pos]); 2128 2129 type = le16_to_cpu(blk->type); 2130 offset = le16_to_cpu(blk->offset); 2131 version = le32_to_cpu(blk->ver) >> 8; 2132 2133 cs_dsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", 2134 file, blocks, le32_to_cpu(blk->id), 2135 (le32_to_cpu(blk->ver) >> 16) & 0xff, 2136 (le32_to_cpu(blk->ver) >> 8) & 0xff, 2137 le32_to_cpu(blk->ver) & 0xff); 2138 cs_dsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n", 2139 file, blocks, le32_to_cpu(blk->len), offset, type); 2140 2141 reg = 0; 2142 region_name = "Unknown"; 2143 switch (type) { 2144 case (WMFW_NAME_TEXT << 8): 2145 text = kzalloc(le32_to_cpu(blk->len) + 1, GFP_KERNEL); 2146 break; 2147 case (WMFW_INFO_TEXT << 8): 2148 case (WMFW_METADATA << 8): 2149 break; 2150 case (WMFW_ABSOLUTE << 8): 2151 /* 2152 * Old files may use this for global 2153 * coefficients. 2154 */ 2155 if (le32_to_cpu(blk->id) == dsp->fw_id && 2156 offset == 0) { 2157 region_name = "global coefficients"; 2158 mem = cs_dsp_find_region(dsp, type); 2159 if (!mem) { 2160 cs_dsp_err(dsp, "No ZM\n"); 2161 break; 2162 } 2163 reg = dsp->ops->region_to_reg(mem, 0); 2164 2165 } else { 2166 region_name = "register"; 2167 reg = offset; 2168 } 2169 break; 2170 2171 case WMFW_ADSP1_DM: 2172 case WMFW_ADSP1_ZM: 2173 case WMFW_ADSP2_XM: 2174 case WMFW_ADSP2_YM: 2175 case WMFW_HALO_XM_PACKED: 2176 case WMFW_HALO_YM_PACKED: 2177 case WMFW_HALO_PM_PACKED: 2178 cs_dsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", 2179 file, blocks, le32_to_cpu(blk->len), 2180 type, le32_to_cpu(blk->id)); 2181 2182 region_name = cs_dsp_mem_region_name(type); 2183 mem = cs_dsp_find_region(dsp, type); 2184 if (!mem) { 2185 cs_dsp_err(dsp, "No base for region %x\n", type); 2186 break; 2187 } 2188 2189 alg_region = cs_dsp_find_alg_region(dsp, type, 2190 le32_to_cpu(blk->id)); 2191 if (alg_region) { 2192 if (version != alg_region->ver) 2193 cs_dsp_warn(dsp, 2194 "Algorithm coefficient version %d.%d.%d but expected %d.%d.%d\n", 2195 (version >> 16) & 0xFF, 2196 (version >> 8) & 0xFF, 2197 version & 0xFF, 2198 (alg_region->ver >> 16) & 0xFF, 2199 (alg_region->ver >> 8) & 0xFF, 2200 alg_region->ver & 0xFF); 2201 2202 reg = alg_region->base; 2203 reg = dsp->ops->region_to_reg(mem, reg); 2204 reg += offset; 2205 } else { 2206 cs_dsp_err(dsp, "No %s for algorithm %x\n", 2207 region_name, le32_to_cpu(blk->id)); 2208 } 2209 break; 2210 2211 default: 2212 cs_dsp_err(dsp, "%s.%d: Unknown region type %x at %d\n", 2213 file, blocks, type, pos); 2214 break; 2215 } 2216 2217 if (text) { 2218 memcpy(text, blk->data, le32_to_cpu(blk->len)); 2219 cs_dsp_info(dsp, "%s: %s\n", dsp->fw_name, text); 2220 kfree(text); 2221 text = NULL; 2222 } 2223 2224 if (reg) { 2225 if (le32_to_cpu(blk->len) > 2226 firmware->size - pos - sizeof(*blk)) { 2227 cs_dsp_err(dsp, 2228 "%s.%d: %s region len %d bytes exceeds file length %zu\n", 2229 file, blocks, region_name, 2230 le32_to_cpu(blk->len), 2231 firmware->size); 2232 ret = -EINVAL; 2233 goto out_fw; 2234 } 2235 2236 buf = cs_dsp_buf_alloc(blk->data, 2237 le32_to_cpu(blk->len), 2238 &buf_list); 2239 if (!buf) { 2240 cs_dsp_err(dsp, "Out of memory\n"); 2241 ret = -ENOMEM; 2242 goto out_fw; 2243 } 2244 2245 cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", 2246 file, blocks, le32_to_cpu(blk->len), 2247 reg); 2248 ret = regmap_raw_write_async(regmap, reg, buf->buf, 2249 le32_to_cpu(blk->len)); 2250 if (ret != 0) { 2251 cs_dsp_err(dsp, 2252 "%s.%d: Failed to write to %x in %s: %d\n", 2253 file, blocks, reg, region_name, ret); 2254 } 2255 } 2256 2257 pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03; 2258 blocks++; 2259 } 2260 2261 ret = regmap_async_complete(regmap); 2262 if (ret != 0) 2263 cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret); 2264 2265 if (pos > firmware->size) 2266 cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 2267 file, blocks, pos - firmware->size); 2268 2269 cs_dsp_debugfs_save_binname(dsp, file); 2270 2271 out_fw: 2272 regmap_async_complete(regmap); 2273 cs_dsp_buf_free(&buf_list); 2274 kfree(text); 2275 return ret; 2276 } 2277 2278 static int cs_dsp_create_name(struct cs_dsp *dsp) 2279 { 2280 if (!dsp->name) { 2281 dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d", 2282 dsp->num); 2283 if (!dsp->name) 2284 return -ENOMEM; 2285 } 2286 2287 return 0; 2288 } 2289 2290 static int cs_dsp_common_init(struct cs_dsp *dsp) 2291 { 2292 int ret; 2293 2294 ret = cs_dsp_create_name(dsp); 2295 if (ret) 2296 return ret; 2297 2298 INIT_LIST_HEAD(&dsp->alg_regions); 2299 INIT_LIST_HEAD(&dsp->ctl_list); 2300 2301 mutex_init(&dsp->pwr_lock); 2302 2303 #ifdef CONFIG_DEBUG_FS 2304 /* Ensure this is invalid if client never provides a debugfs root */ 2305 dsp->debugfs_root = ERR_PTR(-ENODEV); 2306 #endif 2307 2308 return 0; 2309 } 2310 2311 /** 2312 * cs_dsp_adsp1_init() - Initialise a cs_dsp structure representing a ADSP1 device 2313 * @dsp: pointer to DSP structure 2314 * 2315 * Return: Zero for success, a negative number on error. 2316 */ 2317 int cs_dsp_adsp1_init(struct cs_dsp *dsp) 2318 { 2319 dsp->ops = &cs_dsp_adsp1_ops; 2320 2321 return cs_dsp_common_init(dsp); 2322 } 2323 EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_init, FW_CS_DSP); 2324 2325 /** 2326 * cs_dsp_adsp1_power_up() - Load and start the named firmware 2327 * @dsp: pointer to DSP structure 2328 * @wmfw_firmware: the firmware to be sent 2329 * @wmfw_filename: file name of firmware to be sent 2330 * @coeff_firmware: the coefficient data to be sent 2331 * @coeff_filename: file name of coefficient to data be sent 2332 * @fw_name: the user-friendly firmware name 2333 * 2334 * Return: Zero for success, a negative number on error. 2335 */ 2336 int cs_dsp_adsp1_power_up(struct cs_dsp *dsp, 2337 const struct firmware *wmfw_firmware, char *wmfw_filename, 2338 const struct firmware *coeff_firmware, char *coeff_filename, 2339 const char *fw_name) 2340 { 2341 unsigned int val; 2342 int ret; 2343 2344 mutex_lock(&dsp->pwr_lock); 2345 2346 dsp->fw_name = fw_name; 2347 2348 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2349 ADSP1_SYS_ENA, ADSP1_SYS_ENA); 2350 2351 /* 2352 * For simplicity set the DSP clock rate to be the 2353 * SYSCLK rate rather than making it configurable. 2354 */ 2355 if (dsp->sysclk_reg) { 2356 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); 2357 if (ret != 0) { 2358 cs_dsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); 2359 goto err_mutex; 2360 } 2361 2362 val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift; 2363 2364 ret = regmap_update_bits(dsp->regmap, 2365 dsp->base + ADSP1_CONTROL_31, 2366 ADSP1_CLK_SEL_MASK, val); 2367 if (ret != 0) { 2368 cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret); 2369 goto err_mutex; 2370 } 2371 } 2372 2373 ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename); 2374 if (ret != 0) 2375 goto err_ena; 2376 2377 ret = cs_dsp_adsp1_setup_algs(dsp); 2378 if (ret != 0) 2379 goto err_ena; 2380 2381 ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename); 2382 if (ret != 0) 2383 goto err_ena; 2384 2385 /* Initialize caches for enabled and unset controls */ 2386 ret = cs_dsp_coeff_init_control_caches(dsp); 2387 if (ret != 0) 2388 goto err_ena; 2389 2390 /* Sync set controls */ 2391 ret = cs_dsp_coeff_sync_controls(dsp); 2392 if (ret != 0) 2393 goto err_ena; 2394 2395 dsp->booted = true; 2396 2397 /* Start the core running */ 2398 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2399 ADSP1_CORE_ENA | ADSP1_START, 2400 ADSP1_CORE_ENA | ADSP1_START); 2401 2402 dsp->running = true; 2403 2404 mutex_unlock(&dsp->pwr_lock); 2405 2406 return 0; 2407 2408 err_ena: 2409 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2410 ADSP1_SYS_ENA, 0); 2411 err_mutex: 2412 mutex_unlock(&dsp->pwr_lock); 2413 return ret; 2414 } 2415 EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_up, FW_CS_DSP); 2416 2417 /** 2418 * cs_dsp_adsp1_power_down() - Halts the DSP 2419 * @dsp: pointer to DSP structure 2420 */ 2421 void cs_dsp_adsp1_power_down(struct cs_dsp *dsp) 2422 { 2423 struct cs_dsp_coeff_ctl *ctl; 2424 2425 mutex_lock(&dsp->pwr_lock); 2426 2427 dsp->running = false; 2428 dsp->booted = false; 2429 2430 /* Halt the core */ 2431 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2432 ADSP1_CORE_ENA | ADSP1_START, 0); 2433 2434 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, 2435 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0); 2436 2437 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 2438 ADSP1_SYS_ENA, 0); 2439 2440 list_for_each_entry(ctl, &dsp->ctl_list, list) 2441 ctl->enabled = 0; 2442 2443 cs_dsp_free_alg_regions(dsp); 2444 2445 mutex_unlock(&dsp->pwr_lock); 2446 } 2447 EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_down, FW_CS_DSP); 2448 2449 static int cs_dsp_adsp2v2_enable_core(struct cs_dsp *dsp) 2450 { 2451 unsigned int val; 2452 int ret, count; 2453 2454 /* Wait for the RAM to start, should be near instantaneous */ 2455 for (count = 0; count < 10; ++count) { 2456 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val); 2457 if (ret != 0) 2458 return ret; 2459 2460 if (val & ADSP2_RAM_RDY) 2461 break; 2462 2463 usleep_range(250, 500); 2464 } 2465 2466 if (!(val & ADSP2_RAM_RDY)) { 2467 cs_dsp_err(dsp, "Failed to start DSP RAM\n"); 2468 return -EBUSY; 2469 } 2470 2471 cs_dsp_dbg(dsp, "RAM ready after %d polls\n", count); 2472 2473 return 0; 2474 } 2475 2476 static int cs_dsp_adsp2_enable_core(struct cs_dsp *dsp) 2477 { 2478 int ret; 2479 2480 ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL, 2481 ADSP2_SYS_ENA, ADSP2_SYS_ENA); 2482 if (ret != 0) 2483 return ret; 2484 2485 return cs_dsp_adsp2v2_enable_core(dsp); 2486 } 2487 2488 static int cs_dsp_adsp2_lock(struct cs_dsp *dsp, unsigned int lock_regions) 2489 { 2490 struct regmap *regmap = dsp->regmap; 2491 unsigned int code0, code1, lock_reg; 2492 2493 if (!(lock_regions & CS_ADSP2_REGION_ALL)) 2494 return 0; 2495 2496 lock_regions &= CS_ADSP2_REGION_ALL; 2497 lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0; 2498 2499 while (lock_regions) { 2500 code0 = code1 = 0; 2501 if (lock_regions & BIT(0)) { 2502 code0 = ADSP2_LOCK_CODE_0; 2503 code1 = ADSP2_LOCK_CODE_1; 2504 } 2505 if (lock_regions & BIT(1)) { 2506 code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT; 2507 code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT; 2508 } 2509 regmap_write(regmap, lock_reg, code0); 2510 regmap_write(regmap, lock_reg, code1); 2511 lock_regions >>= 2; 2512 lock_reg += 2; 2513 } 2514 2515 return 0; 2516 } 2517 2518 static int cs_dsp_adsp2_enable_memory(struct cs_dsp *dsp) 2519 { 2520 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2521 ADSP2_MEM_ENA, ADSP2_MEM_ENA); 2522 } 2523 2524 static void cs_dsp_adsp2_disable_memory(struct cs_dsp *dsp) 2525 { 2526 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2527 ADSP2_MEM_ENA, 0); 2528 } 2529 2530 static void cs_dsp_adsp2_disable_core(struct cs_dsp *dsp) 2531 { 2532 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); 2533 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); 2534 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); 2535 2536 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2537 ADSP2_SYS_ENA, 0); 2538 } 2539 2540 static void cs_dsp_adsp2v2_disable_core(struct cs_dsp *dsp) 2541 { 2542 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); 2543 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); 2544 regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0); 2545 } 2546 2547 static int cs_dsp_halo_configure_mpu(struct cs_dsp *dsp, unsigned int lock_regions) 2548 { 2549 struct reg_sequence config[] = { 2550 { dsp->base + HALO_MPU_LOCK_CONFIG, 0x5555 }, 2551 { dsp->base + HALO_MPU_LOCK_CONFIG, 0xAAAA }, 2552 { dsp->base + HALO_MPU_XMEM_ACCESS_0, 0xFFFFFFFF }, 2553 { dsp->base + HALO_MPU_YMEM_ACCESS_0, 0xFFFFFFFF }, 2554 { dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions }, 2555 { dsp->base + HALO_MPU_XREG_ACCESS_0, lock_regions }, 2556 { dsp->base + HALO_MPU_YREG_ACCESS_0, lock_regions }, 2557 { dsp->base + HALO_MPU_XMEM_ACCESS_1, 0xFFFFFFFF }, 2558 { dsp->base + HALO_MPU_YMEM_ACCESS_1, 0xFFFFFFFF }, 2559 { dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions }, 2560 { dsp->base + HALO_MPU_XREG_ACCESS_1, lock_regions }, 2561 { dsp->base + HALO_MPU_YREG_ACCESS_1, lock_regions }, 2562 { dsp->base + HALO_MPU_XMEM_ACCESS_2, 0xFFFFFFFF }, 2563 { dsp->base + HALO_MPU_YMEM_ACCESS_2, 0xFFFFFFFF }, 2564 { dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions }, 2565 { dsp->base + HALO_MPU_XREG_ACCESS_2, lock_regions }, 2566 { dsp->base + HALO_MPU_YREG_ACCESS_2, lock_regions }, 2567 { dsp->base + HALO_MPU_XMEM_ACCESS_3, 0xFFFFFFFF }, 2568 { dsp->base + HALO_MPU_YMEM_ACCESS_3, 0xFFFFFFFF }, 2569 { dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions }, 2570 { dsp->base + HALO_MPU_XREG_ACCESS_3, lock_regions }, 2571 { dsp->base + HALO_MPU_YREG_ACCESS_3, lock_regions }, 2572 { dsp->base + HALO_MPU_LOCK_CONFIG, 0 }, 2573 }; 2574 2575 return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config)); 2576 } 2577 2578 /** 2579 * cs_dsp_set_dspclk() - Applies the given frequency to the given cs_dsp 2580 * @dsp: pointer to DSP structure 2581 * @freq: clock rate to set 2582 * 2583 * This is only for use on ADSP2 cores. 2584 * 2585 * Return: Zero for success, a negative number on error. 2586 */ 2587 int cs_dsp_set_dspclk(struct cs_dsp *dsp, unsigned int freq) 2588 { 2589 int ret; 2590 2591 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING, 2592 ADSP2_CLK_SEL_MASK, 2593 freq << ADSP2_CLK_SEL_SHIFT); 2594 if (ret) 2595 cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret); 2596 2597 return ret; 2598 } 2599 EXPORT_SYMBOL_NS_GPL(cs_dsp_set_dspclk, FW_CS_DSP); 2600 2601 static void cs_dsp_stop_watchdog(struct cs_dsp *dsp) 2602 { 2603 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG, 2604 ADSP2_WDT_ENA_MASK, 0); 2605 } 2606 2607 static void cs_dsp_halo_stop_watchdog(struct cs_dsp *dsp) 2608 { 2609 regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL, 2610 HALO_WDT_EN_MASK, 0); 2611 } 2612 2613 /** 2614 * cs_dsp_power_up() - Downloads firmware to the DSP 2615 * @dsp: pointer to DSP structure 2616 * @wmfw_firmware: the firmware to be sent 2617 * @wmfw_filename: file name of firmware to be sent 2618 * @coeff_firmware: the coefficient data to be sent 2619 * @coeff_filename: file name of coefficient to data be sent 2620 * @fw_name: the user-friendly firmware name 2621 * 2622 * This function is used on ADSP2 and Halo DSP cores, it powers-up the DSP core 2623 * and downloads the firmware but does not start the firmware running. The 2624 * cs_dsp booted flag will be set once completed and if the core has a low-power 2625 * memory retention mode it will be put into this state after the firmware is 2626 * downloaded. 2627 * 2628 * Return: Zero for success, a negative number on error. 2629 */ 2630 int cs_dsp_power_up(struct cs_dsp *dsp, 2631 const struct firmware *wmfw_firmware, char *wmfw_filename, 2632 const struct firmware *coeff_firmware, char *coeff_filename, 2633 const char *fw_name) 2634 { 2635 int ret; 2636 2637 mutex_lock(&dsp->pwr_lock); 2638 2639 dsp->fw_name = fw_name; 2640 2641 if (dsp->ops->enable_memory) { 2642 ret = dsp->ops->enable_memory(dsp); 2643 if (ret != 0) 2644 goto err_mutex; 2645 } 2646 2647 if (dsp->ops->enable_core) { 2648 ret = dsp->ops->enable_core(dsp); 2649 if (ret != 0) 2650 goto err_mem; 2651 } 2652 2653 ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename); 2654 if (ret != 0) 2655 goto err_ena; 2656 2657 ret = dsp->ops->setup_algs(dsp); 2658 if (ret != 0) 2659 goto err_ena; 2660 2661 ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename); 2662 if (ret != 0) 2663 goto err_ena; 2664 2665 /* Initialize caches for enabled and unset controls */ 2666 ret = cs_dsp_coeff_init_control_caches(dsp); 2667 if (ret != 0) 2668 goto err_ena; 2669 2670 if (dsp->ops->disable_core) 2671 dsp->ops->disable_core(dsp); 2672 2673 dsp->booted = true; 2674 2675 mutex_unlock(&dsp->pwr_lock); 2676 2677 return 0; 2678 err_ena: 2679 if (dsp->ops->disable_core) 2680 dsp->ops->disable_core(dsp); 2681 err_mem: 2682 if (dsp->ops->disable_memory) 2683 dsp->ops->disable_memory(dsp); 2684 err_mutex: 2685 mutex_unlock(&dsp->pwr_lock); 2686 2687 return ret; 2688 } 2689 EXPORT_SYMBOL_NS_GPL(cs_dsp_power_up, FW_CS_DSP); 2690 2691 /** 2692 * cs_dsp_power_down() - Powers-down the DSP 2693 * @dsp: pointer to DSP structure 2694 * 2695 * cs_dsp_stop() must have been called before this function. The core will be 2696 * fully powered down and so the memory will not be retained. 2697 */ 2698 void cs_dsp_power_down(struct cs_dsp *dsp) 2699 { 2700 struct cs_dsp_coeff_ctl *ctl; 2701 2702 mutex_lock(&dsp->pwr_lock); 2703 2704 cs_dsp_debugfs_clear(dsp); 2705 2706 dsp->fw_id = 0; 2707 dsp->fw_id_version = 0; 2708 2709 dsp->booted = false; 2710 2711 if (dsp->ops->disable_memory) 2712 dsp->ops->disable_memory(dsp); 2713 2714 list_for_each_entry(ctl, &dsp->ctl_list, list) 2715 ctl->enabled = 0; 2716 2717 cs_dsp_free_alg_regions(dsp); 2718 2719 mutex_unlock(&dsp->pwr_lock); 2720 2721 cs_dsp_dbg(dsp, "Shutdown complete\n"); 2722 } 2723 EXPORT_SYMBOL_NS_GPL(cs_dsp_power_down, FW_CS_DSP); 2724 2725 static int cs_dsp_adsp2_start_core(struct cs_dsp *dsp) 2726 { 2727 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2728 ADSP2_CORE_ENA | ADSP2_START, 2729 ADSP2_CORE_ENA | ADSP2_START); 2730 } 2731 2732 static void cs_dsp_adsp2_stop_core(struct cs_dsp *dsp) 2733 { 2734 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2735 ADSP2_CORE_ENA | ADSP2_START, 0); 2736 } 2737 2738 /** 2739 * cs_dsp_run() - Starts the firmware running 2740 * @dsp: pointer to DSP structure 2741 * 2742 * cs_dsp_power_up() must have previously been called successfully. 2743 * 2744 * Return: Zero for success, a negative number on error. 2745 */ 2746 int cs_dsp_run(struct cs_dsp *dsp) 2747 { 2748 int ret; 2749 2750 mutex_lock(&dsp->pwr_lock); 2751 2752 if (!dsp->booted) { 2753 ret = -EIO; 2754 goto err; 2755 } 2756 2757 if (dsp->ops->enable_core) { 2758 ret = dsp->ops->enable_core(dsp); 2759 if (ret != 0) 2760 goto err; 2761 } 2762 2763 if (dsp->client_ops->pre_run) { 2764 ret = dsp->client_ops->pre_run(dsp); 2765 if (ret) 2766 goto err; 2767 } 2768 2769 /* Sync set controls */ 2770 ret = cs_dsp_coeff_sync_controls(dsp); 2771 if (ret != 0) 2772 goto err; 2773 2774 if (dsp->ops->lock_memory) { 2775 ret = dsp->ops->lock_memory(dsp, dsp->lock_regions); 2776 if (ret != 0) { 2777 cs_dsp_err(dsp, "Error configuring MPU: %d\n", ret); 2778 goto err; 2779 } 2780 } 2781 2782 if (dsp->ops->start_core) { 2783 ret = dsp->ops->start_core(dsp); 2784 if (ret != 0) 2785 goto err; 2786 } 2787 2788 dsp->running = true; 2789 2790 if (dsp->client_ops->post_run) { 2791 ret = dsp->client_ops->post_run(dsp); 2792 if (ret) 2793 goto err; 2794 } 2795 2796 mutex_unlock(&dsp->pwr_lock); 2797 2798 return 0; 2799 2800 err: 2801 if (dsp->ops->stop_core) 2802 dsp->ops->stop_core(dsp); 2803 if (dsp->ops->disable_core) 2804 dsp->ops->disable_core(dsp); 2805 mutex_unlock(&dsp->pwr_lock); 2806 2807 return ret; 2808 } 2809 EXPORT_SYMBOL_NS_GPL(cs_dsp_run, FW_CS_DSP); 2810 2811 /** 2812 * cs_dsp_stop() - Stops the firmware 2813 * @dsp: pointer to DSP structure 2814 * 2815 * Memory will not be disabled so firmware will remain loaded. 2816 */ 2817 void cs_dsp_stop(struct cs_dsp *dsp) 2818 { 2819 /* Tell the firmware to cleanup */ 2820 cs_dsp_signal_event_controls(dsp, CS_DSP_FW_EVENT_SHUTDOWN); 2821 2822 if (dsp->ops->stop_watchdog) 2823 dsp->ops->stop_watchdog(dsp); 2824 2825 /* Log firmware state, it can be useful for analysis */ 2826 if (dsp->ops->show_fw_status) 2827 dsp->ops->show_fw_status(dsp); 2828 2829 mutex_lock(&dsp->pwr_lock); 2830 2831 if (dsp->client_ops->pre_stop) 2832 dsp->client_ops->pre_stop(dsp); 2833 2834 dsp->running = false; 2835 2836 if (dsp->ops->stop_core) 2837 dsp->ops->stop_core(dsp); 2838 if (dsp->ops->disable_core) 2839 dsp->ops->disable_core(dsp); 2840 2841 if (dsp->client_ops->post_stop) 2842 dsp->client_ops->post_stop(dsp); 2843 2844 mutex_unlock(&dsp->pwr_lock); 2845 2846 cs_dsp_dbg(dsp, "Execution stopped\n"); 2847 } 2848 EXPORT_SYMBOL_NS_GPL(cs_dsp_stop, FW_CS_DSP); 2849 2850 static int cs_dsp_halo_start_core(struct cs_dsp *dsp) 2851 { 2852 int ret; 2853 2854 ret = regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, 2855 HALO_CORE_RESET | HALO_CORE_EN, 2856 HALO_CORE_RESET | HALO_CORE_EN); 2857 if (ret) 2858 return ret; 2859 2860 return regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, 2861 HALO_CORE_RESET, 0); 2862 } 2863 2864 static void cs_dsp_halo_stop_core(struct cs_dsp *dsp) 2865 { 2866 regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, 2867 HALO_CORE_EN, 0); 2868 2869 /* reset halo core with CORE_SOFT_RESET */ 2870 regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET, 2871 HALO_CORE_SOFT_RESET_MASK, 1); 2872 } 2873 2874 /** 2875 * cs_dsp_adsp2_init() - Initialise a cs_dsp structure representing a ADSP2 core 2876 * @dsp: pointer to DSP structure 2877 * 2878 * Return: Zero for success, a negative number on error. 2879 */ 2880 int cs_dsp_adsp2_init(struct cs_dsp *dsp) 2881 { 2882 int ret; 2883 2884 switch (dsp->rev) { 2885 case 0: 2886 /* 2887 * Disable the DSP memory by default when in reset for a small 2888 * power saving. 2889 */ 2890 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2891 ADSP2_MEM_ENA, 0); 2892 if (ret) { 2893 cs_dsp_err(dsp, 2894 "Failed to clear memory retention: %d\n", ret); 2895 return ret; 2896 } 2897 2898 dsp->ops = &cs_dsp_adsp2_ops[0]; 2899 break; 2900 case 1: 2901 dsp->ops = &cs_dsp_adsp2_ops[1]; 2902 break; 2903 default: 2904 dsp->ops = &cs_dsp_adsp2_ops[2]; 2905 break; 2906 } 2907 2908 return cs_dsp_common_init(dsp); 2909 } 2910 EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_init, FW_CS_DSP); 2911 2912 /** 2913 * cs_dsp_halo_init() - Initialise a cs_dsp structure representing a HALO Core DSP 2914 * @dsp: pointer to DSP structure 2915 * 2916 * Return: Zero for success, a negative number on error. 2917 */ 2918 int cs_dsp_halo_init(struct cs_dsp *dsp) 2919 { 2920 if (dsp->no_core_startstop) 2921 dsp->ops = &cs_dsp_halo_ao_ops; 2922 else 2923 dsp->ops = &cs_dsp_halo_ops; 2924 2925 return cs_dsp_common_init(dsp); 2926 } 2927 EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_init, FW_CS_DSP); 2928 2929 /** 2930 * cs_dsp_remove() - Clean a cs_dsp before deletion 2931 * @dsp: pointer to DSP structure 2932 */ 2933 void cs_dsp_remove(struct cs_dsp *dsp) 2934 { 2935 struct cs_dsp_coeff_ctl *ctl; 2936 2937 while (!list_empty(&dsp->ctl_list)) { 2938 ctl = list_first_entry(&dsp->ctl_list, struct cs_dsp_coeff_ctl, list); 2939 2940 if (dsp->client_ops->control_remove) 2941 dsp->client_ops->control_remove(ctl); 2942 2943 list_del(&ctl->list); 2944 cs_dsp_free_ctl_blk(ctl); 2945 } 2946 } 2947 EXPORT_SYMBOL_NS_GPL(cs_dsp_remove, FW_CS_DSP); 2948 2949 /** 2950 * cs_dsp_read_raw_data_block() - Reads a block of data from DSP memory 2951 * @dsp: pointer to DSP structure 2952 * @mem_type: the type of DSP memory containing the data to be read 2953 * @mem_addr: the address of the data within the memory region 2954 * @num_words: the length of the data to read 2955 * @data: a buffer to store the fetched data 2956 * 2957 * If this is used to read unpacked 24-bit memory, each 24-bit DSP word will 2958 * occupy 32-bits in data (MSbyte will be 0). This padding can be removed using 2959 * cs_dsp_remove_padding() 2960 * 2961 * Return: Zero for success, a negative number on error. 2962 */ 2963 int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, 2964 unsigned int num_words, __be32 *data) 2965 { 2966 struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type); 2967 unsigned int reg; 2968 int ret; 2969 2970 lockdep_assert_held(&dsp->pwr_lock); 2971 2972 if (!mem) 2973 return -EINVAL; 2974 2975 reg = dsp->ops->region_to_reg(mem, mem_addr); 2976 2977 ret = regmap_raw_read(dsp->regmap, reg, data, 2978 sizeof(*data) * num_words); 2979 if (ret < 0) 2980 return ret; 2981 2982 return 0; 2983 } 2984 EXPORT_SYMBOL_NS_GPL(cs_dsp_read_raw_data_block, FW_CS_DSP); 2985 2986 /** 2987 * cs_dsp_read_data_word() - Reads a word from DSP memory 2988 * @dsp: pointer to DSP structure 2989 * @mem_type: the type of DSP memory containing the data to be read 2990 * @mem_addr: the address of the data within the memory region 2991 * @data: a buffer to store the fetched data 2992 * 2993 * Return: Zero for success, a negative number on error. 2994 */ 2995 int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 *data) 2996 { 2997 __be32 raw; 2998 int ret; 2999 3000 ret = cs_dsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw); 3001 if (ret < 0) 3002 return ret; 3003 3004 *data = be32_to_cpu(raw) & 0x00ffffffu; 3005 3006 return 0; 3007 } 3008 EXPORT_SYMBOL_NS_GPL(cs_dsp_read_data_word, FW_CS_DSP); 3009 3010 /** 3011 * cs_dsp_write_data_word() - Writes a word to DSP memory 3012 * @dsp: pointer to DSP structure 3013 * @mem_type: the type of DSP memory containing the data to be written 3014 * @mem_addr: the address of the data within the memory region 3015 * @data: the data to be written 3016 * 3017 * Return: Zero for success, a negative number on error. 3018 */ 3019 int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 data) 3020 { 3021 struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type); 3022 __be32 val = cpu_to_be32(data & 0x00ffffffu); 3023 unsigned int reg; 3024 3025 lockdep_assert_held(&dsp->pwr_lock); 3026 3027 if (!mem) 3028 return -EINVAL; 3029 3030 reg = dsp->ops->region_to_reg(mem, mem_addr); 3031 3032 return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val)); 3033 } 3034 EXPORT_SYMBOL_NS_GPL(cs_dsp_write_data_word, FW_CS_DSP); 3035 3036 /** 3037 * cs_dsp_remove_padding() - Convert unpacked words to packed bytes 3038 * @buf: buffer containing DSP words read from DSP memory 3039 * @nwords: number of words to convert 3040 * 3041 * DSP words from the register map have pad bytes and the data bytes 3042 * are in swapped order. This swaps to the native endian order and 3043 * strips the pad bytes. 3044 */ 3045 void cs_dsp_remove_padding(u32 *buf, int nwords) 3046 { 3047 const __be32 *pack_in = (__be32 *)buf; 3048 u8 *pack_out = (u8 *)buf; 3049 int i; 3050 3051 for (i = 0; i < nwords; i++) { 3052 u32 word = be32_to_cpu(*pack_in++); 3053 *pack_out++ = (u8)word; 3054 *pack_out++ = (u8)(word >> 8); 3055 *pack_out++ = (u8)(word >> 16); 3056 } 3057 } 3058 EXPORT_SYMBOL_NS_GPL(cs_dsp_remove_padding, FW_CS_DSP); 3059 3060 /** 3061 * cs_dsp_adsp2_bus_error() - Handle a DSP bus error interrupt 3062 * @dsp: pointer to DSP structure 3063 * 3064 * The firmware and DSP state will be logged for future analysis. 3065 */ 3066 void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp) 3067 { 3068 unsigned int val; 3069 struct regmap *regmap = dsp->regmap; 3070 int ret = 0; 3071 3072 mutex_lock(&dsp->pwr_lock); 3073 3074 ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val); 3075 if (ret) { 3076 cs_dsp_err(dsp, 3077 "Failed to read Region Lock Ctrl register: %d\n", ret); 3078 goto error; 3079 } 3080 3081 if (val & ADSP2_WDT_TIMEOUT_STS_MASK) { 3082 cs_dsp_err(dsp, "watchdog timeout error\n"); 3083 dsp->ops->stop_watchdog(dsp); 3084 if (dsp->client_ops->watchdog_expired) 3085 dsp->client_ops->watchdog_expired(dsp); 3086 } 3087 3088 if (val & (ADSP2_ADDR_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) { 3089 if (val & ADSP2_ADDR_ERR_MASK) 3090 cs_dsp_err(dsp, "bus error: address error\n"); 3091 else 3092 cs_dsp_err(dsp, "bus error: region lock error\n"); 3093 3094 ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val); 3095 if (ret) { 3096 cs_dsp_err(dsp, 3097 "Failed to read Bus Err Addr register: %d\n", 3098 ret); 3099 goto error; 3100 } 3101 3102 cs_dsp_err(dsp, "bus error address = 0x%x\n", 3103 val & ADSP2_BUS_ERR_ADDR_MASK); 3104 3105 ret = regmap_read(regmap, 3106 dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR, 3107 &val); 3108 if (ret) { 3109 cs_dsp_err(dsp, 3110 "Failed to read Pmem Xmem Err Addr register: %d\n", 3111 ret); 3112 goto error; 3113 } 3114 3115 cs_dsp_err(dsp, "xmem error address = 0x%x\n", 3116 val & ADSP2_XMEM_ERR_ADDR_MASK); 3117 cs_dsp_err(dsp, "pmem error address = 0x%x\n", 3118 (val & ADSP2_PMEM_ERR_ADDR_MASK) >> 3119 ADSP2_PMEM_ERR_ADDR_SHIFT); 3120 } 3121 3122 regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, 3123 ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT); 3124 3125 error: 3126 mutex_unlock(&dsp->pwr_lock); 3127 } 3128 EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_bus_error, FW_CS_DSP); 3129 3130 /** 3131 * cs_dsp_halo_bus_error() - Handle a DSP bus error interrupt 3132 * @dsp: pointer to DSP structure 3133 * 3134 * The firmware and DSP state will be logged for future analysis. 3135 */ 3136 void cs_dsp_halo_bus_error(struct cs_dsp *dsp) 3137 { 3138 struct regmap *regmap = dsp->regmap; 3139 unsigned int fault[6]; 3140 struct reg_sequence clear[] = { 3141 { dsp->base + HALO_MPU_XM_VIO_STATUS, 0x0 }, 3142 { dsp->base + HALO_MPU_YM_VIO_STATUS, 0x0 }, 3143 { dsp->base + HALO_MPU_PM_VIO_STATUS, 0x0 }, 3144 }; 3145 int ret; 3146 3147 mutex_lock(&dsp->pwr_lock); 3148 3149 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1, 3150 fault); 3151 if (ret) { 3152 cs_dsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret); 3153 goto exit_unlock; 3154 } 3155 3156 cs_dsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n", 3157 *fault & HALO_AHBM_FLAGS_ERR_MASK, 3158 (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >> 3159 HALO_AHBM_CORE_ERR_ADDR_SHIFT); 3160 3161 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0, 3162 fault); 3163 if (ret) { 3164 cs_dsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret); 3165 goto exit_unlock; 3166 } 3167 3168 cs_dsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault); 3169 3170 ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR, 3171 fault, ARRAY_SIZE(fault)); 3172 if (ret) { 3173 cs_dsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret); 3174 goto exit_unlock; 3175 } 3176 3177 cs_dsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]); 3178 cs_dsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]); 3179 cs_dsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]); 3180 3181 ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear)); 3182 if (ret) 3183 cs_dsp_warn(dsp, "Failed to clear MPU status: %d\n", ret); 3184 3185 exit_unlock: 3186 mutex_unlock(&dsp->pwr_lock); 3187 } 3188 EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_bus_error, FW_CS_DSP); 3189 3190 /** 3191 * cs_dsp_halo_wdt_expire() - Handle DSP watchdog expiry 3192 * @dsp: pointer to DSP structure 3193 * 3194 * This is logged for future analysis. 3195 */ 3196 void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp) 3197 { 3198 mutex_lock(&dsp->pwr_lock); 3199 3200 cs_dsp_warn(dsp, "WDT Expiry Fault\n"); 3201 3202 dsp->ops->stop_watchdog(dsp); 3203 if (dsp->client_ops->watchdog_expired) 3204 dsp->client_ops->watchdog_expired(dsp); 3205 3206 mutex_unlock(&dsp->pwr_lock); 3207 } 3208 EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_wdt_expire, FW_CS_DSP); 3209 3210 static const struct cs_dsp_ops cs_dsp_adsp1_ops = { 3211 .validate_version = cs_dsp_validate_version, 3212 .parse_sizes = cs_dsp_adsp1_parse_sizes, 3213 .region_to_reg = cs_dsp_region_to_reg, 3214 }; 3215 3216 static const struct cs_dsp_ops cs_dsp_adsp2_ops[] = { 3217 { 3218 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3219 .validate_version = cs_dsp_validate_version, 3220 .setup_algs = cs_dsp_adsp2_setup_algs, 3221 .region_to_reg = cs_dsp_region_to_reg, 3222 3223 .show_fw_status = cs_dsp_adsp2_show_fw_status, 3224 3225 .enable_memory = cs_dsp_adsp2_enable_memory, 3226 .disable_memory = cs_dsp_adsp2_disable_memory, 3227 3228 .enable_core = cs_dsp_adsp2_enable_core, 3229 .disable_core = cs_dsp_adsp2_disable_core, 3230 3231 .start_core = cs_dsp_adsp2_start_core, 3232 .stop_core = cs_dsp_adsp2_stop_core, 3233 3234 }, 3235 { 3236 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3237 .validate_version = cs_dsp_validate_version, 3238 .setup_algs = cs_dsp_adsp2_setup_algs, 3239 .region_to_reg = cs_dsp_region_to_reg, 3240 3241 .show_fw_status = cs_dsp_adsp2v2_show_fw_status, 3242 3243 .enable_memory = cs_dsp_adsp2_enable_memory, 3244 .disable_memory = cs_dsp_adsp2_disable_memory, 3245 .lock_memory = cs_dsp_adsp2_lock, 3246 3247 .enable_core = cs_dsp_adsp2v2_enable_core, 3248 .disable_core = cs_dsp_adsp2v2_disable_core, 3249 3250 .start_core = cs_dsp_adsp2_start_core, 3251 .stop_core = cs_dsp_adsp2_stop_core, 3252 }, 3253 { 3254 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3255 .validate_version = cs_dsp_validate_version, 3256 .setup_algs = cs_dsp_adsp2_setup_algs, 3257 .region_to_reg = cs_dsp_region_to_reg, 3258 3259 .show_fw_status = cs_dsp_adsp2v2_show_fw_status, 3260 .stop_watchdog = cs_dsp_stop_watchdog, 3261 3262 .enable_memory = cs_dsp_adsp2_enable_memory, 3263 .disable_memory = cs_dsp_adsp2_disable_memory, 3264 .lock_memory = cs_dsp_adsp2_lock, 3265 3266 .enable_core = cs_dsp_adsp2v2_enable_core, 3267 .disable_core = cs_dsp_adsp2v2_disable_core, 3268 3269 .start_core = cs_dsp_adsp2_start_core, 3270 .stop_core = cs_dsp_adsp2_stop_core, 3271 }, 3272 }; 3273 3274 static const struct cs_dsp_ops cs_dsp_halo_ops = { 3275 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3276 .validate_version = cs_dsp_halo_validate_version, 3277 .setup_algs = cs_dsp_halo_setup_algs, 3278 .region_to_reg = cs_dsp_halo_region_to_reg, 3279 3280 .show_fw_status = cs_dsp_halo_show_fw_status, 3281 .stop_watchdog = cs_dsp_halo_stop_watchdog, 3282 3283 .lock_memory = cs_dsp_halo_configure_mpu, 3284 3285 .start_core = cs_dsp_halo_start_core, 3286 .stop_core = cs_dsp_halo_stop_core, 3287 }; 3288 3289 static const struct cs_dsp_ops cs_dsp_halo_ao_ops = { 3290 .parse_sizes = cs_dsp_adsp2_parse_sizes, 3291 .validate_version = cs_dsp_halo_validate_version, 3292 .setup_algs = cs_dsp_halo_setup_algs, 3293 .region_to_reg = cs_dsp_halo_region_to_reg, 3294 .show_fw_status = cs_dsp_halo_show_fw_status, 3295 }; 3296 3297 /** 3298 * cs_dsp_chunk_write() - Format data to a DSP memory chunk 3299 * @ch: Pointer to the chunk structure 3300 * @nbits: Number of bits to write 3301 * @val: Value to write 3302 * 3303 * This function sequentially writes values into the format required for DSP 3304 * memory, it handles both inserting of the padding bytes and converting to 3305 * big endian. Note that data is only committed to the chunk when a whole DSP 3306 * words worth of data is available. 3307 * 3308 * Return: Zero for success, a negative number on error. 3309 */ 3310 int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val) 3311 { 3312 int nwrite, i; 3313 3314 nwrite = min(CS_DSP_DATA_WORD_BITS - ch->cachebits, nbits); 3315 3316 ch->cache <<= nwrite; 3317 ch->cache |= val >> (nbits - nwrite); 3318 ch->cachebits += nwrite; 3319 nbits -= nwrite; 3320 3321 if (ch->cachebits == CS_DSP_DATA_WORD_BITS) { 3322 if (cs_dsp_chunk_end(ch)) 3323 return -ENOSPC; 3324 3325 ch->cache &= 0xFFFFFF; 3326 for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE) 3327 *ch->data++ = (ch->cache & 0xFF000000) >> CS_DSP_DATA_WORD_BITS; 3328 3329 ch->bytes += sizeof(ch->cache); 3330 ch->cachebits = 0; 3331 } 3332 3333 if (nbits) 3334 return cs_dsp_chunk_write(ch, nbits, val); 3335 3336 return 0; 3337 } 3338 EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_write, FW_CS_DSP); 3339 3340 /** 3341 * cs_dsp_chunk_flush() - Pad remaining data with zero and commit to chunk 3342 * @ch: Pointer to the chunk structure 3343 * 3344 * As cs_dsp_chunk_write only writes data when a whole DSP word is ready to 3345 * be written out it is possible that some data will remain in the cache, this 3346 * function will pad that data with zeros upto a whole DSP word and write out. 3347 * 3348 * Return: Zero for success, a negative number on error. 3349 */ 3350 int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch) 3351 { 3352 if (!ch->cachebits) 3353 return 0; 3354 3355 return cs_dsp_chunk_write(ch, CS_DSP_DATA_WORD_BITS - ch->cachebits, 0); 3356 } 3357 EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_flush, FW_CS_DSP); 3358 3359 /** 3360 * cs_dsp_chunk_read() - Parse data from a DSP memory chunk 3361 * @ch: Pointer to the chunk structure 3362 * @nbits: Number of bits to read 3363 * 3364 * This function sequentially reads values from a DSP memory formatted buffer, 3365 * it handles both removing of the padding bytes and converting from big endian. 3366 * 3367 * Return: A negative number is returned on error, otherwise the read value. 3368 */ 3369 int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits) 3370 { 3371 int nread, i; 3372 u32 result; 3373 3374 if (!ch->cachebits) { 3375 if (cs_dsp_chunk_end(ch)) 3376 return -ENOSPC; 3377 3378 ch->cache = 0; 3379 ch->cachebits = CS_DSP_DATA_WORD_BITS; 3380 3381 for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE) 3382 ch->cache |= *ch->data++; 3383 3384 ch->bytes += sizeof(ch->cache); 3385 } 3386 3387 nread = min(ch->cachebits, nbits); 3388 nbits -= nread; 3389 3390 result = ch->cache >> ((sizeof(ch->cache) * BITS_PER_BYTE) - nread); 3391 ch->cache <<= nread; 3392 ch->cachebits -= nread; 3393 3394 if (nbits) 3395 result = (result << nbits) | cs_dsp_chunk_read(ch, nbits); 3396 3397 return result; 3398 } 3399 EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_read, FW_CS_DSP); 3400 3401 MODULE_DESCRIPTION("Cirrus Logic DSP Support"); 3402 MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>"); 3403 MODULE_LICENSE("GPL v2"); 3404