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 <sound/core.h> 27#include <sound/pcm.h> 28#include <sound/pcm_params.h> 29#include <sound/soc.h> 30#include <sound/jack.h> 31#include <sound/initval.h> 32#include <sound/tlv.h> 33 34#include <linux/mfd/arizona/registers.h> 35 36#include "arizona.h" 37#include "wm_adsp.h" 38 39#define adsp_crit(_dsp, fmt, ...) \ 40 dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 41#define adsp_err(_dsp, fmt, ...) \ 42 dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 43#define adsp_warn(_dsp, fmt, ...) \ 44 dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 45#define adsp_info(_dsp, fmt, ...) \ 46 dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 47#define adsp_dbg(_dsp, fmt, ...) \ 48 dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 49 50#define ADSP1_CONTROL_1 0x00 51#define ADSP1_CONTROL_2 0x02 52#define ADSP1_CONTROL_3 0x03 53#define ADSP1_CONTROL_4 0x04 54#define ADSP1_CONTROL_5 0x06 55#define ADSP1_CONTROL_6 0x07 56#define ADSP1_CONTROL_7 0x08 57#define ADSP1_CONTROL_8 0x09 58#define ADSP1_CONTROL_9 0x0A 59#define ADSP1_CONTROL_10 0x0B 60#define ADSP1_CONTROL_11 0x0C 61#define ADSP1_CONTROL_12 0x0D 62#define ADSP1_CONTROL_13 0x0F 63#define ADSP1_CONTROL_14 0x10 64#define ADSP1_CONTROL_15 0x11 65#define ADSP1_CONTROL_16 0x12 66#define ADSP1_CONTROL_17 0x13 67#define ADSP1_CONTROL_18 0x14 68#define ADSP1_CONTROL_19 0x16 69#define ADSP1_CONTROL_20 0x17 70#define ADSP1_CONTROL_21 0x18 71#define ADSP1_CONTROL_22 0x1A 72#define ADSP1_CONTROL_23 0x1B 73#define ADSP1_CONTROL_24 0x1C 74#define ADSP1_CONTROL_25 0x1E 75#define ADSP1_CONTROL_26 0x20 76#define ADSP1_CONTROL_27 0x21 77#define ADSP1_CONTROL_28 0x22 78#define ADSP1_CONTROL_29 0x23 79#define ADSP1_CONTROL_30 0x24 80#define ADSP1_CONTROL_31 0x26 81 82/* 83 * ADSP1 Control 19 84 */ 85#define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ 86#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ 87#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ 88 89 90/* 91 * ADSP1 Control 30 92 */ 93#define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */ 94#define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */ 95#define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */ 96#define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */ 97#define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ 98#define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ 99#define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ 100#define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ 101#define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ 102#define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ 103#define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ 104#define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ 105#define ADSP1_START 0x0001 /* DSP1_START */ 106#define ADSP1_START_MASK 0x0001 /* DSP1_START */ 107#define ADSP1_START_SHIFT 0 /* DSP1_START */ 108#define ADSP1_START_WIDTH 1 /* DSP1_START */ 109 110/* 111 * ADSP1 Control 31 112 */ 113#define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */ 114#define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ 115#define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ 116 117#define ADSP2_CONTROL 0x0 118#define ADSP2_CLOCKING 0x1 119#define ADSP2_STATUS1 0x4 120#define ADSP2_WDMA_CONFIG_1 0x30 121#define ADSP2_WDMA_CONFIG_2 0x31 122#define ADSP2_RDMA_CONFIG_1 0x34 123 124/* 125 * ADSP2 Control 126 */ 127 128#define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */ 129#define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */ 130#define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */ 131#define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */ 132#define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ 133#define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ 134#define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ 135#define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ 136#define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ 137#define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ 138#define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ 139#define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ 140#define ADSP2_START 0x0001 /* DSP1_START */ 141#define ADSP2_START_MASK 0x0001 /* DSP1_START */ 142#define ADSP2_START_SHIFT 0 /* DSP1_START */ 143#define ADSP2_START_WIDTH 1 /* DSP1_START */ 144 145/* 146 * ADSP2 clocking 147 */ 148#define ADSP2_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */ 149#define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ 150#define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ 151 152/* 153 * ADSP2 Status 1 154 */ 155#define ADSP2_RAM_RDY 0x0001 156#define ADSP2_RAM_RDY_MASK 0x0001 157#define ADSP2_RAM_RDY_SHIFT 0 158#define ADSP2_RAM_RDY_WIDTH 1 159 160struct wm_adsp_buf { 161 struct list_head list; 162 void *buf; 163}; 164 165static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len, 166 struct list_head *list) 167{ 168 struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL); 169 170 if (buf == NULL) 171 return NULL; 172 173 buf->buf = vmalloc(len); 174 if (!buf->buf) { 175 vfree(buf); 176 return NULL; 177 } 178 memcpy(buf->buf, src, len); 179 180 if (list) 181 list_add_tail(&buf->list, list); 182 183 return buf; 184} 185 186static void wm_adsp_buf_free(struct list_head *list) 187{ 188 while (!list_empty(list)) { 189 struct wm_adsp_buf *buf = list_first_entry(list, 190 struct wm_adsp_buf, 191 list); 192 list_del(&buf->list); 193 vfree(buf->buf); 194 kfree(buf); 195 } 196} 197 198#define WM_ADSP_NUM_FW 4 199 200#define WM_ADSP_FW_MBC_VSS 0 201#define WM_ADSP_FW_TX 1 202#define WM_ADSP_FW_TX_SPK 2 203#define WM_ADSP_FW_RX_ANC 3 204 205static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { 206 [WM_ADSP_FW_MBC_VSS] = "MBC/VSS", 207 [WM_ADSP_FW_TX] = "Tx", 208 [WM_ADSP_FW_TX_SPK] = "Tx Speaker", 209 [WM_ADSP_FW_RX_ANC] = "Rx ANC", 210}; 211 212static struct { 213 const char *file; 214} wm_adsp_fw[WM_ADSP_NUM_FW] = { 215 [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" }, 216 [WM_ADSP_FW_TX] = { .file = "tx" }, 217 [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" }, 218 [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, 219}; 220 221struct wm_coeff_ctl_ops { 222 int (*xget)(struct snd_kcontrol *kcontrol, 223 struct snd_ctl_elem_value *ucontrol); 224 int (*xput)(struct snd_kcontrol *kcontrol, 225 struct snd_ctl_elem_value *ucontrol); 226 int (*xinfo)(struct snd_kcontrol *kcontrol, 227 struct snd_ctl_elem_info *uinfo); 228}; 229 230struct wm_coeff_ctl { 231 const char *name; 232 struct wm_adsp_alg_region region; 233 struct wm_coeff_ctl_ops ops; 234 struct wm_adsp *adsp; 235 void *private; 236 unsigned int enabled:1; 237 struct list_head list; 238 void *cache; 239 size_t len; 240 unsigned int set:1; 241 struct snd_kcontrol *kcontrol; 242}; 243 244static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, 245 struct snd_ctl_elem_value *ucontrol) 246{ 247 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 248 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 249 struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); 250 251 ucontrol->value.enumerated.item[0] = adsp[e->shift_l].fw; 252 253 return 0; 254} 255 256static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, 257 struct snd_ctl_elem_value *ucontrol) 258{ 259 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 260 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 261 struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); 262 263 if (ucontrol->value.enumerated.item[0] == adsp[e->shift_l].fw) 264 return 0; 265 266 if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW) 267 return -EINVAL; 268 269 if (adsp[e->shift_l].running) 270 return -EBUSY; 271 272 adsp[e->shift_l].fw = ucontrol->value.enumerated.item[0]; 273 274 return 0; 275} 276 277static const struct soc_enum wm_adsp_fw_enum[] = { 278 SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), 279 SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), 280 SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), 281 SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), 282}; 283 284const struct snd_kcontrol_new wm_adsp1_fw_controls[] = { 285 SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], 286 wm_adsp_fw_get, wm_adsp_fw_put), 287 SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], 288 wm_adsp_fw_get, wm_adsp_fw_put), 289 SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], 290 wm_adsp_fw_get, wm_adsp_fw_put), 291}; 292EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls); 293 294#if IS_ENABLED(CONFIG_SND_SOC_ARIZONA) 295static const struct soc_enum wm_adsp2_rate_enum[] = { 296 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1, 297 ARIZONA_DSP1_RATE_SHIFT, 0xf, 298 ARIZONA_RATE_ENUM_SIZE, 299 arizona_rate_text, arizona_rate_val), 300 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1, 301 ARIZONA_DSP1_RATE_SHIFT, 0xf, 302 ARIZONA_RATE_ENUM_SIZE, 303 arizona_rate_text, arizona_rate_val), 304 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1, 305 ARIZONA_DSP1_RATE_SHIFT, 0xf, 306 ARIZONA_RATE_ENUM_SIZE, 307 arizona_rate_text, arizona_rate_val), 308 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1, 309 ARIZONA_DSP1_RATE_SHIFT, 0xf, 310 ARIZONA_RATE_ENUM_SIZE, 311 arizona_rate_text, arizona_rate_val), 312}; 313 314const struct snd_kcontrol_new wm_adsp2_fw_controls[] = { 315 SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], 316 wm_adsp_fw_get, wm_adsp_fw_put), 317 SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]), 318 SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], 319 wm_adsp_fw_get, wm_adsp_fw_put), 320 SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]), 321 SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], 322 wm_adsp_fw_get, wm_adsp_fw_put), 323 SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]), 324 SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], 325 wm_adsp_fw_get, wm_adsp_fw_put), 326 SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]), 327}; 328EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls); 329#endif 330 331static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, 332 int type) 333{ 334 int i; 335 336 for (i = 0; i < dsp->num_mems; i++) 337 if (dsp->mem[i].type == type) 338 return &dsp->mem[i]; 339 340 return NULL; 341} 342 343static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region, 344 unsigned int offset) 345{ 346 if (WARN_ON(!region)) 347 return offset; 348 switch (region->type) { 349 case WMFW_ADSP1_PM: 350 return region->base + (offset * 3); 351 case WMFW_ADSP1_DM: 352 return region->base + (offset * 2); 353 case WMFW_ADSP2_XM: 354 return region->base + (offset * 2); 355 case WMFW_ADSP2_YM: 356 return region->base + (offset * 2); 357 case WMFW_ADSP1_ZM: 358 return region->base + (offset * 2); 359 default: 360 WARN(1, "Unknown memory region type"); 361 return offset; 362 } 363} 364 365static int wm_coeff_info(struct snd_kcontrol *kcontrol, 366 struct snd_ctl_elem_info *uinfo) 367{ 368 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; 369 370 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; 371 uinfo->count = ctl->len; 372 return 0; 373} 374 375static int wm_coeff_write_control(struct snd_kcontrol *kcontrol, 376 const void *buf, size_t len) 377{ 378 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; 379 struct wm_adsp_alg_region *region = &ctl->region; 380 const struct wm_adsp_region *mem; 381 struct wm_adsp *adsp = ctl->adsp; 382 void *scratch; 383 int ret; 384 unsigned int reg; 385 386 mem = wm_adsp_find_region(adsp, region->type); 387 if (!mem) { 388 adsp_err(adsp, "No base for region %x\n", 389 region->type); 390 return -EINVAL; 391 } 392 393 reg = ctl->region.base; 394 reg = wm_adsp_region_to_reg(mem, reg); 395 396 scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA); 397 if (!scratch) 398 return -ENOMEM; 399 400 ret = regmap_raw_write(adsp->regmap, reg, scratch, 401 ctl->len); 402 if (ret) { 403 adsp_err(adsp, "Failed to write %zu bytes to %x: %d\n", 404 ctl->len, reg, ret); 405 kfree(scratch); 406 return ret; 407 } 408 adsp_dbg(adsp, "Wrote %zu bytes to %x\n", ctl->len, reg); 409 410 kfree(scratch); 411 412 return 0; 413} 414 415static int wm_coeff_put(struct snd_kcontrol *kcontrol, 416 struct snd_ctl_elem_value *ucontrol) 417{ 418 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; 419 char *p = ucontrol->value.bytes.data; 420 421 memcpy(ctl->cache, p, ctl->len); 422 423 ctl->set = 1; 424 if (!ctl->enabled) 425 return 0; 426 427 return wm_coeff_write_control(kcontrol, p, ctl->len); 428} 429 430static int wm_coeff_read_control(struct snd_kcontrol *kcontrol, 431 void *buf, size_t len) 432{ 433 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; 434 struct wm_adsp_alg_region *region = &ctl->region; 435 const struct wm_adsp_region *mem; 436 struct wm_adsp *adsp = ctl->adsp; 437 void *scratch; 438 int ret; 439 unsigned int reg; 440 441 mem = wm_adsp_find_region(adsp, region->type); 442 if (!mem) { 443 adsp_err(adsp, "No base for region %x\n", 444 region->type); 445 return -EINVAL; 446 } 447 448 reg = ctl->region.base; 449 reg = wm_adsp_region_to_reg(mem, reg); 450 451 scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA); 452 if (!scratch) 453 return -ENOMEM; 454 455 ret = regmap_raw_read(adsp->regmap, reg, scratch, ctl->len); 456 if (ret) { 457 adsp_err(adsp, "Failed to read %zu bytes from %x: %d\n", 458 ctl->len, reg, ret); 459 kfree(scratch); 460 return ret; 461 } 462 adsp_dbg(adsp, "Read %zu bytes from %x\n", ctl->len, reg); 463 464 memcpy(buf, scratch, ctl->len); 465 kfree(scratch); 466 467 return 0; 468} 469 470static int wm_coeff_get(struct snd_kcontrol *kcontrol, 471 struct snd_ctl_elem_value *ucontrol) 472{ 473 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; 474 char *p = ucontrol->value.bytes.data; 475 476 memcpy(p, ctl->cache, ctl->len); 477 return 0; 478} 479 480struct wmfw_ctl_work { 481 struct wm_adsp *adsp; 482 struct wm_coeff_ctl *ctl; 483 struct work_struct work; 484}; 485 486static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl) 487{ 488 struct snd_kcontrol_new *kcontrol; 489 int ret; 490 491 if (!ctl || !ctl->name) 492 return -EINVAL; 493 494 kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL); 495 if (!kcontrol) 496 return -ENOMEM; 497 kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER; 498 499 kcontrol->name = ctl->name; 500 kcontrol->info = wm_coeff_info; 501 kcontrol->get = wm_coeff_get; 502 kcontrol->put = wm_coeff_put; 503 kcontrol->private_value = (unsigned long)ctl; 504 505 ret = snd_soc_add_card_controls(adsp->card, 506 kcontrol, 1); 507 if (ret < 0) 508 goto err_kcontrol; 509 510 kfree(kcontrol); 511 512 ctl->kcontrol = snd_soc_card_get_kcontrol(adsp->card, 513 ctl->name); 514 515 list_add(&ctl->list, &adsp->ctl_list); 516 return 0; 517 518err_kcontrol: 519 kfree(kcontrol); 520 return ret; 521} 522 523static int wm_adsp_load(struct wm_adsp *dsp) 524{ 525 LIST_HEAD(buf_list); 526 const struct firmware *firmware; 527 struct regmap *regmap = dsp->regmap; 528 unsigned int pos = 0; 529 const struct wmfw_header *header; 530 const struct wmfw_adsp1_sizes *adsp1_sizes; 531 const struct wmfw_adsp2_sizes *adsp2_sizes; 532 const struct wmfw_footer *footer; 533 const struct wmfw_region *region; 534 const struct wm_adsp_region *mem; 535 const char *region_name; 536 char *file, *text; 537 struct wm_adsp_buf *buf; 538 unsigned int reg; 539 int regions = 0; 540 int ret, offset, type, sizes; 541 542 file = kzalloc(PAGE_SIZE, GFP_KERNEL); 543 if (file == NULL) 544 return -ENOMEM; 545 546 snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num, 547 wm_adsp_fw[dsp->fw].file); 548 file[PAGE_SIZE - 1] = '\0'; 549 550 ret = request_firmware(&firmware, file, dsp->dev); 551 if (ret != 0) { 552 adsp_err(dsp, "Failed to request '%s'\n", file); 553 goto out; 554 } 555 ret = -EINVAL; 556 557 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); 558 if (pos >= firmware->size) { 559 adsp_err(dsp, "%s: file too short, %zu bytes\n", 560 file, firmware->size); 561 goto out_fw; 562 } 563 564 header = (void*)&firmware->data[0]; 565 566 if (memcmp(&header->magic[0], "WMFW", 4) != 0) { 567 adsp_err(dsp, "%s: invalid magic\n", file); 568 goto out_fw; 569 } 570 571 if (header->ver != 0) { 572 adsp_err(dsp, "%s: unknown file format %d\n", 573 file, header->ver); 574 goto out_fw; 575 } 576 adsp_info(dsp, "Firmware version: %d\n", header->ver); 577 578 if (header->core != dsp->type) { 579 adsp_err(dsp, "%s: invalid core %d != %d\n", 580 file, header->core, dsp->type); 581 goto out_fw; 582 } 583 584 switch (dsp->type) { 585 case WMFW_ADSP1: 586 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); 587 adsp1_sizes = (void *)&(header[1]); 588 footer = (void *)&(adsp1_sizes[1]); 589 sizes = sizeof(*adsp1_sizes); 590 591 adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", 592 file, le32_to_cpu(adsp1_sizes->dm), 593 le32_to_cpu(adsp1_sizes->pm), 594 le32_to_cpu(adsp1_sizes->zm)); 595 break; 596 597 case WMFW_ADSP2: 598 pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer); 599 adsp2_sizes = (void *)&(header[1]); 600 footer = (void *)&(adsp2_sizes[1]); 601 sizes = sizeof(*adsp2_sizes); 602 603 adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", 604 file, le32_to_cpu(adsp2_sizes->xm), 605 le32_to_cpu(adsp2_sizes->ym), 606 le32_to_cpu(adsp2_sizes->pm), 607 le32_to_cpu(adsp2_sizes->zm)); 608 break; 609 610 default: 611 WARN(1, "Unknown DSP type"); 612 goto out_fw; 613 } 614 615 if (le32_to_cpu(header->len) != sizeof(*header) + 616 sizes + sizeof(*footer)) { 617 adsp_err(dsp, "%s: unexpected header length %d\n", 618 file, le32_to_cpu(header->len)); 619 goto out_fw; 620 } 621 622 adsp_dbg(dsp, "%s: timestamp %llu\n", file, 623 le64_to_cpu(footer->timestamp)); 624 625 while (pos < firmware->size && 626 pos - firmware->size > sizeof(*region)) { 627 region = (void *)&(firmware->data[pos]); 628 region_name = "Unknown"; 629 reg = 0; 630 text = NULL; 631 offset = le32_to_cpu(region->offset) & 0xffffff; 632 type = be32_to_cpu(region->type) & 0xff; 633 mem = wm_adsp_find_region(dsp, type); 634 635 switch (type) { 636 case WMFW_NAME_TEXT: 637 region_name = "Firmware name"; 638 text = kzalloc(le32_to_cpu(region->len) + 1, 639 GFP_KERNEL); 640 break; 641 case WMFW_INFO_TEXT: 642 region_name = "Information"; 643 text = kzalloc(le32_to_cpu(region->len) + 1, 644 GFP_KERNEL); 645 break; 646 case WMFW_ABSOLUTE: 647 region_name = "Absolute"; 648 reg = offset; 649 break; 650 case WMFW_ADSP1_PM: 651 region_name = "PM"; 652 reg = wm_adsp_region_to_reg(mem, offset); 653 break; 654 case WMFW_ADSP1_DM: 655 region_name = "DM"; 656 reg = wm_adsp_region_to_reg(mem, offset); 657 break; 658 case WMFW_ADSP2_XM: 659 region_name = "XM"; 660 reg = wm_adsp_region_to_reg(mem, offset); 661 break; 662 case WMFW_ADSP2_YM: 663 region_name = "YM"; 664 reg = wm_adsp_region_to_reg(mem, offset); 665 break; 666 case WMFW_ADSP1_ZM: 667 region_name = "ZM"; 668 reg = wm_adsp_region_to_reg(mem, offset); 669 break; 670 default: 671 adsp_warn(dsp, 672 "%s.%d: Unknown region type %x at %d(%x)\n", 673 file, regions, type, pos, pos); 674 break; 675 } 676 677 adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file, 678 regions, le32_to_cpu(region->len), offset, 679 region_name); 680 681 if (text) { 682 memcpy(text, region->data, le32_to_cpu(region->len)); 683 adsp_info(dsp, "%s: %s\n", file, text); 684 kfree(text); 685 } 686 687 if (reg) { 688 buf = wm_adsp_buf_alloc(region->data, 689 le32_to_cpu(region->len), 690 &buf_list); 691 if (!buf) { 692 adsp_err(dsp, "Out of memory\n"); 693 ret = -ENOMEM; 694 goto out_fw; 695 } 696 697 ret = regmap_raw_write_async(regmap, reg, buf->buf, 698 le32_to_cpu(region->len)); 699 if (ret != 0) { 700 adsp_err(dsp, 701 "%s.%d: Failed to write %d bytes at %d in %s: %d\n", 702 file, regions, 703 le32_to_cpu(region->len), offset, 704 region_name, ret); 705 goto out_fw; 706 } 707 } 708 709 pos += le32_to_cpu(region->len) + sizeof(*region); 710 regions++; 711 } 712 713 ret = regmap_async_complete(regmap); 714 if (ret != 0) { 715 adsp_err(dsp, "Failed to complete async write: %d\n", ret); 716 goto out_fw; 717 } 718 719 if (pos > firmware->size) 720 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 721 file, regions, pos - firmware->size); 722 723out_fw: 724 regmap_async_complete(regmap); 725 wm_adsp_buf_free(&buf_list); 726 release_firmware(firmware); 727out: 728 kfree(file); 729 730 return ret; 731} 732 733static int wm_coeff_init_control_caches(struct wm_adsp *adsp) 734{ 735 struct wm_coeff_ctl *ctl; 736 int ret; 737 738 list_for_each_entry(ctl, &adsp->ctl_list, list) { 739 if (!ctl->enabled || ctl->set) 740 continue; 741 ret = wm_coeff_read_control(ctl->kcontrol, 742 ctl->cache, 743 ctl->len); 744 if (ret < 0) 745 return ret; 746 } 747 748 return 0; 749} 750 751static int wm_coeff_sync_controls(struct wm_adsp *adsp) 752{ 753 struct wm_coeff_ctl *ctl; 754 int ret; 755 756 list_for_each_entry(ctl, &adsp->ctl_list, list) { 757 if (!ctl->enabled) 758 continue; 759 if (ctl->set) { 760 ret = wm_coeff_write_control(ctl->kcontrol, 761 ctl->cache, 762 ctl->len); 763 if (ret < 0) 764 return ret; 765 } 766 } 767 768 return 0; 769} 770 771static void wm_adsp_ctl_work(struct work_struct *work) 772{ 773 struct wmfw_ctl_work *ctl_work = container_of(work, 774 struct wmfw_ctl_work, 775 work); 776 777 wmfw_add_ctl(ctl_work->adsp, ctl_work->ctl); 778 kfree(ctl_work); 779} 780 781static int wm_adsp_create_control(struct wm_adsp *dsp, 782 const struct wm_adsp_alg_region *region) 783 784{ 785 struct wm_coeff_ctl *ctl; 786 struct wmfw_ctl_work *ctl_work; 787 char *name; 788 char *region_name; 789 int ret; 790 791 name = kmalloc(PAGE_SIZE, GFP_KERNEL); 792 if (!name) 793 return -ENOMEM; 794 795 switch (region->type) { 796 case WMFW_ADSP1_PM: 797 region_name = "PM"; 798 break; 799 case WMFW_ADSP1_DM: 800 region_name = "DM"; 801 break; 802 case WMFW_ADSP2_XM: 803 region_name = "XM"; 804 break; 805 case WMFW_ADSP2_YM: 806 region_name = "YM"; 807 break; 808 case WMFW_ADSP1_ZM: 809 region_name = "ZM"; 810 break; 811 default: 812 ret = -EINVAL; 813 goto err_name; 814 } 815 816 snprintf(name, PAGE_SIZE, "DSP%d %s %x", 817 dsp->num, region_name, region->alg); 818 819 list_for_each_entry(ctl, &dsp->ctl_list, 820 list) { 821 if (!strcmp(ctl->name, name)) { 822 if (!ctl->enabled) 823 ctl->enabled = 1; 824 goto found; 825 } 826 } 827 828 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); 829 if (!ctl) { 830 ret = -ENOMEM; 831 goto err_name; 832 } 833 ctl->region = *region; 834 ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL); 835 if (!ctl->name) { 836 ret = -ENOMEM; 837 goto err_ctl; 838 } 839 ctl->enabled = 1; 840 ctl->set = 0; 841 ctl->ops.xget = wm_coeff_get; 842 ctl->ops.xput = wm_coeff_put; 843 ctl->adsp = dsp; 844 845 ctl->len = region->len; 846 ctl->cache = kzalloc(ctl->len, GFP_KERNEL); 847 if (!ctl->cache) { 848 ret = -ENOMEM; 849 goto err_ctl_name; 850 } 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->adsp = dsp; 859 ctl_work->ctl = ctl; 860 INIT_WORK(&ctl_work->work, wm_adsp_ctl_work); 861 schedule_work(&ctl_work->work); 862 863found: 864 kfree(name); 865 866 return 0; 867 868err_ctl_cache: 869 kfree(ctl->cache); 870err_ctl_name: 871 kfree(ctl->name); 872err_ctl: 873 kfree(ctl); 874err_name: 875 kfree(name); 876 return ret; 877} 878 879static int wm_adsp_setup_algs(struct wm_adsp *dsp) 880{ 881 struct regmap *regmap = dsp->regmap; 882 struct wmfw_adsp1_id_hdr adsp1_id; 883 struct wmfw_adsp2_id_hdr adsp2_id; 884 struct wmfw_adsp1_alg_hdr *adsp1_alg; 885 struct wmfw_adsp2_alg_hdr *adsp2_alg; 886 void *alg, *buf; 887 struct wm_adsp_alg_region *region; 888 const struct wm_adsp_region *mem; 889 unsigned int pos, term; 890 size_t algs, buf_size; 891 __be32 val; 892 int i, ret; 893 894 switch (dsp->type) { 895 case WMFW_ADSP1: 896 mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM); 897 break; 898 case WMFW_ADSP2: 899 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); 900 break; 901 default: 902 mem = NULL; 903 break; 904 } 905 906 if (WARN_ON(!mem)) 907 return -EINVAL; 908 909 switch (dsp->type) { 910 case WMFW_ADSP1: 911 ret = regmap_raw_read(regmap, mem->base, &adsp1_id, 912 sizeof(adsp1_id)); 913 if (ret != 0) { 914 adsp_err(dsp, "Failed to read algorithm info: %d\n", 915 ret); 916 return ret; 917 } 918 919 buf = &adsp1_id; 920 buf_size = sizeof(adsp1_id); 921 922 algs = be32_to_cpu(adsp1_id.algs); 923 dsp->fw_id = be32_to_cpu(adsp1_id.fw.id); 924 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", 925 dsp->fw_id, 926 (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16, 927 (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8, 928 be32_to_cpu(adsp1_id.fw.ver) & 0xff, 929 algs); 930 931 region = kzalloc(sizeof(*region), GFP_KERNEL); 932 if (!region) 933 return -ENOMEM; 934 region->type = WMFW_ADSP1_ZM; 935 region->alg = be32_to_cpu(adsp1_id.fw.id); 936 region->base = be32_to_cpu(adsp1_id.zm); 937 list_add_tail(®ion->list, &dsp->alg_regions); 938 939 region = kzalloc(sizeof(*region), GFP_KERNEL); 940 if (!region) 941 return -ENOMEM; 942 region->type = WMFW_ADSP1_DM; 943 region->alg = be32_to_cpu(adsp1_id.fw.id); 944 region->base = be32_to_cpu(adsp1_id.dm); 945 list_add_tail(®ion->list, &dsp->alg_regions); 946 947 pos = sizeof(adsp1_id) / 2; 948 term = pos + ((sizeof(*adsp1_alg) * algs) / 2); 949 break; 950 951 case WMFW_ADSP2: 952 ret = regmap_raw_read(regmap, mem->base, &adsp2_id, 953 sizeof(adsp2_id)); 954 if (ret != 0) { 955 adsp_err(dsp, "Failed to read algorithm info: %d\n", 956 ret); 957 return ret; 958 } 959 960 buf = &adsp2_id; 961 buf_size = sizeof(adsp2_id); 962 963 algs = be32_to_cpu(adsp2_id.algs); 964 dsp->fw_id = be32_to_cpu(adsp2_id.fw.id); 965 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", 966 dsp->fw_id, 967 (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16, 968 (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8, 969 be32_to_cpu(adsp2_id.fw.ver) & 0xff, 970 algs); 971 972 region = kzalloc(sizeof(*region), GFP_KERNEL); 973 if (!region) 974 return -ENOMEM; 975 region->type = WMFW_ADSP2_XM; 976 region->alg = be32_to_cpu(adsp2_id.fw.id); 977 region->base = be32_to_cpu(adsp2_id.xm); 978 list_add_tail(®ion->list, &dsp->alg_regions); 979 980 region = kzalloc(sizeof(*region), GFP_KERNEL); 981 if (!region) 982 return -ENOMEM; 983 region->type = WMFW_ADSP2_YM; 984 region->alg = be32_to_cpu(adsp2_id.fw.id); 985 region->base = be32_to_cpu(adsp2_id.ym); 986 list_add_tail(®ion->list, &dsp->alg_regions); 987 988 region = kzalloc(sizeof(*region), GFP_KERNEL); 989 if (!region) 990 return -ENOMEM; 991 region->type = WMFW_ADSP2_ZM; 992 region->alg = be32_to_cpu(adsp2_id.fw.id); 993 region->base = be32_to_cpu(adsp2_id.zm); 994 list_add_tail(®ion->list, &dsp->alg_regions); 995 996 pos = sizeof(adsp2_id) / 2; 997 term = pos + ((sizeof(*adsp2_alg) * algs) / 2); 998 break; 999 1000 default: 1001 WARN(1, "Unknown DSP type"); 1002 return -EINVAL; 1003 } 1004 1005 if (algs == 0) { 1006 adsp_err(dsp, "No algorithms\n"); 1007 return -EINVAL; 1008 } 1009 1010 if (algs > 1024) { 1011 adsp_err(dsp, "Algorithm count %zx excessive\n", algs); 1012 print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET, 1013 buf, buf_size); 1014 return -EINVAL; 1015 } 1016 1017 /* Read the terminator first to validate the length */ 1018 ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val)); 1019 if (ret != 0) { 1020 adsp_err(dsp, "Failed to read algorithm list end: %d\n", 1021 ret); 1022 return ret; 1023 } 1024 1025 if (be32_to_cpu(val) != 0xbedead) 1026 adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", 1027 term, be32_to_cpu(val)); 1028 1029 alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA); 1030 if (!alg) 1031 return -ENOMEM; 1032 1033 ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2); 1034 if (ret != 0) { 1035 adsp_err(dsp, "Failed to read algorithm list: %d\n", 1036 ret); 1037 goto out; 1038 } 1039 1040 adsp1_alg = alg; 1041 adsp2_alg = alg; 1042 1043 for (i = 0; i < algs; i++) { 1044 switch (dsp->type) { 1045 case WMFW_ADSP1: 1046 adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", 1047 i, be32_to_cpu(adsp1_alg[i].alg.id), 1048 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, 1049 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, 1050 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, 1051 be32_to_cpu(adsp1_alg[i].dm), 1052 be32_to_cpu(adsp1_alg[i].zm)); 1053 1054 region = kzalloc(sizeof(*region), GFP_KERNEL); 1055 if (!region) { 1056 ret = -ENOMEM; 1057 goto out; 1058 } 1059 region->type = WMFW_ADSP1_DM; 1060 region->alg = be32_to_cpu(adsp1_alg[i].alg.id); 1061 region->base = be32_to_cpu(adsp1_alg[i].dm); 1062 region->len = 0; 1063 list_add_tail(®ion->list, &dsp->alg_regions); 1064 if (i + 1 < algs) { 1065 region->len = be32_to_cpu(adsp1_alg[i + 1].dm); 1066 region->len -= be32_to_cpu(adsp1_alg[i].dm); 1067 region->len *= 4; 1068 wm_adsp_create_control(dsp, region); 1069 } else { 1070 adsp_warn(dsp, "Missing length info for region DM with ID %x\n", 1071 be32_to_cpu(adsp1_alg[i].alg.id)); 1072 } 1073 1074 region = kzalloc(sizeof(*region), GFP_KERNEL); 1075 if (!region) { 1076 ret = -ENOMEM; 1077 goto out; 1078 } 1079 region->type = WMFW_ADSP1_ZM; 1080 region->alg = be32_to_cpu(adsp1_alg[i].alg.id); 1081 region->base = be32_to_cpu(adsp1_alg[i].zm); 1082 region->len = 0; 1083 list_add_tail(®ion->list, &dsp->alg_regions); 1084 if (i + 1 < algs) { 1085 region->len = be32_to_cpu(adsp1_alg[i + 1].zm); 1086 region->len -= be32_to_cpu(adsp1_alg[i].zm); 1087 region->len *= 4; 1088 wm_adsp_create_control(dsp, region); 1089 } else { 1090 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 1091 be32_to_cpu(adsp1_alg[i].alg.id)); 1092 } 1093 break; 1094 1095 case WMFW_ADSP2: 1096 adsp_info(dsp, 1097 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", 1098 i, be32_to_cpu(adsp2_alg[i].alg.id), 1099 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, 1100 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, 1101 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, 1102 be32_to_cpu(adsp2_alg[i].xm), 1103 be32_to_cpu(adsp2_alg[i].ym), 1104 be32_to_cpu(adsp2_alg[i].zm)); 1105 1106 region = kzalloc(sizeof(*region), GFP_KERNEL); 1107 if (!region) { 1108 ret = -ENOMEM; 1109 goto out; 1110 } 1111 region->type = WMFW_ADSP2_XM; 1112 region->alg = be32_to_cpu(adsp2_alg[i].alg.id); 1113 region->base = be32_to_cpu(adsp2_alg[i].xm); 1114 region->len = 0; 1115 list_add_tail(®ion->list, &dsp->alg_regions); 1116 if (i + 1 < algs) { 1117 region->len = be32_to_cpu(adsp2_alg[i + 1].xm); 1118 region->len -= be32_to_cpu(adsp2_alg[i].xm); 1119 region->len *= 4; 1120 wm_adsp_create_control(dsp, region); 1121 } else { 1122 adsp_warn(dsp, "Missing length info for region XM with ID %x\n", 1123 be32_to_cpu(adsp2_alg[i].alg.id)); 1124 } 1125 1126 region = kzalloc(sizeof(*region), GFP_KERNEL); 1127 if (!region) { 1128 ret = -ENOMEM; 1129 goto out; 1130 } 1131 region->type = WMFW_ADSP2_YM; 1132 region->alg = be32_to_cpu(adsp2_alg[i].alg.id); 1133 region->base = be32_to_cpu(adsp2_alg[i].ym); 1134 region->len = 0; 1135 list_add_tail(®ion->list, &dsp->alg_regions); 1136 if (i + 1 < algs) { 1137 region->len = be32_to_cpu(adsp2_alg[i + 1].ym); 1138 region->len -= be32_to_cpu(adsp2_alg[i].ym); 1139 region->len *= 4; 1140 wm_adsp_create_control(dsp, region); 1141 } else { 1142 adsp_warn(dsp, "Missing length info for region YM with ID %x\n", 1143 be32_to_cpu(adsp2_alg[i].alg.id)); 1144 } 1145 1146 region = kzalloc(sizeof(*region), GFP_KERNEL); 1147 if (!region) { 1148 ret = -ENOMEM; 1149 goto out; 1150 } 1151 region->type = WMFW_ADSP2_ZM; 1152 region->alg = be32_to_cpu(adsp2_alg[i].alg.id); 1153 region->base = be32_to_cpu(adsp2_alg[i].zm); 1154 region->len = 0; 1155 list_add_tail(®ion->list, &dsp->alg_regions); 1156 if (i + 1 < algs) { 1157 region->len = be32_to_cpu(adsp2_alg[i + 1].zm); 1158 region->len -= be32_to_cpu(adsp2_alg[i].zm); 1159 region->len *= 4; 1160 wm_adsp_create_control(dsp, region); 1161 } else { 1162 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 1163 be32_to_cpu(adsp2_alg[i].alg.id)); 1164 } 1165 break; 1166 } 1167 } 1168 1169out: 1170 kfree(alg); 1171 return ret; 1172} 1173 1174static int wm_adsp_load_coeff(struct wm_adsp *dsp) 1175{ 1176 LIST_HEAD(buf_list); 1177 struct regmap *regmap = dsp->regmap; 1178 struct wmfw_coeff_hdr *hdr; 1179 struct wmfw_coeff_item *blk; 1180 const struct firmware *firmware; 1181 const struct wm_adsp_region *mem; 1182 struct wm_adsp_alg_region *alg_region; 1183 const char *region_name; 1184 int ret, pos, blocks, type, offset, reg; 1185 char *file; 1186 struct wm_adsp_buf *buf; 1187 1188 file = kzalloc(PAGE_SIZE, GFP_KERNEL); 1189 if (file == NULL) 1190 return -ENOMEM; 1191 1192 snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num, 1193 wm_adsp_fw[dsp->fw].file); 1194 file[PAGE_SIZE - 1] = '\0'; 1195 1196 ret = request_firmware(&firmware, file, dsp->dev); 1197 if (ret != 0) { 1198 adsp_warn(dsp, "Failed to request '%s'\n", file); 1199 ret = 0; 1200 goto out; 1201 } 1202 ret = -EINVAL; 1203 1204 if (sizeof(*hdr) >= firmware->size) { 1205 adsp_err(dsp, "%s: file too short, %zu bytes\n", 1206 file, firmware->size); 1207 goto out_fw; 1208 } 1209 1210 hdr = (void*)&firmware->data[0]; 1211 if (memcmp(hdr->magic, "WMDR", 4) != 0) { 1212 adsp_err(dsp, "%s: invalid magic\n", file); 1213 goto out_fw; 1214 } 1215 1216 switch (be32_to_cpu(hdr->rev) & 0xff) { 1217 case 1: 1218 break; 1219 default: 1220 adsp_err(dsp, "%s: Unsupported coefficient file format %d\n", 1221 file, be32_to_cpu(hdr->rev) & 0xff); 1222 ret = -EINVAL; 1223 goto out_fw; 1224 } 1225 1226 adsp_dbg(dsp, "%s: v%d.%d.%d\n", file, 1227 (le32_to_cpu(hdr->ver) >> 16) & 0xff, 1228 (le32_to_cpu(hdr->ver) >> 8) & 0xff, 1229 le32_to_cpu(hdr->ver) & 0xff); 1230 1231 pos = le32_to_cpu(hdr->len); 1232 1233 blocks = 0; 1234 while (pos < firmware->size && 1235 pos - firmware->size > sizeof(*blk)) { 1236 blk = (void*)(&firmware->data[pos]); 1237 1238 type = le16_to_cpu(blk->type); 1239 offset = le16_to_cpu(blk->offset); 1240 1241 adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", 1242 file, blocks, le32_to_cpu(blk->id), 1243 (le32_to_cpu(blk->ver) >> 16) & 0xff, 1244 (le32_to_cpu(blk->ver) >> 8) & 0xff, 1245 le32_to_cpu(blk->ver) & 0xff); 1246 adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n", 1247 file, blocks, le32_to_cpu(blk->len), offset, type); 1248 1249 reg = 0; 1250 region_name = "Unknown"; 1251 switch (type) { 1252 case (WMFW_NAME_TEXT << 8): 1253 case (WMFW_INFO_TEXT << 8): 1254 break; 1255 case (WMFW_ABSOLUTE << 8): 1256 /* 1257 * Old files may use this for global 1258 * coefficients. 1259 */ 1260 if (le32_to_cpu(blk->id) == dsp->fw_id && 1261 offset == 0) { 1262 region_name = "global coefficients"; 1263 mem = wm_adsp_find_region(dsp, type); 1264 if (!mem) { 1265 adsp_err(dsp, "No ZM\n"); 1266 break; 1267 } 1268 reg = wm_adsp_region_to_reg(mem, 0); 1269 1270 } else { 1271 region_name = "register"; 1272 reg = offset; 1273 } 1274 break; 1275 1276 case WMFW_ADSP1_DM: 1277 case WMFW_ADSP1_ZM: 1278 case WMFW_ADSP2_XM: 1279 case WMFW_ADSP2_YM: 1280 adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", 1281 file, blocks, le32_to_cpu(blk->len), 1282 type, le32_to_cpu(blk->id)); 1283 1284 mem = wm_adsp_find_region(dsp, type); 1285 if (!mem) { 1286 adsp_err(dsp, "No base for region %x\n", type); 1287 break; 1288 } 1289 1290 reg = 0; 1291 list_for_each_entry(alg_region, 1292 &dsp->alg_regions, list) { 1293 if (le32_to_cpu(blk->id) == alg_region->alg && 1294 type == alg_region->type) { 1295 reg = alg_region->base; 1296 reg = wm_adsp_region_to_reg(mem, 1297 reg); 1298 reg += offset; 1299 break; 1300 } 1301 } 1302 1303 if (reg == 0) 1304 adsp_err(dsp, "No %x for algorithm %x\n", 1305 type, le32_to_cpu(blk->id)); 1306 break; 1307 1308 default: 1309 adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n", 1310 file, blocks, type, pos); 1311 break; 1312 } 1313 1314 if (reg) { 1315 buf = wm_adsp_buf_alloc(blk->data, 1316 le32_to_cpu(blk->len), 1317 &buf_list); 1318 if (!buf) { 1319 adsp_err(dsp, "Out of memory\n"); 1320 ret = -ENOMEM; 1321 goto out_fw; 1322 } 1323 1324 adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", 1325 file, blocks, le32_to_cpu(blk->len), 1326 reg); 1327 ret = regmap_raw_write_async(regmap, reg, buf->buf, 1328 le32_to_cpu(blk->len)); 1329 if (ret != 0) { 1330 adsp_err(dsp, 1331 "%s.%d: Failed to write to %x in %s: %d\n", 1332 file, blocks, reg, region_name, ret); 1333 } 1334 } 1335 1336 pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03; 1337 blocks++; 1338 } 1339 1340 ret = regmap_async_complete(regmap); 1341 if (ret != 0) 1342 adsp_err(dsp, "Failed to complete async write: %d\n", ret); 1343 1344 if (pos > firmware->size) 1345 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 1346 file, blocks, pos - firmware->size); 1347 1348out_fw: 1349 regmap_async_complete(regmap); 1350 release_firmware(firmware); 1351 wm_adsp_buf_free(&buf_list); 1352out: 1353 kfree(file); 1354 return ret; 1355} 1356 1357int wm_adsp1_init(struct wm_adsp *adsp) 1358{ 1359 INIT_LIST_HEAD(&adsp->alg_regions); 1360 1361 return 0; 1362} 1363EXPORT_SYMBOL_GPL(wm_adsp1_init); 1364 1365int wm_adsp1_event(struct snd_soc_dapm_widget *w, 1366 struct snd_kcontrol *kcontrol, 1367 int event) 1368{ 1369 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 1370 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); 1371 struct wm_adsp *dsp = &dsps[w->shift]; 1372 struct wm_adsp_alg_region *alg_region; 1373 struct wm_coeff_ctl *ctl; 1374 int ret; 1375 int val; 1376 1377 dsp->card = codec->component.card; 1378 1379 switch (event) { 1380 case SND_SOC_DAPM_POST_PMU: 1381 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1382 ADSP1_SYS_ENA, ADSP1_SYS_ENA); 1383 1384 /* 1385 * For simplicity set the DSP clock rate to be the 1386 * SYSCLK rate rather than making it configurable. 1387 */ 1388 if(dsp->sysclk_reg) { 1389 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); 1390 if (ret != 0) { 1391 adsp_err(dsp, "Failed to read SYSCLK state: %d\n", 1392 ret); 1393 return ret; 1394 } 1395 1396 val = (val & dsp->sysclk_mask) 1397 >> dsp->sysclk_shift; 1398 1399 ret = regmap_update_bits(dsp->regmap, 1400 dsp->base + ADSP1_CONTROL_31, 1401 ADSP1_CLK_SEL_MASK, val); 1402 if (ret != 0) { 1403 adsp_err(dsp, "Failed to set clock rate: %d\n", 1404 ret); 1405 return ret; 1406 } 1407 } 1408 1409 ret = wm_adsp_load(dsp); 1410 if (ret != 0) 1411 goto err; 1412 1413 ret = wm_adsp_setup_algs(dsp); 1414 if (ret != 0) 1415 goto err; 1416 1417 ret = wm_adsp_load_coeff(dsp); 1418 if (ret != 0) 1419 goto err; 1420 1421 /* Initialize caches for enabled and unset controls */ 1422 ret = wm_coeff_init_control_caches(dsp); 1423 if (ret != 0) 1424 goto err; 1425 1426 /* Sync set controls */ 1427 ret = wm_coeff_sync_controls(dsp); 1428 if (ret != 0) 1429 goto err; 1430 1431 /* Start the core running */ 1432 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1433 ADSP1_CORE_ENA | ADSP1_START, 1434 ADSP1_CORE_ENA | ADSP1_START); 1435 break; 1436 1437 case SND_SOC_DAPM_PRE_PMD: 1438 /* Halt the core */ 1439 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1440 ADSP1_CORE_ENA | ADSP1_START, 0); 1441 1442 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, 1443 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0); 1444 1445 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1446 ADSP1_SYS_ENA, 0); 1447 1448 list_for_each_entry(ctl, &dsp->ctl_list, list) 1449 ctl->enabled = 0; 1450 1451 while (!list_empty(&dsp->alg_regions)) { 1452 alg_region = list_first_entry(&dsp->alg_regions, 1453 struct wm_adsp_alg_region, 1454 list); 1455 list_del(&alg_region->list); 1456 kfree(alg_region); 1457 } 1458 break; 1459 1460 default: 1461 break; 1462 } 1463 1464 return 0; 1465 1466err: 1467 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1468 ADSP1_SYS_ENA, 0); 1469 return ret; 1470} 1471EXPORT_SYMBOL_GPL(wm_adsp1_event); 1472 1473static int wm_adsp2_ena(struct wm_adsp *dsp) 1474{ 1475 unsigned int val; 1476 int ret, count; 1477 1478 ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL, 1479 ADSP2_SYS_ENA, ADSP2_SYS_ENA); 1480 if (ret != 0) 1481 return ret; 1482 1483 /* Wait for the RAM to start, should be near instantaneous */ 1484 for (count = 0; count < 10; ++count) { 1485 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, 1486 &val); 1487 if (ret != 0) 1488 return ret; 1489 1490 if (val & ADSP2_RAM_RDY) 1491 break; 1492 1493 msleep(1); 1494 } 1495 1496 if (!(val & ADSP2_RAM_RDY)) { 1497 adsp_err(dsp, "Failed to start DSP RAM\n"); 1498 return -EBUSY; 1499 } 1500 1501 adsp_dbg(dsp, "RAM ready after %d polls\n", count); 1502 1503 return 0; 1504} 1505 1506static void wm_adsp2_boot_work(struct work_struct *work) 1507{ 1508 struct wm_adsp *dsp = container_of(work, 1509 struct wm_adsp, 1510 boot_work); 1511 int ret; 1512 unsigned int val; 1513 1514 /* 1515 * For simplicity set the DSP clock rate to be the 1516 * SYSCLK rate rather than making it configurable. 1517 */ 1518 ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val); 1519 if (ret != 0) { 1520 adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); 1521 return; 1522 } 1523 val = (val & ARIZONA_SYSCLK_FREQ_MASK) 1524 >> ARIZONA_SYSCLK_FREQ_SHIFT; 1525 1526 ret = regmap_update_bits_async(dsp->regmap, 1527 dsp->base + ADSP2_CLOCKING, 1528 ADSP2_CLK_SEL_MASK, val); 1529 if (ret != 0) { 1530 adsp_err(dsp, "Failed to set clock rate: %d\n", ret); 1531 return; 1532 } 1533 1534 if (dsp->dvfs) { 1535 ret = regmap_read(dsp->regmap, 1536 dsp->base + ADSP2_CLOCKING, &val); 1537 if (ret != 0) { 1538 adsp_err(dsp, "Failed to read clocking: %d\n", ret); 1539 return; 1540 } 1541 1542 if ((val & ADSP2_CLK_SEL_MASK) >= 3) { 1543 ret = regulator_enable(dsp->dvfs); 1544 if (ret != 0) { 1545 adsp_err(dsp, 1546 "Failed to enable supply: %d\n", 1547 ret); 1548 return; 1549 } 1550 1551 ret = regulator_set_voltage(dsp->dvfs, 1552 1800000, 1553 1800000); 1554 if (ret != 0) { 1555 adsp_err(dsp, 1556 "Failed to raise supply: %d\n", 1557 ret); 1558 return; 1559 } 1560 } 1561 } 1562 1563 ret = wm_adsp2_ena(dsp); 1564 if (ret != 0) 1565 return; 1566 1567 ret = wm_adsp_load(dsp); 1568 if (ret != 0) 1569 goto err; 1570 1571 ret = wm_adsp_setup_algs(dsp); 1572 if (ret != 0) 1573 goto err; 1574 1575 ret = wm_adsp_load_coeff(dsp); 1576 if (ret != 0) 1577 goto err; 1578 1579 /* Initialize caches for enabled and unset controls */ 1580 ret = wm_coeff_init_control_caches(dsp); 1581 if (ret != 0) 1582 goto err; 1583 1584 /* Sync set controls */ 1585 ret = wm_coeff_sync_controls(dsp); 1586 if (ret != 0) 1587 goto err; 1588 1589 dsp->running = true; 1590 1591 return; 1592 1593err: 1594 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 1595 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); 1596} 1597 1598int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, 1599 struct snd_kcontrol *kcontrol, int event) 1600{ 1601 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 1602 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); 1603 struct wm_adsp *dsp = &dsps[w->shift]; 1604 1605 dsp->card = codec->component.card; 1606 1607 switch (event) { 1608 case SND_SOC_DAPM_PRE_PMU: 1609 queue_work(system_unbound_wq, &dsp->boot_work); 1610 break; 1611 default: 1612 break; 1613 } 1614 1615 return 0; 1616} 1617EXPORT_SYMBOL_GPL(wm_adsp2_early_event); 1618 1619int wm_adsp2_event(struct snd_soc_dapm_widget *w, 1620 struct snd_kcontrol *kcontrol, int event) 1621{ 1622 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 1623 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); 1624 struct wm_adsp *dsp = &dsps[w->shift]; 1625 struct wm_adsp_alg_region *alg_region; 1626 struct wm_coeff_ctl *ctl; 1627 int ret; 1628 1629 switch (event) { 1630 case SND_SOC_DAPM_POST_PMU: 1631 flush_work(&dsp->boot_work); 1632 1633 if (!dsp->running) 1634 return -EIO; 1635 1636 ret = regmap_update_bits(dsp->regmap, 1637 dsp->base + ADSP2_CONTROL, 1638 ADSP2_CORE_ENA | ADSP2_START, 1639 ADSP2_CORE_ENA | ADSP2_START); 1640 if (ret != 0) 1641 goto err; 1642 break; 1643 1644 case SND_SOC_DAPM_PRE_PMD: 1645 dsp->running = false; 1646 1647 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 1648 ADSP2_SYS_ENA | ADSP2_CORE_ENA | 1649 ADSP2_START, 0); 1650 1651 /* Make sure DMAs are quiesced */ 1652 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); 1653 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); 1654 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); 1655 1656 if (dsp->dvfs) { 1657 ret = regulator_set_voltage(dsp->dvfs, 1200000, 1658 1800000); 1659 if (ret != 0) 1660 adsp_warn(dsp, 1661 "Failed to lower supply: %d\n", 1662 ret); 1663 1664 ret = regulator_disable(dsp->dvfs); 1665 if (ret != 0) 1666 adsp_err(dsp, 1667 "Failed to enable supply: %d\n", 1668 ret); 1669 } 1670 1671 list_for_each_entry(ctl, &dsp->ctl_list, list) 1672 ctl->enabled = 0; 1673 1674 while (!list_empty(&dsp->alg_regions)) { 1675 alg_region = list_first_entry(&dsp->alg_regions, 1676 struct wm_adsp_alg_region, 1677 list); 1678 list_del(&alg_region->list); 1679 kfree(alg_region); 1680 } 1681 1682 adsp_dbg(dsp, "Shutdown complete\n"); 1683 break; 1684 1685 default: 1686 break; 1687 } 1688 1689 return 0; 1690err: 1691 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 1692 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); 1693 return ret; 1694} 1695EXPORT_SYMBOL_GPL(wm_adsp2_event); 1696 1697int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) 1698{ 1699 int ret; 1700 1701 /* 1702 * Disable the DSP memory by default when in reset for a small 1703 * power saving. 1704 */ 1705 ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL, 1706 ADSP2_MEM_ENA, 0); 1707 if (ret != 0) { 1708 adsp_err(adsp, "Failed to clear memory retention: %d\n", ret); 1709 return ret; 1710 } 1711 1712 INIT_LIST_HEAD(&adsp->alg_regions); 1713 INIT_LIST_HEAD(&adsp->ctl_list); 1714 INIT_WORK(&adsp->boot_work, wm_adsp2_boot_work); 1715 1716 if (dvfs) { 1717 adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); 1718 if (IS_ERR(adsp->dvfs)) { 1719 ret = PTR_ERR(adsp->dvfs); 1720 adsp_err(adsp, "Failed to get DCVDD: %d\n", ret); 1721 return ret; 1722 } 1723 1724 ret = regulator_enable(adsp->dvfs); 1725 if (ret != 0) { 1726 adsp_err(adsp, "Failed to enable DCVDD: %d\n", ret); 1727 return ret; 1728 } 1729 1730 ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000); 1731 if (ret != 0) { 1732 adsp_err(adsp, "Failed to initialise DVFS: %d\n", ret); 1733 return ret; 1734 } 1735 1736 ret = regulator_disable(adsp->dvfs); 1737 if (ret != 0) { 1738 adsp_err(adsp, "Failed to disable DCVDD: %d\n", ret); 1739 return ret; 1740 } 1741 } 1742 1743 return 0; 1744} 1745EXPORT_SYMBOL_GPL(wm_adsp2_init); 1746 1747MODULE_LICENSE("GPL v2"); 1748