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 <sound/core.h> 25 #include <sound/pcm.h> 26 #include <sound/pcm_params.h> 27 #include <sound/soc.h> 28 #include <sound/jack.h> 29 #include <sound/initval.h> 30 #include <sound/tlv.h> 31 32 #include <linux/mfd/arizona/registers.h> 33 34 #include "arizona.h" 35 #include "wm_adsp.h" 36 37 #define adsp_crit(_dsp, fmt, ...) \ 38 dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 39 #define adsp_err(_dsp, fmt, ...) \ 40 dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 41 #define adsp_warn(_dsp, fmt, ...) \ 42 dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 43 #define adsp_info(_dsp, fmt, ...) \ 44 dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 45 #define adsp_dbg(_dsp, fmt, ...) \ 46 dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) 47 48 #define ADSP1_CONTROL_1 0x00 49 #define ADSP1_CONTROL_2 0x02 50 #define ADSP1_CONTROL_3 0x03 51 #define ADSP1_CONTROL_4 0x04 52 #define ADSP1_CONTROL_5 0x06 53 #define ADSP1_CONTROL_6 0x07 54 #define ADSP1_CONTROL_7 0x08 55 #define ADSP1_CONTROL_8 0x09 56 #define ADSP1_CONTROL_9 0x0A 57 #define ADSP1_CONTROL_10 0x0B 58 #define ADSP1_CONTROL_11 0x0C 59 #define ADSP1_CONTROL_12 0x0D 60 #define ADSP1_CONTROL_13 0x0F 61 #define ADSP1_CONTROL_14 0x10 62 #define ADSP1_CONTROL_15 0x11 63 #define ADSP1_CONTROL_16 0x12 64 #define ADSP1_CONTROL_17 0x13 65 #define ADSP1_CONTROL_18 0x14 66 #define ADSP1_CONTROL_19 0x16 67 #define ADSP1_CONTROL_20 0x17 68 #define ADSP1_CONTROL_21 0x18 69 #define ADSP1_CONTROL_22 0x1A 70 #define ADSP1_CONTROL_23 0x1B 71 #define ADSP1_CONTROL_24 0x1C 72 #define ADSP1_CONTROL_25 0x1E 73 #define ADSP1_CONTROL_26 0x20 74 #define ADSP1_CONTROL_27 0x21 75 #define ADSP1_CONTROL_28 0x22 76 #define ADSP1_CONTROL_29 0x23 77 #define ADSP1_CONTROL_30 0x24 78 #define ADSP1_CONTROL_31 0x26 79 80 /* 81 * ADSP1 Control 19 82 */ 83 #define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ 84 #define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ 85 #define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ 86 87 88 /* 89 * ADSP1 Control 30 90 */ 91 #define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */ 92 #define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */ 93 #define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */ 94 #define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */ 95 #define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ 96 #define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ 97 #define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ 98 #define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ 99 #define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ 100 #define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ 101 #define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ 102 #define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ 103 #define ADSP1_START 0x0001 /* DSP1_START */ 104 #define ADSP1_START_MASK 0x0001 /* DSP1_START */ 105 #define ADSP1_START_SHIFT 0 /* DSP1_START */ 106 #define ADSP1_START_WIDTH 1 /* DSP1_START */ 107 108 /* 109 * ADSP1 Control 31 110 */ 111 #define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */ 112 #define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ 113 #define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ 114 115 #define ADSP2_CONTROL 0x0 116 #define ADSP2_CLOCKING 0x1 117 #define ADSP2_STATUS1 0x4 118 #define ADSP2_WDMA_CONFIG_1 0x30 119 #define ADSP2_WDMA_CONFIG_2 0x31 120 #define ADSP2_RDMA_CONFIG_1 0x34 121 122 /* 123 * ADSP2 Control 124 */ 125 126 #define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */ 127 #define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */ 128 #define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */ 129 #define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */ 130 #define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ 131 #define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ 132 #define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ 133 #define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ 134 #define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ 135 #define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ 136 #define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ 137 #define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ 138 #define ADSP2_START 0x0001 /* DSP1_START */ 139 #define ADSP2_START_MASK 0x0001 /* DSP1_START */ 140 #define ADSP2_START_SHIFT 0 /* DSP1_START */ 141 #define ADSP2_START_WIDTH 1 /* DSP1_START */ 142 143 /* 144 * ADSP2 clocking 145 */ 146 #define ADSP2_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */ 147 #define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ 148 #define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ 149 150 /* 151 * ADSP2 Status 1 152 */ 153 #define ADSP2_RAM_RDY 0x0001 154 #define ADSP2_RAM_RDY_MASK 0x0001 155 #define ADSP2_RAM_RDY_SHIFT 0 156 #define ADSP2_RAM_RDY_WIDTH 1 157 158 struct wm_adsp_buf { 159 struct list_head list; 160 void *buf; 161 }; 162 163 static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len, 164 struct list_head *list) 165 { 166 struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL); 167 168 if (buf == NULL) 169 return NULL; 170 171 buf->buf = kmemdup(src, len, GFP_KERNEL | GFP_DMA); 172 if (!buf->buf) { 173 kfree(buf); 174 return NULL; 175 } 176 177 if (list) 178 list_add_tail(&buf->list, list); 179 180 return buf; 181 } 182 183 static void wm_adsp_buf_free(struct list_head *list) 184 { 185 while (!list_empty(list)) { 186 struct wm_adsp_buf *buf = list_first_entry(list, 187 struct wm_adsp_buf, 188 list); 189 list_del(&buf->list); 190 kfree(buf->buf); 191 kfree(buf); 192 } 193 } 194 195 #define WM_ADSP_NUM_FW 4 196 197 #define WM_ADSP_FW_MBC_VSS 0 198 #define WM_ADSP_FW_TX 1 199 #define WM_ADSP_FW_TX_SPK 2 200 #define WM_ADSP_FW_RX_ANC 3 201 202 static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { 203 [WM_ADSP_FW_MBC_VSS] = "MBC/VSS", 204 [WM_ADSP_FW_TX] = "Tx", 205 [WM_ADSP_FW_TX_SPK] = "Tx Speaker", 206 [WM_ADSP_FW_RX_ANC] = "Rx ANC", 207 }; 208 209 static struct { 210 const char *file; 211 } wm_adsp_fw[WM_ADSP_NUM_FW] = { 212 [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" }, 213 [WM_ADSP_FW_TX] = { .file = "tx" }, 214 [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" }, 215 [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, 216 }; 217 218 static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, 219 struct snd_ctl_elem_value *ucontrol) 220 { 221 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 222 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 223 struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); 224 225 ucontrol->value.integer.value[0] = adsp[e->shift_l].fw; 226 227 return 0; 228 } 229 230 static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, 231 struct snd_ctl_elem_value *ucontrol) 232 { 233 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 234 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 235 struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); 236 237 if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw) 238 return 0; 239 240 if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW) 241 return -EINVAL; 242 243 if (adsp[e->shift_l].running) 244 return -EBUSY; 245 246 adsp[e->shift_l].fw = ucontrol->value.integer.value[0]; 247 248 return 0; 249 } 250 251 static const struct soc_enum wm_adsp_fw_enum[] = { 252 SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), 253 SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), 254 SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), 255 SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), 256 }; 257 258 const struct snd_kcontrol_new wm_adsp1_fw_controls[] = { 259 SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], 260 wm_adsp_fw_get, wm_adsp_fw_put), 261 SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], 262 wm_adsp_fw_get, wm_adsp_fw_put), 263 SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], 264 wm_adsp_fw_get, wm_adsp_fw_put), 265 }; 266 EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls); 267 268 #if IS_ENABLED(CONFIG_SND_SOC_ARIZONA) 269 static const struct soc_enum wm_adsp2_rate_enum[] = { 270 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1, 271 ARIZONA_DSP1_RATE_SHIFT, 0xf, 272 ARIZONA_RATE_ENUM_SIZE, 273 arizona_rate_text, arizona_rate_val), 274 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1, 275 ARIZONA_DSP1_RATE_SHIFT, 0xf, 276 ARIZONA_RATE_ENUM_SIZE, 277 arizona_rate_text, arizona_rate_val), 278 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1, 279 ARIZONA_DSP1_RATE_SHIFT, 0xf, 280 ARIZONA_RATE_ENUM_SIZE, 281 arizona_rate_text, arizona_rate_val), 282 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1, 283 ARIZONA_DSP1_RATE_SHIFT, 0xf, 284 ARIZONA_RATE_ENUM_SIZE, 285 arizona_rate_text, arizona_rate_val), 286 }; 287 288 const struct snd_kcontrol_new wm_adsp2_fw_controls[] = { 289 SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], 290 wm_adsp_fw_get, wm_adsp_fw_put), 291 SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]), 292 SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], 293 wm_adsp_fw_get, wm_adsp_fw_put), 294 SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]), 295 SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], 296 wm_adsp_fw_get, wm_adsp_fw_put), 297 SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]), 298 SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], 299 wm_adsp_fw_get, wm_adsp_fw_put), 300 SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]), 301 }; 302 EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls); 303 #endif 304 305 static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, 306 int type) 307 { 308 int i; 309 310 for (i = 0; i < dsp->num_mems; i++) 311 if (dsp->mem[i].type == type) 312 return &dsp->mem[i]; 313 314 return NULL; 315 } 316 317 static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region, 318 unsigned int offset) 319 { 320 switch (region->type) { 321 case WMFW_ADSP1_PM: 322 return region->base + (offset * 3); 323 case WMFW_ADSP1_DM: 324 return region->base + (offset * 2); 325 case WMFW_ADSP2_XM: 326 return region->base + (offset * 2); 327 case WMFW_ADSP2_YM: 328 return region->base + (offset * 2); 329 case WMFW_ADSP1_ZM: 330 return region->base + (offset * 2); 331 default: 332 WARN_ON(NULL != "Unknown memory region type"); 333 return offset; 334 } 335 } 336 337 static int wm_adsp_load(struct wm_adsp *dsp) 338 { 339 LIST_HEAD(buf_list); 340 const struct firmware *firmware; 341 struct regmap *regmap = dsp->regmap; 342 unsigned int pos = 0; 343 const struct wmfw_header *header; 344 const struct wmfw_adsp1_sizes *adsp1_sizes; 345 const struct wmfw_adsp2_sizes *adsp2_sizes; 346 const struct wmfw_footer *footer; 347 const struct wmfw_region *region; 348 const struct wm_adsp_region *mem; 349 const char *region_name; 350 char *file, *text; 351 struct wm_adsp_buf *buf; 352 unsigned int reg; 353 int regions = 0; 354 int ret, offset, type, sizes; 355 356 file = kzalloc(PAGE_SIZE, GFP_KERNEL); 357 if (file == NULL) 358 return -ENOMEM; 359 360 snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num, 361 wm_adsp_fw[dsp->fw].file); 362 file[PAGE_SIZE - 1] = '\0'; 363 364 ret = request_firmware(&firmware, file, dsp->dev); 365 if (ret != 0) { 366 adsp_err(dsp, "Failed to request '%s'\n", file); 367 goto out; 368 } 369 ret = -EINVAL; 370 371 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); 372 if (pos >= firmware->size) { 373 adsp_err(dsp, "%s: file too short, %zu bytes\n", 374 file, firmware->size); 375 goto out_fw; 376 } 377 378 header = (void*)&firmware->data[0]; 379 380 if (memcmp(&header->magic[0], "WMFW", 4) != 0) { 381 adsp_err(dsp, "%s: invalid magic\n", file); 382 goto out_fw; 383 } 384 385 if (header->ver != 0) { 386 adsp_err(dsp, "%s: unknown file format %d\n", 387 file, header->ver); 388 goto out_fw; 389 } 390 391 if (header->core != dsp->type) { 392 adsp_err(dsp, "%s: invalid core %d != %d\n", 393 file, header->core, dsp->type); 394 goto out_fw; 395 } 396 397 switch (dsp->type) { 398 case WMFW_ADSP1: 399 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); 400 adsp1_sizes = (void *)&(header[1]); 401 footer = (void *)&(adsp1_sizes[1]); 402 sizes = sizeof(*adsp1_sizes); 403 404 adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", 405 file, le32_to_cpu(adsp1_sizes->dm), 406 le32_to_cpu(adsp1_sizes->pm), 407 le32_to_cpu(adsp1_sizes->zm)); 408 break; 409 410 case WMFW_ADSP2: 411 pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer); 412 adsp2_sizes = (void *)&(header[1]); 413 footer = (void *)&(adsp2_sizes[1]); 414 sizes = sizeof(*adsp2_sizes); 415 416 adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", 417 file, le32_to_cpu(adsp2_sizes->xm), 418 le32_to_cpu(adsp2_sizes->ym), 419 le32_to_cpu(adsp2_sizes->pm), 420 le32_to_cpu(adsp2_sizes->zm)); 421 break; 422 423 default: 424 BUG_ON(NULL == "Unknown DSP type"); 425 goto out_fw; 426 } 427 428 if (le32_to_cpu(header->len) != sizeof(*header) + 429 sizes + sizeof(*footer)) { 430 adsp_err(dsp, "%s: unexpected header length %d\n", 431 file, le32_to_cpu(header->len)); 432 goto out_fw; 433 } 434 435 adsp_dbg(dsp, "%s: timestamp %llu\n", file, 436 le64_to_cpu(footer->timestamp)); 437 438 while (pos < firmware->size && 439 pos - firmware->size > sizeof(*region)) { 440 region = (void *)&(firmware->data[pos]); 441 region_name = "Unknown"; 442 reg = 0; 443 text = NULL; 444 offset = le32_to_cpu(region->offset) & 0xffffff; 445 type = be32_to_cpu(region->type) & 0xff; 446 mem = wm_adsp_find_region(dsp, type); 447 448 switch (type) { 449 case WMFW_NAME_TEXT: 450 region_name = "Firmware name"; 451 text = kzalloc(le32_to_cpu(region->len) + 1, 452 GFP_KERNEL); 453 break; 454 case WMFW_INFO_TEXT: 455 region_name = "Information"; 456 text = kzalloc(le32_to_cpu(region->len) + 1, 457 GFP_KERNEL); 458 break; 459 case WMFW_ABSOLUTE: 460 region_name = "Absolute"; 461 reg = offset; 462 break; 463 case WMFW_ADSP1_PM: 464 BUG_ON(!mem); 465 region_name = "PM"; 466 reg = wm_adsp_region_to_reg(mem, offset); 467 break; 468 case WMFW_ADSP1_DM: 469 BUG_ON(!mem); 470 region_name = "DM"; 471 reg = wm_adsp_region_to_reg(mem, offset); 472 break; 473 case WMFW_ADSP2_XM: 474 BUG_ON(!mem); 475 region_name = "XM"; 476 reg = wm_adsp_region_to_reg(mem, offset); 477 break; 478 case WMFW_ADSP2_YM: 479 BUG_ON(!mem); 480 region_name = "YM"; 481 reg = wm_adsp_region_to_reg(mem, offset); 482 break; 483 case WMFW_ADSP1_ZM: 484 BUG_ON(!mem); 485 region_name = "ZM"; 486 reg = wm_adsp_region_to_reg(mem, offset); 487 break; 488 default: 489 adsp_warn(dsp, 490 "%s.%d: Unknown region type %x at %d(%x)\n", 491 file, regions, type, pos, pos); 492 break; 493 } 494 495 adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file, 496 regions, le32_to_cpu(region->len), offset, 497 region_name); 498 499 if (text) { 500 memcpy(text, region->data, le32_to_cpu(region->len)); 501 adsp_info(dsp, "%s: %s\n", file, text); 502 kfree(text); 503 } 504 505 if (reg) { 506 buf = wm_adsp_buf_alloc(region->data, 507 le32_to_cpu(region->len), 508 &buf_list); 509 if (!buf) { 510 adsp_err(dsp, "Out of memory\n"); 511 return -ENOMEM; 512 } 513 514 ret = regmap_raw_write_async(regmap, reg, buf->buf, 515 le32_to_cpu(region->len)); 516 if (ret != 0) { 517 adsp_err(dsp, 518 "%s.%d: Failed to write %d bytes at %d in %s: %d\n", 519 file, regions, 520 le32_to_cpu(region->len), offset, 521 region_name, ret); 522 goto out_fw; 523 } 524 } 525 526 pos += le32_to_cpu(region->len) + sizeof(*region); 527 regions++; 528 } 529 530 ret = regmap_async_complete(regmap); 531 if (ret != 0) { 532 adsp_err(dsp, "Failed to complete async write: %d\n", ret); 533 goto out_fw; 534 } 535 536 if (pos > firmware->size) 537 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 538 file, regions, pos - firmware->size); 539 540 out_fw: 541 regmap_async_complete(regmap); 542 wm_adsp_buf_free(&buf_list); 543 release_firmware(firmware); 544 out: 545 kfree(file); 546 547 return ret; 548 } 549 550 static int wm_adsp_setup_algs(struct wm_adsp *dsp) 551 { 552 struct regmap *regmap = dsp->regmap; 553 struct wmfw_adsp1_id_hdr adsp1_id; 554 struct wmfw_adsp2_id_hdr adsp2_id; 555 struct wmfw_adsp1_alg_hdr *adsp1_alg; 556 struct wmfw_adsp2_alg_hdr *adsp2_alg; 557 void *alg, *buf; 558 struct wm_adsp_alg_region *region; 559 const struct wm_adsp_region *mem; 560 unsigned int pos, term; 561 size_t algs, buf_size; 562 __be32 val; 563 int i, ret; 564 565 switch (dsp->type) { 566 case WMFW_ADSP1: 567 mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM); 568 break; 569 case WMFW_ADSP2: 570 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); 571 break; 572 default: 573 mem = NULL; 574 break; 575 } 576 577 if (mem == NULL) { 578 BUG_ON(mem != NULL); 579 return -EINVAL; 580 } 581 582 switch (dsp->type) { 583 case WMFW_ADSP1: 584 ret = regmap_raw_read(regmap, mem->base, &adsp1_id, 585 sizeof(adsp1_id)); 586 if (ret != 0) { 587 adsp_err(dsp, "Failed to read algorithm info: %d\n", 588 ret); 589 return ret; 590 } 591 592 buf = &adsp1_id; 593 buf_size = sizeof(adsp1_id); 594 595 algs = be32_to_cpu(adsp1_id.algs); 596 dsp->fw_id = be32_to_cpu(adsp1_id.fw.id); 597 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", 598 dsp->fw_id, 599 (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16, 600 (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8, 601 be32_to_cpu(adsp1_id.fw.ver) & 0xff, 602 algs); 603 604 region = kzalloc(sizeof(*region), GFP_KERNEL); 605 if (!region) 606 return -ENOMEM; 607 region->type = WMFW_ADSP1_ZM; 608 region->alg = be32_to_cpu(adsp1_id.fw.id); 609 region->base = be32_to_cpu(adsp1_id.zm); 610 list_add_tail(®ion->list, &dsp->alg_regions); 611 612 region = kzalloc(sizeof(*region), GFP_KERNEL); 613 if (!region) 614 return -ENOMEM; 615 region->type = WMFW_ADSP1_DM; 616 region->alg = be32_to_cpu(adsp1_id.fw.id); 617 region->base = be32_to_cpu(adsp1_id.dm); 618 list_add_tail(®ion->list, &dsp->alg_regions); 619 620 pos = sizeof(adsp1_id) / 2; 621 term = pos + ((sizeof(*adsp1_alg) * algs) / 2); 622 break; 623 624 case WMFW_ADSP2: 625 ret = regmap_raw_read(regmap, mem->base, &adsp2_id, 626 sizeof(adsp2_id)); 627 if (ret != 0) { 628 adsp_err(dsp, "Failed to read algorithm info: %d\n", 629 ret); 630 return ret; 631 } 632 633 buf = &adsp2_id; 634 buf_size = sizeof(adsp2_id); 635 636 algs = be32_to_cpu(adsp2_id.algs); 637 dsp->fw_id = be32_to_cpu(adsp2_id.fw.id); 638 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", 639 dsp->fw_id, 640 (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16, 641 (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8, 642 be32_to_cpu(adsp2_id.fw.ver) & 0xff, 643 algs); 644 645 region = kzalloc(sizeof(*region), GFP_KERNEL); 646 if (!region) 647 return -ENOMEM; 648 region->type = WMFW_ADSP2_XM; 649 region->alg = be32_to_cpu(adsp2_id.fw.id); 650 region->base = be32_to_cpu(adsp2_id.xm); 651 list_add_tail(®ion->list, &dsp->alg_regions); 652 653 region = kzalloc(sizeof(*region), GFP_KERNEL); 654 if (!region) 655 return -ENOMEM; 656 region->type = WMFW_ADSP2_YM; 657 region->alg = be32_to_cpu(adsp2_id.fw.id); 658 region->base = be32_to_cpu(adsp2_id.ym); 659 list_add_tail(®ion->list, &dsp->alg_regions); 660 661 region = kzalloc(sizeof(*region), GFP_KERNEL); 662 if (!region) 663 return -ENOMEM; 664 region->type = WMFW_ADSP2_ZM; 665 region->alg = be32_to_cpu(adsp2_id.fw.id); 666 region->base = be32_to_cpu(adsp2_id.zm); 667 list_add_tail(®ion->list, &dsp->alg_regions); 668 669 pos = sizeof(adsp2_id) / 2; 670 term = pos + ((sizeof(*adsp2_alg) * algs) / 2); 671 break; 672 673 default: 674 BUG_ON(NULL == "Unknown DSP type"); 675 return -EINVAL; 676 } 677 678 if (algs == 0) { 679 adsp_err(dsp, "No algorithms\n"); 680 return -EINVAL; 681 } 682 683 if (algs > 1024) { 684 adsp_err(dsp, "Algorithm count %zx excessive\n", algs); 685 print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET, 686 buf, buf_size); 687 return -EINVAL; 688 } 689 690 /* Read the terminator first to validate the length */ 691 ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val)); 692 if (ret != 0) { 693 adsp_err(dsp, "Failed to read algorithm list end: %d\n", 694 ret); 695 return ret; 696 } 697 698 if (be32_to_cpu(val) != 0xbedead) 699 adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", 700 term, be32_to_cpu(val)); 701 702 alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA); 703 if (!alg) 704 return -ENOMEM; 705 706 ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2); 707 if (ret != 0) { 708 adsp_err(dsp, "Failed to read algorithm list: %d\n", 709 ret); 710 goto out; 711 } 712 713 adsp1_alg = alg; 714 adsp2_alg = alg; 715 716 for (i = 0; i < algs; i++) { 717 switch (dsp->type) { 718 case WMFW_ADSP1: 719 adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", 720 i, be32_to_cpu(adsp1_alg[i].alg.id), 721 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, 722 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, 723 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, 724 be32_to_cpu(adsp1_alg[i].dm), 725 be32_to_cpu(adsp1_alg[i].zm)); 726 727 region = kzalloc(sizeof(*region), GFP_KERNEL); 728 if (!region) 729 return -ENOMEM; 730 region->type = WMFW_ADSP1_DM; 731 region->alg = be32_to_cpu(adsp1_alg[i].alg.id); 732 region->base = be32_to_cpu(adsp1_alg[i].dm); 733 list_add_tail(®ion->list, &dsp->alg_regions); 734 735 region = kzalloc(sizeof(*region), GFP_KERNEL); 736 if (!region) 737 return -ENOMEM; 738 region->type = WMFW_ADSP1_ZM; 739 region->alg = be32_to_cpu(adsp1_alg[i].alg.id); 740 region->base = be32_to_cpu(adsp1_alg[i].zm); 741 list_add_tail(®ion->list, &dsp->alg_regions); 742 break; 743 744 case WMFW_ADSP2: 745 adsp_info(dsp, 746 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", 747 i, be32_to_cpu(adsp2_alg[i].alg.id), 748 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, 749 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, 750 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, 751 be32_to_cpu(adsp2_alg[i].xm), 752 be32_to_cpu(adsp2_alg[i].ym), 753 be32_to_cpu(adsp2_alg[i].zm)); 754 755 region = kzalloc(sizeof(*region), GFP_KERNEL); 756 if (!region) 757 return -ENOMEM; 758 region->type = WMFW_ADSP2_XM; 759 region->alg = be32_to_cpu(adsp2_alg[i].alg.id); 760 region->base = be32_to_cpu(adsp2_alg[i].xm); 761 list_add_tail(®ion->list, &dsp->alg_regions); 762 763 region = kzalloc(sizeof(*region), GFP_KERNEL); 764 if (!region) 765 return -ENOMEM; 766 region->type = WMFW_ADSP2_YM; 767 region->alg = be32_to_cpu(adsp2_alg[i].alg.id); 768 region->base = be32_to_cpu(adsp2_alg[i].ym); 769 list_add_tail(®ion->list, &dsp->alg_regions); 770 771 region = kzalloc(sizeof(*region), GFP_KERNEL); 772 if (!region) 773 return -ENOMEM; 774 region->type = WMFW_ADSP2_ZM; 775 region->alg = be32_to_cpu(adsp2_alg[i].alg.id); 776 region->base = be32_to_cpu(adsp2_alg[i].zm); 777 list_add_tail(®ion->list, &dsp->alg_regions); 778 break; 779 } 780 } 781 782 out: 783 kfree(alg); 784 return ret; 785 } 786 787 static int wm_adsp_load_coeff(struct wm_adsp *dsp) 788 { 789 LIST_HEAD(buf_list); 790 struct regmap *regmap = dsp->regmap; 791 struct wmfw_coeff_hdr *hdr; 792 struct wmfw_coeff_item *blk; 793 const struct firmware *firmware; 794 const struct wm_adsp_region *mem; 795 struct wm_adsp_alg_region *alg_region; 796 const char *region_name; 797 int ret, pos, blocks, type, offset, reg; 798 char *file; 799 struct wm_adsp_buf *buf; 800 int tmp; 801 802 file = kzalloc(PAGE_SIZE, GFP_KERNEL); 803 if (file == NULL) 804 return -ENOMEM; 805 806 snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num, 807 wm_adsp_fw[dsp->fw].file); 808 file[PAGE_SIZE - 1] = '\0'; 809 810 ret = request_firmware(&firmware, file, dsp->dev); 811 if (ret != 0) { 812 adsp_warn(dsp, "Failed to request '%s'\n", file); 813 ret = 0; 814 goto out; 815 } 816 ret = -EINVAL; 817 818 if (sizeof(*hdr) >= firmware->size) { 819 adsp_err(dsp, "%s: file too short, %zu bytes\n", 820 file, firmware->size); 821 goto out_fw; 822 } 823 824 hdr = (void*)&firmware->data[0]; 825 if (memcmp(hdr->magic, "WMDR", 4) != 0) { 826 adsp_err(dsp, "%s: invalid magic\n", file); 827 goto out_fw; 828 } 829 830 switch (be32_to_cpu(hdr->rev) & 0xff) { 831 case 1: 832 break; 833 default: 834 adsp_err(dsp, "%s: Unsupported coefficient file format %d\n", 835 file, be32_to_cpu(hdr->rev) & 0xff); 836 ret = -EINVAL; 837 goto out_fw; 838 } 839 840 adsp_dbg(dsp, "%s: v%d.%d.%d\n", file, 841 (le32_to_cpu(hdr->ver) >> 16) & 0xff, 842 (le32_to_cpu(hdr->ver) >> 8) & 0xff, 843 le32_to_cpu(hdr->ver) & 0xff); 844 845 pos = le32_to_cpu(hdr->len); 846 847 blocks = 0; 848 while (pos < firmware->size && 849 pos - firmware->size > sizeof(*blk)) { 850 blk = (void*)(&firmware->data[pos]); 851 852 type = le16_to_cpu(blk->type); 853 offset = le16_to_cpu(blk->offset); 854 855 adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", 856 file, blocks, le32_to_cpu(blk->id), 857 (le32_to_cpu(blk->ver) >> 16) & 0xff, 858 (le32_to_cpu(blk->ver) >> 8) & 0xff, 859 le32_to_cpu(blk->ver) & 0xff); 860 adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n", 861 file, blocks, le32_to_cpu(blk->len), offset, type); 862 863 reg = 0; 864 region_name = "Unknown"; 865 switch (type) { 866 case (WMFW_NAME_TEXT << 8): 867 case (WMFW_INFO_TEXT << 8): 868 break; 869 case (WMFW_ABSOLUTE << 8): 870 /* 871 * Old files may use this for global 872 * coefficients. 873 */ 874 if (le32_to_cpu(blk->id) == dsp->fw_id && 875 offset == 0) { 876 region_name = "global coefficients"; 877 mem = wm_adsp_find_region(dsp, type); 878 if (!mem) { 879 adsp_err(dsp, "No ZM\n"); 880 break; 881 } 882 reg = wm_adsp_region_to_reg(mem, 0); 883 884 } else { 885 region_name = "register"; 886 reg = offset; 887 } 888 break; 889 890 case WMFW_ADSP1_DM: 891 case WMFW_ADSP1_ZM: 892 case WMFW_ADSP2_XM: 893 case WMFW_ADSP2_YM: 894 adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", 895 file, blocks, le32_to_cpu(blk->len), 896 type, le32_to_cpu(blk->id)); 897 898 mem = wm_adsp_find_region(dsp, type); 899 if (!mem) { 900 adsp_err(dsp, "No base for region %x\n", type); 901 break; 902 } 903 904 reg = 0; 905 list_for_each_entry(alg_region, 906 &dsp->alg_regions, list) { 907 if (le32_to_cpu(blk->id) == alg_region->alg && 908 type == alg_region->type) { 909 reg = alg_region->base; 910 reg = wm_adsp_region_to_reg(mem, 911 reg); 912 reg += offset; 913 } 914 } 915 916 if (reg == 0) 917 adsp_err(dsp, "No %x for algorithm %x\n", 918 type, le32_to_cpu(blk->id)); 919 break; 920 921 default: 922 adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n", 923 file, blocks, type, pos); 924 break; 925 } 926 927 if (reg) { 928 buf = wm_adsp_buf_alloc(blk->data, 929 le32_to_cpu(blk->len), 930 &buf_list); 931 if (!buf) { 932 adsp_err(dsp, "Out of memory\n"); 933 ret = -ENOMEM; 934 goto out_fw; 935 } 936 937 adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", 938 file, blocks, le32_to_cpu(blk->len), 939 reg); 940 ret = regmap_raw_write_async(regmap, reg, buf->buf, 941 le32_to_cpu(blk->len)); 942 if (ret != 0) { 943 adsp_err(dsp, 944 "%s.%d: Failed to write to %x in %s\n", 945 file, blocks, reg, region_name); 946 } 947 } 948 949 tmp = le32_to_cpu(blk->len) % 4; 950 if (tmp) 951 pos += le32_to_cpu(blk->len) + (4 - tmp) + sizeof(*blk); 952 else 953 pos += le32_to_cpu(blk->len) + sizeof(*blk); 954 955 blocks++; 956 } 957 958 ret = regmap_async_complete(regmap); 959 if (ret != 0) 960 adsp_err(dsp, "Failed to complete async write: %d\n", ret); 961 962 if (pos > firmware->size) 963 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 964 file, blocks, pos - firmware->size); 965 966 out_fw: 967 release_firmware(firmware); 968 wm_adsp_buf_free(&buf_list); 969 out: 970 kfree(file); 971 return ret; 972 } 973 974 int wm_adsp1_init(struct wm_adsp *adsp) 975 { 976 INIT_LIST_HEAD(&adsp->alg_regions); 977 978 return 0; 979 } 980 EXPORT_SYMBOL_GPL(wm_adsp1_init); 981 982 int wm_adsp1_event(struct snd_soc_dapm_widget *w, 983 struct snd_kcontrol *kcontrol, 984 int event) 985 { 986 struct snd_soc_codec *codec = w->codec; 987 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); 988 struct wm_adsp *dsp = &dsps[w->shift]; 989 int ret; 990 int val; 991 992 switch (event) { 993 case SND_SOC_DAPM_POST_PMU: 994 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 995 ADSP1_SYS_ENA, ADSP1_SYS_ENA); 996 997 /* 998 * For simplicity set the DSP clock rate to be the 999 * SYSCLK rate rather than making it configurable. 1000 */ 1001 if(dsp->sysclk_reg) { 1002 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); 1003 if (ret != 0) { 1004 adsp_err(dsp, "Failed to read SYSCLK state: %d\n", 1005 ret); 1006 return ret; 1007 } 1008 1009 val = (val & dsp->sysclk_mask) 1010 >> dsp->sysclk_shift; 1011 1012 ret = regmap_update_bits(dsp->regmap, 1013 dsp->base + ADSP1_CONTROL_31, 1014 ADSP1_CLK_SEL_MASK, val); 1015 if (ret != 0) { 1016 adsp_err(dsp, "Failed to set clock rate: %d\n", 1017 ret); 1018 return ret; 1019 } 1020 } 1021 1022 ret = wm_adsp_load(dsp); 1023 if (ret != 0) 1024 goto err; 1025 1026 ret = wm_adsp_setup_algs(dsp); 1027 if (ret != 0) 1028 goto err; 1029 1030 ret = wm_adsp_load_coeff(dsp); 1031 if (ret != 0) 1032 goto err; 1033 1034 /* Start the core running */ 1035 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1036 ADSP1_CORE_ENA | ADSP1_START, 1037 ADSP1_CORE_ENA | ADSP1_START); 1038 break; 1039 1040 case SND_SOC_DAPM_PRE_PMD: 1041 /* Halt the core */ 1042 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1043 ADSP1_CORE_ENA | ADSP1_START, 0); 1044 1045 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, 1046 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0); 1047 1048 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1049 ADSP1_SYS_ENA, 0); 1050 break; 1051 1052 default: 1053 break; 1054 } 1055 1056 return 0; 1057 1058 err: 1059 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1060 ADSP1_SYS_ENA, 0); 1061 return ret; 1062 } 1063 EXPORT_SYMBOL_GPL(wm_adsp1_event); 1064 1065 static int wm_adsp2_ena(struct wm_adsp *dsp) 1066 { 1067 unsigned int val; 1068 int ret, count; 1069 1070 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 1071 ADSP2_SYS_ENA, ADSP2_SYS_ENA); 1072 if (ret != 0) 1073 return ret; 1074 1075 /* Wait for the RAM to start, should be near instantaneous */ 1076 count = 0; 1077 do { 1078 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, 1079 &val); 1080 if (ret != 0) 1081 return ret; 1082 } while (!(val & ADSP2_RAM_RDY) && ++count < 10); 1083 1084 if (!(val & ADSP2_RAM_RDY)) { 1085 adsp_err(dsp, "Failed to start DSP RAM\n"); 1086 return -EBUSY; 1087 } 1088 1089 adsp_dbg(dsp, "RAM ready after %d polls\n", count); 1090 adsp_info(dsp, "RAM ready after %d polls\n", count); 1091 1092 return 0; 1093 } 1094 1095 int wm_adsp2_event(struct snd_soc_dapm_widget *w, 1096 struct snd_kcontrol *kcontrol, int event) 1097 { 1098 struct snd_soc_codec *codec = w->codec; 1099 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); 1100 struct wm_adsp *dsp = &dsps[w->shift]; 1101 struct wm_adsp_alg_region *alg_region; 1102 unsigned int val; 1103 int ret; 1104 1105 switch (event) { 1106 case SND_SOC_DAPM_POST_PMU: 1107 /* 1108 * For simplicity set the DSP clock rate to be the 1109 * SYSCLK rate rather than making it configurable. 1110 */ 1111 ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val); 1112 if (ret != 0) { 1113 adsp_err(dsp, "Failed to read SYSCLK state: %d\n", 1114 ret); 1115 return ret; 1116 } 1117 val = (val & ARIZONA_SYSCLK_FREQ_MASK) 1118 >> ARIZONA_SYSCLK_FREQ_SHIFT; 1119 1120 ret = regmap_update_bits(dsp->regmap, 1121 dsp->base + ADSP2_CLOCKING, 1122 ADSP2_CLK_SEL_MASK, val); 1123 if (ret != 0) { 1124 adsp_err(dsp, "Failed to set clock rate: %d\n", 1125 ret); 1126 return ret; 1127 } 1128 1129 if (dsp->dvfs) { 1130 ret = regmap_read(dsp->regmap, 1131 dsp->base + ADSP2_CLOCKING, &val); 1132 if (ret != 0) { 1133 dev_err(dsp->dev, 1134 "Failed to read clocking: %d\n", ret); 1135 return ret; 1136 } 1137 1138 if ((val & ADSP2_CLK_SEL_MASK) >= 3) { 1139 ret = regulator_enable(dsp->dvfs); 1140 if (ret != 0) { 1141 dev_err(dsp->dev, 1142 "Failed to enable supply: %d\n", 1143 ret); 1144 return ret; 1145 } 1146 1147 ret = regulator_set_voltage(dsp->dvfs, 1148 1800000, 1149 1800000); 1150 if (ret != 0) { 1151 dev_err(dsp->dev, 1152 "Failed to raise supply: %d\n", 1153 ret); 1154 return ret; 1155 } 1156 } 1157 } 1158 1159 ret = wm_adsp2_ena(dsp); 1160 if (ret != 0) 1161 return ret; 1162 1163 ret = wm_adsp_load(dsp); 1164 if (ret != 0) 1165 goto err; 1166 1167 ret = wm_adsp_setup_algs(dsp); 1168 if (ret != 0) 1169 goto err; 1170 1171 ret = wm_adsp_load_coeff(dsp); 1172 if (ret != 0) 1173 goto err; 1174 1175 ret = regmap_update_bits(dsp->regmap, 1176 dsp->base + ADSP2_CONTROL, 1177 ADSP2_CORE_ENA | ADSP2_START, 1178 ADSP2_CORE_ENA | ADSP2_START); 1179 if (ret != 0) 1180 goto err; 1181 1182 dsp->running = true; 1183 break; 1184 1185 case SND_SOC_DAPM_PRE_PMD: 1186 dsp->running = false; 1187 1188 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 1189 ADSP2_SYS_ENA | ADSP2_CORE_ENA | 1190 ADSP2_START, 0); 1191 1192 /* Make sure DMAs are quiesced */ 1193 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); 1194 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); 1195 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); 1196 1197 if (dsp->dvfs) { 1198 ret = regulator_set_voltage(dsp->dvfs, 1200000, 1199 1800000); 1200 if (ret != 0) 1201 dev_warn(dsp->dev, 1202 "Failed to lower supply: %d\n", 1203 ret); 1204 1205 ret = regulator_disable(dsp->dvfs); 1206 if (ret != 0) 1207 dev_err(dsp->dev, 1208 "Failed to enable supply: %d\n", 1209 ret); 1210 } 1211 1212 while (!list_empty(&dsp->alg_regions)) { 1213 alg_region = list_first_entry(&dsp->alg_regions, 1214 struct wm_adsp_alg_region, 1215 list); 1216 list_del(&alg_region->list); 1217 kfree(alg_region); 1218 } 1219 break; 1220 1221 default: 1222 break; 1223 } 1224 1225 return 0; 1226 err: 1227 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 1228 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); 1229 return ret; 1230 } 1231 EXPORT_SYMBOL_GPL(wm_adsp2_event); 1232 1233 int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) 1234 { 1235 int ret; 1236 1237 /* 1238 * Disable the DSP memory by default when in reset for a small 1239 * power saving. 1240 */ 1241 ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL, 1242 ADSP2_MEM_ENA, 0); 1243 if (ret != 0) { 1244 adsp_err(adsp, "Failed to clear memory retention: %d\n", ret); 1245 return ret; 1246 } 1247 1248 INIT_LIST_HEAD(&adsp->alg_regions); 1249 1250 if (dvfs) { 1251 adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); 1252 if (IS_ERR(adsp->dvfs)) { 1253 ret = PTR_ERR(adsp->dvfs); 1254 dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret); 1255 return ret; 1256 } 1257 1258 ret = regulator_enable(adsp->dvfs); 1259 if (ret != 0) { 1260 dev_err(adsp->dev, "Failed to enable DCVDD: %d\n", 1261 ret); 1262 return ret; 1263 } 1264 1265 ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000); 1266 if (ret != 0) { 1267 dev_err(adsp->dev, "Failed to initialise DVFS: %d\n", 1268 ret); 1269 return ret; 1270 } 1271 1272 ret = regulator_disable(adsp->dvfs); 1273 if (ret != 0) { 1274 dev_err(adsp->dev, "Failed to disable DCVDD: %d\n", 1275 ret); 1276 return ret; 1277 } 1278 } 1279 1280 return 0; 1281 } 1282 EXPORT_SYMBOL_GPL(wm_adsp2_init); 1283