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