1/* 2 * wm_adsp.c -- Wolfson ADSP support 3 * 4 * Copyright 2012 Wolfson Microelectronics plc 5 * 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13#include <linux/module.h> 14#include <linux/moduleparam.h> 15#include <linux/init.h> 16#include <linux/delay.h> 17#include <linux/firmware.h> 18#include <linux/list.h> 19#include <linux/pm.h> 20#include <linux/pm_runtime.h> 21#include <linux/regmap.h> 22#include <linux/regulator/consumer.h> 23#include <linux/slab.h> 24#include <linux/vmalloc.h> 25#include <linux/workqueue.h> 26#include <linux/debugfs.h> 27#include <sound/core.h> 28#include <sound/pcm.h> 29#include <sound/pcm_params.h> 30#include <sound/soc.h> 31#include <sound/jack.h> 32#include <sound/initval.h> 33#include <sound/tlv.h> 34 35#include <linux/mfd/arizona/registers.h> 36 37#include "arizona.h" 38#include "wm_adsp.h" 39 40#define adsp_crit(_dsp, fmt, ...) \ 41 dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 42#define adsp_err(_dsp, fmt, ...) \ 43 dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 44#define adsp_warn(_dsp, fmt, ...) \ 45 dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 46#define adsp_info(_dsp, fmt, ...) \ 47 dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 48#define adsp_dbg(_dsp, fmt, ...) \ 49 dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 50 51#define ADSP1_CONTROL_1 0x00 52#define ADSP1_CONTROL_2 0x02 53#define ADSP1_CONTROL_3 0x03 54#define ADSP1_CONTROL_4 0x04 55#define ADSP1_CONTROL_5 0x06 56#define ADSP1_CONTROL_6 0x07 57#define ADSP1_CONTROL_7 0x08 58#define ADSP1_CONTROL_8 0x09 59#define ADSP1_CONTROL_9 0x0A 60#define ADSP1_CONTROL_10 0x0B 61#define ADSP1_CONTROL_11 0x0C 62#define ADSP1_CONTROL_12 0x0D 63#define ADSP1_CONTROL_13 0x0F 64#define ADSP1_CONTROL_14 0x10 65#define ADSP1_CONTROL_15 0x11 66#define ADSP1_CONTROL_16 0x12 67#define ADSP1_CONTROL_17 0x13 68#define ADSP1_CONTROL_18 0x14 69#define ADSP1_CONTROL_19 0x16 70#define ADSP1_CONTROL_20 0x17 71#define ADSP1_CONTROL_21 0x18 72#define ADSP1_CONTROL_22 0x1A 73#define ADSP1_CONTROL_23 0x1B 74#define ADSP1_CONTROL_24 0x1C 75#define ADSP1_CONTROL_25 0x1E 76#define ADSP1_CONTROL_26 0x20 77#define ADSP1_CONTROL_27 0x21 78#define ADSP1_CONTROL_28 0x22 79#define ADSP1_CONTROL_29 0x23 80#define ADSP1_CONTROL_30 0x24 81#define ADSP1_CONTROL_31 0x26 82 83/* 84 * ADSP1 Control 19 85 */ 86#define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ 87#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ 88#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ 89 90 91/* 92 * ADSP1 Control 30 93 */ 94#define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */ 95#define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */ 96#define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */ 97#define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */ 98#define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ 99#define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ 100#define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ 101#define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ 102#define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ 103#define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ 104#define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ 105#define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ 106#define ADSP1_START 0x0001 /* DSP1_START */ 107#define ADSP1_START_MASK 0x0001 /* DSP1_START */ 108#define ADSP1_START_SHIFT 0 /* DSP1_START */ 109#define ADSP1_START_WIDTH 1 /* DSP1_START */ 110 111/* 112 * ADSP1 Control 31 113 */ 114#define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */ 115#define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ 116#define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ 117 118#define ADSP2_CONTROL 0x0 119#define ADSP2_CLOCKING 0x1 120#define ADSP2_STATUS1 0x4 121#define ADSP2_WDMA_CONFIG_1 0x30 122#define ADSP2_WDMA_CONFIG_2 0x31 123#define ADSP2_RDMA_CONFIG_1 0x34 124 125#define ADSP2_SCRATCH0 0x40 126#define ADSP2_SCRATCH1 0x41 127#define ADSP2_SCRATCH2 0x42 128#define ADSP2_SCRATCH3 0x43 129 130/* 131 * ADSP2 Control 132 */ 133 134#define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */ 135#define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */ 136#define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */ 137#define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */ 138#define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ 139#define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ 140#define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ 141#define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ 142#define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ 143#define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ 144#define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ 145#define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ 146#define ADSP2_START 0x0001 /* DSP1_START */ 147#define ADSP2_START_MASK 0x0001 /* DSP1_START */ 148#define ADSP2_START_SHIFT 0 /* DSP1_START */ 149#define ADSP2_START_WIDTH 1 /* DSP1_START */ 150 151/* 152 * ADSP2 clocking 153 */ 154#define ADSP2_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */ 155#define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ 156#define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ 157 158/* 159 * ADSP2 Status 1 160 */ 161#define ADSP2_RAM_RDY 0x0001 162#define ADSP2_RAM_RDY_MASK 0x0001 163#define ADSP2_RAM_RDY_SHIFT 0 164#define ADSP2_RAM_RDY_WIDTH 1 165 166struct wm_adsp_buf { 167 struct list_head list; 168 void *buf; 169}; 170 171static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len, 172 struct list_head *list) 173{ 174 struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL); 175 176 if (buf == NULL) 177 return NULL; 178 179 buf->buf = vmalloc(len); 180 if (!buf->buf) { 181 vfree(buf); 182 return NULL; 183 } 184 memcpy(buf->buf, src, len); 185 186 if (list) 187 list_add_tail(&buf->list, list); 188 189 return buf; 190} 191 192static void wm_adsp_buf_free(struct list_head *list) 193{ 194 while (!list_empty(list)) { 195 struct wm_adsp_buf *buf = list_first_entry(list, 196 struct wm_adsp_buf, 197 list); 198 list_del(&buf->list); 199 vfree(buf->buf); 200 kfree(buf); 201 } 202} 203 204#define WM_ADSP_NUM_FW 4 205 206#define WM_ADSP_FW_MBC_VSS 0 207#define WM_ADSP_FW_TX 1 208#define WM_ADSP_FW_TX_SPK 2 209#define WM_ADSP_FW_RX_ANC 3 210 211static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { 212 [WM_ADSP_FW_MBC_VSS] = "MBC/VSS", 213 [WM_ADSP_FW_TX] = "Tx", 214 [WM_ADSP_FW_TX_SPK] = "Tx Speaker", 215 [WM_ADSP_FW_RX_ANC] = "Rx ANC", 216}; 217 218static struct { 219 const char *file; 220} wm_adsp_fw[WM_ADSP_NUM_FW] = { 221 [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" }, 222 [WM_ADSP_FW_TX] = { .file = "tx" }, 223 [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" }, 224 [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, 225}; 226 227struct wm_coeff_ctl_ops { 228 int (*xget)(struct snd_kcontrol *kcontrol, 229 struct snd_ctl_elem_value *ucontrol); 230 int (*xput)(struct snd_kcontrol *kcontrol, 231 struct snd_ctl_elem_value *ucontrol); 232 int (*xinfo)(struct snd_kcontrol *kcontrol, 233 struct snd_ctl_elem_info *uinfo); 234}; 235 236struct wm_coeff_ctl { 237 const char *name; 238 const char *fw_name; 239 struct wm_adsp_alg_region alg_region; 240 struct wm_coeff_ctl_ops ops; 241 struct wm_adsp *dsp; 242 unsigned int enabled:1; 243 struct list_head list; 244 void *cache; 245 unsigned int offset; 246 size_t len; 247 unsigned int set:1; 248 struct snd_kcontrol *kcontrol; 249 unsigned int flags; 250}; 251 252#ifdef CONFIG_DEBUG_FS 253static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s) 254{ 255 char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); 256 257 mutex_lock(&dsp->debugfs_lock); 258 kfree(dsp->wmfw_file_name); 259 dsp->wmfw_file_name = tmp; 260 mutex_unlock(&dsp->debugfs_lock); 261} 262 263static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s) 264{ 265 char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); 266 267 mutex_lock(&dsp->debugfs_lock); 268 kfree(dsp->bin_file_name); 269 dsp->bin_file_name = tmp; 270 mutex_unlock(&dsp->debugfs_lock); 271} 272 273static void wm_adsp_debugfs_clear(struct wm_adsp *dsp) 274{ 275 mutex_lock(&dsp->debugfs_lock); 276 kfree(dsp->wmfw_file_name); 277 kfree(dsp->bin_file_name); 278 dsp->wmfw_file_name = NULL; 279 dsp->bin_file_name = NULL; 280 mutex_unlock(&dsp->debugfs_lock); 281} 282 283static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, 284 char __user *user_buf, 285 size_t count, loff_t *ppos) 286{ 287 struct wm_adsp *dsp = file->private_data; 288 ssize_t ret; 289 290 mutex_lock(&dsp->debugfs_lock); 291 292 if (!dsp->wmfw_file_name || !dsp->running) 293 ret = 0; 294 else 295 ret = simple_read_from_buffer(user_buf, count, ppos, 296 dsp->wmfw_file_name, 297 strlen(dsp->wmfw_file_name)); 298 299 mutex_unlock(&dsp->debugfs_lock); 300 return ret; 301} 302 303static ssize_t wm_adsp_debugfs_bin_read(struct file *file, 304 char __user *user_buf, 305 size_t count, loff_t *ppos) 306{ 307 struct wm_adsp *dsp = file->private_data; 308 ssize_t ret; 309 310 mutex_lock(&dsp->debugfs_lock); 311 312 if (!dsp->bin_file_name || !dsp->running) 313 ret = 0; 314 else 315 ret = simple_read_from_buffer(user_buf, count, ppos, 316 dsp->bin_file_name, 317 strlen(dsp->bin_file_name)); 318 319 mutex_unlock(&dsp->debugfs_lock); 320 return ret; 321} 322 323static const struct { 324 const char *name; 325 const struct file_operations fops; 326} wm_adsp_debugfs_fops[] = { 327 { 328 .name = "wmfw_file_name", 329 .fops = { 330 .open = simple_open, 331 .read = wm_adsp_debugfs_wmfw_read, 332 }, 333 }, 334 { 335 .name = "bin_file_name", 336 .fops = { 337 .open = simple_open, 338 .read = wm_adsp_debugfs_bin_read, 339 }, 340 }, 341}; 342 343static void wm_adsp2_init_debugfs(struct wm_adsp *dsp, 344 struct snd_soc_codec *codec) 345{ 346 struct dentry *root = NULL; 347 char *root_name; 348 int i; 349 350 if (!codec->component.debugfs_root) { 351 adsp_err(dsp, "No codec debugfs root\n"); 352 goto err; 353 } 354 355 root_name = kmalloc(PAGE_SIZE, GFP_KERNEL); 356 if (!root_name) 357 goto err; 358 359 snprintf(root_name, PAGE_SIZE, "dsp%d", dsp->num); 360 root = debugfs_create_dir(root_name, codec->component.debugfs_root); 361 kfree(root_name); 362 363 if (!root) 364 goto err; 365 366 if (!debugfs_create_bool("running", S_IRUGO, root, &dsp->running)) 367 goto err; 368 369 if (!debugfs_create_x32("fw_id", S_IRUGO, root, &dsp->fw_id)) 370 goto err; 371 372 if (!debugfs_create_x32("fw_version", S_IRUGO, root, 373 &dsp->fw_id_version)) 374 goto err; 375 376 for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) { 377 if (!debugfs_create_file(wm_adsp_debugfs_fops[i].name, 378 S_IRUGO, root, dsp, 379 &wm_adsp_debugfs_fops[i].fops)) 380 goto err; 381 } 382 383 dsp->debugfs_root = root; 384 return; 385 386err: 387 debugfs_remove_recursive(root); 388 adsp_err(dsp, "Failed to create debugfs\n"); 389} 390 391static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp) 392{ 393 wm_adsp_debugfs_clear(dsp); 394 debugfs_remove_recursive(dsp->debugfs_root); 395} 396#else 397static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp, 398 struct snd_soc_codec *codec) 399{ 400} 401 402static inline void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp) 403{ 404} 405 406static inline void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, 407 const char *s) 408{ 409} 410 411static inline void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, 412 const char *s) 413{ 414} 415 416static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp) 417{ 418} 419#endif 420 421static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, 422 struct snd_ctl_elem_value *ucontrol) 423{ 424 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 425 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 426 struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); 427 428 ucontrol->value.integer.value[0] = dsp[e->shift_l].fw; 429 430 return 0; 431} 432 433static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, 434 struct snd_ctl_elem_value *ucontrol) 435{ 436 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 437 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 438 struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); 439 440 if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw) 441 return 0; 442 443 if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW) 444 return -EINVAL; 445 446 if (dsp[e->shift_l].running) 447 return -EBUSY; 448 449 dsp[e->shift_l].fw = ucontrol->value.integer.value[0]; 450 451 return 0; 452} 453 454static const struct soc_enum wm_adsp_fw_enum[] = { 455 SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), 456 SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), 457 SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), 458 SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), 459}; 460 461const struct snd_kcontrol_new wm_adsp_fw_controls[] = { 462 SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], 463 wm_adsp_fw_get, wm_adsp_fw_put), 464 SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], 465 wm_adsp_fw_get, wm_adsp_fw_put), 466 SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], 467 wm_adsp_fw_get, wm_adsp_fw_put), 468 SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], 469 wm_adsp_fw_get, wm_adsp_fw_put), 470}; 471EXPORT_SYMBOL_GPL(wm_adsp_fw_controls); 472 473static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, 474 int type) 475{ 476 int i; 477 478 for (i = 0; i < dsp->num_mems; i++) 479 if (dsp->mem[i].type == type) 480 return &dsp->mem[i]; 481 482 return NULL; 483} 484 485static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem, 486 unsigned int offset) 487{ 488 if (WARN_ON(!mem)) 489 return offset; 490 switch (mem->type) { 491 case WMFW_ADSP1_PM: 492 return mem->base + (offset * 3); 493 case WMFW_ADSP1_DM: 494 return mem->base + (offset * 2); 495 case WMFW_ADSP2_XM: 496 return mem->base + (offset * 2); 497 case WMFW_ADSP2_YM: 498 return mem->base + (offset * 2); 499 case WMFW_ADSP1_ZM: 500 return mem->base + (offset * 2); 501 default: 502 WARN(1, "Unknown memory region type"); 503 return offset; 504 } 505} 506 507static void wm_adsp2_show_fw_status(struct wm_adsp *dsp) 508{ 509 u16 scratch[4]; 510 int ret; 511 512 ret = regmap_raw_read(dsp->regmap, dsp->base + ADSP2_SCRATCH0, 513 scratch, sizeof(scratch)); 514 if (ret) { 515 adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret); 516 return; 517 } 518 519 adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", 520 be16_to_cpu(scratch[0]), 521 be16_to_cpu(scratch[1]), 522 be16_to_cpu(scratch[2]), 523 be16_to_cpu(scratch[3])); 524} 525 526static int wm_coeff_info(struct snd_kcontrol *kcontrol, 527 struct snd_ctl_elem_info *uinfo) 528{ 529 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; 530 531 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; 532 uinfo->count = ctl->len; 533 return 0; 534} 535 536static int wm_coeff_write_control(struct wm_coeff_ctl *ctl, 537 const void *buf, size_t len) 538{ 539 struct wm_adsp_alg_region *alg_region = &ctl->alg_region; 540 const struct wm_adsp_region *mem; 541 struct wm_adsp *dsp = ctl->dsp; 542 void *scratch; 543 int ret; 544 unsigned int reg; 545 546 mem = wm_adsp_find_region(dsp, alg_region->type); 547 if (!mem) { 548 adsp_err(dsp, "No base for region %x\n", 549 alg_region->type); 550 return -EINVAL; 551 } 552 553 reg = ctl->alg_region.base + ctl->offset; 554 reg = wm_adsp_region_to_reg(mem, reg); 555 556 scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA); 557 if (!scratch) 558 return -ENOMEM; 559 560 ret = regmap_raw_write(dsp->regmap, reg, scratch, 561 ctl->len); 562 if (ret) { 563 adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n", 564 ctl->len, reg, ret); 565 kfree(scratch); 566 return ret; 567 } 568 adsp_dbg(dsp, "Wrote %zu bytes to %x\n", ctl->len, reg); 569 570 kfree(scratch); 571 572 return 0; 573} 574 575static int wm_coeff_put(struct snd_kcontrol *kcontrol, 576 struct snd_ctl_elem_value *ucontrol) 577{ 578 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; 579 char *p = ucontrol->value.bytes.data; 580 581 memcpy(ctl->cache, p, ctl->len); 582 583 ctl->set = 1; 584 if (!ctl->enabled) 585 return 0; 586 587 return wm_coeff_write_control(ctl, p, ctl->len); 588} 589 590static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, 591 void *buf, size_t len) 592{ 593 struct wm_adsp_alg_region *alg_region = &ctl->alg_region; 594 const struct wm_adsp_region *mem; 595 struct wm_adsp *dsp = ctl->dsp; 596 void *scratch; 597 int ret; 598 unsigned int reg; 599 600 mem = wm_adsp_find_region(dsp, alg_region->type); 601 if (!mem) { 602 adsp_err(dsp, "No base for region %x\n", 603 alg_region->type); 604 return -EINVAL; 605 } 606 607 reg = ctl->alg_region.base + ctl->offset; 608 reg = wm_adsp_region_to_reg(mem, reg); 609 610 scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA); 611 if (!scratch) 612 return -ENOMEM; 613 614 ret = regmap_raw_read(dsp->regmap, reg, scratch, ctl->len); 615 if (ret) { 616 adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n", 617 ctl->len, reg, ret); 618 kfree(scratch); 619 return ret; 620 } 621 adsp_dbg(dsp, "Read %zu bytes from %x\n", ctl->len, reg); 622 623 memcpy(buf, scratch, ctl->len); 624 kfree(scratch); 625 626 return 0; 627} 628 629static int wm_coeff_get(struct snd_kcontrol *kcontrol, 630 struct snd_ctl_elem_value *ucontrol) 631{ 632 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; 633 char *p = ucontrol->value.bytes.data; 634 635 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { 636 if (ctl->enabled) 637 return wm_coeff_read_control(ctl, p, ctl->len); 638 else 639 return -EPERM; 640 } 641 642 memcpy(p, ctl->cache, ctl->len); 643 644 return 0; 645} 646 647struct wmfw_ctl_work { 648 struct wm_adsp *dsp; 649 struct wm_coeff_ctl *ctl; 650 struct work_struct work; 651}; 652 653static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) 654{ 655 struct snd_kcontrol_new *kcontrol; 656 int ret; 657 658 if (!ctl || !ctl->name) 659 return -EINVAL; 660 661 kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL); 662 if (!kcontrol) 663 return -ENOMEM; 664 kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER; 665 666 kcontrol->name = ctl->name; 667 kcontrol->info = wm_coeff_info; 668 kcontrol->get = wm_coeff_get; 669 kcontrol->put = wm_coeff_put; 670 kcontrol->private_value = (unsigned long)ctl; 671 672 if (ctl->flags) { 673 if (ctl->flags & WMFW_CTL_FLAG_WRITEABLE) 674 kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_WRITE; 675 if (ctl->flags & WMFW_CTL_FLAG_READABLE) 676 kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ; 677 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) 678 kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE; 679 } 680 681 ret = snd_soc_add_card_controls(dsp->card, 682 kcontrol, 1); 683 if (ret < 0) 684 goto err_kcontrol; 685 686 kfree(kcontrol); 687 688 ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card, 689 ctl->name); 690 691 return 0; 692 693err_kcontrol: 694 kfree(kcontrol); 695 return ret; 696} 697 698static int wm_coeff_init_control_caches(struct wm_adsp *dsp) 699{ 700 struct wm_coeff_ctl *ctl; 701 int ret; 702 703 list_for_each_entry(ctl, &dsp->ctl_list, list) { 704 if (!ctl->enabled || ctl->set) 705 continue; 706 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) 707 continue; 708 709 ret = wm_coeff_read_control(ctl, 710 ctl->cache, 711 ctl->len); 712 if (ret < 0) 713 return ret; 714 } 715 716 return 0; 717} 718 719static int wm_coeff_sync_controls(struct wm_adsp *dsp) 720{ 721 struct wm_coeff_ctl *ctl; 722 int ret; 723 724 list_for_each_entry(ctl, &dsp->ctl_list, list) { 725 if (!ctl->enabled) 726 continue; 727 if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) { 728 ret = wm_coeff_write_control(ctl, 729 ctl->cache, 730 ctl->len); 731 if (ret < 0) 732 return ret; 733 } 734 } 735 736 return 0; 737} 738 739static void wm_adsp_ctl_work(struct work_struct *work) 740{ 741 struct wmfw_ctl_work *ctl_work = container_of(work, 742 struct wmfw_ctl_work, 743 work); 744 745 wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl); 746 kfree(ctl_work); 747} 748 749static int wm_adsp_create_control(struct wm_adsp *dsp, 750 const struct wm_adsp_alg_region *alg_region, 751 unsigned int offset, unsigned int len, 752 const char *subname, unsigned int subname_len, 753 unsigned int flags) 754{ 755 struct wm_coeff_ctl *ctl; 756 struct wmfw_ctl_work *ctl_work; 757 char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 758 char *region_name; 759 int ret; 760 761 if (flags & WMFW_CTL_FLAG_SYS) 762 return 0; 763 764 switch (alg_region->type) { 765 case WMFW_ADSP1_PM: 766 region_name = "PM"; 767 break; 768 case WMFW_ADSP1_DM: 769 region_name = "DM"; 770 break; 771 case WMFW_ADSP2_XM: 772 region_name = "XM"; 773 break; 774 case WMFW_ADSP2_YM: 775 region_name = "YM"; 776 break; 777 case WMFW_ADSP1_ZM: 778 region_name = "ZM"; 779 break; 780 default: 781 adsp_err(dsp, "Unknown region type: %d\n", alg_region->type); 782 return -EINVAL; 783 } 784 785 switch (dsp->fw_ver) { 786 case 0: 787 case 1: 788 snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x", 789 dsp->num, region_name, alg_region->alg); 790 break; 791 default: 792 ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, 793 "DSP%d%c %.12s %x", dsp->num, *region_name, 794 wm_adsp_fw_text[dsp->fw], alg_region->alg); 795 796 /* Truncate the subname from the start if it is too long */ 797 if (subname) { 798 int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2; 799 int skip = 0; 800 801 if (subname_len > avail) 802 skip = subname_len - avail; 803 804 snprintf(name + ret, 805 SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s", 806 subname_len - skip, subname + skip); 807 } 808 break; 809 } 810 811 list_for_each_entry(ctl, &dsp->ctl_list, 812 list) { 813 if (!strcmp(ctl->name, name)) { 814 if (!ctl->enabled) 815 ctl->enabled = 1; 816 return 0; 817 } 818 } 819 820 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); 821 if (!ctl) 822 return -ENOMEM; 823 ctl->fw_name = wm_adsp_fw_text[dsp->fw]; 824 ctl->alg_region = *alg_region; 825 ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL); 826 if (!ctl->name) { 827 ret = -ENOMEM; 828 goto err_ctl; 829 } 830 ctl->enabled = 1; 831 ctl->set = 0; 832 ctl->ops.xget = wm_coeff_get; 833 ctl->ops.xput = wm_coeff_put; 834 ctl->dsp = dsp; 835 836 ctl->flags = flags; 837 ctl->offset = offset; 838 if (len > 512) { 839 adsp_warn(dsp, "Truncating control %s from %d\n", 840 ctl->name, len); 841 len = 512; 842 } 843 ctl->len = len; 844 ctl->cache = kzalloc(ctl->len, GFP_KERNEL); 845 if (!ctl->cache) { 846 ret = -ENOMEM; 847 goto err_ctl_name; 848 } 849 850 list_add(&ctl->list, &dsp->ctl_list); 851 852 ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL); 853 if (!ctl_work) { 854 ret = -ENOMEM; 855 goto err_ctl_cache; 856 } 857 858 ctl_work->dsp = dsp; 859 ctl_work->ctl = ctl; 860 INIT_WORK(&ctl_work->work, wm_adsp_ctl_work); 861 schedule_work(&ctl_work->work); 862 863 return 0; 864 865err_ctl_cache: 866 kfree(ctl->cache); 867err_ctl_name: 868 kfree(ctl->name); 869err_ctl: 870 kfree(ctl); 871 872 return ret; 873} 874 875struct wm_coeff_parsed_alg { 876 int id; 877 const u8 *name; 878 int name_len; 879 int ncoeff; 880}; 881 882struct wm_coeff_parsed_coeff { 883 int offset; 884 int mem_type; 885 const u8 *name; 886 int name_len; 887 int ctl_type; 888 int flags; 889 int len; 890}; 891 892static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) 893{ 894 int length; 895 896 switch (bytes) { 897 case 1: 898 length = **pos; 899 break; 900 case 2: 901 length = le16_to_cpu(*((__le16 *)*pos)); 902 break; 903 default: 904 return 0; 905 } 906 907 if (str) 908 *str = *pos + bytes; 909 910 *pos += ((length + bytes) + 3) & ~0x03; 911 912 return length; 913} 914 915static int wm_coeff_parse_int(int bytes, const u8 **pos) 916{ 917 int val = 0; 918 919 switch (bytes) { 920 case 2: 921 val = le16_to_cpu(*((__le16 *)*pos)); 922 break; 923 case 4: 924 val = le32_to_cpu(*((__le32 *)*pos)); 925 break; 926 default: 927 break; 928 } 929 930 *pos += bytes; 931 932 return val; 933} 934 935static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data, 936 struct wm_coeff_parsed_alg *blk) 937{ 938 const struct wmfw_adsp_alg_data *raw; 939 940 switch (dsp->fw_ver) { 941 case 0: 942 case 1: 943 raw = (const struct wmfw_adsp_alg_data *)*data; 944 *data = raw->data; 945 946 blk->id = le32_to_cpu(raw->id); 947 blk->name = raw->name; 948 blk->name_len = strlen(raw->name); 949 blk->ncoeff = le32_to_cpu(raw->ncoeff); 950 break; 951 default: 952 blk->id = wm_coeff_parse_int(sizeof(raw->id), data); 953 blk->name_len = wm_coeff_parse_string(sizeof(u8), data, 954 &blk->name); 955 wm_coeff_parse_string(sizeof(u16), data, NULL); 956 blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data); 957 break; 958 } 959 960 adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); 961 adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); 962 adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff); 963} 964 965static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data, 966 struct wm_coeff_parsed_coeff *blk) 967{ 968 const struct wmfw_adsp_coeff_data *raw; 969 const u8 *tmp; 970 int length; 971 972 switch (dsp->fw_ver) { 973 case 0: 974 case 1: 975 raw = (const struct wmfw_adsp_coeff_data *)*data; 976 *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size); 977 978 blk->offset = le16_to_cpu(raw->hdr.offset); 979 blk->mem_type = le16_to_cpu(raw->hdr.type); 980 blk->name = raw->name; 981 blk->name_len = strlen(raw->name); 982 blk->ctl_type = le16_to_cpu(raw->ctl_type); 983 blk->flags = le16_to_cpu(raw->flags); 984 blk->len = le32_to_cpu(raw->len); 985 break; 986 default: 987 tmp = *data; 988 blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp); 989 blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp); 990 length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp); 991 blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp, 992 &blk->name); 993 wm_coeff_parse_string(sizeof(u8), &tmp, NULL); 994 wm_coeff_parse_string(sizeof(u16), &tmp, NULL); 995 blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp); 996 blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp); 997 blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp); 998 999 *data = *data + sizeof(raw->hdr) + length; 1000 break; 1001 } 1002 1003 adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type); 1004 adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset); 1005 adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name); 1006 adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags); 1007 adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type); 1008 adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); 1009} 1010 1011static int wm_adsp_parse_coeff(struct wm_adsp *dsp, 1012 const struct wmfw_region *region) 1013{ 1014 struct wm_adsp_alg_region alg_region = {}; 1015 struct wm_coeff_parsed_alg alg_blk; 1016 struct wm_coeff_parsed_coeff coeff_blk; 1017 const u8 *data = region->data; 1018 int i, ret; 1019 1020 wm_coeff_parse_alg(dsp, &data, &alg_blk); 1021 for (i = 0; i < alg_blk.ncoeff; i++) { 1022 wm_coeff_parse_coeff(dsp, &data, &coeff_blk); 1023 1024 switch (coeff_blk.ctl_type) { 1025 case SNDRV_CTL_ELEM_TYPE_BYTES: 1026 break; 1027 default: 1028 adsp_err(dsp, "Unknown control type: %d\n", 1029 coeff_blk.ctl_type); 1030 return -EINVAL; 1031 } 1032 1033 alg_region.type = coeff_blk.mem_type; 1034 alg_region.alg = alg_blk.id; 1035 1036 ret = wm_adsp_create_control(dsp, &alg_region, 1037 coeff_blk.offset, 1038 coeff_blk.len, 1039 coeff_blk.name, 1040 coeff_blk.name_len, 1041 coeff_blk.flags); 1042 if (ret < 0) 1043 adsp_err(dsp, "Failed to create control: %.*s, %d\n", 1044 coeff_blk.name_len, coeff_blk.name, ret); 1045 } 1046 1047 return 0; 1048} 1049 1050static int wm_adsp_load(struct wm_adsp *dsp) 1051{ 1052 LIST_HEAD(buf_list); 1053 const struct firmware *firmware; 1054 struct regmap *regmap = dsp->regmap; 1055 unsigned int pos = 0; 1056 const struct wmfw_header *header; 1057 const struct wmfw_adsp1_sizes *adsp1_sizes; 1058 const struct wmfw_adsp2_sizes *adsp2_sizes; 1059 const struct wmfw_footer *footer; 1060 const struct wmfw_region *region; 1061 const struct wm_adsp_region *mem; 1062 const char *region_name; 1063 char *file, *text; 1064 struct wm_adsp_buf *buf; 1065 unsigned int reg; 1066 int regions = 0; 1067 int ret, offset, type, sizes; 1068 1069 file = kzalloc(PAGE_SIZE, GFP_KERNEL); 1070 if (file == NULL) 1071 return -ENOMEM; 1072 1073 snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num, 1074 wm_adsp_fw[dsp->fw].file); 1075 file[PAGE_SIZE - 1] = '\0'; 1076 1077 ret = request_firmware(&firmware, file, dsp->dev); 1078 if (ret != 0) { 1079 adsp_err(dsp, "Failed to request '%s'\n", file); 1080 goto out; 1081 } 1082 ret = -EINVAL; 1083 1084 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); 1085 if (pos >= firmware->size) { 1086 adsp_err(dsp, "%s: file too short, %zu bytes\n", 1087 file, firmware->size); 1088 goto out_fw; 1089 } 1090 1091 header = (void*)&firmware->data[0]; 1092 1093 if (memcmp(&header->magic[0], "WMFW", 4) != 0) { 1094 adsp_err(dsp, "%s: invalid magic\n", file); 1095 goto out_fw; 1096 } 1097 1098 switch (header->ver) { 1099 case 0: 1100 adsp_warn(dsp, "%s: Depreciated file format %d\n", 1101 file, header->ver); 1102 break; 1103 case 1: 1104 case 2: 1105 break; 1106 default: 1107 adsp_err(dsp, "%s: unknown file format %d\n", 1108 file, header->ver); 1109 goto out_fw; 1110 } 1111 1112 adsp_info(dsp, "Firmware version: %d\n", header->ver); 1113 dsp->fw_ver = header->ver; 1114 1115 if (header->core != dsp->type) { 1116 adsp_err(dsp, "%s: invalid core %d != %d\n", 1117 file, header->core, dsp->type); 1118 goto out_fw; 1119 } 1120 1121 switch (dsp->type) { 1122 case WMFW_ADSP1: 1123 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); 1124 adsp1_sizes = (void *)&(header[1]); 1125 footer = (void *)&(adsp1_sizes[1]); 1126 sizes = sizeof(*adsp1_sizes); 1127 1128 adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", 1129 file, le32_to_cpu(adsp1_sizes->dm), 1130 le32_to_cpu(adsp1_sizes->pm), 1131 le32_to_cpu(adsp1_sizes->zm)); 1132 break; 1133 1134 case WMFW_ADSP2: 1135 pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer); 1136 adsp2_sizes = (void *)&(header[1]); 1137 footer = (void *)&(adsp2_sizes[1]); 1138 sizes = sizeof(*adsp2_sizes); 1139 1140 adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", 1141 file, le32_to_cpu(adsp2_sizes->xm), 1142 le32_to_cpu(adsp2_sizes->ym), 1143 le32_to_cpu(adsp2_sizes->pm), 1144 le32_to_cpu(adsp2_sizes->zm)); 1145 break; 1146 1147 default: 1148 WARN(1, "Unknown DSP type"); 1149 goto out_fw; 1150 } 1151 1152 if (le32_to_cpu(header->len) != sizeof(*header) + 1153 sizes + sizeof(*footer)) { 1154 adsp_err(dsp, "%s: unexpected header length %d\n", 1155 file, le32_to_cpu(header->len)); 1156 goto out_fw; 1157 } 1158 1159 adsp_dbg(dsp, "%s: timestamp %llu\n", file, 1160 le64_to_cpu(footer->timestamp)); 1161 1162 while (pos < firmware->size && 1163 pos - firmware->size > sizeof(*region)) { 1164 region = (void *)&(firmware->data[pos]); 1165 region_name = "Unknown"; 1166 reg = 0; 1167 text = NULL; 1168 offset = le32_to_cpu(region->offset) & 0xffffff; 1169 type = be32_to_cpu(region->type) & 0xff; 1170 mem = wm_adsp_find_region(dsp, type); 1171 1172 switch (type) { 1173 case WMFW_NAME_TEXT: 1174 region_name = "Firmware name"; 1175 text = kzalloc(le32_to_cpu(region->len) + 1, 1176 GFP_KERNEL); 1177 break; 1178 case WMFW_ALGORITHM_DATA: 1179 region_name = "Algorithm"; 1180 ret = wm_adsp_parse_coeff(dsp, region); 1181 if (ret != 0) 1182 goto out_fw; 1183 break; 1184 case WMFW_INFO_TEXT: 1185 region_name = "Information"; 1186 text = kzalloc(le32_to_cpu(region->len) + 1, 1187 GFP_KERNEL); 1188 break; 1189 case WMFW_ABSOLUTE: 1190 region_name = "Absolute"; 1191 reg = offset; 1192 break; 1193 case WMFW_ADSP1_PM: 1194 region_name = "PM"; 1195 reg = wm_adsp_region_to_reg(mem, offset); 1196 break; 1197 case WMFW_ADSP1_DM: 1198 region_name = "DM"; 1199 reg = wm_adsp_region_to_reg(mem, offset); 1200 break; 1201 case WMFW_ADSP2_XM: 1202 region_name = "XM"; 1203 reg = wm_adsp_region_to_reg(mem, offset); 1204 break; 1205 case WMFW_ADSP2_YM: 1206 region_name = "YM"; 1207 reg = wm_adsp_region_to_reg(mem, offset); 1208 break; 1209 case WMFW_ADSP1_ZM: 1210 region_name = "ZM"; 1211 reg = wm_adsp_region_to_reg(mem, offset); 1212 break; 1213 default: 1214 adsp_warn(dsp, 1215 "%s.%d: Unknown region type %x at %d(%x)\n", 1216 file, regions, type, pos, pos); 1217 break; 1218 } 1219 1220 adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file, 1221 regions, le32_to_cpu(region->len), offset, 1222 region_name); 1223 1224 if (text) { 1225 memcpy(text, region->data, le32_to_cpu(region->len)); 1226 adsp_info(dsp, "%s: %s\n", file, text); 1227 kfree(text); 1228 } 1229 1230 if (reg) { 1231 buf = wm_adsp_buf_alloc(region->data, 1232 le32_to_cpu(region->len), 1233 &buf_list); 1234 if (!buf) { 1235 adsp_err(dsp, "Out of memory\n"); 1236 ret = -ENOMEM; 1237 goto out_fw; 1238 } 1239 1240 ret = regmap_raw_write_async(regmap, reg, buf->buf, 1241 le32_to_cpu(region->len)); 1242 if (ret != 0) { 1243 adsp_err(dsp, 1244 "%s.%d: Failed to write %d bytes at %d in %s: %d\n", 1245 file, regions, 1246 le32_to_cpu(region->len), offset, 1247 region_name, ret); 1248 goto out_fw; 1249 } 1250 } 1251 1252 pos += le32_to_cpu(region->len) + sizeof(*region); 1253 regions++; 1254 } 1255 1256 ret = regmap_async_complete(regmap); 1257 if (ret != 0) { 1258 adsp_err(dsp, "Failed to complete async write: %d\n", ret); 1259 goto out_fw; 1260 } 1261 1262 if (pos > firmware->size) 1263 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 1264 file, regions, pos - firmware->size); 1265 1266 wm_adsp_debugfs_save_wmfwname(dsp, file); 1267 1268out_fw: 1269 regmap_async_complete(regmap); 1270 wm_adsp_buf_free(&buf_list); 1271 release_firmware(firmware); 1272out: 1273 kfree(file); 1274 1275 return ret; 1276} 1277 1278static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp, 1279 const struct wm_adsp_alg_region *alg_region) 1280{ 1281 struct wm_coeff_ctl *ctl; 1282 1283 list_for_each_entry(ctl, &dsp->ctl_list, list) { 1284 if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] && 1285 alg_region->alg == ctl->alg_region.alg && 1286 alg_region->type == ctl->alg_region.type) { 1287 ctl->alg_region.base = alg_region->base; 1288 } 1289 } 1290} 1291 1292static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, 1293 unsigned int pos, unsigned int len) 1294{ 1295 void *alg; 1296 int ret; 1297 __be32 val; 1298 1299 if (n_algs == 0) { 1300 adsp_err(dsp, "No algorithms\n"); 1301 return ERR_PTR(-EINVAL); 1302 } 1303 1304 if (n_algs > 1024) { 1305 adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs); 1306 return ERR_PTR(-EINVAL); 1307 } 1308 1309 /* Read the terminator first to validate the length */ 1310 ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val)); 1311 if (ret != 0) { 1312 adsp_err(dsp, "Failed to read algorithm list end: %d\n", 1313 ret); 1314 return ERR_PTR(ret); 1315 } 1316 1317 if (be32_to_cpu(val) != 0xbedead) 1318 adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", 1319 pos + len, be32_to_cpu(val)); 1320 1321 alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA); 1322 if (!alg) 1323 return ERR_PTR(-ENOMEM); 1324 1325 ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2); 1326 if (ret != 0) { 1327 adsp_err(dsp, "Failed to read algorithm list: %d\n", 1328 ret); 1329 kfree(alg); 1330 return ERR_PTR(ret); 1331 } 1332 1333 return alg; 1334} 1335 1336static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp, 1337 int type, __be32 id, 1338 __be32 base) 1339{ 1340 struct wm_adsp_alg_region *alg_region; 1341 1342 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL); 1343 if (!alg_region) 1344 return ERR_PTR(-ENOMEM); 1345 1346 alg_region->type = type; 1347 alg_region->alg = be32_to_cpu(id); 1348 alg_region->base = be32_to_cpu(base); 1349 1350 list_add_tail(&alg_region->list, &dsp->alg_regions); 1351 1352 if (dsp->fw_ver > 0) 1353 wm_adsp_ctl_fixup_base(dsp, alg_region); 1354 1355 return alg_region; 1356} 1357 1358static int wm_adsp1_setup_algs(struct wm_adsp *dsp) 1359{ 1360 struct wmfw_adsp1_id_hdr adsp1_id; 1361 struct wmfw_adsp1_alg_hdr *adsp1_alg; 1362 struct wm_adsp_alg_region *alg_region; 1363 const struct wm_adsp_region *mem; 1364 unsigned int pos, len; 1365 size_t n_algs; 1366 int i, ret; 1367 1368 mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM); 1369 if (WARN_ON(!mem)) 1370 return -EINVAL; 1371 1372 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id, 1373 sizeof(adsp1_id)); 1374 if (ret != 0) { 1375 adsp_err(dsp, "Failed to read algorithm info: %d\n", 1376 ret); 1377 return ret; 1378 } 1379 1380 n_algs = be32_to_cpu(adsp1_id.n_algs); 1381 dsp->fw_id = be32_to_cpu(adsp1_id.fw.id); 1382 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", 1383 dsp->fw_id, 1384 (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16, 1385 (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8, 1386 be32_to_cpu(adsp1_id.fw.ver) & 0xff, 1387 n_algs); 1388 1389 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM, 1390 adsp1_id.fw.id, adsp1_id.zm); 1391 if (IS_ERR(alg_region)) 1392 return PTR_ERR(alg_region); 1393 1394 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM, 1395 adsp1_id.fw.id, adsp1_id.dm); 1396 if (IS_ERR(alg_region)) 1397 return PTR_ERR(alg_region); 1398 1399 pos = sizeof(adsp1_id) / 2; 1400 len = (sizeof(*adsp1_alg) * n_algs) / 2; 1401 1402 adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len); 1403 if (IS_ERR(adsp1_alg)) 1404 return PTR_ERR(adsp1_alg); 1405 1406 for (i = 0; i < n_algs; i++) { 1407 adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", 1408 i, be32_to_cpu(adsp1_alg[i].alg.id), 1409 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, 1410 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, 1411 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, 1412 be32_to_cpu(adsp1_alg[i].dm), 1413 be32_to_cpu(adsp1_alg[i].zm)); 1414 1415 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM, 1416 adsp1_alg[i].alg.id, 1417 adsp1_alg[i].dm); 1418 if (IS_ERR(alg_region)) { 1419 ret = PTR_ERR(alg_region); 1420 goto out; 1421 } 1422 if (dsp->fw_ver == 0) { 1423 if (i + 1 < n_algs) { 1424 len = be32_to_cpu(adsp1_alg[i + 1].dm); 1425 len -= be32_to_cpu(adsp1_alg[i].dm); 1426 len *= 4; 1427 wm_adsp_create_control(dsp, alg_region, 0, 1428 len, NULL, 0, 0); 1429 } else { 1430 adsp_warn(dsp, "Missing length info for region DM with ID %x\n", 1431 be32_to_cpu(adsp1_alg[i].alg.id)); 1432 } 1433 } 1434 1435 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM, 1436 adsp1_alg[i].alg.id, 1437 adsp1_alg[i].zm); 1438 if (IS_ERR(alg_region)) { 1439 ret = PTR_ERR(alg_region); 1440 goto out; 1441 } 1442 if (dsp->fw_ver == 0) { 1443 if (i + 1 < n_algs) { 1444 len = be32_to_cpu(adsp1_alg[i + 1].zm); 1445 len -= be32_to_cpu(adsp1_alg[i].zm); 1446 len *= 4; 1447 wm_adsp_create_control(dsp, alg_region, 0, 1448 len, NULL, 0, 0); 1449 } else { 1450 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 1451 be32_to_cpu(adsp1_alg[i].alg.id)); 1452 } 1453 } 1454 } 1455 1456out: 1457 kfree(adsp1_alg); 1458 return ret; 1459} 1460 1461static int wm_adsp2_setup_algs(struct wm_adsp *dsp) 1462{ 1463 struct wmfw_adsp2_id_hdr adsp2_id; 1464 struct wmfw_adsp2_alg_hdr *adsp2_alg; 1465 struct wm_adsp_alg_region *alg_region; 1466 const struct wm_adsp_region *mem; 1467 unsigned int pos, len; 1468 size_t n_algs; 1469 int i, ret; 1470 1471 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); 1472 if (WARN_ON(!mem)) 1473 return -EINVAL; 1474 1475 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id, 1476 sizeof(adsp2_id)); 1477 if (ret != 0) { 1478 adsp_err(dsp, "Failed to read algorithm info: %d\n", 1479 ret); 1480 return ret; 1481 } 1482 1483 n_algs = be32_to_cpu(adsp2_id.n_algs); 1484 dsp->fw_id = be32_to_cpu(adsp2_id.fw.id); 1485 dsp->fw_id_version = be32_to_cpu(adsp2_id.fw.ver); 1486 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", 1487 dsp->fw_id, 1488 (dsp->fw_id_version & 0xff0000) >> 16, 1489 (dsp->fw_id_version & 0xff00) >> 8, 1490 dsp->fw_id_version & 0xff, 1491 n_algs); 1492 1493 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, 1494 adsp2_id.fw.id, adsp2_id.xm); 1495 if (IS_ERR(alg_region)) 1496 return PTR_ERR(alg_region); 1497 1498 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM, 1499 adsp2_id.fw.id, adsp2_id.ym); 1500 if (IS_ERR(alg_region)) 1501 return PTR_ERR(alg_region); 1502 1503 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM, 1504 adsp2_id.fw.id, adsp2_id.zm); 1505 if (IS_ERR(alg_region)) 1506 return PTR_ERR(alg_region); 1507 1508 pos = sizeof(adsp2_id) / 2; 1509 len = (sizeof(*adsp2_alg) * n_algs) / 2; 1510 1511 adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len); 1512 if (IS_ERR(adsp2_alg)) 1513 return PTR_ERR(adsp2_alg); 1514 1515 for (i = 0; i < n_algs; i++) { 1516 adsp_info(dsp, 1517 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", 1518 i, be32_to_cpu(adsp2_alg[i].alg.id), 1519 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, 1520 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, 1521 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, 1522 be32_to_cpu(adsp2_alg[i].xm), 1523 be32_to_cpu(adsp2_alg[i].ym), 1524 be32_to_cpu(adsp2_alg[i].zm)); 1525 1526 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, 1527 adsp2_alg[i].alg.id, 1528 adsp2_alg[i].xm); 1529 if (IS_ERR(alg_region)) { 1530 ret = PTR_ERR(alg_region); 1531 goto out; 1532 } 1533 if (dsp->fw_ver == 0) { 1534 if (i + 1 < n_algs) { 1535 len = be32_to_cpu(adsp2_alg[i + 1].xm); 1536 len -= be32_to_cpu(adsp2_alg[i].xm); 1537 len *= 4; 1538 wm_adsp_create_control(dsp, alg_region, 0, 1539 len, NULL, 0, 0); 1540 } else { 1541 adsp_warn(dsp, "Missing length info for region XM with ID %x\n", 1542 be32_to_cpu(adsp2_alg[i].alg.id)); 1543 } 1544 } 1545 1546 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM, 1547 adsp2_alg[i].alg.id, 1548 adsp2_alg[i].ym); 1549 if (IS_ERR(alg_region)) { 1550 ret = PTR_ERR(alg_region); 1551 goto out; 1552 } 1553 if (dsp->fw_ver == 0) { 1554 if (i + 1 < n_algs) { 1555 len = be32_to_cpu(adsp2_alg[i + 1].ym); 1556 len -= be32_to_cpu(adsp2_alg[i].ym); 1557 len *= 4; 1558 wm_adsp_create_control(dsp, alg_region, 0, 1559 len, NULL, 0, 0); 1560 } else { 1561 adsp_warn(dsp, "Missing length info for region YM with ID %x\n", 1562 be32_to_cpu(adsp2_alg[i].alg.id)); 1563 } 1564 } 1565 1566 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM, 1567 adsp2_alg[i].alg.id, 1568 adsp2_alg[i].zm); 1569 if (IS_ERR(alg_region)) { 1570 ret = PTR_ERR(alg_region); 1571 goto out; 1572 } 1573 if (dsp->fw_ver == 0) { 1574 if (i + 1 < n_algs) { 1575 len = be32_to_cpu(adsp2_alg[i + 1].zm); 1576 len -= be32_to_cpu(adsp2_alg[i].zm); 1577 len *= 4; 1578 wm_adsp_create_control(dsp, alg_region, 0, 1579 len, NULL, 0, 0); 1580 } else { 1581 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 1582 be32_to_cpu(adsp2_alg[i].alg.id)); 1583 } 1584 } 1585 } 1586 1587out: 1588 kfree(adsp2_alg); 1589 return ret; 1590} 1591 1592static int wm_adsp_load_coeff(struct wm_adsp *dsp) 1593{ 1594 LIST_HEAD(buf_list); 1595 struct regmap *regmap = dsp->regmap; 1596 struct wmfw_coeff_hdr *hdr; 1597 struct wmfw_coeff_item *blk; 1598 const struct firmware *firmware; 1599 const struct wm_adsp_region *mem; 1600 struct wm_adsp_alg_region *alg_region; 1601 const char *region_name; 1602 int ret, pos, blocks, type, offset, reg; 1603 char *file; 1604 struct wm_adsp_buf *buf; 1605 1606 file = kzalloc(PAGE_SIZE, GFP_KERNEL); 1607 if (file == NULL) 1608 return -ENOMEM; 1609 1610 snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num, 1611 wm_adsp_fw[dsp->fw].file); 1612 file[PAGE_SIZE - 1] = '\0'; 1613 1614 ret = request_firmware(&firmware, file, dsp->dev); 1615 if (ret != 0) { 1616 adsp_warn(dsp, "Failed to request '%s'\n", file); 1617 ret = 0; 1618 goto out; 1619 } 1620 ret = -EINVAL; 1621 1622 if (sizeof(*hdr) >= firmware->size) { 1623 adsp_err(dsp, "%s: file too short, %zu bytes\n", 1624 file, firmware->size); 1625 goto out_fw; 1626 } 1627 1628 hdr = (void*)&firmware->data[0]; 1629 if (memcmp(hdr->magic, "WMDR", 4) != 0) { 1630 adsp_err(dsp, "%s: invalid magic\n", file); 1631 goto out_fw; 1632 } 1633 1634 switch (be32_to_cpu(hdr->rev) & 0xff) { 1635 case 1: 1636 break; 1637 default: 1638 adsp_err(dsp, "%s: Unsupported coefficient file format %d\n", 1639 file, be32_to_cpu(hdr->rev) & 0xff); 1640 ret = -EINVAL; 1641 goto out_fw; 1642 } 1643 1644 adsp_dbg(dsp, "%s: v%d.%d.%d\n", file, 1645 (le32_to_cpu(hdr->ver) >> 16) & 0xff, 1646 (le32_to_cpu(hdr->ver) >> 8) & 0xff, 1647 le32_to_cpu(hdr->ver) & 0xff); 1648 1649 pos = le32_to_cpu(hdr->len); 1650 1651 blocks = 0; 1652 while (pos < firmware->size && 1653 pos - firmware->size > sizeof(*blk)) { 1654 blk = (void*)(&firmware->data[pos]); 1655 1656 type = le16_to_cpu(blk->type); 1657 offset = le16_to_cpu(blk->offset); 1658 1659 adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", 1660 file, blocks, le32_to_cpu(blk->id), 1661 (le32_to_cpu(blk->ver) >> 16) & 0xff, 1662 (le32_to_cpu(blk->ver) >> 8) & 0xff, 1663 le32_to_cpu(blk->ver) & 0xff); 1664 adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n", 1665 file, blocks, le32_to_cpu(blk->len), offset, type); 1666 1667 reg = 0; 1668 region_name = "Unknown"; 1669 switch (type) { 1670 case (WMFW_NAME_TEXT << 8): 1671 case (WMFW_INFO_TEXT << 8): 1672 break; 1673 case (WMFW_ABSOLUTE << 8): 1674 /* 1675 * Old files may use this for global 1676 * coefficients. 1677 */ 1678 if (le32_to_cpu(blk->id) == dsp->fw_id && 1679 offset == 0) { 1680 region_name = "global coefficients"; 1681 mem = wm_adsp_find_region(dsp, type); 1682 if (!mem) { 1683 adsp_err(dsp, "No ZM\n"); 1684 break; 1685 } 1686 reg = wm_adsp_region_to_reg(mem, 0); 1687 1688 } else { 1689 region_name = "register"; 1690 reg = offset; 1691 } 1692 break; 1693 1694 case WMFW_ADSP1_DM: 1695 case WMFW_ADSP1_ZM: 1696 case WMFW_ADSP2_XM: 1697 case WMFW_ADSP2_YM: 1698 adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", 1699 file, blocks, le32_to_cpu(blk->len), 1700 type, le32_to_cpu(blk->id)); 1701 1702 mem = wm_adsp_find_region(dsp, type); 1703 if (!mem) { 1704 adsp_err(dsp, "No base for region %x\n", type); 1705 break; 1706 } 1707 1708 reg = 0; 1709 list_for_each_entry(alg_region, 1710 &dsp->alg_regions, list) { 1711 if (le32_to_cpu(blk->id) == alg_region->alg && 1712 type == alg_region->type) { 1713 reg = alg_region->base; 1714 reg = wm_adsp_region_to_reg(mem, 1715 reg); 1716 reg += offset; 1717 break; 1718 } 1719 } 1720 1721 if (reg == 0) 1722 adsp_err(dsp, "No %x for algorithm %x\n", 1723 type, le32_to_cpu(blk->id)); 1724 break; 1725 1726 default: 1727 adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n", 1728 file, blocks, type, pos); 1729 break; 1730 } 1731 1732 if (reg) { 1733 buf = wm_adsp_buf_alloc(blk->data, 1734 le32_to_cpu(blk->len), 1735 &buf_list); 1736 if (!buf) { 1737 adsp_err(dsp, "Out of memory\n"); 1738 ret = -ENOMEM; 1739 goto out_fw; 1740 } 1741 1742 adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", 1743 file, blocks, le32_to_cpu(blk->len), 1744 reg); 1745 ret = regmap_raw_write_async(regmap, reg, buf->buf, 1746 le32_to_cpu(blk->len)); 1747 if (ret != 0) { 1748 adsp_err(dsp, 1749 "%s.%d: Failed to write to %x in %s: %d\n", 1750 file, blocks, reg, region_name, ret); 1751 } 1752 } 1753 1754 pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03; 1755 blocks++; 1756 } 1757 1758 ret = regmap_async_complete(regmap); 1759 if (ret != 0) 1760 adsp_err(dsp, "Failed to complete async write: %d\n", ret); 1761 1762 if (pos > firmware->size) 1763 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 1764 file, blocks, pos - firmware->size); 1765 1766 wm_adsp_debugfs_save_binname(dsp, file); 1767 1768out_fw: 1769 regmap_async_complete(regmap); 1770 release_firmware(firmware); 1771 wm_adsp_buf_free(&buf_list); 1772out: 1773 kfree(file); 1774 return ret; 1775} 1776 1777int wm_adsp1_init(struct wm_adsp *dsp) 1778{ 1779 INIT_LIST_HEAD(&dsp->alg_regions); 1780 1781#ifdef CONFIG_DEBUG_FS 1782 mutex_init(&dsp->debugfs_lock); 1783#endif 1784 return 0; 1785} 1786EXPORT_SYMBOL_GPL(wm_adsp1_init); 1787 1788int wm_adsp1_event(struct snd_soc_dapm_widget *w, 1789 struct snd_kcontrol *kcontrol, 1790 int event) 1791{ 1792 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 1793 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); 1794 struct wm_adsp *dsp = &dsps[w->shift]; 1795 struct wm_adsp_alg_region *alg_region; 1796 struct wm_coeff_ctl *ctl; 1797 int ret; 1798 int val; 1799 1800 dsp->card = codec->component.card; 1801 1802 switch (event) { 1803 case SND_SOC_DAPM_POST_PMU: 1804 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1805 ADSP1_SYS_ENA, ADSP1_SYS_ENA); 1806 1807 /* 1808 * For simplicity set the DSP clock rate to be the 1809 * SYSCLK rate rather than making it configurable. 1810 */ 1811 if(dsp->sysclk_reg) { 1812 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); 1813 if (ret != 0) { 1814 adsp_err(dsp, "Failed to read SYSCLK state: %d\n", 1815 ret); 1816 return ret; 1817 } 1818 1819 val = (val & dsp->sysclk_mask) 1820 >> dsp->sysclk_shift; 1821 1822 ret = regmap_update_bits(dsp->regmap, 1823 dsp->base + ADSP1_CONTROL_31, 1824 ADSP1_CLK_SEL_MASK, val); 1825 if (ret != 0) { 1826 adsp_err(dsp, "Failed to set clock rate: %d\n", 1827 ret); 1828 return ret; 1829 } 1830 } 1831 1832 ret = wm_adsp_load(dsp); 1833 if (ret != 0) 1834 goto err; 1835 1836 ret = wm_adsp1_setup_algs(dsp); 1837 if (ret != 0) 1838 goto err; 1839 1840 ret = wm_adsp_load_coeff(dsp); 1841 if (ret != 0) 1842 goto err; 1843 1844 /* Initialize caches for enabled and unset controls */ 1845 ret = wm_coeff_init_control_caches(dsp); 1846 if (ret != 0) 1847 goto err; 1848 1849 /* Sync set controls */ 1850 ret = wm_coeff_sync_controls(dsp); 1851 if (ret != 0) 1852 goto err; 1853 1854 /* Start the core running */ 1855 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1856 ADSP1_CORE_ENA | ADSP1_START, 1857 ADSP1_CORE_ENA | ADSP1_START); 1858 break; 1859 1860 case SND_SOC_DAPM_PRE_PMD: 1861 /* Halt the core */ 1862 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1863 ADSP1_CORE_ENA | ADSP1_START, 0); 1864 1865 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, 1866 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0); 1867 1868 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1869 ADSP1_SYS_ENA, 0); 1870 1871 list_for_each_entry(ctl, &dsp->ctl_list, list) 1872 ctl->enabled = 0; 1873 1874 while (!list_empty(&dsp->alg_regions)) { 1875 alg_region = list_first_entry(&dsp->alg_regions, 1876 struct wm_adsp_alg_region, 1877 list); 1878 list_del(&alg_region->list); 1879 kfree(alg_region); 1880 } 1881 break; 1882 1883 default: 1884 break; 1885 } 1886 1887 return 0; 1888 1889err: 1890 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1891 ADSP1_SYS_ENA, 0); 1892 return ret; 1893} 1894EXPORT_SYMBOL_GPL(wm_adsp1_event); 1895 1896static int wm_adsp2_ena(struct wm_adsp *dsp) 1897{ 1898 unsigned int val; 1899 int ret, count; 1900 1901 ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL, 1902 ADSP2_SYS_ENA, ADSP2_SYS_ENA); 1903 if (ret != 0) 1904 return ret; 1905 1906 /* Wait for the RAM to start, should be near instantaneous */ 1907 for (count = 0; count < 10; ++count) { 1908 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, 1909 &val); 1910 if (ret != 0) 1911 return ret; 1912 1913 if (val & ADSP2_RAM_RDY) 1914 break; 1915 1916 msleep(1); 1917 } 1918 1919 if (!(val & ADSP2_RAM_RDY)) { 1920 adsp_err(dsp, "Failed to start DSP RAM\n"); 1921 return -EBUSY; 1922 } 1923 1924 adsp_dbg(dsp, "RAM ready after %d polls\n", count); 1925 1926 return 0; 1927} 1928 1929static void wm_adsp2_boot_work(struct work_struct *work) 1930{ 1931 struct wm_adsp *dsp = container_of(work, 1932 struct wm_adsp, 1933 boot_work); 1934 int ret; 1935 unsigned int val; 1936 1937 /* 1938 * For simplicity set the DSP clock rate to be the 1939 * SYSCLK rate rather than making it configurable. 1940 */ 1941 ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val); 1942 if (ret != 0) { 1943 adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); 1944 return; 1945 } 1946 val = (val & ARIZONA_SYSCLK_FREQ_MASK) 1947 >> ARIZONA_SYSCLK_FREQ_SHIFT; 1948 1949 ret = regmap_update_bits_async(dsp->regmap, 1950 dsp->base + ADSP2_CLOCKING, 1951 ADSP2_CLK_SEL_MASK, val); 1952 if (ret != 0) { 1953 adsp_err(dsp, "Failed to set clock rate: %d\n", ret); 1954 return; 1955 } 1956 1957 ret = wm_adsp2_ena(dsp); 1958 if (ret != 0) 1959 return; 1960 1961 ret = wm_adsp_load(dsp); 1962 if (ret != 0) 1963 goto err; 1964 1965 ret = wm_adsp2_setup_algs(dsp); 1966 if (ret != 0) 1967 goto err; 1968 1969 ret = wm_adsp_load_coeff(dsp); 1970 if (ret != 0) 1971 goto err; 1972 1973 /* Initialize caches for enabled and unset controls */ 1974 ret = wm_coeff_init_control_caches(dsp); 1975 if (ret != 0) 1976 goto err; 1977 1978 /* Sync set controls */ 1979 ret = wm_coeff_sync_controls(dsp); 1980 if (ret != 0) 1981 goto err; 1982 1983 dsp->running = true; 1984 1985 return; 1986 1987err: 1988 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 1989 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); 1990} 1991 1992int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, 1993 struct snd_kcontrol *kcontrol, int event) 1994{ 1995 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 1996 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); 1997 struct wm_adsp *dsp = &dsps[w->shift]; 1998 1999 dsp->card = codec->component.card; 2000 2001 switch (event) { 2002 case SND_SOC_DAPM_PRE_PMU: 2003 queue_work(system_unbound_wq, &dsp->boot_work); 2004 break; 2005 default: 2006 break; 2007 } 2008 2009 return 0; 2010} 2011EXPORT_SYMBOL_GPL(wm_adsp2_early_event); 2012 2013int wm_adsp2_event(struct snd_soc_dapm_widget *w, 2014 struct snd_kcontrol *kcontrol, int event) 2015{ 2016 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 2017 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); 2018 struct wm_adsp *dsp = &dsps[w->shift]; 2019 struct wm_adsp_alg_region *alg_region; 2020 struct wm_coeff_ctl *ctl; 2021 int ret; 2022 2023 switch (event) { 2024 case SND_SOC_DAPM_POST_PMU: 2025 flush_work(&dsp->boot_work); 2026 2027 if (!dsp->running) 2028 return -EIO; 2029 2030 ret = regmap_update_bits(dsp->regmap, 2031 dsp->base + ADSP2_CONTROL, 2032 ADSP2_CORE_ENA | ADSP2_START, 2033 ADSP2_CORE_ENA | ADSP2_START); 2034 if (ret != 0) 2035 goto err; 2036 break; 2037 2038 case SND_SOC_DAPM_PRE_PMD: 2039 /* Log firmware state, it can be useful for analysis */ 2040 wm_adsp2_show_fw_status(dsp); 2041 2042 wm_adsp_debugfs_clear(dsp); 2043 2044 dsp->fw_id = 0; 2045 dsp->fw_id_version = 0; 2046 dsp->running = false; 2047 2048 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2049 ADSP2_SYS_ENA | ADSP2_CORE_ENA | 2050 ADSP2_START, 0); 2051 2052 /* Make sure DMAs are quiesced */ 2053 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); 2054 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); 2055 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); 2056 2057 list_for_each_entry(ctl, &dsp->ctl_list, list) 2058 ctl->enabled = 0; 2059 2060 while (!list_empty(&dsp->alg_regions)) { 2061 alg_region = list_first_entry(&dsp->alg_regions, 2062 struct wm_adsp_alg_region, 2063 list); 2064 list_del(&alg_region->list); 2065 kfree(alg_region); 2066 } 2067 2068 adsp_dbg(dsp, "Shutdown complete\n"); 2069 break; 2070 2071 default: 2072 break; 2073 } 2074 2075 return 0; 2076err: 2077 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2078 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); 2079 return ret; 2080} 2081EXPORT_SYMBOL_GPL(wm_adsp2_event); 2082 2083int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec) 2084{ 2085 wm_adsp2_init_debugfs(dsp, codec); 2086 2087 return snd_soc_add_codec_controls(codec, 2088 &wm_adsp_fw_controls[dsp->num - 1], 2089 1); 2090} 2091EXPORT_SYMBOL_GPL(wm_adsp2_codec_probe); 2092 2093int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec) 2094{ 2095 wm_adsp2_cleanup_debugfs(dsp); 2096 2097 return 0; 2098} 2099EXPORT_SYMBOL_GPL(wm_adsp2_codec_remove); 2100 2101int wm_adsp2_init(struct wm_adsp *dsp) 2102{ 2103 int ret; 2104 2105 /* 2106 * Disable the DSP memory by default when in reset for a small 2107 * power saving. 2108 */ 2109 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2110 ADSP2_MEM_ENA, 0); 2111 if (ret != 0) { 2112 adsp_err(dsp, "Failed to clear memory retention: %d\n", ret); 2113 return ret; 2114 } 2115 2116 INIT_LIST_HEAD(&dsp->alg_regions); 2117 INIT_LIST_HEAD(&dsp->ctl_list); 2118 INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work); 2119 2120#ifdef CONFIG_DEBUG_FS 2121 mutex_init(&dsp->debugfs_lock); 2122#endif 2123 return 0; 2124} 2125EXPORT_SYMBOL_GPL(wm_adsp2_init); 2126 2127MODULE_LICENSE("GPL v2"); 2128