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